@deepseek-harness-tui/dsh-tui 0.8.4 → 0.8.6
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/lib/types/activityPrefs.d.ts +10 -0
- package/lib/types/activityPrefs.d.ts.map +1 -1
- package/lib/types/activityPrefs.js +17 -0
- package/lib/types/cc/figures.d.ts +7 -0
- package/lib/types/cc/figures.d.ts.map +1 -1
- package/lib/types/cc/figures.js +23 -0
- package/lib/types/cc/markdown.d.ts.map +1 -1
- package/lib/types/cc/markdown.js +47 -14
- package/lib/types/cc/syntaxTheme.d.ts +12 -0
- package/lib/types/cc/syntaxTheme.d.ts.map +1 -0
- package/lib/types/cc/syntaxTheme.js +76 -0
- package/lib/types/components/EffortChargeGlyph.d.ts +26 -0
- package/lib/types/components/EffortChargeGlyph.d.ts.map +1 -0
- package/lib/types/components/EffortChargeGlyph.js +70 -0
- package/lib/types/components/EffortInputBorder.d.ts +36 -0
- package/lib/types/components/EffortInputBorder.d.ts.map +1 -0
- package/lib/types/components/EffortInputBorder.js +73 -0
- package/lib/types/components/EffortTierBadge.d.ts +26 -0
- package/lib/types/components/EffortTierBadge.d.ts.map +1 -0
- package/lib/types/components/EffortTierBadge.js +97 -0
- package/lib/types/components/LoadedContextPanel.js +1 -1
- package/lib/types/components/MessageList.d.ts +4 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +9 -11
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +8 -3
- package/lib/types/components/SplitDiffView.d.ts +4 -5
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +18 -65
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +10 -2
- package/lib/types/components/activityFrames.d.ts +7 -28
- package/lib/types/components/activityFrames.d.ts.map +1 -1
- package/lib/types/components/activityFrames.js +7 -94
- package/lib/types/components/design-system/ThemedBox.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemedBox.js +4 -1
- package/lib/types/components/design-system/ThemedText.js +2 -2
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +12 -6
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +25 -9
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +4 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +45 -17
- package/lib/types/components/messages/UserPromptMessage.d.ts +4 -6
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +5 -9
- package/lib/types/dsh-adapter/channel.d.ts +22 -0
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +204 -19
- package/lib/types/dsh-adapter/index.d.ts +5 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +19 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +176 -4
- package/lib/types/dsh-adapter/settings-sections.d.ts +13 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +31 -6
- package/lib/types/ink/ink.d.ts +9 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +24 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +35 -6
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +109 -50
- package/lib/types/screens/StatusLine.d.ts +8 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +62 -39
- package/lib/types/settings-sections.d.ts +1 -1
- package/lib/types/settings-sections.d.ts.map +1 -1
- package/lib/types/theme.d.ts +12 -0
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +51 -21
- package/lib/types/tips.js +2 -2
- package/lib/types/trajectory/effortIgnition.d.ts +66 -0
- package/lib/types/trajectory/effortIgnition.d.ts.map +1 -0
- package/lib/types/trajectory/effortIgnition.js +142 -0
- package/lib/types/tuiDisplayPrefs.d.ts +47 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -0
- package/lib/types/tuiDisplayPrefs.js +60 -0
- package/package.json +6 -3
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* EffortTierBadge — 输入行尾的档位字样徽标:三幕点焰的第二幕载体
|
|
4
|
+
* (与 EffortInputBorder 的双框扫光同一时间轴、同一触发),切到最高
|
|
5
|
+
* 思考强度档时光带行至中段,输入行居中浮现档名(当前档名大写,字母间距从
|
|
6
|
+
* 10 个空格减速聚拢到 1 个——连续位置逐字母取整保证帧帧有移动,
|
|
7
|
+
* 明亮蓝加粗,由暗渐亮),随后随图层整体渐隐让位——行数恒定,静
|
|
8
|
+
* 止时完全不渲染;输入行有文字时不显示(绝不遮挡内容)。
|
|
9
|
+
*
|
|
10
|
+
* 触发判定在渲染期做(props-变化-调整模式,与边框/充能组件同模
|
|
11
|
+
* 式);冷启动恢复偏好/单档表/无档位表/无共享时钟均不触发。时钟
|
|
12
|
+
* 复用 Ink core 共享时钟,仅动画窗口订阅(keepAlive),播完归零。
|
|
13
|
+
*/
|
|
14
|
+
import { useContext, useEffect, useReducer, useState } from 'react';
|
|
15
|
+
import { Text } from '../ui.js';
|
|
16
|
+
import { ClockContext } from '../ink/components/ClockContext.js';
|
|
17
|
+
import { rgbString } from '../trajectory/motion.js';
|
|
18
|
+
import { IGNITION_TIMELINE, ignitionHues } from '../trajectory/effortIgnition.js';
|
|
19
|
+
/** 字母间距聚拢:从 10 个空格减速收敛到 1 个(ease-out,快收慢停)。 */
|
|
20
|
+
const GAP_START = 10;
|
|
21
|
+
const GAP_END = 1;
|
|
22
|
+
const CONVERGE_MS = 500;
|
|
23
|
+
export function EffortTierBadge({ effort, levels, onLight, columns, leadingColumns, }) {
|
|
24
|
+
const clock = useContext(ClockContext);
|
|
25
|
+
const [overlay, setOverlay] = useState(null);
|
|
26
|
+
const [prevEffort, setPrevEffort] = useState(effort);
|
|
27
|
+
const [, forceRender] = useReducer((tick) => tick + 1, 0);
|
|
28
|
+
// 渲染期触发(与边框/充能同模式):effort 变化的首帧就以新状态渲染。
|
|
29
|
+
if (effort !== prevEffort) {
|
|
30
|
+
setPrevEffort(effort);
|
|
31
|
+
if (clock !== null &&
|
|
32
|
+
effort !== undefined &&
|
|
33
|
+
levels !== undefined &&
|
|
34
|
+
levels.length > 1 &&
|
|
35
|
+
effort === levels[levels.length - 1]) {
|
|
36
|
+
setOverlay({ label: effort.toUpperCase(), startedAtMs: clock.now() });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const elapsedMs = overlay === null ? Infinity : Math.max(0, (clock?.now() ?? Date.now()) - overlay.startedAtMs);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (overlay === null || clock === null)
|
|
42
|
+
return;
|
|
43
|
+
return clock.subscribe(() => forceRender(), /* keepAlive */ true);
|
|
44
|
+
}, [overlay, clock]);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (overlay !== null && elapsedMs >= IGNITION_TIMELINE.fadeEndMs)
|
|
47
|
+
setOverlay(null);
|
|
48
|
+
}, [overlay, elapsedMs]);
|
|
49
|
+
if (overlay === null || elapsedMs < IGNITION_TIMELINE.labelStartMs)
|
|
50
|
+
return null;
|
|
51
|
+
const brighten = Math.min(1, (elapsedMs - IGNITION_TIMELINE.labelStartMs) / IGNITION_TIMELINE.labelBrightenMs);
|
|
52
|
+
const fade = elapsedMs < IGNITION_TIMELINE.fadeStartMs
|
|
53
|
+
? 1
|
|
54
|
+
: Math.max(0, 1 - (elapsedMs - IGNITION_TIMELINE.fadeStartMs) / (IGNITION_TIMELINE.fadeEndMs - IGNITION_TIMELINE.fadeStartMs));
|
|
55
|
+
const alpha = brighten * fade;
|
|
56
|
+
if (alpha <= 0)
|
|
57
|
+
return null;
|
|
58
|
+
const band = onLight ? { r: 240, g: 240, b: 242 } : { r: 27, g: 30, b: 40 };
|
|
59
|
+
// 明亮蓝:accent 混白 35% 提亮(用户拍板的高亮观感)。
|
|
60
|
+
const hue = ignitionHues(onLight)[0];
|
|
61
|
+
const whiten = (x) => Math.round(x + (255 - x) * 0.35);
|
|
62
|
+
const bright = { r: whiten(hue.r), g: whiten(hue.g), b: whiten(hue.b) };
|
|
63
|
+
const mix = (x, y) => Math.round(x + (y - x) * alpha);
|
|
64
|
+
const color = rgbString({ r: mix(band.r, bright.r), g: mix(band.g, bright.g), b: mix(band.b, bright.b) });
|
|
65
|
+
// 字母间距聚拢(Codex 的 converge 语义):间距是连续浮点,字母位置
|
|
66
|
+
// 以**行中心为锚**对称收缩——pos_i = center + (i-(n-1)/2)·(1+gap),
|
|
67
|
+
// 左右字母各向中心移动一半(奇数档名的居中字母原位不动),两侧速
|
|
68
|
+
// 度天然均衡;每字母独立按连续位置取整落列,不同字母在不同帧跨
|
|
69
|
+
// 格,每帧至少一个在动(把间距整体取整会让 ease-out 慢末段上百毫
|
|
70
|
+
// 秒才跨一格,看起来就是卡顿)。曲线混入 15% 线性做末段保底速度。
|
|
71
|
+
const progress = Math.min(1, Math.max(0, (elapsedMs - IGNITION_TIMELINE.labelStartMs) / CONVERGE_MS));
|
|
72
|
+
// 跳变间隔均匀化:离散格子上「减速」若靠曲线导数趋零实现,末段会
|
|
73
|
+
// 出现几十帧不动一格的长停顿再突跳(卡感来源)。改为 90% 线性 +
|
|
74
|
+
// 10% easeOutQuad 的轻缓收尾——跳变间隔全程近似恒定(约 55ms/格),
|
|
75
|
+
// 仅末端轻微放慢,终端上的观感是均匀顺滑的聚拢。
|
|
76
|
+
const eased = 1 - progress;
|
|
77
|
+
const easedWithFloor = 0.9 * eased + 0.1 * (1 - progress * progress);
|
|
78
|
+
const gapF = GAP_END + (GAP_START - GAP_END) * easedWithFloor;
|
|
79
|
+
const letterCount = overlay.label.length;
|
|
80
|
+
// 锚点是**终端几何中心**(不是 ❯/光标之后可用区的中心——那会整体
|
|
81
|
+
// 偏右约 1.5 格;可用区起点在左,其"中点"不含左部占位)。左右字母
|
|
82
|
+
// 严格镜像——Math.round 对 .5 恒向上,正负方向舍入不对称会让跨格
|
|
83
|
+
// 时刻错开;左字母的落列由右字母的舍入结果镜像得出(2C − col),
|
|
84
|
+
// M/X 每次同帧反向同跳,全程对称于终端中心。
|
|
85
|
+
const C = Math.round((columns - 1) / 2) - leadingColumns;
|
|
86
|
+
let spaced = '';
|
|
87
|
+
let column = 0;
|
|
88
|
+
for (let i = 0; i < letterCount; i++) {
|
|
89
|
+
const off = (i - (letterCount - 1) / 2) * (1 + gapF);
|
|
90
|
+
const at = off >= 0
|
|
91
|
+
? Math.round(C + off)
|
|
92
|
+
: 2 * C - Math.round(C - off);
|
|
93
|
+
spaced += ' '.repeat(Math.max(0, at - column)) + overlay.label[i];
|
|
94
|
+
column = at + 1;
|
|
95
|
+
}
|
|
96
|
+
return (_jsx(Text, { bold: true, color: color, children: spaced }));
|
|
97
|
+
}
|
|
@@ -26,5 +26,5 @@ export function LoadedContextPanel({ context, open, onToggle, }) {
|
|
|
26
26
|
const summary = summarizeLoadedContext(context);
|
|
27
27
|
if (summary === '')
|
|
28
28
|
return null;
|
|
29
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [_jsx(Box, { paddingX: 1, backgroundColor: open ? '
|
|
29
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [_jsx(Box, { paddingX: 1, backgroundColor: open ? 'userMessageBackgroundHover' : undefined, children: _jsxs(Text, { bold: open, wrap: "truncate", children: [open ? '▼' : '▶', " ", _jsxs(Text, { dimColor: true, children: ["\uFF08Ctrl+P", open ? t('context-panel-collapse') : t('context-panel-expand'), "\uFF09"] }), " ", t('context-loaded'), " \u00B7 ", summary] }) }), open && (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [context.sections.length > 0 && (_jsx(Group, { title: t('context-panel-sections', { n: context.sections.length }), children: context.sections.map(section => (_jsx(Entry, { entry: section }, section.name))) })), context.files.length > 0 && (_jsx(Group, { title: t('context-panel-files', { n: context.files.length }), children: context.files.map(file => (_jsx(Text, { dimColor: true, children: file.displayPath }, file.displayPath))) })), context.contexts.length > 0 && (_jsx(Group, { title: t('context-panel-runtime', { n: context.contexts.length }), children: context.contexts.map(entry => (_jsx(Entry, { entry: entry }, entry.name))) })), context.skills.length > 0 && (_jsx(Group, { title: t('context-panel-skills', { n: context.skills.length }), children: context.skills.map(skill => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, dimColor: true, children: skill.name }), _jsx(Text, { dimColor: true, wrap: "wrap", children: skill.description })] }, skill.name))) })), context.tools.length > 0 && (_jsx(Group, { title: t('context-panel-tools', { n: context.tools.length }), children: context.tools.map(tool => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, dimColor: true, children: tool.name }), _jsx(Text, { dimColor: true, wrap: "wrap", children: truncateContextText(tool.description, 160) })] }, tool.name))) })), _jsx(Text, { dimColor: true, children: "\u00B7 /context" })] }))] }));
|
|
30
30
|
}
|
|
@@ -2,7 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { type ScrollBoxHandle } from '../ui.js';
|
|
3
3
|
import type { ChatRow } from '../dsh-adapter/channel.js';
|
|
4
4
|
import type { DOMElement } from '../ink/dom.js';
|
|
5
|
-
|
|
5
|
+
import type { ToolBackground } from '../tuiDisplayPrefs.js';
|
|
6
|
+
export declare function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout, thinkingFold, toolBackground, showAll, onToggleAll, onLoadOlder, thinkingVisible, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }: {
|
|
6
7
|
rows: readonly ChatRow[];
|
|
7
8
|
expanded: boolean;
|
|
8
9
|
expandedRows: ReadonlySet<number>;
|
|
@@ -13,6 +14,8 @@ export declare function MessageList({ rows, expanded, expandedRows, selectedId,
|
|
|
13
14
|
diffLayout?: 'auto' | 'split' | 'unified';
|
|
14
15
|
/** Thinking-block display mode from channel (`preview`/`full`). */
|
|
15
16
|
thinkingFold?: 'preview' | 'full';
|
|
17
|
+
/** Tool-card background treatment from the live channel settings. */
|
|
18
|
+
toolBackground?: ToolBackground;
|
|
16
19
|
showAll: boolean;
|
|
17
20
|
onToggleAll: () => void;
|
|
18
21
|
/** Restore folded-away older rows from the session log (CC-style "load
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAyC,MAAM,2BAA2B,CAAA;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAyC,MAAM,2BAA2B,CAAA;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAa/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AA2B3D,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,UAAmB,EACnB,YAAwB,EACxB,cAAuB,EACvB,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAsB,EACtB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC,mEAAmE;IACnE,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,qEAAqE;IACrE,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB;2EACuE;IACvE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/D,oDAAoD;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACrC,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,qBA8VA;AAsRD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,KAAK,CAAC,SAAS,CAMlB"}
|
|
@@ -17,7 +17,7 @@ import { truncateToWidth } from '../ink/truncateToWidth.js';
|
|
|
17
17
|
/**
|
|
18
18
|
* Transcript rows rendered in the Claude Code visual language: user prompts
|
|
19
19
|
* on a grey bubble with a `❯` pointer, assistant text with a `●` bullet and
|
|
20
|
-
* markdown, thinking folded to
|
|
20
|
+
* markdown, thinking folded to `⚓ Thinking (ctrl+o to expand)`, tool calls as
|
|
21
21
|
* status-dot cards. `expanded` (Ctrl+O) shows full reasoning + full tool
|
|
22
22
|
* args/results; `expandedRows` (message-selection mode, Enter) expands single
|
|
23
23
|
* rows; `selectedId` highlights the selected row.
|
|
@@ -37,7 +37,7 @@ const DEFAULT_ROW_HEIGHT = 2;
|
|
|
37
37
|
/** Cold-start estimate of the header block above the rows; corrected by the
|
|
38
38
|
* first layout measurement. */
|
|
39
39
|
const DEFAULT_HEADER_LINES = 14;
|
|
40
|
-
export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout = 'auto', thinkingFold = 'preview', showAll, onToggleAll, onLoadOlder, thinkingVisible = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }) {
|
|
40
|
+
export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, diffLayout = 'auto', thinkingFold = 'preview', toolBackground = 'none', showAll, onToggleAll, onLoadOlder, thinkingVisible = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }) {
|
|
41
41
|
const hiddenCount = rows.length - MAX_RENDERED_ROWS;
|
|
42
42
|
// The thinking filter runs BEFORE virtualization so window indices line up.
|
|
43
43
|
const visibleRows = (showAll || hiddenCount <= 0
|
|
@@ -54,14 +54,12 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
54
54
|
prev = row.kind;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
//
|
|
58
|
-
//
|
|
57
|
+
// Selection keeps its highlight; expanded rows render with no fill (the
|
|
58
|
+
// diff line tints inside cards are the only backgrounds in the transcript).
|
|
59
59
|
const rowBackground = (rowId) => {
|
|
60
60
|
const isSelected = selectedId === rowId;
|
|
61
61
|
if (isSelected)
|
|
62
62
|
return 'messageActionsBackground';
|
|
63
|
-
if (expandedRows.has(rowId))
|
|
64
|
-
return 'userMessageBackgroundHover';
|
|
65
63
|
return undefined;
|
|
66
64
|
};
|
|
67
65
|
// --- layout virtualization ---------------------------------------------
|
|
@@ -334,10 +332,10 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
334
332
|
// spacing; only the very first row of the whole list has none.
|
|
335
333
|
const addMargin = margins.get(row.id) === true;
|
|
336
334
|
const tool = row.tool;
|
|
337
|
-
return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: row.text, executionTarget: row.executionTarget, streaming: row.streaming === true, durationMs: row.durationMs, time: row.time, addMargin: addMargin, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, nowSec: tool?.status === 'running' ? nowSec : undefined, onToggleRow: onToggleRow, setRowRef: setRowRef }, row.id));
|
|
335
|
+
return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: row.text, executionTarget: row.executionTarget, streaming: row.streaming === true, durationMs: row.durationMs, time: row.time, addMargin: addMargin, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, nowSec: tool?.status === 'running' ? nowSec : undefined, onToggleRow: onToggleRow, setRowRef: setRowRef }, row.id));
|
|
338
336
|
}), bottomPad > 0 && _jsx(Box, { height: bottomPad, flexShrink: 0 })] }));
|
|
339
337
|
}
|
|
340
|
-
function TranscriptRow({ rowId, kind, text, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, diffLayout, thinkingFold, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, onToggleRow, setRowRef, }) {
|
|
338
|
+
function TranscriptRow({ rowId, kind, text, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, diffLayout, thinkingFold, toolBackground, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, onToggleRow, setRowRef, }) {
|
|
341
339
|
const ref = React.useCallback((el) => {
|
|
342
340
|
setRowRef(rowId, el);
|
|
343
341
|
}, [setRowRef, rowId]);
|
|
@@ -346,11 +344,11 @@ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, duration
|
|
|
346
344
|
}, [onToggleRow, rowId]);
|
|
347
345
|
switch (kind) {
|
|
348
346
|
case 'user':
|
|
349
|
-
return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(UserPromptMessage, { text: text, addMargin: addMargin, isSelected: isSelected,
|
|
347
|
+
return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(UserPromptMessage, { text: text, addMargin: addMargin, isSelected: isSelected, onClick: onClick }) }));
|
|
350
348
|
case 'assistant':
|
|
351
349
|
return streaming ? (_jsxs(Box, { alignItems: "flex-start", flexDirection: "row", marginTop: addMargin ? 1 : 0, width: "100%", backgroundColor: background, children: [_jsx(Box, { minWidth: 2, children: _jsx(Text, { color: "text", children: "\u25CF" }) }), _jsx(Box, { flexDirection: "column", children: _jsx(StreamingMarkdown, { children: stripNarration(text) }) })] })) : (_jsxs(Box, { width: "100%", flexDirection: "column", backgroundColor: background, ref: ref, children: [expanded && (_jsx(Box, { flexDirection: "row", justifyContent: "flex-end", gap: 1, marginTop: 1, children: _jsx(MessageMetadata, { timestamp: time, model: model }) })), _jsx(AssistantTextMessage, { text: stripNarration(text), addMargin: addMargin, isSelected: isSelected, isExpanded: isExpanded, onClick: onClick })] }));
|
|
352
350
|
case 'reasoning':
|
|
353
|
-
return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantThinkingMessage, { thinking: text, addMargin: addMargin, preview: streaming &&
|
|
351
|
+
return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantThinkingMessage, { thinking: text, addMargin: addMargin, streaming: streaming, preview: streaming &&
|
|
354
352
|
thinkingFold === 'preview' &&
|
|
355
353
|
!expanded &&
|
|
356
354
|
!isExpanded,
|
|
@@ -382,7 +380,7 @@ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, duration
|
|
|
382
380
|
startedAt: toolStartedAt,
|
|
383
381
|
durationMs: toolDurationMs,
|
|
384
382
|
};
|
|
385
|
-
return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantToolUseMessage, { tool: tool, addMargin: addMargin, verbose: isExpanded || expanded, isSelected: isSelected, isExpanded: isExpanded, footnote: toolFootnote, diffLayout: diffLayout }) }));
|
|
383
|
+
return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantToolUseMessage, { tool: tool, addMargin: addMargin, verbose: isExpanded || expanded, isSelected: isSelected, isExpanded: isExpanded, footnote: toolFootnote, diffLayout: diffLayout, toolBackground: toolBackground }) }));
|
|
386
384
|
}
|
|
387
385
|
case 'notice':
|
|
388
386
|
return (_jsx(Box, { marginTop: 1, ref: ref, children: _jsx(Divider, { title: ` ${text} ` }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAkDxD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,IAAI,OAAO,CAAA;IAClB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,IAAI,IAAI,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACrD,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,8EAA8E;IAC9E,eAAe,CAAC,IAAI,IAAI,CAAA;IACxB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,GACd,EAAE,gBAAgB,qBA46BlB"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { readFile, unlink } from 'node:fs/promises';
|
|
4
4
|
import { basename } from 'node:path';
|
|
5
5
|
import { t } from '../i18n.js';
|
|
6
|
-
import { Box, Text, useInput, useTerminalSize } from '../ui.js';
|
|
6
|
+
import { Box, Text, useInput, useTerminalSize, useTheme } from '../ui.js';
|
|
7
|
+
import { EffortChargeGlyph } from './EffortChargeGlyph.js';
|
|
8
|
+
import { EffortInputBorder } from './EffortInputBorder.js';
|
|
9
|
+
import { EffortTierBadge } from './EffortTierBadge.js';
|
|
10
|
+
import { isLightThemeActive } from '../theme.js';
|
|
7
11
|
import { useDeclaredCursor } from '../ink/hooks/use-declared-cursor.js';
|
|
8
12
|
import { stringWidth } from '../ink/stringWidth.js';
|
|
9
13
|
import { formatClipboardInsert, readClipboard } from '../utils/clipboard.js';
|
|
@@ -89,6 +93,7 @@ const MAX_VISIBLE_LINES = 5;
|
|
|
89
93
|
* aborts the turn and sends the current input immediately.
|
|
90
94
|
*/
|
|
91
95
|
export function PromptInput({ channel, helpOpen, onToggleHelp, onRunCommand, selectionActive, fillText, onFillConsumed, onRewindRequest, controllerRef, }) {
|
|
96
|
+
const [themeName] = useTheme();
|
|
92
97
|
const [value, setValue] = React.useState('');
|
|
93
98
|
const [cursor, setCursor] = React.useState(0);
|
|
94
99
|
const valueRef = React.useRef(value);
|
|
@@ -882,7 +887,7 @@ export function PromptInput({ channel, helpOpen, onToggleHelp, onRunCommand, sel
|
|
|
882
887
|
.filter(item => item.placement === 'steer')
|
|
883
888
|
.map(item => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [' ', "\u21B3 ", item.text] }, item.id)))] })), channel.pending.some(item => item.placement === 'followup') && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["\u23F3 ", t('input-pending-queue-label')] }), channel.pending
|
|
884
889
|
.filter(item => item.placement === 'followup')
|
|
885
|
-
.map(item => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [' ', "\u21B3 ", item.text] }, item.id)))] })), _jsxs(Text, { dimColor: true, children: ["Alt+\u2191 ", t('input-pending-actions-hint')] })] })), fileOverlayOpen && (_jsx(Box, { paddingLeft: 2, paddingBottom: 1, children: _jsx(FileSuggestions, { files: fileMatches, selectedIndex: fileSelected, columns: columns }) })), overlayOpen && (_jsx(Box, { paddingLeft: 2, paddingBottom: 1, children: _jsx(CommandSuggestions, { commands: suggestions, selectedIndex: selectedCommand, columns: columns }) }))] })), lastNotification && (_jsx(Box, { position: "absolute", marginTop: -1, height: 1, width: "100%", paddingLeft: 2, paddingRight: 1, flexDirection: "column", justifyContent: "flex-end", overflow: "hidden", children: _jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { color: lastNotification.color, dimColor: !lastNotification.color, wrap: "truncate", children: lastNotification.text }) }) })), _jsx(
|
|
890
|
+
.map(item => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [' ', "\u21B3 ", item.text] }, item.id)))] })), _jsxs(Text, { dimColor: true, children: ["Alt+\u2191 ", t('input-pending-actions-hint')] })] })), fileOverlayOpen && (_jsx(Box, { paddingLeft: 2, paddingBottom: 1, children: _jsx(FileSuggestions, { files: fileMatches, selectedIndex: fileSelected, columns: columns }) })), overlayOpen && (_jsx(Box, { paddingLeft: 2, paddingBottom: 1, children: _jsx(CommandSuggestions, { commands: suggestions, selectedIndex: selectedCommand, columns: columns }) }))] })), lastNotification && (_jsx(Box, { position: "absolute", marginTop: -1, height: 1, width: "100%", paddingLeft: 2, paddingRight: 1, flexDirection: "column", justifyContent: "flex-end", overflow: "hidden", children: _jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { color: lastNotification.color, dimColor: !lastNotification.color, wrap: "truncate", children: lastNotification.text }) }) })), _jsx(EffortInputBorder, { effort: channel.reasoningEffort, levels: channel.effortLevels, columns: columns, onLight: isLightThemeActive(themeName), idleColor: channel.mode.plan === true ? 'planMode' : 'promptBorder', children: _jsxs(Box, { flexDirection: "row", alignItems: "flex-start", width: "100%", children: [_jsx(EffortChargeGlyph, { effort: channel.reasoningEffort, levels: channel.effortLevels, working: channel.working }), _jsx(Box, { ref: valueBoxRef, flexGrow: 1, flexShrink: 1, children: value.length === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { inverse: true, children: " " }), _jsx(EffortTierBadge, { effort: channel.reasoningEffort, levels: channel.effortLevels, onLight: isLightThemeActive(themeName), columns: columns, leadingColumns: 3 })] })) : (_jsx(Box, { flexDirection: "column", children: rendered })) })] }) })] }));
|
|
886
891
|
}
|
|
887
892
|
/**
|
|
888
893
|
* Hard-wrap text into visual rows of at most `width` columns (CJK-aware via
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ToolFileDiff } from '../dsh-adapter/channel.js';
|
|
3
3
|
import { type CliHighlight } from '../cc/cliHighlight.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* or without spaces, ansi256(n), ansi:name (issue #250, P2-5). */
|
|
7
|
-
export declare function chalkFromToken(token: string): (text: string) => string;
|
|
4
|
+
export { chalkFromToken } from '../cc/syntaxTheme.js';
|
|
5
|
+
import type { ToolBackground } from '../tuiDisplayPrefs.js';
|
|
8
6
|
/** Parse a cli-highlight ANSI string into colored runs, preserving open
|
|
9
7
|
* spans across embedded newlines (multi-line strings/comments). Handles
|
|
10
8
|
* truecolor 38;2, 256-color 38;5 (tmux / FORCE_COLOR=2, issue #250 P1-1),
|
|
@@ -17,12 +15,13 @@ export declare function highlightLines(text: string, language: string | undefine
|
|
|
17
15
|
text: string;
|
|
18
16
|
color?: string;
|
|
19
17
|
}[][] | undefined;
|
|
20
|
-
export declare function SplitDiffView({ diffs, width, maxRows, verbose, }: {
|
|
18
|
+
export declare function SplitDiffView({ diffs, width, maxRows, verbose, toolBackground, }: {
|
|
21
19
|
readonly diffs: readonly ToolFileDiff[];
|
|
22
20
|
/** Content width available to the whole two-pane block (divider included). */
|
|
23
21
|
readonly width: number;
|
|
24
22
|
/** Row budget when not verbose; overflow folds into one hint row. */
|
|
25
23
|
readonly maxRows: number;
|
|
26
24
|
readonly verbose: boolean;
|
|
25
|
+
readonly toolBackground?: ToolBackground;
|
|
27
26
|
}): React.ReactNode;
|
|
28
27
|
//# sourceMappingURL=SplitDiffView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SplitDiffView.d.ts","sourceRoot":"","sources":["../../../src/components/SplitDiffView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"SplitDiffView.d.ts","sourceRoot":"","sources":["../../../src/components/SplitDiffView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAIjF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAgE3D;;;oCAGoC;AACpC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAuB9E;AAuBD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,EAAE,EAAE,YAAY,GAAG,IAAI,EACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,EAC7D,QAAQ,EAAE,MAAM,GACf,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,GAAG,SAAS,CAe3D;AAsOD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,cAAuB,GACxB,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;CACzC,GAAG,KAAK,CAAC,SAAS,CAiGlB"}
|
|
@@ -2,73 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Box, Text } from '../ui.js';
|
|
4
4
|
import * as JsDiff from 'diff';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
5
|
import { extname } from 'node:path';
|
|
7
6
|
import { getCliHighlightPromise } from '../cc/cliHighlight.js';
|
|
7
|
+
import { SYNTAX_CLASS_TO_TOKEN, chalkFromToken } from '../cc/syntaxTheme.js';
|
|
8
|
+
// Backward-compatible re-export: repro scripts import chalkFromToken from
|
|
9
|
+
// this module's old home.
|
|
10
|
+
export { chalkFromToken } from '../cc/syntaxTheme.js';
|
|
8
11
|
import { getTheme } from '../theme.js';
|
|
9
12
|
import { useTheme } from './design-system/ThemeProvider.js';
|
|
10
13
|
/** Replace tabs so width math and alignment hold (pi convention). */
|
|
11
14
|
const expandTabs = (text) => text.replaceAll('\t', ' ');
|
|
12
15
|
// --- syntax highlighting ----------------------------------------------------
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* (issue #250, P2-6). */
|
|
16
|
-
const SYNTAX_CLASS_TO_TOKEN = {
|
|
17
|
-
keyword: 'syntaxKeyword',
|
|
18
|
-
built_in: 'syntaxKeyword',
|
|
19
|
-
literal: 'syntaxKeyword',
|
|
20
|
-
string: 'syntaxString',
|
|
21
|
-
subst: 'syntaxString',
|
|
22
|
-
quote: 'syntaxString',
|
|
23
|
-
comment: 'syntaxComment',
|
|
24
|
-
number: 'syntaxNumber',
|
|
25
|
-
title: 'syntaxFunction',
|
|
26
|
-
'title.function_': 'syntaxFunction',
|
|
27
|
-
function: 'syntaxFunction',
|
|
28
|
-
'title.class_': 'syntaxType',
|
|
29
|
-
type: 'syntaxType',
|
|
30
|
-
class: 'syntaxType',
|
|
31
|
-
tag: 'syntaxType',
|
|
32
|
-
name: 'syntaxType',
|
|
33
|
-
attr: 'syntaxVariable',
|
|
34
|
-
attribute: 'syntaxVariable',
|
|
35
|
-
variable: 'syntaxVariable',
|
|
36
|
-
'template-variable': 'syntaxVariable',
|
|
37
|
-
params: 'syntaxVariable',
|
|
38
|
-
operator: 'syntaxOperator',
|
|
39
|
-
punctuation: 'syntaxPunctuation',
|
|
40
|
-
meta: 'syntaxPunctuation',
|
|
41
|
-
symbol: 'syntaxConstant',
|
|
42
|
-
regexp: 'syntaxConstant',
|
|
43
|
-
default: 'syntaxVariable',
|
|
44
|
-
};
|
|
45
|
-
/** chalk style for one raw theme value. Accepts every form the theme
|
|
46
|
-
* loader documents: #rgb, #rrggbb, #rrggbbaa (alpha stripped), rgb() with
|
|
47
|
-
* or without spaces, ansi256(n), ansi:name (issue #250, P2-5). */
|
|
48
|
-
export function chalkFromToken(token) {
|
|
49
|
-
let match = /^#([0-9a-fA-F]{3})$/.exec(token);
|
|
50
|
-
if (match !== null) {
|
|
51
|
-
const [r, g, b] = match[1].split('').map(c => parseInt(c + c, 16));
|
|
52
|
-
return chalk.rgb(r, g, b);
|
|
53
|
-
}
|
|
54
|
-
match = /^#([0-9a-fA-F]{6})(?:[0-9a-fA-F]{2})?$/.exec(token);
|
|
55
|
-
if (match !== null)
|
|
56
|
-
return chalk.hex(`#${match[1]}`);
|
|
57
|
-
match = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/.exec(token);
|
|
58
|
-
if (match !== null)
|
|
59
|
-
return chalk.rgb(Number(match[1]), Number(match[2]), Number(match[3]));
|
|
60
|
-
match = /^ansi256\((\d+)\)$/.exec(token);
|
|
61
|
-
if (match !== null)
|
|
62
|
-
return chalk.ansi256(Number(match[1]));
|
|
63
|
-
match = /^ansi:(\w+)$/.exec(token);
|
|
64
|
-
if (match !== null) {
|
|
65
|
-
const name = match[1] === 'blackBright' ? 'gray' : match[1];
|
|
66
|
-
const style = chalk[name];
|
|
67
|
-
if (style !== undefined)
|
|
68
|
-
return style;
|
|
69
|
-
}
|
|
70
|
-
return (text) => text;
|
|
71
|
-
}
|
|
16
|
+
// The hljs-class → theme-token map and chalkFromToken live in
|
|
17
|
+
// ../cc/syntaxTheme.ts (shared with the markdown code-block renderer).
|
|
72
18
|
/** ANSI 16-color SGR codes → rgb() strings (the dark-ansi palette path). */
|
|
73
19
|
const ANSI16 = {
|
|
74
20
|
30: 'rgb(0,0,0)', 31: 'rgb(128,0,0)', 32: 'rgb(0,128,0)', 33: 'rgb(128,128,0)',
|
|
@@ -327,9 +273,16 @@ function alignFileDiff(fileIndex, oldText, newText) {
|
|
|
327
273
|
return rows;
|
|
328
274
|
}
|
|
329
275
|
// --- rendering --------------------------------------------------------------
|
|
330
|
-
function PaneLine({ side, kind, width, tone, padLeft = false, }) {
|
|
276
|
+
function PaneLine({ side, kind, width, tone, toolBackground, padLeft = false, }) {
|
|
277
|
+
const ordinaryBackground = toolBackground === 'subtle'
|
|
278
|
+
? 'toolCardBackgroundDim'
|
|
279
|
+
: toolBackground === 'strong'
|
|
280
|
+
? 'toolCardBackground'
|
|
281
|
+
: undefined;
|
|
282
|
+
// Additions/removals keep their semantic tint; unchanged and empty panes
|
|
283
|
+
// inherit the configured ordinary tool-card surface.
|
|
331
284
|
const backgroundColor = kind === 'context'
|
|
332
|
-
?
|
|
285
|
+
? ordinaryBackground
|
|
333
286
|
: tone === 'old'
|
|
334
287
|
? 'diffRemovedDimmed'
|
|
335
288
|
: 'diffAddedDimmed';
|
|
@@ -340,7 +293,7 @@ function PaneLine({ side, kind, width, tone, padLeft = false, }) {
|
|
|
340
293
|
const prefix = padLeft ? ` ${marker}` : marker;
|
|
341
294
|
return (_jsxs(Box, { width: width, flexShrink: 0, backgroundColor: backgroundColor, children: [_jsx(Text, { dimColor: true, backgroundColor: backgroundColor, children: `${prefix} ` }), side === undefined ? (_jsx(Text, { backgroundColor: backgroundColor, children: " " })) : (_jsx(Text, { wrap: "truncate", backgroundColor: backgroundColor, children: side.segments.map((segment, index) => segment.changed ? (_jsx(Text, { color: wordColor, bold: true, backgroundColor: backgroundColor, children: segment.text }, index)) : (_jsx(Text, { color: segment.color, backgroundColor: backgroundColor, children: segment.text }, index))) }))] }));
|
|
342
295
|
}
|
|
343
|
-
export function SplitDiffView({ diffs, width, maxRows, verbose, }) {
|
|
296
|
+
export function SplitDiffView({ diffs, width, maxRows, verbose, toolBackground = 'none', }) {
|
|
344
297
|
const [hl, setHl] = React.useState(null);
|
|
345
298
|
React.useEffect(() => {
|
|
346
299
|
let mounted = true;
|
|
@@ -399,7 +352,7 @@ export function SplitDiffView({ diffs, width, maxRows, verbose, }) {
|
|
|
399
352
|
next: highlightLines(expandTabs(diff.newText), language, hl, chTheme, themeSig),
|
|
400
353
|
};
|
|
401
354
|
});
|
|
402
|
-
return (_jsxs(Box, { flexDirection: "column", width: paneWidth * 2 + 1,
|
|
355
|
+
return (_jsxs(Box, { flexDirection: "column", width: paneWidth * 2 + 1, children: [visible.map((row, index) => {
|
|
403
356
|
if ('separator' in row) {
|
|
404
357
|
return (_jsx(Box, { width: paneWidth * 2 + 1, children: _jsx(Text, { dimColor: true, wrap: "truncate", children: row.separator === '⋯' ? '⋯' : ` ${row.separator}` }) }, index));
|
|
405
358
|
}
|
|
@@ -412,6 +365,6 @@ export function SplitDiffView({ diffs, width, maxRows, verbose, }) {
|
|
|
412
365
|
const newSide = row.newWords === undefined
|
|
413
366
|
? undefined
|
|
414
367
|
: { segments: newRuns !== undefined ? mergeRuns(newRuns, row.newWords) : row.newWords };
|
|
415
|
-
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(PaneLine, { side: oldSide, kind: row.kind === 'add' ? 'context' : row.kind, tone: "old", width: paneWidth }), _jsx(Box, { width: 1, flexShrink: 0,
|
|
368
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(PaneLine, { side: oldSide, kind: row.kind === 'add' ? 'context' : row.kind, tone: "old", width: paneWidth, toolBackground: toolBackground }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: "\u2502" }) }), _jsx(PaneLine, { side: newSide, kind: row.kind === 'del' ? 'context' : row.kind, tone: "new", width: paneWidth, toolBackground: toolBackground, padLeft: true })] }, index));
|
|
416
369
|
}), hidden > 0 && (_jsx(Text, { dimColor: true, children: `… +${hidden} lines (ctrl+o to expand)` }))] }));
|
|
417
370
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StreamingMarkdown.d.ts","sourceRoot":"","sources":["../../../src/components/StreamingMarkdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAmDzB,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"StreamingMarkdown.d.ts","sourceRoot":"","sources":["../../../src/components/StreamingMarkdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAmDzB,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAmDlB"}
|
|
@@ -76,6 +76,14 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
|
|
|
76
76
|
prefixRef.current = stripped.substring(0, boundary + advance);
|
|
77
77
|
}
|
|
78
78
|
const stablePrefix = prefixRef.current;
|
|
79
|
-
const
|
|
80
|
-
|
|
79
|
+
const suffixSource = stripped.substring(stablePrefix.length);
|
|
80
|
+
const unstableSuffix = clipSuffixTail(suffixSource, cutRef);
|
|
81
|
+
// A lexer boundary must be strictly outside the stable prefix. If marked
|
|
82
|
+
// reports a raw span that ends at the current cursor (possible around an
|
|
83
|
+
// unfinished fence/table while deltas arrive), rendering both branches can
|
|
84
|
+
// paint the same tail twice. Keep the suffix authoritative and never render
|
|
85
|
+
// an overlapping empty/duplicate boundary.
|
|
86
|
+
const hasDistinctSuffix = unstableSuffix !== '' &&
|
|
87
|
+
(stablePrefix === '' || !unstableSuffix.startsWith(stablePrefix));
|
|
88
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [stablePrefix && _jsx(Markdown, { dimColor: dimColor, children: stablePrefix }), hasDistinctSuffix && _jsx(Markdown, { dimColor: dimColor, cacheTokens: false, children: unstableSuffix })] }));
|
|
81
89
|
}
|
|
@@ -1,31 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Working-activity indicator presets
|
|
3
|
-
* working-activity
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Working-activity indicator presets — thin re-export of the single source
|
|
3
|
+
* of truth in the `dsh-working-activity` package (`src/frames.ts`). The TUI
|
|
4
|
+
* keeps this shim so existing importers (`/activity` picker, status line,
|
|
5
|
+
* channel, activity prefs) resolve the same names without moving; all preset
|
|
6
|
+
* data (the pi-extension union, 35 presets) lives upstream.
|
|
7
|
+
* @module dsh-tui/components/activityFrames
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
export interface FramePreset {
|
|
10
|
-
readonly frames: readonly string[];
|
|
11
|
-
readonly intervalMs: number;
|
|
12
|
-
}
|
|
13
|
-
/** Named working-activity frame presets, keyed by preset name (`claude`, `moon`, `sand`, ...). */
|
|
14
|
-
export declare const FRAME_PRESETS: Record<string, FramePreset>;
|
|
15
|
-
/** The pi extension's default preset. */
|
|
16
|
-
export declare const DEFAULT_PRESET = "moon8";
|
|
17
|
-
/** Every selectable preset name, `random` first (the pi selector order). */
|
|
18
|
-
export declare const PRESET_NAMES: readonly string[];
|
|
19
|
-
/**
|
|
20
|
-
* Whether `name` selects a known preset or `random`.
|
|
21
|
-
* @param name - Candidate preset name.
|
|
22
|
-
* @returns True when the name resolves to a preset.
|
|
23
|
-
*/
|
|
24
|
-
export declare function isPresetName(name: string): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Resolve a preset name (`random` picks one per process).
|
|
27
|
-
* @param name - Preset name, or undefined for the default.
|
|
28
|
-
* @returns The matching preset; unknown or absent names fall back to the default.
|
|
29
|
-
*/
|
|
30
|
-
export declare function resolvePreset(name: string | undefined): FramePreset;
|
|
9
|
+
export * from 'dsh-working-activity/frames';
|
|
31
10
|
//# sourceMappingURL=activityFrames.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activityFrames.d.ts","sourceRoot":"","sources":["../../../src/components/activityFrames.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"activityFrames.d.ts","sourceRoot":"","sources":["../../../src/components/activityFrames.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,6BAA6B,CAAA"}
|
|
@@ -1,96 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Working-activity indicator presets
|
|
3
|
-
* working-activity
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Working-activity indicator presets — thin re-export of the single source
|
|
3
|
+
* of truth in the `dsh-working-activity` package (`src/frames.ts`). The TUI
|
|
4
|
+
* keeps this shim so existing importers (`/activity` picker, status line,
|
|
5
|
+
* channel, activity prefs) resolve the same names without moving; all preset
|
|
6
|
+
* data (the pi-extension union, 35 presets) lives upstream.
|
|
7
|
+
* @module dsh-tui/components/activityFrames
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
const TE = '\uFE0E';
|
|
10
|
-
/** Named working-activity frame presets, keyed by preset name (`claude`, `moon`, `sand`, ...). */
|
|
11
|
-
export const FRAME_PRESETS = {
|
|
12
|
-
// Claude Code's real sequence: · ✢ * ✶ ✻ ✽ forward + backward.
|
|
13
|
-
claude: {
|
|
14
|
-
frames: ['·', `✢${TE}`, '*', `✶${TE}`, `✻${TE}`, `✽${TE}`, `✻${TE}`, `✶${TE}`, '*', `✢${TE}`],
|
|
15
|
-
intervalMs: 150,
|
|
16
|
-
},
|
|
17
|
-
star2: { frames: [`✶${TE}`, `✸${TE}`, `✹${TE}`, `✺${TE}`, `✹${TE}`, `✷${TE}`], intervalMs: 140 },
|
|
18
|
-
sand: {
|
|
19
|
-
frames: ['⠁', '⠂', '⠄', '⡀', '⡈', '⡐', '⡠', '⣀', '⣁', '⣂', '⣄', '⣌', '⣔', '⣤', '⣥', '⣦', '⣮', '⣶', '⣷', '⣿', '⡿', '⠿', '⢟', '⠟', '⡛', '⠛', '⠫', '⢋', '⠋', '⠍', '⡉', '⠉', '⠑', '⠡', '⢁'],
|
|
20
|
-
intervalMs: 120,
|
|
21
|
-
},
|
|
22
|
-
triangle: { frames: ['◢', '◣', '◤', '◥'], intervalMs: 180 },
|
|
23
|
-
box: { frames: ['▖', '▘', '▝', '▗'], intervalMs: 180 },
|
|
24
|
-
box2: { frames: ['▌', '▀', '▐', '▄'], intervalMs: 180 },
|
|
25
|
-
corners: { frames: ['◰', '◳', '◲', '◱'], intervalMs: 190 },
|
|
26
|
-
point: { frames: ['∙∙∙', '●∙∙', '∙●∙', '∙∙●', '∙∙∙'], intervalMs: 190 },
|
|
27
|
-
layer: { frames: ['-', '=', '≡'], intervalMs: 220 },
|
|
28
|
-
flip: { frames: ['_', '_', '_', '-', '`', '`', "'", '´', '-', '_', '_', '_'], intervalMs: 140 },
|
|
29
|
-
aesthetic: {
|
|
30
|
-
frames: ['▰▱▱▱▱▱▱', '▰▰▱▱▱▱▱', '▰▰▰▱▱▱▱', '▰▰▰▰▱▱▱', '▰▰▰▰▰▱▱', '▰▰▰▰▰▰▱', '▰▰▰▰▰▰▰', '▰▱▱▱▱▱▱'],
|
|
31
|
-
intervalMs: 140,
|
|
32
|
-
},
|
|
33
|
-
hamburger: { frames: ['☱', '☲', '☴'], intervalMs: 220 },
|
|
34
|
-
moon: { frames: ['◐', '◓', '◑', '◒'], intervalMs: 240 },
|
|
35
|
-
// kimi-code MoonLoader 同款:8 帧 emoji 月相,120ms 一帧,比半圆版更丝滑。
|
|
36
|
-
// 不带 \uFE0E:保留彩色 emoji 渲染(Windows Terminal 等现代终端效果最佳)。
|
|
37
|
-
moon8: { frames: ['🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘'], intervalMs: 120 },
|
|
38
|
-
// 鲸鱼喷水:🐳 固定,水柱升起(· → | → ║)再回落,顶珠 ° 模拟水花(对齐 pi 版)。
|
|
39
|
-
'whale-spout': {
|
|
40
|
-
frames: ['🐳 ', '🐳° ', '🐳|°', '🐳║°', '🐳|°', '🐳° ', '🐳 '],
|
|
41
|
-
intervalMs: 160,
|
|
42
|
-
},
|
|
43
|
-
// 鲸鱼转圈:🐳 + 环绕方向指示(逆时针转圈语义,对齐 pi 版)。
|
|
44
|
-
'whale-spin': {
|
|
45
|
-
frames: ['🐳→', '🐳↘', '🐳↓', '🐳↙', '🐳←', '🐳↖', '🐳↑', '🐳↗'],
|
|
46
|
-
intervalMs: 150,
|
|
47
|
-
},
|
|
48
|
-
comet: {
|
|
49
|
-
frames: ['● ', ' ● ', ' ● ', ' ● ', ' ●', ' ● ', ' ● ', ' ● '],
|
|
50
|
-
intervalMs: 160,
|
|
51
|
-
},
|
|
52
|
-
breathe: { frames: ['▁', '▃', '▅', '▇', '▅', '▃'], intervalMs: 210 },
|
|
53
|
-
dots: { frames: ['⣾', '⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽'], intervalMs: 140 },
|
|
54
|
-
arrow: { frames: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'], intervalMs: 160 },
|
|
55
|
-
spark: { frames: ['·', '∘', '°', '✧', '°', '∘'], intervalMs: 240 },
|
|
56
|
-
bar: { frames: ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█', '▉', '▊', '▋', '▌', '▍', '▎'], intervalMs: 120 },
|
|
57
|
-
braille: { frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'], intervalMs: 120 },
|
|
58
|
-
arc: { frames: ['◜', '◠', '◝', '◞', '◡', '◟'], intervalMs: 160 },
|
|
59
|
-
circle: { frames: ['◴', '◷', '◶', '◵'], intervalMs: 190 },
|
|
60
|
-
grow: { frames: ['.', 'o', 'O', '0', 'O', 'o'], intervalMs: 210 },
|
|
61
|
-
noise: { frames: ['▓', '▒', '░', '▒'], intervalMs: 160 },
|
|
62
|
-
bounce: { frames: ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'], intervalMs: 140 },
|
|
63
|
-
rainbow: {
|
|
64
|
-
frames: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃', '▂'],
|
|
65
|
-
intervalMs: 120,
|
|
66
|
-
},
|
|
67
|
-
dqpb: { frames: ['d', 'q', 'p', 'b'], intervalMs: 210 },
|
|
68
|
-
toggle: { frames: ['⊶', '⊷'], intervalMs: 300 },
|
|
69
|
-
};
|
|
70
|
-
/** The pi extension's default preset. */
|
|
71
|
-
export const DEFAULT_PRESET = 'moon8';
|
|
72
|
-
/** Every selectable preset name, `random` first (the pi selector order). */
|
|
73
|
-
export const PRESET_NAMES = ['random', ...Object.keys(FRAME_PRESETS)];
|
|
74
|
-
/**
|
|
75
|
-
* Whether `name` selects a known preset or `random`.
|
|
76
|
-
* @param name - Candidate preset name.
|
|
77
|
-
* @returns True when the name resolves to a preset.
|
|
78
|
-
*/
|
|
79
|
-
export function isPresetName(name) {
|
|
80
|
-
return name === 'random' || Object.hasOwn(FRAME_PRESETS, name);
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Resolve a preset name (`random` picks one per process).
|
|
84
|
-
* @param name - Preset name, or undefined for the default.
|
|
85
|
-
* @returns The matching preset; unknown or absent names fall back to the default.
|
|
86
|
-
*/
|
|
87
|
-
export function resolvePreset(name) {
|
|
88
|
-
if (name === 'random') {
|
|
89
|
-
const names = Object.keys(FRAME_PRESETS);
|
|
90
|
-
// FRAME_PRESETS is non-empty by construction, so any random index is in
|
|
91
|
-
// range and the lookup always lands on a preset.
|
|
92
|
-
const pick = names[Math.floor(Math.random() * names.length)];
|
|
93
|
-
return FRAME_PRESETS[pick];
|
|
94
|
-
}
|
|
95
|
-
return FRAME_PRESETS[name ?? ''] ?? FRAME_PRESETS[DEFAULT_PRESET];
|
|
96
|
-
}
|
|
9
|
+
export * from 'dsh-working-activity/frames';
|