@deepseek-harness-tui/dsh-tui 0.8.7 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -10
- package/bin/dsh-tui.js +1 -1
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +4 -2
- package/lib/types/components/ActivityPicker.d.ts +4 -1
- package/lib/types/components/ActivityPicker.d.ts.map +1 -1
- package/lib/types/components/ActivityPicker.js +2 -2
- package/lib/types/components/BtwPanel.d.ts.map +1 -1
- package/lib/types/components/BtwPanel.js +1 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
- package/lib/types/components/Chat/SubagentMessage.js +11 -3
- package/lib/types/components/CommandSuggestions.d.ts +21 -4
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- package/lib/types/components/CommandSuggestions.js +41 -14
- package/lib/types/components/EffortSlider.d.ts +4 -1
- package/lib/types/components/EffortSlider.d.ts.map +1 -1
- package/lib/types/components/EffortSlider.js +4 -2
- package/lib/types/components/ExtensionDialog.js +6 -2
- package/lib/types/components/FileSuggestions.d.ts +26 -5
- package/lib/types/components/FileSuggestions.d.ts.map +1 -1
- package/lib/types/components/FileSuggestions.js +53 -16
- package/lib/types/components/GoalTodoPanel.d.ts +26 -2
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +86 -17
- package/lib/types/components/HelpMenu.d.ts +7 -1
- package/lib/types/components/HelpMenu.d.ts.map +1 -1
- package/lib/types/components/HelpMenu.js +12 -4
- package/lib/types/components/HistorySearchDialog.d.ts +4 -1
- package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
- package/lib/types/components/HistorySearchDialog.js +2 -2
- package/lib/types/components/LangPicker.d.ts +14 -0
- package/lib/types/components/LangPicker.d.ts.map +1 -0
- package/lib/types/components/LangPicker.js +17 -0
- package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
- package/lib/types/components/LoadedContextPanel.js +3 -1
- package/lib/types/components/LogoV2.d.ts +5 -1
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +12 -3
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +12 -3
- package/lib/types/components/MessageList.d.ts +43 -2
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +553 -41
- package/lib/types/components/ModelPicker.d.ts +4 -1
- package/lib/types/components/ModelPicker.d.ts.map +1 -1
- package/lib/types/components/ModelPicker.js +2 -2
- package/lib/types/components/PermissionsPicker.d.ts +21 -0
- package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
- package/lib/types/components/PermissionsPicker.js +27 -0
- package/lib/types/components/PlanPicker.d.ts +15 -0
- package/lib/types/components/PlanPicker.d.ts.map +1 -0
- package/lib/types/components/PlanPicker.js +18 -0
- package/lib/types/components/PresetPicker.d.ts +4 -1
- package/lib/types/components/PresetPicker.d.ts.map +1 -1
- package/lib/types/components/PresetPicker.js +2 -2
- package/lib/types/components/PromptInput.d.ts +4 -3
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +273 -50
- package/lib/types/components/RewindPicker.d.ts +12 -1
- package/lib/types/components/RewindPicker.d.ts.map +1 -1
- package/lib/types/components/RewindPicker.js +6 -4
- package/lib/types/components/ScrollbarGutter.d.ts +28 -0
- package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
- package/lib/types/components/ScrollbarGutter.js +68 -0
- package/lib/types/components/Select.d.ts +8 -1
- package/lib/types/components/Select.d.ts.map +1 -1
- package/lib/types/components/Select.js +4 -2
- package/lib/types/components/SkillsPicker.d.ts +4 -1
- package/lib/types/components/SkillsPicker.d.ts.map +1 -1
- package/lib/types/components/SkillsPicker.js +2 -2
- package/lib/types/components/SubagentCard.d.ts +2 -1
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +6 -1
- package/lib/types/components/SubagentDashboard.d.ts +4 -0
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
- package/lib/types/components/SubagentDashboard.js +9 -1
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +5 -4
- package/lib/types/components/SuggestionCard.d.ts +63 -0
- package/lib/types/components/SuggestionCard.d.ts.map +1 -0
- package/lib/types/components/SuggestionCard.js +77 -0
- package/lib/types/components/ThemePicker.d.ts +4 -1
- package/lib/types/components/ThemePicker.d.ts.map +1 -1
- package/lib/types/components/ThemePicker.js +2 -2
- package/lib/types/components/ThinkingToggle.d.ts +4 -1
- package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
- package/lib/types/components/ThinkingToggle.js +2 -2
- package/lib/types/components/TimelineRail.d.ts +53 -0
- package/lib/types/components/TimelineRail.d.ts.map +1 -0
- package/lib/types/components/TimelineRail.js +190 -0
- package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
- package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
- package/lib/types/components/WorkspaceFlowPicker.js +4 -2
- package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
- package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
- package/lib/types/components/WorkspaceMenuPicker.js +19 -0
- package/lib/types/components/WorkspacePicker.d.ts +4 -1
- package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
- package/lib/types/components/WorkspacePicker.js +2 -2
- package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
- package/lib/types/components/approvals/ApprovalPanel.js +5 -1
- package/lib/types/components/design-system/ListItem.d.ts +8 -1
- package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
- package/lib/types/components/design-system/ListItem.js +8 -3
- package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
- package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantTextMessage.js +6 -2
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +10 -4
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +4 -2
- package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +34 -2
- package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
- package/lib/types/components/questions/PlanReviewPanel.js +13 -2
- package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
- package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
- package/lib/types/components/sessions/SessionListRow.js +4 -2
- package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
- package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
- package/lib/types/components/trajectory/HotspotView.js +8 -2
- package/lib/types/components/trajectory/Ledger.d.ts +9 -1
- package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
- package/lib/types/components/trajectory/Ledger.js +23 -5
- package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
- package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
- package/lib/types/components/trajectory/WaveBand.js +7 -2
- package/lib/types/dsh-adapter/channel.d.ts +27 -6
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +432 -66
- package/lib/types/dsh-adapter/contract.d.ts +58 -18
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +124 -36
- package/lib/types/dsh-adapter/index.d.ts +10 -2
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +10 -13
- package/lib/types/dsh-adapter/plugin.d.ts +0 -9
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +136 -6
- package/lib/types/i18n.d.ts +194 -16
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +73 -10
- package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
- package/lib/types/ink/components/AlternateScreen.js +13 -1
- package/lib/types/ink/components/App.d.ts +12 -1
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +101 -4
- package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
- package/lib/types/ink/components/ClockContext.js +2 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
- package/lib/types/ink/components/ScrollBox.js +170 -91
- package/lib/types/ink/constants.d.ts +9 -0
- package/lib/types/ink/constants.d.ts.map +1 -1
- package/lib/types/ink/constants.js +9 -0
- package/lib/types/ink/events/click-event.d.ts +7 -16
- package/lib/types/ink/events/click-event.d.ts.map +1 -1
- package/lib/types/ink/events/click-event.js +16 -19
- package/lib/types/ink/events/event-handlers.d.ts +11 -1
- package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
- package/lib/types/ink/events/event-handlers.js +2 -0
- package/lib/types/ink/events/input-event.d.ts +9 -0
- package/lib/types/ink/events/input-event.d.ts.map +1 -1
- package/lib/types/ink/events/input-event.js +4 -0
- package/lib/types/ink/events/pointer-event.d.ts +61 -0
- package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
- package/lib/types/ink/events/pointer-event.js +61 -0
- package/lib/types/ink/events/wheel-event.d.ts +17 -0
- package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
- package/lib/types/ink/events/wheel-event.js +20 -0
- package/lib/types/ink/geometry-trace.d.ts +51 -0
- package/lib/types/ink/geometry-trace.d.ts.map +1 -0
- package/lib/types/ink/geometry-trace.js +83 -0
- package/lib/types/ink/hit-test.d.ts +56 -1
- package/lib/types/ink/hit-test.d.ts.map +1 -1
- package/lib/types/ink/hit-test.js +146 -8
- package/lib/types/ink/ink.d.ts +58 -1
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +268 -52
- package/lib/types/ink/node-cache.d.ts +5 -0
- package/lib/types/ink/node-cache.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.d.ts +8 -0
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +101 -12
- package/lib/types/ink/render-node-to-output.d.ts +16 -3
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +144 -25
- package/lib/types/ink/selection.d.ts +29 -4
- package/lib/types/ink/selection.d.ts.map +1 -1
- package/lib/types/ink/selection.js +41 -5
- package/lib/types/ink/timeline-rail.d.ts +138 -0
- package/lib/types/ink/timeline-rail.d.ts.map +1 -0
- package/lib/types/ink/timeline-rail.js +179 -0
- package/lib/types/ink/wrap-text.d.ts.map +1 -1
- package/lib/types/ink/wrap-text.js +47 -5
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +819 -337
- package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
- package/lib/types/screens/SessionBrowser.js +56 -29
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +64 -22
- package/lib/types/screens/StatusLine.d.ts +2 -1
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +17 -1
- package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
- package/lib/types/screens/TrajectoryScene.js +81 -14
- package/lib/types/screens/chatOverlay.d.ts +221 -0
- package/lib/types/screens/chatOverlay.d.ts.map +1 -0
- package/lib/types/screens/chatOverlay.js +114 -0
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +64 -10
- package/lib/types/tuiDisplayPrefs.d.ts +15 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +9 -0
- package/lib/types/utils/debug.d.ts +10 -0
- package/lib/types/utils/debug.d.ts.map +1 -1
- package/lib/types/utils/debug.js +24 -0
- package/lib/types/utils/fileSuggestions.d.ts +19 -0
- package/lib/types/utils/fileSuggestions.d.ts.map +1 -0
- package/lib/types/utils/fileSuggestions.js +40 -0
- package/lib/types/utils/mentions.d.ts.map +1 -1
- package/lib/types/utils/mentions.js +3 -1
- package/lib/types/utils/paths.d.ts.map +1 -1
- package/lib/types/utils/paths.js +1 -0
- package/package.json +69 -66
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text, NoSelect } from '../ui.js';
|
|
4
|
+
import { stringWidth } from '../ink/stringWidth.js';
|
|
5
|
+
import { RAIL_WIDTH, railEligible, computeRailGeometry, wrapPreviewLines, } from '../ink/timeline-rail.js';
|
|
6
|
+
/** ▴ / ▾ (U+25B4 / U+25BE — the small triangles; CP437-safe on ConHost too). */
|
|
7
|
+
const CHEVRON_UP = ' ▴';
|
|
8
|
+
const CHEVRON_DOWN = ' ▾';
|
|
9
|
+
/** Tick glyphs, right-aligned across the 2-col rail (Grok Build spec):
|
|
10
|
+
* active = heavy stroke, hover = wide light stroke, idle = short dim
|
|
11
|
+
* stroke in the rightmost cell. */
|
|
12
|
+
const TICK_ACTIVE = '━━';
|
|
13
|
+
const TICK_HOVER = '──';
|
|
14
|
+
const TICK_IDLE = ' ─';
|
|
15
|
+
/** Pointer rest time before the hover preview card pops (ms). Sweeps
|
|
16
|
+
* never mount a card; only a deliberate pause does. */
|
|
17
|
+
const HOVER_DWELL_MS = 120;
|
|
18
|
+
/**
|
|
19
|
+
* Timeline rail: the fullscreen transcript's turn navigator — a 2-column
|
|
20
|
+
* gutter REPLACING the classic scrollbar (Grok Build's timeline sidebar,
|
|
21
|
+
* ported to the dsh Ink tree).
|
|
22
|
+
*
|
|
23
|
+
* - one tick per user turn; tick position encodes conversation order,
|
|
24
|
+
* not scroll proportion (a long answer must not skew the timeline);
|
|
25
|
+
* - the tick of the turn owning the viewport top row (the turn being
|
|
26
|
+
* read — same anchor the sticky prompt header pins) renders as `━━`;
|
|
27
|
+
* hovering a tick widens it to `──` and pops a preview card left of
|
|
28
|
+
* the rail; idle ticks are a short dim ` ─`;
|
|
29
|
+
* - ▲ / ▾ step between turns by STRICT geometry (nearest prompt above /
|
|
30
|
+
* below the viewport top — never `active ± 1`, which can name a turn
|
|
31
|
+
* no scroll reaches), so a dim chevron is always a guaranteed no-op;
|
|
32
|
+
* - clicking a tick (or chevron) jumps by content coordinate — the
|
|
33
|
+
* prompt's measured top — no element seek, no force-mount race;
|
|
34
|
+
* - more turns than rows: the window slides around the active tick, and
|
|
35
|
+
* pins to the tail while at the bottom (never excluding active);
|
|
36
|
+
* - hidden below 60 terminal columns, under 2 turns, under 3 viewport
|
|
37
|
+
* rows, or when the content fits (inline mode keeps the terminal's
|
|
38
|
+
* native scrollback).
|
|
39
|
+
*
|
|
40
|
+
* The whole 2-column width is the hit target; the rail is fenced with
|
|
41
|
+
* NoSelect so click-drag text selection never picks up its glyphs, and
|
|
42
|
+
* the wheel scrolls the transcript (the rail has no scroll of its own).
|
|
43
|
+
*/
|
|
44
|
+
export function TimelineRail({ handle, turns, activeId, upId, downId, terminalWidth, hoverEnabled, onRevealTurn, }) {
|
|
45
|
+
const [, setTick] = React.useState(0);
|
|
46
|
+
const [hover, setHover] = React.useState(null);
|
|
47
|
+
// Dwell-gated preview card: the card pops only after the pointer RESTS
|
|
48
|
+
// on a tick for HOVER_DWELL_MS. Sweeping the rail fires enter/leave per
|
|
49
|
+
// cell — without the gate each crossing mounts an absolute-positioned
|
|
50
|
+
// card at a new spot (flapping previews, absolute-rect churn, and the
|
|
51
|
+
// fast-sweep residue users reported). The glyph highlight stays instant
|
|
52
|
+
// (cheap, no overlay); only the card waits for intent.
|
|
53
|
+
const [cardIndex, setCardIndex] = React.useState(null);
|
|
54
|
+
const dwellTimerRef = React.useRef(null);
|
|
55
|
+
const clearDwell = React.useCallback(() => {
|
|
56
|
+
if (dwellTimerRef.current !== null) {
|
|
57
|
+
clearTimeout(dwellTimerRef.current);
|
|
58
|
+
dwellTimerRef.current = null;
|
|
59
|
+
}
|
|
60
|
+
setCardIndex(null);
|
|
61
|
+
}, []);
|
|
62
|
+
const armDwell = React.useCallback((index) => {
|
|
63
|
+
if (dwellTimerRef.current !== null)
|
|
64
|
+
clearTimeout(dwellTimerRef.current);
|
|
65
|
+
dwellTimerRef.current = setTimeout(() => {
|
|
66
|
+
dwellTimerRef.current = null;
|
|
67
|
+
setCardIndex(index);
|
|
68
|
+
}, HOVER_DWELL_MS);
|
|
69
|
+
}, []);
|
|
70
|
+
React.useEffect(() => () => {
|
|
71
|
+
if (dwellTimerRef.current !== null)
|
|
72
|
+
clearTimeout(dwellTimerRef.current);
|
|
73
|
+
}, []);
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
if (!handle)
|
|
76
|
+
return;
|
|
77
|
+
return handle.subscribe(() => {
|
|
78
|
+
setTick(t => t + 1);
|
|
79
|
+
// A scroll (wheel over the rail, tick/chevron jump, header click)
|
|
80
|
+
// slides the tick window under a STATIONARY pointer — without this,
|
|
81
|
+
// the hover card keeps re-narrating whatever turn now sits under the
|
|
82
|
+
// pointer cell, flapping previews across turns every frame (reads as
|
|
83
|
+
// ghosting). OpenCode's modality rule: only a real mouse move may
|
|
84
|
+
// re-enter hover; Grok likewise clears the hover popup on tick click.
|
|
85
|
+
// setHover(null) on an already-null hover is a React no-op.
|
|
86
|
+
setHover(null);
|
|
87
|
+
clearDwell();
|
|
88
|
+
});
|
|
89
|
+
}, [handle, clearDwell]);
|
|
90
|
+
if (!handle)
|
|
91
|
+
return null;
|
|
92
|
+
const viewport = handle.getViewportHeight();
|
|
93
|
+
const content = handle.getScrollHeight();
|
|
94
|
+
const maxScroll = Math.max(0, content - viewport);
|
|
95
|
+
if (!railEligible({
|
|
96
|
+
turnCount: turns.length,
|
|
97
|
+
terminalWidth,
|
|
98
|
+
viewportRows: viewport,
|
|
99
|
+
scrollable: content > viewport,
|
|
100
|
+
}))
|
|
101
|
+
return null;
|
|
102
|
+
const activeIndex = turns.findIndex(t => t.id === activeId);
|
|
103
|
+
// Tail-pin the tick window while the viewport sits at the bottom
|
|
104
|
+
// (sticky flag OR positional) — newest ticks stay on screen.
|
|
105
|
+
const atBottom = handle.isSticky() || handle.getScrollTop() >= maxScroll;
|
|
106
|
+
const geo = computeRailGeometry(turns.length, viewport, activeIndex === -1 ? null : activeIndex, atBottom);
|
|
107
|
+
if (!geo)
|
|
108
|
+
return null;
|
|
109
|
+
// Jump by CONTENT COORDINATE, not by element: the target row is usually
|
|
110
|
+
// unmounted (virtualization), and the element-based seek's force-mount
|
|
111
|
+
// path races React's synchronous re-render (the renderer's deferred
|
|
112
|
+
// Yoga read can see a detached anchor and silently no-op). The turn's
|
|
113
|
+
// reported top is the measured text position — scrollTo() lands the
|
|
114
|
+
// prompt exactly at the viewport top; the renderer clamps unreachable
|
|
115
|
+
// tail tops to maxScroll (their turns stay on screen, just short of
|
|
116
|
+
// owning the top row — and ▼ never names them, see timeline-rail.ts).
|
|
117
|
+
// FOLDDED turns have no measured top (-1): their click (and ▲ naming
|
|
118
|
+
// one) routes through onRevealTurn instead — expand the fold, then the
|
|
119
|
+
// existing force-mount seek lands the row once it measures.
|
|
120
|
+
const jumpToIndex = (index) => {
|
|
121
|
+
const turn = turns[index];
|
|
122
|
+
if (!turn)
|
|
123
|
+
return;
|
|
124
|
+
if (turn.folded)
|
|
125
|
+
onRevealTurn(turn.id);
|
|
126
|
+
else
|
|
127
|
+
handle.scrollTo(turn.top);
|
|
128
|
+
};
|
|
129
|
+
const jumpToId = (id) => {
|
|
130
|
+
if (id === null)
|
|
131
|
+
return;
|
|
132
|
+
const index = turns.findIndex(t => t.id === id);
|
|
133
|
+
if (index !== -1)
|
|
134
|
+
jumpToIndex(index);
|
|
135
|
+
};
|
|
136
|
+
const shown = geo.windowEnd - geo.windowStart;
|
|
137
|
+
const chevron = (kind) => {
|
|
138
|
+
const enabled = (kind === 'up' ? upId : downId) !== null;
|
|
139
|
+
const hovered = hover?.kind === kind;
|
|
140
|
+
const glyph = kind === 'up' ? CHEVRON_UP : CHEVRON_DOWN;
|
|
141
|
+
const color = !enabled ? 'subtle' : hovered ? 'text' : 'inactive';
|
|
142
|
+
return (_jsx(Box, { height: 1, flexShrink: 0, onClick: () => jumpToId(kind === 'up' ? upId : downId), onMouseEnter: () => setHover({ kind }), onMouseLeave: () => setHover(null), children: _jsx(Text, { color: color, children: glyph }) }, kind));
|
|
143
|
+
};
|
|
144
|
+
const tickRows = [];
|
|
145
|
+
for (let k = 0; k < shown; k++) {
|
|
146
|
+
const index = geo.windowStart + k;
|
|
147
|
+
const turn = turns[index];
|
|
148
|
+
const isActive = index === activeIndex;
|
|
149
|
+
const isHovered = hover?.kind === 'tick' && hover.index === index;
|
|
150
|
+
const glyph = isActive ? TICK_ACTIVE : isHovered ? TICK_HOVER : TICK_IDLE;
|
|
151
|
+
const color = isActive || isHovered ? 'text' : 'subtle';
|
|
152
|
+
tickRows.push(_jsx(Box, { height: 1, flexShrink: 0, onClick: () => jumpToIndex(index), onMouseEnter: () => {
|
|
153
|
+
setHover({ kind: 'tick', index });
|
|
154
|
+
armDwell(index);
|
|
155
|
+
}, onMouseLeave: () => {
|
|
156
|
+
setHover(null);
|
|
157
|
+
clearDwell();
|
|
158
|
+
}, children: _jsx(Text, { color: color, children: glyph }) }, turn.id));
|
|
159
|
+
}
|
|
160
|
+
// Hover preview card, anchored left of the rail and vertically centered
|
|
161
|
+
// on the hovered tick (shrink-to-fit, rounded chrome). Dwell-gated: only
|
|
162
|
+
// cardIndex (armed after HOVER_DWELL_MS of rest) draws — a sweep keeps
|
|
163
|
+
// hover flashing on glyphs but never mounts the overlay. Suppressed
|
|
164
|
+
// while an overlay owns the screen — the rail stops narrating over
|
|
165
|
+
// dialogs.
|
|
166
|
+
let card = null;
|
|
167
|
+
if (hoverEnabled && cardIndex !== null) {
|
|
168
|
+
const turn = turns[cardIndex];
|
|
169
|
+
if (turn && turn.preview.length > 0) {
|
|
170
|
+
const tickRow = geo.tickTop + cardIndex - geo.windowStart;
|
|
171
|
+
if (tickRow >= geo.tickTop && tickRow < geo.downRow) {
|
|
172
|
+
const budget = Math.min(32, Math.max(16, Math.floor((terminalWidth - RAIL_WIDTH) / 2)));
|
|
173
|
+
const lines = wrapPreviewLines(turn.preview, budget);
|
|
174
|
+
if (lines.length > 0 && lines.some(l => l.length > 0)) {
|
|
175
|
+
const widest = Math.max(...lines.map(l => stringWidth(l)));
|
|
176
|
+
const cardW = widest + 4; // rounded border ×2 + padding ×2
|
|
177
|
+
const cardH = lines.length + 2;
|
|
178
|
+
if (cardH <= viewport) {
|
|
179
|
+
const top = Math.max(0, Math.min(tickRow - Math.floor(cardH / 2), viewport - cardH));
|
|
180
|
+
card = (_jsx(Box, { position: "absolute", top: top, right: RAIL_WIDTH + 1, width: cardW, height: cardH, flexDirection: "column", flexShrink: 0, borderStyle: "round", borderColor: "inactive", backgroundColor: "toolCardBackgroundDim", paddingX: 1, children: lines.map((line, i) => (_jsx(Text, { color: "text", wrap: "truncate-end", children: line }, i))) }));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return (_jsx(NoSelect, { fromLeftEdge: true, children: _jsxs("ink-box", { onWheel: e => {
|
|
187
|
+
if (e.deltaY !== 0)
|
|
188
|
+
handle.scrollBy(e.deltaY);
|
|
189
|
+
}, style: { flexDirection: 'column', flexShrink: 0, width: RAIL_WIDTH }, children: [_jsx(Box, { height: geo.upRow, flexShrink: 0 }), chevron('up'), tickRows, chevron('down'), card] }) }));
|
|
190
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { TuiWorkspaceChoice } from '../workspaces.js';
|
|
3
3
|
/** Generic nested choice surface returned by a workspace provider command. */
|
|
4
|
-
export declare function WorkspaceFlowPicker({ title, choices, focusIndex, busy, input, }: {
|
|
4
|
+
export declare function WorkspaceFlowPicker({ title, choices, focusIndex, busy, input, onPick, }: {
|
|
5
5
|
title: string;
|
|
6
6
|
choices: readonly TuiWorkspaceChoice[];
|
|
7
7
|
focusIndex: number;
|
|
@@ -11,5 +11,10 @@ export declare function WorkspaceFlowPicker({ title, choices, focusIndex, busy,
|
|
|
11
11
|
cursor: number;
|
|
12
12
|
placeholder?: string;
|
|
13
13
|
} | null;
|
|
14
|
+
/** Mouse pick (fullscreen): reports the clicked row's absolute index —
|
|
15
|
+
* Chat applies it with the same code path as the keyboard Enter. Rows
|
|
16
|
+
* are inert while busy (keyboard is swallowed too) and while the inline
|
|
17
|
+
* text input owns the interaction. */
|
|
18
|
+
onPick?: (index: number) => void;
|
|
14
19
|
}): React.ReactNode;
|
|
15
20
|
//# sourceMappingURL=WorkspaceFlowPicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceFlowPicker.d.ts","sourceRoot":"","sources":["../../../src/components/WorkspaceFlowPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAO1D,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,OAAO,EACP,UAAU,EACV,IAAY,EACZ,KAAY,
|
|
1
|
+
{"version":3,"file":"WorkspaceFlowPicker.d.ts","sourceRoot":"","sources":["../../../src/components/WorkspaceFlowPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAO1D,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,OAAO,EACP,UAAU,EACV,IAAY,EACZ,KAAY,EACZ,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACtE;;;2CAGuC;IACvC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CA0DlB"}
|
|
@@ -6,10 +6,12 @@ import { ListItem } from './design-system/ListItem.js';
|
|
|
6
6
|
import { HintLine } from './design-system/HintLine.js';
|
|
7
7
|
const WINDOW = 8;
|
|
8
8
|
/** Generic nested choice surface returned by a workspace provider command. */
|
|
9
|
-
export function WorkspaceFlowPicker({ title, choices, focusIndex, busy = false, input = null, }) {
|
|
9
|
+
export function WorkspaceFlowPicker({ title, choices, focusIndex, busy = false, input = null, onPick, }) {
|
|
10
10
|
const start = Math.max(0, Math.min(focusIndex - Math.floor(WINDOW / 2), choices.length - WINDOW));
|
|
11
11
|
const visible = choices.slice(start, start + WINDOW);
|
|
12
|
-
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: title }) }), visible.map((choice, index) => (_jsxs(ListItem, { isFocused: start + index === focusIndex, isSelected: false, description: choice.description, showScrollUp: index === 0 && start > 0, showScrollDown: index === visible.length - 1 && start + visible.length < choices.length,
|
|
12
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: title }) }), visible.map((choice, index) => (_jsxs(ListItem, { isFocused: start + index === focusIndex, isSelected: false, description: choice.description, disabled: busy, showScrollUp: index === 0 && start > 0, showScrollDown: index === visible.length - 1 && start + visible.length < choices.length, onClick: onPick !== undefined && !busy && input === null
|
|
13
|
+
? () => onPick(start + index)
|
|
14
|
+
: undefined, children: [choice.badge ? `${choice.badge} · ` : '', choice.label] }, choice.id))), input !== null && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "remember", children: "\u276F " }), input.value.length === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { inverse: true, children: " " }), _jsx(Text, { dimColor: true, children: input.placeholder ?? '' })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { children: input.value.slice(0, input.cursor) }), _jsx(Text, { inverse: true, children: input.value[input.cursor] ?? ' ' }), _jsx(Text, { children: input.value.slice(input.cursor + 1) })] }))] }))] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: busy
|
|
13
15
|
? t('workspace-flow-loading')
|
|
14
16
|
: input !== null
|
|
15
17
|
? t('workspace-flow-input-hint')
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Bare `/workspace` action menu: the built-in subcommands (resume / rename /
|
|
4
|
+
* open) plus any dynamically registered workspace extensions. Enter runs the
|
|
5
|
+
* focused action through the same paths a hand-typed subcommand takes;
|
|
6
|
+
* actions needing free text (rename/open) fall back to their usage notice.
|
|
7
|
+
*/
|
|
8
|
+
export declare function WorkspaceMenuPicker({ options, focusIndex, onPick, }: {
|
|
9
|
+
options: readonly {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
description: string;
|
|
13
|
+
}[];
|
|
14
|
+
focusIndex: number;
|
|
15
|
+
/** Mouse pick (fullscreen): reports the clicked row's index — Chat
|
|
16
|
+
* applies it with the same code path as the keyboard Enter. */
|
|
17
|
+
onPick?: (index: number) => void;
|
|
18
|
+
}): React.ReactNode;
|
|
19
|
+
//# sourceMappingURL=WorkspaceMenuPicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkspaceMenuPicker.d.ts","sourceRoot":"","sources":["../../../src/components/WorkspaceMenuPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,UAAU,EACV,MAAM,GACP,EAAE;IACD,OAAO,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACtE,UAAU,EAAE,MAAM,CAAA;IAClB;oEACgE;IAChE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CAyBlB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { Box, Text } from '../ui.js';
|
|
4
|
+
import { Pane } from './design-system/Pane.js';
|
|
5
|
+
import { Select } from './Select.js';
|
|
6
|
+
import { HintLine } from './design-system/HintLine.js';
|
|
7
|
+
/**
|
|
8
|
+
* Bare `/workspace` action menu: the built-in subcommands (resume / rename /
|
|
9
|
+
* open) plus any dynamically registered workspace extensions. Enter runs the
|
|
10
|
+
* focused action through the same paths a hand-typed subcommand takes;
|
|
11
|
+
* actions needing free text (rename/open) fall back to their usage notice.
|
|
12
|
+
*/
|
|
13
|
+
export function WorkspaceMenuPicker({ options, focusIndex, onPick, }) {
|
|
14
|
+
return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('workspace-menu-title') }) }), _jsx(Select, { options: options.map(option => ({
|
|
15
|
+
value: option.id,
|
|
16
|
+
label: option.label,
|
|
17
|
+
description: option.description,
|
|
18
|
+
})), focusIndex: focusIndex, selectedValue: undefined, onPick: onPick === undefined ? undefined : (index) => onPick(index) }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-confirm-exit') }) })] }) }));
|
|
19
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { TuiWorkspaceTarget } from '../workspaces.js';
|
|
3
3
|
/** `/workspace` target picker contributed by local and optional providers. */
|
|
4
|
-
export declare function WorkspacePicker({ targets, focusIndex, currentCwd, }: {
|
|
4
|
+
export declare function WorkspacePicker({ targets, focusIndex, currentCwd, onPick, }: {
|
|
5
5
|
targets: readonly TuiWorkspaceTarget[];
|
|
6
6
|
focusIndex: number;
|
|
7
7
|
currentCwd: string;
|
|
8
|
+
/** Mouse pick (fullscreen): reports the clicked row's absolute index —
|
|
9
|
+
* Chat applies it with the same code path as the keyboard Enter. */
|
|
10
|
+
onPick?: (index: number) => void;
|
|
8
11
|
}): React.ReactNode;
|
|
9
12
|
//# sourceMappingURL=WorkspacePicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacePicker.d.ts","sourceRoot":"","sources":["../../../src/components/WorkspacePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAO1D,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,UAAU,EACV,UAAU,
|
|
1
|
+
{"version":3,"file":"WorkspacePicker.d.ts","sourceRoot":"","sources":["../../../src/components/WorkspacePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAO1D,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,UAAU,EACV,UAAU,EACV,MAAM,GACP,EAAE;IACD,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB;yEACqE;IACrE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CA0BlB"}
|
|
@@ -6,8 +6,8 @@ import { ListItem } from './design-system/ListItem.js';
|
|
|
6
6
|
import { HintLine } from './design-system/HintLine.js';
|
|
7
7
|
const WINDOW = 8;
|
|
8
8
|
/** `/workspace` target picker contributed by local and optional providers. */
|
|
9
|
-
export function WorkspacePicker({ targets, focusIndex, currentCwd, }) {
|
|
9
|
+
export function WorkspacePicker({ targets, focusIndex, currentCwd, onPick, }) {
|
|
10
10
|
const start = Math.max(0, Math.min(focusIndex - Math.floor(WINDOW / 2), targets.length - WINDOW));
|
|
11
11
|
const visible = targets.slice(start, start + WINDOW);
|
|
12
|
-
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('workspace-picker-title') }) }), visible.map((target, index) => (_jsxs(ListItem, { isFocused: start + index === focusIndex, isSelected: target.cwd === currentCwd, description: target.description ?? target.uri, showScrollUp: index === 0 && start > 0, showScrollDown: index === visible.length - 1 && start + visible.length < targets.length, children: [target.badge, " \u00B7 ", target.label] }, target.uri)))] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('workspace-picker-hint') }) })] }));
|
|
12
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('workspace-picker-title') }) }), visible.map((target, index) => (_jsxs(ListItem, { isFocused: start + index === focusIndex, isSelected: target.cwd === currentCwd, description: target.description ?? target.uri, showScrollUp: index === 0 && start > 0, showScrollDown: index === visible.length - 1 && start + visible.length < targets.length, onClick: onPick === undefined ? undefined : () => onPick(start + index), children: [target.badge, " \u00B7 ", target.label] }, target.uri)))] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('workspace-picker-hint') }) })] }));
|
|
13
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApprovalPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/approvals/ApprovalPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,KAAK,IAAI,CAAA;CAClE,CAAA;AAID,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,kBAAkB,GAAG,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"ApprovalPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/approvals/ApprovalPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,KAAK,IAAI,CAAA;CAClE,CAAA;AAID,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,kBAAkB,GAAG,KAAK,CAAC,SAAS,CA+EzF"}
|
|
@@ -20,6 +20,9 @@ import { POINTER } from '../../cc/figures.js';
|
|
|
20
20
|
const OUTCOMES = ['allowed-once', 'rejected'];
|
|
21
21
|
export function ApprovalPanel({ approval, onDecide }) {
|
|
22
22
|
const [focusIndex, setFocusIndex] = React.useState(0);
|
|
23
|
+
// Hover highlight per decision row (mouse affordance; the click handler
|
|
24
|
+
// below mirrors the keyboard Enter on the focused row).
|
|
25
|
+
const [hoverIndex, setHoverIndex] = React.useState(-1);
|
|
23
26
|
useInput((input, key) => {
|
|
24
27
|
if (key.escape || (key.ctrl && input === 'c')) {
|
|
25
28
|
onDecide('rejected');
|
|
@@ -44,6 +47,7 @@ export function ApprovalPanel({ approval, onDecide }) {
|
|
|
44
47
|
const optionLabels = [t('approval-yes'), t('approval-no')];
|
|
45
48
|
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, paddingRight: 2, width: "100%", children: [_jsx(Divider, { color: "permission", title: t('approval-waiting', { tool: approval.toolName }), padding: 4 }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [approval.command !== undefined && (_jsx(Box, { flexDirection: "column", paddingX: 2, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: approval.command }) })), approval.reason !== undefined && (_jsx(Text, { dimColor: true, wrap: "wrap", children: approval.reason })), _jsx(Text, { dimColor: true, children: t('approval-proceed') })] }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: optionLabels.map((label, index) => {
|
|
46
49
|
const focused = index === focusIndex;
|
|
47
|
-
|
|
50
|
+
const hovered = index === hoverIndex;
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "row", marginTop: focused ? 1 : 0, onClick: () => onDecide(OUTCOMES[index]), onMouseEnter: () => setHoverIndex(index), onMouseLeave: () => setHoverIndex(current => (current === index ? -1 : current)), backgroundColor: hovered && !focused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: focused, children: focused ? POINTER : ' ' }) }), _jsxs(Text, { bold: focused, color: focused ? 'claude' : undefined, wrap: "wrap", children: [index + 1, ". ", label] })] }, label));
|
|
48
52
|
}) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('approval-hint') }) })] }));
|
|
49
53
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { type ReactNode } from 'react';
|
|
2
|
+
import type { ClickEvent } from '../../ink/events/click-event.js';
|
|
2
3
|
export type ListItemProps = {
|
|
3
4
|
/** Whether this item is currently focused (keyboard selection).
|
|
4
5
|
* Shows the pointer indicator (❯) when true. */
|
|
@@ -24,6 +25,12 @@ export type ListItemProps = {
|
|
|
24
25
|
* @default true
|
|
25
26
|
*/
|
|
26
27
|
declareCursor?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Mouse click handler (fullscreen mode). When provided the row becomes
|
|
30
|
+
* clickable and gains a subtle hover background so the affordance is
|
|
31
|
+
* visible; when absent the row renders exactly as before.
|
|
32
|
+
*/
|
|
33
|
+
onClick?: (event: ClickEvent) => void;
|
|
27
34
|
};
|
|
28
35
|
/**
|
|
29
36
|
* A list item for selection UIs, mirroring Claude Code's
|
|
@@ -32,5 +39,5 @@ export type ListItemProps = {
|
|
|
32
39
|
* and CC's color states (focused = suggestion blue, selected = success
|
|
33
40
|
* green).
|
|
34
41
|
*/
|
|
35
|
-
export declare function ListItem({ isFocused, isSelected, children, description, showScrollDown, showScrollUp, styled, disabled, declareCursor, }: ListItemProps): React.ReactNode;
|
|
42
|
+
export declare function ListItem({ isFocused, isSelected, children, description, showScrollDown, showScrollUp, styled, disabled, declareCursor, onClick, }: ListItemProps): React.ReactNode;
|
|
36
43
|
//# sourceMappingURL=ListItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListItem.d.ts","sourceRoot":"","sources":["../../../../src/components/design-system/ListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"ListItem.d.ts","sourceRoot":"","sources":["../../../../src/components/design-system/ListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,MAAM,MAAM,aAAa,GAAG;IAC1B;qDACiD;IACjD,SAAS,EAAE,OAAO,CAAA;IAClB;uDACmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4CAA4C;IAC5C,QAAQ,EAAE,SAAS,CAAA;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,UAAkB,EAClB,QAAQ,EACR,WAAW,EACX,cAAc,EACd,YAAY,EACZ,MAAa,EACb,QAAgB,EAChB,aAAa,EACb,OAAO,GACR,EAAE,aAAa,GAAG,KAAK,CAAC,SAAS,CAoFjC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
3
|
import { Box, Text } from '../../ui.js';
|
|
4
4
|
import { useDeclaredCursor } from '../../ink/hooks/use-declared-cursor.js';
|
|
5
5
|
import { POINTER, DOWN_ARROW, UP_ARROW, TICK } from '../../cc/figures.js';
|
|
@@ -10,7 +10,7 @@ import { POINTER, DOWN_ARROW, UP_ARROW, TICK } from '../../cc/figures.js';
|
|
|
10
10
|
* and CC's color states (focused = suggestion blue, selected = success
|
|
11
11
|
* green).
|
|
12
12
|
*/
|
|
13
|
-
export function ListItem({ isFocused, isSelected = false, children, description, showScrollDown, showScrollUp, styled = true, disabled = false, declareCursor, }) {
|
|
13
|
+
export function ListItem({ isFocused, isSelected = false, children, description, showScrollDown, showScrollUp, styled = true, disabled = false, declareCursor, onClick, }) {
|
|
14
14
|
// Park the native terminal cursor on the pointer indicator so screen
|
|
15
15
|
// readers / magnifiers track the focused item (CC behavior). (0,0) is the
|
|
16
16
|
// top-left of this Box, where the pointer renders.
|
|
@@ -19,6 +19,11 @@ export function ListItem({ isFocused, isSelected = false, children, description,
|
|
|
19
19
|
column: 0,
|
|
20
20
|
active: isFocused && !disabled && declareCursor !== false,
|
|
21
21
|
});
|
|
22
|
+
// Hover highlight only when the row is actually clickable — the extra
|
|
23
|
+
// background is the mouse affordance (there is no cursor-shape feedback
|
|
24
|
+
// in a terminal).
|
|
25
|
+
const [hovered, setHovered] = useState(false);
|
|
26
|
+
const clickable = Boolean(onClick) && !disabled;
|
|
22
27
|
function renderIndicator() {
|
|
23
28
|
if (disabled) {
|
|
24
29
|
return _jsx(Text, { children: " " });
|
|
@@ -54,7 +59,7 @@ export function ListItem({ isFocused, isSelected = false, children, description,
|
|
|
54
59
|
// 非 Fragment 的 element(如调用方自己的 <Text>)保留原样——其子树高度
|
|
55
60
|
// 由调用方负责。
|
|
56
61
|
const flatChildren = flattenDeep(children);
|
|
57
|
-
return (_jsxs(Box, { ref: cursorRef, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", gap: 1, height: 1, flexShrink: 0, overflow: "hidden", width: "100%", children: [renderIndicator(), styled ? (_jsx(Text, { color: getTextColor(), dimColor: disabled, wrap: "truncate-end", children: flatChildren })) : (flatChildren), isSelected && !disabled && _jsx(Text, { color: "success", children: TICK })] }), description && (_jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: "inactive", wrap: "truncate", children: flattenLine(description) }) }))] }));
|
|
62
|
+
return (_jsxs(Box, { ref: cursorRef, flexDirection: "column", onClick: clickable ? onClick : undefined, onMouseEnter: clickable ? () => setHovered(true) : undefined, onMouseLeave: clickable ? () => setHovered(false) : undefined, backgroundColor: clickable && hovered ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, height: 1, flexShrink: 0, overflow: "hidden", width: "100%", children: [renderIndicator(), styled ? (_jsx(Text, { color: getTextColor(), dimColor: disabled, wrap: "truncate-end", children: flatChildren })) : (flatChildren), isSelected && !disabled && _jsx(Text, { color: "success", children: TICK })] }), description && (_jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: "inactive", wrap: "truncate", children: flattenLine(description) }) }))] }));
|
|
58
63
|
}
|
|
59
64
|
/** 单行化:内嵌换行折叠为空格(行尾/行首换行随之消除)。 */
|
|
60
65
|
function flattenLine(s) {
|
|
@@ -7,11 +7,14 @@ type Props = {
|
|
|
7
7
|
isSelected?: boolean;
|
|
8
8
|
/** Row expanded on its own (persistent hover-grey background, CC). */
|
|
9
9
|
isExpanded?: boolean;
|
|
10
|
-
onClick?(): void;
|
|
11
10
|
};
|
|
12
11
|
/**
|
|
13
12
|
* Assistant text message: bullet + markdown body (mirroring Claude Code's default branch).
|
|
13
|
+
*
|
|
14
|
+
* Deliberately not clickable: the transcript is reading material and the
|
|
15
|
+
* mouse's job there is text selection (user feedback — row hover tints and
|
|
16
|
+
* fold toggling were noise, not affordance).
|
|
14
17
|
*/
|
|
15
|
-
export declare function AssistantTextMessage({ text, addMargin, isSelected, isExpanded,
|
|
18
|
+
export declare function AssistantTextMessage({ text, addMargin, isSelected, isExpanded, }: Props): React.ReactNode;
|
|
16
19
|
export {};
|
|
17
20
|
//# sourceMappingURL=AssistantTextMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantTextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantTextMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAA;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sEAAsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"AssistantTextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantTextMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAA;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sEAAsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,SAAS,EACT,UAAkB,EAClB,UAAkB,GACnB,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA0BzB"}
|
|
@@ -4,11 +4,15 @@ import { BLACK_CIRCLE } from '../../cc/figures.js';
|
|
|
4
4
|
import { Markdown } from '../Markdown.js';
|
|
5
5
|
/**
|
|
6
6
|
* Assistant text message: bullet + markdown body (mirroring Claude Code's default branch).
|
|
7
|
+
*
|
|
8
|
+
* Deliberately not clickable: the transcript is reading material and the
|
|
9
|
+
* mouse's job there is text selection (user feedback — row hover tints and
|
|
10
|
+
* fold toggling were noise, not affordance).
|
|
7
11
|
*/
|
|
8
|
-
export function AssistantTextMessage({ text, addMargin, isSelected = false, isExpanded = false,
|
|
12
|
+
export function AssistantTextMessage({ text, addMargin, isSelected = false, isExpanded = false, }) {
|
|
9
13
|
return (_jsx(Box, { alignItems: "flex-start", flexDirection: "row", justifyContent: "space-between", marginTop: addMargin ? 1 : 0, width: "100%", backgroundColor: isSelected
|
|
10
14
|
? 'messageActionsBackground'
|
|
11
15
|
: isExpanded
|
|
12
16
|
? 'userMessageBackgroundHover'
|
|
13
|
-
: undefined,
|
|
17
|
+
: undefined, children: _jsxs(Box, { flexDirection: "row", children: [_jsx(NoSelect, { fromLeftEdge: true, minWidth: 2, children: _jsx(Text, { color: isSelected ? 'suggestion' : 'text', children: BLACK_CIRCLE }) }), _jsx(Box, { flexDirection: "column", children: _jsx(Markdown, { children: text }) })] }) }));
|
|
14
18
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { ClickEvent } from '../../ink/events/click-event.js';
|
|
2
3
|
type Props = {
|
|
3
4
|
thinking: string;
|
|
4
5
|
/** Adds the top margin between messages (CC: addMargin). */
|
|
@@ -17,7 +18,7 @@ type Props = {
|
|
|
17
18
|
durationMs?: number;
|
|
18
19
|
/** Message-selection mode highlight. */
|
|
19
20
|
isSelected?: boolean;
|
|
20
|
-
onClick?(): void;
|
|
21
|
+
onClick?(event: ClickEvent): void;
|
|
21
22
|
};
|
|
22
23
|
/**
|
|
23
24
|
* Thinking block: folded `⚓ Thinking (ctrl+o to expand)`, expanded shows the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantThinkingMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantThinkingMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"AssistantThinkingMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantThinkingMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAUjE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAA;IAClB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAA;IAChB;;4CAEwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;8EAE0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAClC,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,SAAS,EACT,OAAO,EACP,SAAiB,EACjB,OAAe,EACf,UAAU,EACV,UAAkB,EAClB,OAAO,GACR,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAkIzB"}
|
|
@@ -49,7 +49,13 @@ export function AssistantThinkingMessage({ thinking, addMargin, verbose, streami
|
|
|
49
49
|
const pulse = (Math.sin(frame * 0.9) + 1) / 2;
|
|
50
50
|
const pulseColor = interpolateColor(BRAND, ICE, pulse);
|
|
51
51
|
const frameText = THINKING_SPINNER_FRAMES[frame % THINKING_SPINNER_FRAMES.length];
|
|
52
|
-
|
|
52
|
+
// Hover 轻指示:可点击折叠时折叠头从 dim 提亮为正常色(不刷整行背景,
|
|
53
|
+
// 转录视觉保持安静)。
|
|
54
|
+
const [hovered, setHovered] = React.useState(false);
|
|
55
|
+
const hoverProps = onClick !== undefined
|
|
56
|
+
? { onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false) }
|
|
57
|
+
: {};
|
|
58
|
+
const header = streaming ? (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { children: minimal ? frameText : chalk.rgb(pulseColor.r, pulseColor.g, pulseColor.b).bold(frameText) }), _jsx(Text, { dimColor: !hovered, color: hovered ? 'text' : undefined, italic: true, children: ` ${label}` })] })) : (_jsx(Text, { italic: true, dimColor: !hovered, color: hovered ? 'text' : undefined, children: `${minimal ? '*' : THINKING_SETTLED_MARKER} ${label}` }));
|
|
53
59
|
if (preview) {
|
|
54
60
|
// Live ticker: the model's last few reasoning lines, dimmed, one Text
|
|
55
61
|
// per row so each truncates to the width independently, padded to a
|
|
@@ -64,10 +70,10 @@ export function AssistantThinkingMessage({ thinking, addMargin, verbose, streami
|
|
|
64
70
|
// Pad with single spaces — an empty-string Text renders with zero
|
|
65
71
|
// height in ink, so '' padding would not hold the row open.
|
|
66
72
|
const rows = Array.from({ length: PREVIEW_ROWS }, (_, i) => visible[i] ?? ' ');
|
|
67
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: addMargin ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, onClick: onClick, children: [header, _jsx(Box, { flexDirection: "column", paddingLeft: 2, height: PREVIEW_ROWS, flexShrink: 0, overflow: "hidden", children: rows.map((line, i) => (_jsxs(Box, { flexDirection: "row", height: 1, children: [_jsx(Text, { dimColor: true, italic: true, children: '│ ' }), _jsx(Box, { flexDirection: "row", flexGrow: 1, children: _jsx(Text, { dimColor: true, italic: true, wrap: i === rows.length - 1 ? 'truncate-start' : 'truncate', children: i === 0 && clipped ? `…${line}` : line }) })] }, i))) })] }));
|
|
73
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: addMargin ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, onClick: onClick, ...hoverProps, children: [header, _jsx(Box, { flexDirection: "column", paddingLeft: 2, height: PREVIEW_ROWS, flexShrink: 0, overflow: "hidden", children: rows.map((line, i) => (_jsxs(Box, { flexDirection: "row", height: 1, children: [_jsx(Text, { dimColor: true, italic: true, children: '│ ' }), _jsx(Box, { flexDirection: "row", flexGrow: 1, children: _jsx(Text, { dimColor: true, italic: true, wrap: i === rows.length - 1 ? 'truncate-start' : 'truncate', children: i === 0 && clipped ? `…${line}` : line }) })] }, i))) })] }));
|
|
68
74
|
}
|
|
69
75
|
if (!verbose) {
|
|
70
|
-
return (_jsx(Box, { marginTop: addMargin ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, onClick: onClick, children: header }));
|
|
76
|
+
return (_jsx(Box, { marginTop: addMargin ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, onClick: onClick, ...hoverProps, children: header }));
|
|
71
77
|
}
|
|
72
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: addMargin ? 1 : 0, width: "100%", backgroundColor: isSelected ? 'messageActionsBackground' : undefined, onClick: onClick, children: [header, _jsx(Box, { paddingLeft: 2, children: _jsx(StreamingMarkdown, { dimColor: true, children: thinking }) })] }));
|
|
78
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: addMargin ? 1 : 0, width: "100%", backgroundColor: isSelected ? 'messageActionsBackground' : undefined, onClick: onClick, ...hoverProps, children: [header, _jsx(Box, { paddingLeft: 2, children: _jsx(StreamingMarkdown, { dimColor: true, children: thinking }) })] }));
|
|
73
79
|
}
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { ToolRow } from '../../dsh-adapter/channel.js';
|
|
3
3
|
import type { ToolBackground } from '../../tuiDisplayPrefs.js';
|
|
4
4
|
import type { Theme } from '../../theme.js';
|
|
5
|
+
import type { ClickEvent } from '../../ink/events/click-event.js';
|
|
5
6
|
type Props = {
|
|
6
7
|
tool: ToolRow;
|
|
7
8
|
/** Adds the top margin between messages (CC: addMargin). */
|
|
@@ -12,6 +13,12 @@ type Props = {
|
|
|
12
13
|
isSelected?: boolean;
|
|
13
14
|
/** Row expanded on its own (persistent hover-grey background, CC). */
|
|
14
15
|
isExpanded?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Mouse click (fullscreen): toggles the row's expansion — same action as
|
|
18
|
+
* clicking other transcript rows. Also makes the `(ctrl+o to expand)`
|
|
19
|
+
* hint actionable with the mouse.
|
|
20
|
+
*/
|
|
21
|
+
onClick?(event: ClickEvent): void;
|
|
15
22
|
/**
|
|
16
23
|
* Trajectory pointer, rendered as one more `⎿` line under a failed call.
|
|
17
24
|
*
|
|
@@ -33,6 +40,6 @@ export declare function toolNameColor(raw: string): keyof Theme;
|
|
|
33
40
|
* output, read content — instead of the raw result dump (mirroring Claude Code's `AssistantToolUseMessage.tsx` + the dsh-tools presentation views the
|
|
34
41
|
* channel captures per call).
|
|
35
42
|
*/
|
|
36
|
-
export declare function AssistantToolUseMessage({ tool, addMargin, verbose, isSelected, isExpanded, footnote, diffLayout, toolBackground, }: Props): React.ReactNode;
|
|
43
|
+
export declare function AssistantToolUseMessage({ tool, addMargin, verbose, isSelected, isExpanded, onClick, footnote, diffLayout, toolBackground, }: Props): React.ReactNode;
|
|
37
44
|
export {};
|
|
38
45
|
//# sourceMappingURL=AssistantToolUseMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantToolUseMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantToolUseMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAA8C,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAKvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"AssistantToolUseMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantToolUseMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAA8C,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAKvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAEjE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,OAAO,CAAA;IACb,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAA;IAClB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sEAAsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC,2EAA2E;IAC3E,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC,CAAA;AAgFD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,CAKtD;AAwKD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,IAAI,EACJ,SAAS,EACT,OAAO,EACP,UAAkB,EAClB,UAAkB,EAClB,OAAO,EACP,QAAQ,EACR,UAAmB,EACnB,cAAuB,GACxB,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAsKzB"}
|
|
@@ -221,7 +221,7 @@ function HeaderTitle({ name, title, isTerminal, displayArgs, argsLanguage, nameC
|
|
|
221
221
|
* output, read content — instead of the raw result dump (mirroring Claude Code's `AssistantToolUseMessage.tsx` + the dsh-tools presentation views the
|
|
222
222
|
* channel captures per call).
|
|
223
223
|
*/
|
|
224
|
-
export function AssistantToolUseMessage({ tool, addMargin, verbose, isSelected = false, isExpanded = false, footnote, diffLayout = 'auto', toolBackground = 'none', }) {
|
|
224
|
+
export function AssistantToolUseMessage({ tool, addMargin, verbose, isSelected = false, isExpanded = false, onClick, footnote, diffLayout = 'auto', toolBackground = 'none', }) {
|
|
225
225
|
const isRunning = tool.status === 'running';
|
|
226
226
|
const isError = tool.status === 'error';
|
|
227
227
|
const displayArgs = verbose ? tool.argsFull ?? tool.argsText : tool.argsText;
|
|
@@ -286,9 +286,11 @@ export function AssistantToolUseMessage({ tool, addMargin, verbose, isSelected =
|
|
|
286
286
|
: ordinaryToolBackground === 'strong'
|
|
287
287
|
? 'toolCardBackground'
|
|
288
288
|
: undefined;
|
|
289
|
-
return (_jsx(Box, { ref: viewportRef, flexDirection: "row", justifyContent: "space-between", marginTop: addMargin ? 1 : 0, width: "100%",
|
|
289
|
+
return (_jsx(Box, { ref: viewportRef, flexDirection: "row", justifyContent: "space-between", marginTop: addMargin ? 1 : 0, width: "100%", onClick: onClick,
|
|
290
290
|
// Only selection paints a highlight; the configured treatment applies
|
|
291
291
|
// to an ordinary card. Diff line tints stay - they are content, not chrome.
|
|
292
|
+
// No hover tint: the card stays visually quiet until clicked (user
|
|
293
|
+
// feedback — row-hover color changes read as noise in the transcript).
|
|
292
294
|
backgroundColor: isSelected ? 'messageActionsBackground' : ordinaryBackground, children: _jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { flexDirection: "row", flexWrap: "nowrap", minWidth: minWidth, children: [_jsx(ToolUseLoader, { shouldAnimate: isRunning, isUnresolved: isRunning, isError: isError, toolName: tool.name }), _jsx(HeaderTitle, { name: name, title: headerTitle, isTerminal: headerIsTerminal, displayArgs: displayArgs, argsLanguage: argsLanguage, nameColor: toolNameColor(tool.name) }), !isRunning && (_jsx(Box, { flexWrap: "nowrap", children: _jsx(Text, { dimColor: true, children: elapsedText }) }))] }), useSplitDiff && view?.card === 'diff' ? (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: GUTTER_FIRST }) }), _jsx(SplitDiffView, { diffs: view.diffs, width: columns - 4, maxRows: DIFF_BODY_MAX_LINES, verbose: verbose, toolBackground: ordinaryToolBackground })] })) : (rendered.map((line, index) => (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsx(Text, { color: line.tone === 'add'
|
|
293
295
|
? 'diffAddedWord'
|
|
294
296
|
: line.tone === 'del'
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { ClickEvent } from '../../ink/events/click-event.js';
|
|
2
3
|
type Props = {
|
|
3
4
|
text: string;
|
|
4
5
|
/** Adds the top margin between turns (CC: addMargin). */
|
|
5
6
|
addMargin: boolean;
|
|
6
7
|
/** Message-selection mode highlight. */
|
|
7
8
|
isSelected?: boolean;
|
|
8
|
-
onClick?(): void;
|
|
9
|
+
onClick?(event: ClickEvent): void;
|
|
9
10
|
};
|
|
10
11
|
/**
|
|
11
12
|
* User prompt bubble: `❯ text` in bold briefLabelYou gold with no background
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserPromptMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/UserPromptMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"UserPromptMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/UserPromptMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAEjE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,SAAS,EAAE,OAAO,CAAA;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAClC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,SAAS,EACT,UAAkB,EAClB,OAAO,GACR,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA6BzB"}
|