@deepseek-harness-tui/dsh-tui 0.11.2 → 0.12.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 +21 -5
- package/bin/dsh-tui.js +30 -3
- package/cordis.patch.yml +24 -5
- package/guide/dsh-tui-guide/SKILL.md +37 -0
- package/guide/dsh-tui-guide/configuration.en.md +410 -0
- package/guide/dsh-tui-guide/configuration.md +349 -0
- package/guide/dsh-tui-guide/getting-started.en.md +398 -0
- package/guide/dsh-tui-guide/getting-started.md +397 -0
- package/guide/dsh-tui-guide/interaction.en.md +674 -0
- package/guide/dsh-tui-guide/interaction.md +747 -0
- package/guide/dsh-tui-guide/migrate.en.md +166 -0
- package/guide/dsh-tui-guide/migrate.md +132 -0
- package/guide/dsh-tui-guide/plugins.en.md +68 -0
- package/guide/dsh-tui-guide/plugins.md +56 -0
- package/guide/dsh-tui-guide/themes.en.md +192 -0
- package/guide/dsh-tui-guide/themes.md +185 -0
- package/guide/dsh-tui-guide/user-guide.en.md +608 -0
- package/guide/dsh-tui-guide/user-guide.md +586 -0
- package/guide/dsh-tui-guide/vscode.en.md +301 -0
- package/guide/dsh-tui-guide/vscode.md +272 -0
- package/lib/settings.json +5 -5
- package/lib/types/adapter/channel/ui-policy.d.ts +3 -2
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +4 -0
- package/lib/types/adapter/ports/channel-settings.d.ts +2 -1
- package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-ui.d.ts +29 -2
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +43 -9
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/components/Chat/JobCard.d.ts +9 -0
- package/lib/types/components/Chat/JobCard.d.ts.map +1 -1
- package/lib/types/components/Chat/JobCard.js +42 -15
- package/lib/types/components/Chat/SubagentMessage.js +6 -6
- package/lib/types/components/JobsPanel.d.ts.map +1 -1
- package/lib/types/components/JobsPanel.js +80 -33
- package/lib/types/components/MessageList.js +3 -3
- package/lib/types/components/PresetPicker.d.ts +4 -0
- package/lib/types/components/PresetPicker.d.ts.map +1 -1
- package/lib/types/components/PresetPicker.js +5 -1
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +12 -1
- package/lib/types/components/StarPrompt.d.ts +6 -0
- package/lib/types/components/StarPrompt.d.ts.map +1 -1
- package/lib/types/components/StarPrompt.js +45 -0
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +8 -8
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +108 -10
- package/lib/types/components/WhaleGirl.d.ts +6 -0
- package/lib/types/components/WhaleGirl.d.ts.map +1 -1
- package/lib/types/components/WhaleGirl.js +18 -0
- package/lib/types/components/messages/AssistantThinkingMessage.js +4 -4
- package/lib/types/components/trajectory/MiniWake.d.ts +11 -1
- package/lib/types/components/trajectory/MiniWake.d.ts.map +1 -1
- package/lib/types/components/trajectory/MiniWake.js +9 -3
- package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/external-commands.js +8 -2
- package/lib/types/dsh-adapter/channel/job-projection.d.ts +1 -0
- package/lib/types/dsh-adapter/channel/job-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/job-projection.js +88 -3
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts +13 -0
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-actions.js +48 -7
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.js +25 -9
- package/lib/types/dsh-adapter/channel/preferences.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/preferences.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/preferences.js +17 -7
- package/lib/types/dsh-adapter/channel/state.d.ts +4 -2
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +5 -0
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +16 -1
- package/lib/types/dsh-adapter/contract.d.ts +5 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +9 -3
- package/lib/types/dsh-adapter/jobs.d.ts +82 -16
- package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
- package/lib/types/dsh-adapter/jobs.js +104 -9
- package/lib/types/dsh-adapter/oauth/bonus.d.ts +27 -0
- package/lib/types/dsh-adapter/oauth/bonus.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth/bonus.js +69 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/command.d.ts +2 -1
- package/lib/types/dsh-adapter/oauth/command.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/command.js +7 -4
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/credentials.d.ts +13 -10
- package/lib/types/dsh-adapter/oauth/credentials.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/credentials.js +61 -23
- package/lib/types/dsh-adapter/oauth/deepseek.d.ts +39 -0
- package/lib/types/dsh-adapter/oauth/deepseek.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth/deepseek.js +189 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/index.d.ts +24 -16
- package/lib/types/dsh-adapter/oauth/index.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/index.js +34 -20
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/interaction.d.ts +14 -12
- package/lib/types/dsh-adapter/oauth/interaction.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth/interaction.js +283 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/opener.d.ts +2 -1
- package/lib/types/dsh-adapter/oauth/opener.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/opener.js +1 -1
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/pi-ai.d.ts +10 -3
- package/lib/types/dsh-adapter/oauth/pi-ai.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/pi-ai.js +8 -3
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/profiles.d.ts +6 -3
- package/lib/types/dsh-adapter/oauth/profiles.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/profiles.js +11 -3
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/service.d.ts +14 -7
- package/lib/types/dsh-adapter/oauth/service.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/service.js +82 -17
- package/lib/types/dsh-adapter/plugin.d.ts +8 -1
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +72 -12
- package/lib/types/dsh-adapter/presets.d.ts +6 -4
- package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/presets.js +6 -4
- package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/providerWizard.js +6 -2
- package/lib/types/dsh-adapter/subagents.d.ts +1 -0
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +10 -1
- package/lib/types/i18n.d.ts +174 -18
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +53 -11
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +10 -1
- package/lib/types/ink/parse-keypress.d.ts +35 -0
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +611 -83
- package/lib/types/ink/terminal-querier.d.ts +25 -0
- package/lib/types/ink/terminal-querier.d.ts.map +1 -1
- package/lib/types/ink/terminal-querier.js +42 -0
- package/lib/types/ink/update-overflow-guard.d.ts +24 -0
- package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
- package/lib/types/ink/update-overflow-guard.js +25 -3
- package/lib/types/minimalUiMode.d.ts +19 -0
- package/lib/types/minimalUiMode.d.ts.map +1 -0
- package/lib/types/minimalUiMode.js +23 -0
- package/lib/types/oauth.d.ts +5 -10
- package/lib/types/oauth.d.ts.map +1 -1
- package/lib/types/oauth.js +5 -10
- package/lib/types/screens/Chat.d.ts +4 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +27 -7
- package/lib/types/screens/StatusLine.d.ts +4 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +12 -12
- package/lib/types/settings/definitions.js +4 -4
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +10 -4
- package/lib/types/update.js +2 -2
- package/lib/types/utils/pastedImagePath.d.ts +8 -0
- package/lib/types/utils/pastedImagePath.d.ts.map +1 -1
- package/lib/types/utils/pastedImagePath.js +29 -5
- package/package.json +111 -100
- package/presets/liangshen/agent.cordis.yml +4 -1
- package/presets/liangshen/preset.yml +1 -1
- package/lib/types/minimalMode.d.ts +0 -13
- package/lib/types/minimalMode.d.ts.map +0 -1
- package/lib/types/minimalMode.js +0 -17
- package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +0 -21
- package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +0 -143
- package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +0 -11
- package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +0 -44
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +0 -193
- package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +0 -69
|
@@ -6,8 +6,10 @@ import { Divider } from './design-system/Divider.js';
|
|
|
6
6
|
import { ExitButton } from './SubagentDashboard.js';
|
|
7
7
|
import { isPlainReturnInput } from '../utils/modifiers.js';
|
|
8
8
|
import { toolNameColor } from './messages/AssistantToolUseMessage.js';
|
|
9
|
+
import { Markdown } from './Markdown.js';
|
|
9
10
|
import { getCliHighlightPromise } from '../terminal-utils/cliHighlight.js';
|
|
10
|
-
import {
|
|
11
|
+
import { isMinimalUiMode } from '../minimalUiMode.js';
|
|
12
|
+
import { THINKING_SETTLED_MARKER } from '../terminal-utils/figures.js';
|
|
11
13
|
function formatDuration(ms) {
|
|
12
14
|
if (ms < 1000)
|
|
13
15
|
return `${ms}ms`;
|
|
@@ -21,16 +23,16 @@ function formatTimestamp(ts) {
|
|
|
21
23
|
return new Date(ts).toLocaleTimeString();
|
|
22
24
|
}
|
|
23
25
|
function statusGlyph(status) {
|
|
24
|
-
const
|
|
26
|
+
const minimalUi = isMinimalUiMode();
|
|
25
27
|
if (status === 'completed')
|
|
26
|
-
return { glyph:
|
|
28
|
+
return { glyph: minimalUi ? '✓' : '🟢', color: minimalUi ? undefined : 'success', label: 'done' };
|
|
27
29
|
if (status === 'failed')
|
|
28
|
-
return { glyph:
|
|
30
|
+
return { glyph: minimalUi ? '×' : '🔴', color: minimalUi ? undefined : 'error', label: 'failed' };
|
|
29
31
|
if (status === 'cancelled')
|
|
30
|
-
return { glyph:
|
|
32
|
+
return { glyph: minimalUi ? '×' : '🔴', color: minimalUi ? undefined : 'error', label: 'cancelled' };
|
|
31
33
|
if (status === 'unknown')
|
|
32
|
-
return { glyph:
|
|
33
|
-
return { glyph:
|
|
34
|
+
return { glyph: minimalUi ? '·' : '⚪', color: minimalUi ? undefined : 'subtle', label: 'history' };
|
|
35
|
+
return { glyph: minimalUi ? '·' : '🟡', color: minimalUi ? undefined : 'warning', label: 'running' };
|
|
34
36
|
}
|
|
35
37
|
const PAGES = ['summary', 'output', 'tools'];
|
|
36
38
|
/** One label/value row of the summary stats card. */
|
|
@@ -67,6 +69,39 @@ function JsonArgsText({ raw }) {
|
|
|
67
69
|
return _jsx(Text, { wrap: "wrap", children: highlighted });
|
|
68
70
|
return _jsx(Text, { dimColor: true, wrap: "wrap", children: flat });
|
|
69
71
|
}
|
|
72
|
+
function groupOutputEvents(events) {
|
|
73
|
+
const blocks = [];
|
|
74
|
+
for (const line of events) {
|
|
75
|
+
if (line.kind === 'thinking') {
|
|
76
|
+
const last = blocks[blocks.length - 1];
|
|
77
|
+
if (last !== undefined && last.kind === 'thinking')
|
|
78
|
+
last.lines.push(line);
|
|
79
|
+
else
|
|
80
|
+
blocks.push({ kind: 'thinking', lines: [line] });
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// Consecutive prose lines are ONE markdown document: without the fold a
|
|
84
|
+
// `**bold**` line, its list items and its paragraph break would render as
|
|
85
|
+
// raw syntax separated by blank rows. Activity pointers and tool/error
|
|
86
|
+
// rows stay independent single lines.
|
|
87
|
+
if (line.kind === 'text' && !isActivityLine(line.text)) {
|
|
88
|
+
const last = blocks[blocks.length - 1];
|
|
89
|
+
if (last !== undefined && last.kind === 'prose')
|
|
90
|
+
last.lines.push(line);
|
|
91
|
+
else
|
|
92
|
+
blocks.push({ kind: 'prose', lines: [line] });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
blocks.push({ kind: 'line', line });
|
|
96
|
+
}
|
|
97
|
+
return blocks;
|
|
98
|
+
}
|
|
99
|
+
/** The child's own status line reaches us as a text delta (\`⏵ reading …\`);
|
|
100
|
+
* it is activity, not prose, so it renders as a dim pointer row. */
|
|
101
|
+
const ACTIVITY_GLYPHS = ['⏵', '▶', '▸', '»'];
|
|
102
|
+
function isActivityLine(text) {
|
|
103
|
+
return ACTIVITY_GLYPHS.includes(text.trimStart().slice(0, 1));
|
|
104
|
+
}
|
|
70
105
|
/**
|
|
71
106
|
* SubagentDetailScene — full-screen paged detail view for one subagent.
|
|
72
107
|
* Header block (identity + stats) stays fixed; the body pages through
|
|
@@ -86,6 +121,27 @@ export function SubagentDetailScene({ subagent, onBack, onInterrupt, }) {
|
|
|
86
121
|
const info = statusGlyph(subagent.status);
|
|
87
122
|
const totalTokens = subagent.tokens?.total ?? ((subagent.tokens?.input ?? 0) + (subagent.tokens?.output ?? 0) || 0);
|
|
88
123
|
const pageIndex = PAGES.indexOf(page);
|
|
124
|
+
/** Folded reasoning runs (the transcript's thinking grammar). Enter flips
|
|
125
|
+
* every run at once so one key stays predictable across thought steps. */
|
|
126
|
+
const [thinkingOpen, setThinkingOpen] = React.useState(false);
|
|
127
|
+
const blocks = groupOutputEvents(subagent.outputEvents);
|
|
128
|
+
const hasThinking = blocks.some(block => block.kind === 'thinking');
|
|
129
|
+
const settled = !isRunning;
|
|
130
|
+
// The deliverable is the LAST prose block: a `── Conclusion ──` rule goes in
|
|
131
|
+
// front of it once the run settles, so the answer is never the last line of
|
|
132
|
+
// a wall of reasoning.
|
|
133
|
+
const answerBlock = (() => {
|
|
134
|
+
if (!settled)
|
|
135
|
+
return -1;
|
|
136
|
+
for (let i = blocks.length - 1; i >= 0; i--) {
|
|
137
|
+
const block = blocks[i];
|
|
138
|
+
if (block.kind === 'prose' && block.lines.some(p => p.text.trim() !== ''))
|
|
139
|
+
return i;
|
|
140
|
+
if (block.kind === 'line' && block.line.kind === 'text' && block.line.text.trim() !== '')
|
|
141
|
+
return i;
|
|
142
|
+
}
|
|
143
|
+
return -1;
|
|
144
|
+
})();
|
|
89
145
|
const turnPage = (delta) => {
|
|
90
146
|
const next = (pageIndex + delta + PAGES.length) % PAGES.length;
|
|
91
147
|
setPage(PAGES[next]);
|
|
@@ -94,6 +150,17 @@ export function SubagentDetailScene({ subagent, onBack, onInterrupt, }) {
|
|
|
94
150
|
// tail -f: while the subagent runs and the output page is showing, follow
|
|
95
151
|
// the newest streamed line. Page switches or settlement stop the follow so
|
|
96
152
|
// manual ↑ scrolling wins.
|
|
153
|
+
// Expanding the reasoning grows the box past its viewport, and the renderer
|
|
154
|
+
// then treats the growth as "was at bottom" (maxScroll was 0 while the folded
|
|
155
|
+
// body fit) and re-pins the view to the bottom — pushing the fold header out
|
|
156
|
+
// of sight. Re-anchor AFTER that frame: the first immediate lands behind the
|
|
157
|
+
// renderer's own scheduling, and the second behind the re-pin frame it caused.
|
|
158
|
+
React.useEffect(() => {
|
|
159
|
+
if (page !== 'output')
|
|
160
|
+
return;
|
|
161
|
+
const first = setImmediate(() => scrollRef.current?.scrollTo?.(0));
|
|
162
|
+
return () => clearImmediate(first);
|
|
163
|
+
}, [thinkingOpen, page]);
|
|
97
164
|
const outputLength = subagent.outputEvents.length;
|
|
98
165
|
React.useEffect(() => {
|
|
99
166
|
if (page !== 'output' || !isRunning)
|
|
@@ -133,7 +200,13 @@ export function SubagentDetailScene({ subagent, onBack, onInterrupt, }) {
|
|
|
133
200
|
}
|
|
134
201
|
if (isPlainReturnInput(input, key)) {
|
|
135
202
|
event.stopImmediatePropagation();
|
|
136
|
-
|
|
203
|
+
// Enter folds the reasoning while the output page is showing (the
|
|
204
|
+
// transcript's ctrl+o equivalent). Elsewhere it keeps its "leave the
|
|
205
|
+
// detail" meaning, which Esc and the ✕ button still provide.
|
|
206
|
+
if (page === 'output' && hasThinking)
|
|
207
|
+
setThinkingOpen(open => !open);
|
|
208
|
+
else
|
|
209
|
+
onBack();
|
|
137
210
|
return;
|
|
138
211
|
}
|
|
139
212
|
event.stopImmediatePropagation();
|
|
@@ -142,6 +215,31 @@ export function SubagentDetailScene({ subagent, onBack, onInterrupt, }) {
|
|
|
142
215
|
const active = page === name;
|
|
143
216
|
return (_jsxs(React.Fragment, { children: [_jsx(Box, { onClick: () => setPage(name), backgroundColor: !active ? 'userMessageBackgroundHover' : undefined, children: _jsx(Text, { color: active ? 'accent' : undefined, bold: active, inverse: active, children: ` ${label} ` }) }), _jsx(Text, { dimColor: true, children: name === PAGES[PAGES.length - 1] ? '' : '│' })] }, name));
|
|
144
217
|
};
|
|
145
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: info.color, bold: true, children: info.glyph }), _jsx(Text, { bold: true, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsx(Text, { dimColor: true, children: "\u00B7" }), _jsx(Text, { color: info.color, children: info.label }), _jsx(Box, { flexGrow: 1 }), _jsx(ExitButton, { onClick: onBack })] }), _jsxs(Text, { children: [_jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsxs(Text, { dimColor: true, children: [elapsed !== undefined ? ` · ${formatDuration(elapsed)} · ` : ' · ', totalTokens || '—', " tok \u00B7 ", subagent.toolCalls.length, " tools"] })] }), _jsxs(Text, { dimColor: true, children: [`${t('subagent-started')} ${formatTimestamp(subagent.startedAt)}`
|
|
146
|
-
+ (subagent.completedAt ? ` · ${t('subagent-completed')} ${formatTimestamp(subagent.completedAt)}` : ''), ` · id ${subagent.agentId}`] }), subagent.error && (_jsx(Box, { marginTop: 0, children: _jsx(Text, { color: "error", wrap: "wrap", children: `${t('subagent-error-label')}: ${subagent.error}` }) })), _jsxs(Box, { flexDirection: "row", gap: 0, marginTop: 1, children: [tab('summary', t('subagent-tab-summary')), tab('output', t('subagent-output-label')), tab('tools', t('subagent-tools')), _jsx(Text, { dimColor: true, children: ` ${pageIndex + 1}/${PAGES.length}` })] }), _jsx(Text, { dimColor: true, children: '─'.repeat(Math.max(20, Math.min(72, columns - 6))) }), _jsx(Box, { flexDirection: "column", paddingX: 1, maxHeight: Math.max(10, rows - 14), children: _jsxs(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: [page === 'summary' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(StatGrid, { subagent: subagent, totalTokens: totalTokens, elapsed: elapsed, statusLabel: info.label, statusColor: info.color }), subagent.summary && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, bold: true, children: '─ summary ' }), _jsx(Text, { wrap: "wrap", children: subagent.summary })] })), !subagent.summary && (_jsx(Text, { dimColor: true, children: isRunning ? t('subagent-no-output') : t('subagent-no-summary') }))] })), page === 'output' && (subagent.outputEvents.length === 0 && subagent.output.length === 0 ? (_jsx(Text, { dimColor: true, children: t('subagent-no-output') })) : (
|
|
218
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: info.color, bold: true, children: info.glyph }), _jsx(Text, { bold: true, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsx(Text, { dimColor: true, children: "\u00B7" }), _jsx(Text, { color: info.color, children: info.label }), subagent.mode === 'continuable' && _jsx(Text, { color: "warning", children: t('subagent-mode-continuable') }), subagent.mode === 'one-shot' && _jsx(Text, { dimColor: true, children: t('subagent-mode-one-shot') }), _jsx(Box, { flexGrow: 1 }), _jsx(ExitButton, { onClick: onBack })] }), _jsxs(Text, { children: [_jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsxs(Text, { dimColor: true, children: [elapsed !== undefined ? ` · ${formatDuration(elapsed)} · ` : ' · ', totalTokens || '—', " tok \u00B7 ", subagent.toolCalls.length, " tools"] })] }), _jsxs(Text, { dimColor: true, children: [`${t('subagent-started')} ${formatTimestamp(subagent.startedAt)}`
|
|
219
|
+
+ (subagent.completedAt ? ` · ${t('subagent-completed')} ${formatTimestamp(subagent.completedAt)}` : ''), ` · id ${subagent.agentId.slice(0, 8)}`] }), subagent.error && (_jsx(Box, { marginTop: 0, children: _jsx(Text, { color: "error", wrap: "wrap", children: `${t('subagent-error-label')}: ${subagent.error}` }) })), _jsxs(Box, { flexDirection: "row", gap: 0, marginTop: 1, children: [tab('summary', t('subagent-tab-summary')), tab('output', subagent.outputEvents.length > 0 ? `${t('subagent-output-label')} ${subagent.outputEvents.length}` : t('subagent-output-label')), tab('tools', subagent.toolCalls.length > 0 ? `${t('subagent-tools')} ${subagent.toolCalls.length}` : t('subagent-tools')), _jsx(Text, { dimColor: true, children: ` ${pageIndex + 1}/${PAGES.length}` })] }), _jsx(Text, { dimColor: true, children: '─'.repeat(Math.max(20, Math.min(72, columns - 6))) }), _jsx(Box, { flexDirection: "column", paddingX: 1, maxHeight: Math.max(10, rows - 14), children: _jsxs(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: [page === 'summary' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(StatGrid, { subagent: subagent, totalTokens: totalTokens, elapsed: elapsed, statusLabel: info.label, statusColor: info.color }), subagent.summary && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, bold: true, children: '─ summary ' }), _jsx(Text, { wrap: "wrap", children: subagent.summary })] })), !subagent.summary && (_jsx(Text, { dimColor: true, children: isRunning ? t('subagent-no-output') : t('subagent-no-summary') }))] })), page === 'output' && (subagent.outputEvents.length === 0 && subagent.output.length === 0 ? (_jsx(Text, { dimColor: true, children: t('subagent-no-output') })) : (blocks.map((block, index) => {
|
|
220
|
+
if (block.kind === 'thinking') {
|
|
221
|
+
const text = block.lines.map(line => line.text).join('\n');
|
|
222
|
+
const chars = text.replace(/\s+/g, '').length;
|
|
223
|
+
const label = `${THINKING_SETTLED_MARKER} ${t('subagent-thinking-fold', { count: block.lines.length, chars })}`;
|
|
224
|
+
const hint = thinkingOpen ? t('subagent-thinking-collapse') : t('subagent-thinking-expand');
|
|
225
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { italic: true, dimColor: true, children: `${label} · ${hint}` }), thinkingOpen ? (_jsx(Box, { flexDirection: "column", paddingLeft: 2, children: block.lines.map((line, i) => (_jsx(Text, { dimColor: true, italic: true, wrap: "wrap", children: line.text }, i))) })) : (_jsx(Text, { dimColor: true, italic: true, wrap: "truncate-end", children: ` ${block.lines[0]?.text.replace(/\s+/g, ' ').trim() ?? ''}` }))] }, `think-${index}`));
|
|
226
|
+
}
|
|
227
|
+
if (block.kind === 'prose') {
|
|
228
|
+
const proseText = block.lines.map(p => p.text).join('\n');
|
|
229
|
+
const proseUnsettled = isRunning && block.lines.some(p => p.settled === false);
|
|
230
|
+
const isProseAnswer = index === answerBlock;
|
|
231
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [isProseAnswer && (_jsx(Text, { dimColor: true, children: `── ${t('subagent-conclusion')} ${'─'.repeat(Math.max(8, Math.min(60, columns - 16)))}` })), _jsx(Markdown, { dimColor: false, cacheTokens: true, children: proseText }), proseUnsettled && _jsx(Text, { dimColor: true, children: '▌' })] }, `prose-${index}`));
|
|
232
|
+
}
|
|
233
|
+
const line = block.line;
|
|
234
|
+
const unsettled = !line.settled && isRunning ? ' ▍' : '';
|
|
235
|
+
if (line.kind === 'text' && isActivityLine(line.text)) {
|
|
236
|
+
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: "accent", children: '⏵' }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [line.text.replace(/^[\s⏵▶▸»]+/, ''), unsettled] })] }, `act-${index}`));
|
|
237
|
+
}
|
|
238
|
+
const isAnswer = index === answerBlock;
|
|
239
|
+
// Tool / error / system rows get a leading row gap so a wall
|
|
240
|
+
// of streamed rows stops reading as one cramped paragraph.
|
|
241
|
+
const rowGap = line.kind === 'tool' || line.kind === 'error' || line.kind === 'system';
|
|
242
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: rowGap && index !== 0 ? 1 : 0, children: [isAnswer && (_jsx(Text, { dimColor: true, children: `── ${t('subagent-conclusion')} ${'─'.repeat(Math.max(8, Math.min(60, columns - 16)))}` })), _jsxs(Text, { wrap: "wrap", bold: isAnswer, dimColor: line.kind === 'system', color: line.kind === 'error' ? 'error' : line.kind === 'tool' ? 'accent' : undefined, children: [line.kind === 'tool' ? `● ${line.text}` : line.text, unsettled] })] }, `line-${index}`));
|
|
243
|
+
}))), page === 'tools' && (subagent.toolCalls.length === 0 ? (_jsx(Text, { dimColor: true, children: t('subagent-no-tools') })) : (subagent.toolCalls.map((tool, index) => (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: tool.status === 'failed' ? 'error' : tool.status === 'running' ? 'warning' : 'success', children: tool.status === 'running' ? '·' : tool.status === 'failed' ? '×' : '✓' }), _jsx(Text, { color: toolNameColor(tool.name), children: tool.name }), tool.endedAt && _jsx(Text, { dimColor: true, children: formatDuration(tool.endedAt - tool.startedAt) })] }), tool.argsPreview && (_jsx(Box, { flexDirection: "row", paddingLeft: 2, children: _jsx(JsonArgsText, { raw: tool.argsPreview }) })), tool.resultPreview && (_jsx(Box, { flexDirection: "row", paddingLeft: 2, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: `⎿ ${tool.resultPreview}` }) })), tool.error && (_jsx(Box, { flexDirection: "row", paddingLeft: 2, children: _jsx(Text, { color: "error", wrap: "wrap", children: tool.error }) }))] }, tool.id ?? index)))))] }) }), _jsx(Divider, { color: "subtle", title: "" }), _jsxs(Box, { marginTop: 0, flexDirection: "row", children: [_jsx(Text, { dimColor: true, children: `←/→ ${t('subagent-hint-page')} · ↑/↓ ${t('subagent-hint-scroll')}`
|
|
244
|
+
+ (page === 'output' && hasThinking ? ` · ${t('subagent-hint-fold')}` : '') }), isRunning && onInterrupt && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Box, { onClick: () => onInterrupt(subagent.agentId), children: _jsx(Text, { dimColor: true, bold: true, color: "warning", children: "X interrupt" }) })] })), _jsx(Text, { dimColor: true, children: ` · Esc ${t('subagent-hint-back')}` })] })] }));
|
|
147
245
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { TerminalImageSource } from '../ink/terminal-image.js';
|
|
2
3
|
/**
|
|
3
4
|
* The maid portrait (鲸鱼娘) that can stand in for the header's pixel whale
|
|
4
5
|
* (settings `dsh-tui.whaleGirl`): the author-designed 30×30 true-color
|
|
@@ -26,4 +27,9 @@ export declare const WHALE_GIRL_CENTER = 19.5;
|
|
|
26
27
|
export declare function WhaleGirlArt({ width }: {
|
|
27
28
|
width?: number;
|
|
28
29
|
}): React.ReactNode;
|
|
30
|
+
/** The same heart-pose portrait used by the Star celebration, rendered as cells when image protocols are absent. */
|
|
31
|
+
export declare function WhaleGirlHappyArt({ source, width }: {
|
|
32
|
+
source?: TerminalImageSource;
|
|
33
|
+
width?: number;
|
|
34
|
+
}): React.ReactNode;
|
|
29
35
|
//# sourceMappingURL=WhaleGirl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WhaleGirl.d.ts","sourceRoot":"","sources":["../../../src/components/WhaleGirl.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"WhaleGirl.d.ts","sourceRoot":"","sources":["../../../src/components/WhaleGirl.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEnE;;;;;;;;GAQG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAI5C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAW3E;AAED,oHAAoH;AACpH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,KAAU,EAAE,EAAE;IACxD,MAAM,CAAC,EAAE,mBAAmB,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,GAAG,KAAK,CAAC,SAAS,CAoBlB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import { Box, Text } from '../ui.js';
|
|
3
4
|
import { renderCellRows } from './Whale.js';
|
|
4
5
|
import { WHALE_GIRL_COLS, WHALE_GIRL_SPRITE, WHALE_GIRL_SPRITE_ROWS } from './whaleGirlSprite.js';
|
|
@@ -30,3 +31,20 @@ export function WhaleGirlArt({ width }) {
|
|
|
30
31
|
const pad = width === undefined ? 0 : Math.max(0, Math.floor((width - WHALE_GIRL_COLS) / 2));
|
|
31
32
|
return (_jsx(Box, { flexDirection: "column", flexShrink: 0, width: width, children: WHALE_GIRL_ROWS.map((row, index) => (_jsxs(Text, { wrap: "truncate-end", children: [pad > 0 ? ' '.repeat(pad) : '', row] }, index))) }));
|
|
32
33
|
}
|
|
34
|
+
/** The same heart-pose portrait used by the Star celebration, rendered as cells when image protocols are absent. */
|
|
35
|
+
export function WhaleGirlHappyArt({ source, width = 40 }) {
|
|
36
|
+
const rows = React.useMemo(() => {
|
|
37
|
+
if (source === undefined)
|
|
38
|
+
return WHALE_GIRL_ROWS;
|
|
39
|
+
return renderCellRows(WHALE_GIRL_COLS, 32, (x, y) => {
|
|
40
|
+
const sx = Math.min(source.width - 1, Math.floor((x + 0.5) * source.width / WHALE_GIRL_COLS));
|
|
41
|
+
const sy = Math.min(source.height - 1, Math.floor((y + 0.5) * source.height / 32));
|
|
42
|
+
const at = (sy * source.width + sx) * 4;
|
|
43
|
+
if ((source.data[at + 3] ?? 0) < 80)
|
|
44
|
+
return undefined;
|
|
45
|
+
return [source.data[at] ?? 0, source.data[at + 1] ?? 0, source.data[at + 2] ?? 0];
|
|
46
|
+
});
|
|
47
|
+
}, [source]);
|
|
48
|
+
const pad = Math.max(0, Math.floor((width - WHALE_GIRL_COLS) / 2));
|
|
49
|
+
return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, width: width, children: [source === undefined && _jsx(Text, { color: "#f477a7", wrap: "truncate-end", children: ' ♥ ♥' }), rows.map((row, index) => (_jsxs(Text, { wrap: "truncate-end", children: [' '.repeat(pad), row] }, index)))] }));
|
|
50
|
+
}
|
|
@@ -8,7 +8,7 @@ import { formatDuration } from '../../terminal-utils/format.js';
|
|
|
8
8
|
import { THINKING_SPINNER_FRAMES, THINKING_SPINNER_INTERVAL_MS, THINKING_SETTLED_MARKER, } from '../../terminal-utils/figures.js';
|
|
9
9
|
import { BRAND, ICE } from '../shimmer.js';
|
|
10
10
|
import { interpolateColor } from '../Spinner/spinnerUtils.js';
|
|
11
|
-
import {
|
|
11
|
+
import { isMinimalUiMode } from '../../minimalUiMode.js';
|
|
12
12
|
import { primaryComboString } from '../../utils/keymap.js';
|
|
13
13
|
/** Preview body rows — a FIXED row count (kimicode-style constant-height
|
|
14
14
|
* ticker). Ink's truncate slices the whole string across newlines as one
|
|
@@ -48,10 +48,10 @@ export function AssistantThinkingMessage({ thinking, textFull, marginTopOnTurn,
|
|
|
48
48
|
: '';
|
|
49
49
|
// Kimi Code style blue pulse: the streaming glyph breathes along the
|
|
50
50
|
// header's brand→ice ladder, one sine period per ~7 frames (≈0.56s) —
|
|
51
|
-
// lively without strobing.
|
|
51
|
+
// lively without strobing. The minimal UI drops the color (plain glyph);
|
|
52
52
|
// settled always keeps the plain dim anchor.
|
|
53
53
|
const label = `${t('thinking-label')}${duration}${streaming ? '…' : ` ${t('hint-expand-ctrl-o', { key: primaryComboString('transcript') })}`}`;
|
|
54
|
-
const
|
|
54
|
+
const minimalUi = isMinimalUiMode();
|
|
55
55
|
const pulse = (Math.sin(frame * 0.9) + 1) / 2;
|
|
56
56
|
const pulseColor = interpolateColor(BRAND, ICE, pulse);
|
|
57
57
|
const frameText = THINKING_SPINNER_FRAMES[frame % THINKING_SPINNER_FRAMES.length];
|
|
@@ -61,7 +61,7 @@ export function AssistantThinkingMessage({ thinking, textFull, marginTopOnTurn,
|
|
|
61
61
|
const hoverProps = onClick !== undefined
|
|
62
62
|
? { onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false) }
|
|
63
63
|
: {};
|
|
64
|
-
const header = streaming ? (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { children:
|
|
64
|
+
const header = streaming ? (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { children: minimalUi ? 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: `${minimalUi ? '*' : THINKING_SETTLED_MARKER} ${label}` }));
|
|
65
65
|
if (preview) {
|
|
66
66
|
// Live ticker: the model's last few reasoning lines, dimmed, one Text
|
|
67
67
|
// per row so each truncates to the width independently, padded to a
|
|
@@ -11,7 +11,7 @@ import type { WaveBand } from '../../dsh-adapter/types.js';
|
|
|
11
11
|
* @returns Glyph count, or 0 when the strip should not render at all.
|
|
12
12
|
*/
|
|
13
13
|
export declare function miniWakeWidth(columns: number): number;
|
|
14
|
-
export declare function MiniWake({ band, hint, tick, }: {
|
|
14
|
+
export declare function MiniWake({ band, hint, tick, onOpen, hoverHint, }: {
|
|
15
15
|
/** The session projected onto {@link miniWakeWidth} columns. */
|
|
16
16
|
band: WaveBand;
|
|
17
17
|
/**
|
|
@@ -20,5 +20,15 @@ export declare function MiniWake({ band, hint, tick, }: {
|
|
|
20
20
|
*/
|
|
21
21
|
hint?: string;
|
|
22
22
|
tick: number;
|
|
23
|
+
/**
|
|
24
|
+
* Open the trajectory scene. The strip is the conversation's permanent
|
|
25
|
+
* pointer at that second view, so pointing AT it and clicking is the
|
|
26
|
+
* gesture the affordance implies — the key chord stays as the alternative,
|
|
27
|
+
* not the only way in.
|
|
28
|
+
*/
|
|
29
|
+
onOpen?: () => void;
|
|
30
|
+
/** Key chord revealed while the pointer rests on the strip (the first-run
|
|
31
|
+
* hint has already retired by then). */
|
|
32
|
+
hoverHint?: string;
|
|
23
33
|
}): React.ReactNode;
|
|
24
34
|
//# sourceMappingURL=MiniWake.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiniWake.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/MiniWake.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,4BAA4B,CAAA;AAwCvE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,IAAI,EACJ,IAAI,
|
|
1
|
+
{"version":3,"file":"MiniWake.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/MiniWake.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,4BAA4B,CAAA;AAwCvE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,SAAS,GACV,EAAE;IACD,gEAAgE;IAChE,IAAI,EAAE,QAAQ,CAAA;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;6CACyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAmDlB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import chalk from 'chalk';
|
|
3
|
-
import { Box, Text, useTheme } from '../../ui.js';
|
|
4
|
+
import { Box, NoSelect, Text, useTheme } from '../../ui.js';
|
|
4
5
|
import { getTheme } from '../../theme.js';
|
|
5
6
|
import { alive, mix } from '../../trajectory/motion.js';
|
|
6
7
|
import { parseRGB } from '../Spinner/spinnerUtils.js';
|
|
@@ -59,9 +60,10 @@ export function miniWakeWidth(columns) {
|
|
|
59
60
|
return 8;
|
|
60
61
|
return 0;
|
|
61
62
|
}
|
|
62
|
-
export function MiniWake({ band, hint, tick, }) {
|
|
63
|
+
export function MiniWake({ band, hint, tick, onOpen, hoverHint, }) {
|
|
63
64
|
const [themeName] = useTheme();
|
|
64
65
|
const theme = getTheme(themeName);
|
|
66
|
+
const [hovered, setHovered] = React.useState(false);
|
|
65
67
|
if (band.buckets.length === 0)
|
|
66
68
|
return null;
|
|
67
69
|
const logFloor = Math.log1p(Math.max(0, band.floor));
|
|
@@ -85,7 +87,11 @@ export function MiniWake({ band, hint, tick, }) {
|
|
|
85
87
|
const colour = failed ? theme.error : channelColor(dominantChannel(bucket), theme);
|
|
86
88
|
strip += chalk.hex(toHex(colour))(shown >= BLOCKS.length ? FULL : BLOCKS[shown - 1]);
|
|
87
89
|
}
|
|
88
|
-
|
|
90
|
+
// The hint slot narrates the affordance: first-run chord, then — while the
|
|
91
|
+
// pointer is on the strip — the chord again, because that is the moment the
|
|
92
|
+
// user is asking "what does this thing do".
|
|
93
|
+
const shownHint = hint ?? (hovered && onOpen !== undefined ? hoverHint : undefined);
|
|
94
|
+
return (_jsx(NoSelect, { children: _jsxs(Box, { flexShrink: 0, flexDirection: "row", gap: 1, onClick: onOpen, onMouseEnter: onOpen !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onOpen !== undefined ? () => setHovered(false) : undefined, children: [_jsx(Text, { children: strip }), shownHint !== undefined ? _jsx(Text, { color: hovered && hint === undefined ? 'accent' : 'subtle', children: shownHint }) : null] }) }));
|
|
89
95
|
}
|
|
90
96
|
/** Theme colour → `#rrggbb`, the form chalk needs. */
|
|
91
97
|
function toHex(colour) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-commands.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/external-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAKjF,OAAO,EAAkD,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1G,OAAO,KAAK,EAAqB,gBAAgB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAcjH;0DAC0D;AAC1D,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE;IACJ,cAAc,EAAE,cAAc,GAAG,SAAS,CAAA;IAC1C,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAA;IACpD,KAAK,IAAI,KAAK,CAAA;IACd,OAAO,IAAI,OAAO,CAAA;IAClB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAA;IACzC,MAAM,CAAC,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3G,QAAQ,EAAE,cAAc,CAAA;IACxB,WAAW,IAAI,kBAAkB,GAAG,SAAS,CAAA;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CACtG;mBA+HO,MAAM,YACF,MAAM,cACL,SAAS,gBAAgB,EAAE,KACrC,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"external-commands.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/external-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAKjF,OAAO,EAAkD,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1G,OAAO,KAAK,EAAqB,gBAAgB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAcjH;0DAC0D;AAC1D,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE;IACJ,cAAc,EAAE,cAAc,GAAG,SAAS,CAAA;IAC1C,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAA;IACpD,KAAK,IAAI,KAAK,CAAA;IACd,OAAO,IAAI,OAAO,CAAA;IAClB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAA;IACzC,MAAM,CAAC,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3G,QAAQ,EAAE,cAAc,CAAA;IACxB,WAAW,IAAI,kBAAkB,GAAG,SAAS,CAAA;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CACtG;mBA+HO,MAAM,YACF,MAAM,cACL,SAAS,gBAAgB,EAAE,KACrC,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;uBAiFtC,MAAM,YACF,MAAM,cACL,SAAS,gBAAgB,EAAE,KACrC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;EAG/B"}
|
|
@@ -111,8 +111,6 @@ export function createExternalCommandInvoker(ctx, deps) {
|
|
|
111
111
|
/** Run one DSH registry command (`/plan`, …) on the live agent while
|
|
112
112
|
* preserving its settled result kind for composer admission. */
|
|
113
113
|
const invoke = async (name, rawInput, imageRefs = []) => {
|
|
114
|
-
const capture = deps.capture();
|
|
115
|
-
assertCapabilityShadowPolicy('host.commands.invoke', deps.runtime.mode, deps.runtime.slices);
|
|
116
114
|
const service = deps.commandService;
|
|
117
115
|
if (service === undefined)
|
|
118
116
|
return undefined;
|
|
@@ -123,6 +121,14 @@ export function createExternalCommandInvoker(ctx, deps) {
|
|
|
123
121
|
// apply another scope's owner policy.
|
|
124
122
|
const definition = service.find(commandAgent, name);
|
|
125
123
|
try {
|
|
124
|
+
// The channel-lifetime capture and the shadow/capability policy check
|
|
125
|
+
// live INSIDE the try: both can throw (a lease that ended between
|
|
126
|
+
// keystrokes, a shadow-mode denial), and `invoke` is an async action
|
|
127
|
+
// whose callers treat a rejection as unhandled — the same refusal must
|
|
128
|
+
// degrade to the settled `{ kind: 'error' }` outcome every other
|
|
129
|
+
// failure below uses.
|
|
130
|
+
const capture = deps.capture();
|
|
131
|
+
assertCapabilityShadowPolicy('host.commands.invoke', deps.runtime.mode, deps.runtime.slices);
|
|
126
132
|
const signal = new AbortController().signal;
|
|
127
133
|
const line = `/${name}${rawInput}`;
|
|
128
134
|
const batch = await registryCommandImages(service, line, deps.composer.includeLegacyImageRefs(line, imageRefs), stagedSnapshot, signal);
|
|
@@ -24,5 +24,6 @@ export declare function createJobProjection(getState: () => Pick<ChannelState, '
|
|
|
24
24
|
attach: (jobs: JobsRuntime | undefined, ownService?: (dispose: () => void) => void) => void;
|
|
25
25
|
dropRows: () => void;
|
|
26
26
|
reset: () => void;
|
|
27
|
+
reanchor: () => void;
|
|
27
28
|
};
|
|
28
29
|
//# sourceMappingURL=job-projection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-projection.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/job-projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAGnD,OAAO,EAAE,kBAAkB,EAAqB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAW,UAAU,EAAE,MAAM,YAAY,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,IAAI,CAAC,YAAY,EAAE,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC,EACtE,IAAI,EAAE;IACJ,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,KAAK,CAAC,CAAA;IAC5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAA;IACxG,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACzB,KAAK,IAAI,KAAK,CAAA;IACd,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;;;
|
|
1
|
+
{"version":3,"file":"job-projection.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/job-projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAGnD,OAAO,EAAE,kBAAkB,EAAqB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAW,UAAU,EAAE,MAAM,YAAY,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,IAAI,CAAC,YAAY,EAAE,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC,EACtE,IAAI,EAAE;IACJ,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,KAAK,CAAC,CAAA;IAC5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAA;IACxG,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACzB,KAAK,IAAI,KAAK,CAAA;IACd,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;;;mBA4FqB,WAAW,GAAG,SAAS,eAAe,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,KAAG,IAAI;oBA4G3E,IAAI;iBACP,IAAI;oBAQD,IAAI;EAG1B"}
|
|
@@ -9,6 +9,8 @@ import { BackgroundJobStore, formatJobDuration } from '../jobs.js';
|
|
|
9
9
|
export function createJobProjection(getState, deps) {
|
|
10
10
|
const jobRowsByJobId = new Map();
|
|
11
11
|
let jobsRuntime;
|
|
12
|
+
/** The live attachment's conditional roster re-read (see `reanchor`). */
|
|
13
|
+
let reanchorActive;
|
|
12
14
|
let detachActive;
|
|
13
15
|
let attachmentToken;
|
|
14
16
|
let attachmentCurrent = () => false;
|
|
@@ -30,6 +32,7 @@ export function createJobProjection(getState, deps) {
|
|
|
30
32
|
label: job.label,
|
|
31
33
|
status: job.status,
|
|
32
34
|
...(job.detail === undefined ? {} : { detail: job.detail }),
|
|
35
|
+
...(job.progress === undefined ? {} : { progress: job.progress }),
|
|
33
36
|
startedAt: job.startedAt,
|
|
34
37
|
...(job.finishedAt === undefined ? {} : { finishedAt: job.finishedAt }),
|
|
35
38
|
outputLines: job.outputLines,
|
|
@@ -63,7 +66,10 @@ export function createJobProjection(getState, deps) {
|
|
|
63
66
|
return false;
|
|
64
67
|
const job = store.get(id);
|
|
65
68
|
try {
|
|
66
|
-
|
|
69
|
+
// The kernel fence compares job.owner.id === caller, so the caller
|
|
70
|
+
// MUST be the session id string — the Agent object matches nothing
|
|
71
|
+
// and every owned-job kill would throw "another session".
|
|
72
|
+
jobs.kill(id, sessionCaller(), 'dsh-tui /jobs panel');
|
|
67
73
|
}
|
|
68
74
|
catch {
|
|
69
75
|
return false;
|
|
@@ -74,6 +80,15 @@ export function createJobProjection(getState, deps) {
|
|
|
74
80
|
return true;
|
|
75
81
|
},
|
|
76
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* Caller identity for the kernel fence: the owning session id string
|
|
85
|
+
* (`Agent.id`). The registry compares `job.owner.id === caller`, so the
|
|
86
|
+
* Agent object the channel holds is only good for extracting the id.
|
|
87
|
+
*/
|
|
88
|
+
const sessionCaller = () => {
|
|
89
|
+
const agent = deps.agent();
|
|
90
|
+
return agent?.id;
|
|
91
|
+
};
|
|
77
92
|
/**
|
|
78
93
|
* Each service attachment has one idempotent disposer, dual-owned by the
|
|
79
94
|
* Channel and (when injected) the service context. Reattachment revokes the
|
|
@@ -88,19 +103,53 @@ export function createJobProjection(getState, deps) {
|
|
|
88
103
|
let detached = false;
|
|
89
104
|
let detach;
|
|
90
105
|
const current = () => !detached && attachmentToken === token && detachActive === detach && jobsRuntime === jobs && deps.owner.current();
|
|
106
|
+
// The caller the roster was last read with. `reanchor` compares against it
|
|
107
|
+
// so a bind that did NOT change the session stays a no-op — mounting binds
|
|
108
|
+
// the channel's own agent immediately after the service attaches, and
|
|
109
|
+
// re-reading there would be a second, redundant list().
|
|
110
|
+
let lastCaller;
|
|
111
|
+
let callerKnown = false;
|
|
91
112
|
const refresh = () => {
|
|
92
113
|
// Check before list(): retained callbacks must not touch a revoked or
|
|
93
114
|
// replaced service, nor invoke any store/row work after owner disposal.
|
|
94
115
|
if (!current())
|
|
95
116
|
return;
|
|
96
117
|
try {
|
|
97
|
-
const
|
|
118
|
+
const caller = sessionCaller();
|
|
119
|
+
lastCaller = caller;
|
|
120
|
+
callerKnown = true;
|
|
121
|
+
const snapshot = jobs.list(caller);
|
|
98
122
|
if (!current())
|
|
99
123
|
return;
|
|
100
124
|
store.replace(snapshot);
|
|
101
125
|
}
|
|
102
126
|
catch { /* optional service is disposing */ }
|
|
103
127
|
};
|
|
128
|
+
/** Re-read only when the bound session actually changed. */
|
|
129
|
+
const reanchorThis = () => {
|
|
130
|
+
if (callerKnown && sessionCaller() === lastCaller)
|
|
131
|
+
return;
|
|
132
|
+
dropRows();
|
|
133
|
+
store.reset();
|
|
134
|
+
refresh();
|
|
135
|
+
};
|
|
136
|
+
/** One kernel `output` event: pull the ring increment past our cursor. */
|
|
137
|
+
const pullOutput = (id) => {
|
|
138
|
+
if (!current())
|
|
139
|
+
return;
|
|
140
|
+
if (jobs.readAt === undefined)
|
|
141
|
+
return;
|
|
142
|
+
const cursor = store.kernelCursorOf(id);
|
|
143
|
+
if (cursor === undefined)
|
|
144
|
+
return;
|
|
145
|
+
try {
|
|
146
|
+
const read = jobs.readAt(id, cursor, sessionCaller());
|
|
147
|
+
if (!current())
|
|
148
|
+
return;
|
|
149
|
+
store.onKernelOutput(id, read);
|
|
150
|
+
}
|
|
151
|
+
catch { /* job gone or fenced mid-pull; roster refresh follows */ }
|
|
152
|
+
};
|
|
104
153
|
// Publish the attachment identity before subscription: registries are
|
|
105
154
|
// allowed to synchronously deliver their current snapshot from on*().
|
|
106
155
|
// Every registration below is transactional because a second on*() can
|
|
@@ -118,6 +167,8 @@ export function createJobProjection(getState, deps) {
|
|
|
118
167
|
}
|
|
119
168
|
if (jobsRuntime === jobs)
|
|
120
169
|
jobsRuntime = undefined;
|
|
170
|
+
if (reanchorActive === reanchorThis)
|
|
171
|
+
reanchorActive = undefined;
|
|
121
172
|
for (const dispose of disposers.splice(0))
|
|
122
173
|
dispose?.();
|
|
123
174
|
// A service-context detach happens before channel teardown on remount;
|
|
@@ -130,7 +181,34 @@ export function createJobProjection(getState, deps) {
|
|
|
130
181
|
detachActive = detach;
|
|
131
182
|
attachmentToken = token;
|
|
132
183
|
attachmentCurrent = current;
|
|
184
|
+
reanchorActive = reanchorThis;
|
|
133
185
|
try {
|
|
186
|
+
const bus = jobs.events;
|
|
187
|
+
if (bus !== undefined && typeof bus.subscribe === 'function') {
|
|
188
|
+
// Kernel bus: lifecycle commits re-read the roster; output events
|
|
189
|
+
// pull non-consuming readAt increments with the store's own cursor.
|
|
190
|
+
// Subscribe to EVERY owner on purpose: this filter is captured at
|
|
191
|
+
// attach, but the channel still rebinds afterwards (dsh-tui opens a
|
|
192
|
+
// fresh session at boot and only then resumes the user's), and a filter
|
|
193
|
+
// frozen to the boot session starves the panel for good — the kernel
|
|
194
|
+
// drops every foreign-owner event, refresh() never runs again and the
|
|
195
|
+
// roster stays at the empty list read during attach. Nothing extra is
|
|
196
|
+
// exposed by widening it: the roster read is list(caller) and the ring
|
|
197
|
+
// pull is readAt(id, cursor, caller), both fenced with the caller AT
|
|
198
|
+
// CALL TIME, so another session's jobs fall out (and a foreign ring
|
|
199
|
+
// read throws into the contained catch).
|
|
200
|
+
disposers.push(bus.subscribe({ owners: 'all' }, event => {
|
|
201
|
+
if (!current())
|
|
202
|
+
return;
|
|
203
|
+
try {
|
|
204
|
+
if (event.type === 'output')
|
|
205
|
+
pullOutput(event.id);
|
|
206
|
+
else
|
|
207
|
+
refresh();
|
|
208
|
+
}
|
|
209
|
+
catch { /* contained per-event; the next event re-syncs */ }
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
134
212
|
if (typeof jobs.onJobsChanged === 'function')
|
|
135
213
|
disposers.push(jobs.onJobsChanged(refresh));
|
|
136
214
|
if (typeof jobs.onJobDone === 'function')
|
|
@@ -146,5 +224,12 @@ export function createJobProjection(getState, deps) {
|
|
|
146
224
|
};
|
|
147
225
|
const dropRows = () => { jobRowsByJobId.clear(); };
|
|
148
226
|
const reset = () => { dropRows(); store.reset(); };
|
|
149
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Re-anchor after the live agent changed. `reset()` runs while the OLD
|
|
229
|
+
* binding is still installed (resetSessionProjection precedes bindAgent), so
|
|
230
|
+
* it can only clear; the re-read has to happen here, once the new agent is
|
|
231
|
+
* bound, or the next session's jobs would only appear on its first event.
|
|
232
|
+
*/
|
|
233
|
+
const reanchor = () => { reanchorActive?.(); };
|
|
234
|
+
return { store, control, attach, dropRows, reset, reanchor };
|
|
150
235
|
}
|
|
@@ -7,6 +7,19 @@ import type { ChannelState } from './types.js';
|
|
|
7
7
|
import type { createChannelBinding } from './binding.js';
|
|
8
8
|
type Binding = ReturnType<typeof createChannelBinding>;
|
|
9
9
|
type ModeState = Pick<ChannelState, 'mode' | 'modeIndex' | 'emit'>;
|
|
10
|
+
/**
|
|
11
|
+
* Fail-soft reporting for a session-mode write. The mutation path reaches
|
|
12
|
+
* kernel-owned state (`session.append`, `approval.setPolicy` → the agent
|
|
13
|
+
* inbox) that can legitimately refuse while a turn is publishing, and the
|
|
14
|
+
* keyboard entry point (`Shift+Tab`) cannot await it — a rejection there
|
|
15
|
+
* becomes an unhandledRejection, which the process guard treats as fatal and
|
|
16
|
+
* which kills the TUI with the session still open. A refused switch is a
|
|
17
|
+
* user-visible outcome, not a crash: log it, say so in the status line, and
|
|
18
|
+
* re-derive the indicator from the durable log so the UI cannot keep showing
|
|
19
|
+
* a mode the session never entered. Shared by the base actions and the
|
|
20
|
+
* permission-aware composition so both report the same way.
|
|
21
|
+
*/
|
|
22
|
+
export declare function reportModeSwitchFailure(ctx: Context, notify: ChannelState['notify'], refreshMode: () => void, error: unknown): void;
|
|
10
23
|
/** Durable session-mode folds and transitions. Construction is inert; root wires it after state construction. */
|
|
11
24
|
export declare function createModeActions(ctx: Context, state: ModeState, deps: {
|
|
12
25
|
owner: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mode-actions.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/mode-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAsB,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAChG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAExD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AACtD,KAAK,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC,CAAA;AAElE,iHAAiH;AACjH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE;IACJ,KAAK,EAAE;QAAE,OAAO,IAAI,OAAO,CAAA;KAAE,CAAA;IAC7B,OAAO,EAAE,qBAAqB,CAAA;IAC9B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC,CAAA;IACzD,YAAY,EAAE,SAAS,eAAe,EAAE,CAAA;IACxC,cAAc,CAAC,EAAE;QAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;IAC9D,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAChF,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;CAC/B;uBAyDqB,IAAI;
|
|
1
|
+
{"version":3,"file":"mode-actions.d.ts","sourceRoot":"","sources":["../../../../src/dsh-adapter/channel/mode-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAsB,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAChG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAExD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AACtD,KAAK,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC,CAAA;AAElE;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,EAC9B,WAAW,EAAE,MAAM,IAAI,EACvB,KAAK,EAAE,OAAO,GACb,IAAI,CAUN;AAED,iHAAiH;AACjH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE;IACJ,KAAK,EAAE;QAAE,OAAO,IAAI,OAAO,CAAA;KAAE,CAAA;IAC7B,OAAO,EAAE,qBAAqB,CAAA;IAC9B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC,CAAA;IACzD,YAAY,EAAE,SAAS,eAAe,EAAE,CAAA;IACxC,cAAc,CAAC,EAAE;QAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;IAC9D,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAChF,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;CAC/B;uBAyDqB,IAAI;qBA4JE,OAAO,CAAC,IAAI,CAAC;sBA1EV,eAAe,sDAA0B,OAAO,CAAC,IAAI,CAAC;8BAuFpD,KAAK,CAAC,SAAS,CAAC,SAAS,YAAY,KAAG,IAAI;EA4B9E"}
|