@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
|
@@ -1,54 +1,80 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Box, Text, useInput, ScrollBox, useTerminalSize, useAnimationFrame } from '../ui.js';
|
|
4
4
|
import { formatJobDuration } from '../dsh-adapter/jobs.js';
|
|
5
|
+
import { JobProgress } from './Chat/JobCard.js';
|
|
6
|
+
import { Markdown } from './Markdown.js';
|
|
5
7
|
import { t } from '../i18n.js';
|
|
6
8
|
import { Divider } from './design-system/Divider.js';
|
|
7
9
|
import { ExitButton } from './SubagentDashboard.js';
|
|
8
10
|
import { isPlainReturnInput } from '../utils/modifiers.js';
|
|
9
|
-
import {
|
|
10
|
-
import { stringWidth } from '../ink/stringWidth.js';
|
|
11
|
+
import { isMinimalUiMode } from '../minimalUiMode.js';
|
|
11
12
|
function statusInfo(status) {
|
|
12
|
-
const
|
|
13
|
+
const minimalUi = isMinimalUiMode();
|
|
13
14
|
switch (status) {
|
|
14
15
|
case 'completed':
|
|
15
|
-
return { glyph:
|
|
16
|
+
return { glyph: minimalUi ? '✓' : '●', label: t('jobs-status-completed'), color: minimalUi ? undefined : 'success' };
|
|
16
17
|
case 'failed':
|
|
17
|
-
return { glyph:
|
|
18
|
+
return { glyph: minimalUi ? '×' : '●', label: t('jobs-status-failed'), color: minimalUi ? undefined : 'error' };
|
|
18
19
|
case 'killed':
|
|
19
|
-
return { glyph:
|
|
20
|
+
return { glyph: minimalUi ? '×' : '●', label: t('jobs-status-killed'), color: minimalUi ? undefined : 'error' };
|
|
20
21
|
case 'stopping':
|
|
21
|
-
return { glyph:
|
|
22
|
+
return { glyph: minimalUi ? '·' : '●', label: t('jobs-status-stopping'), color: minimalUi ? undefined : 'warning' };
|
|
22
23
|
default:
|
|
23
|
-
return { glyph:
|
|
24
|
+
return { glyph: minimalUi ? '·' : '●', label: t('jobs-status-running'), color: minimalUi ? undefined : 'warning' };
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
function isTerminalStatus(status) {
|
|
28
|
+
return status === 'completed' || status === 'killed' || status === 'failed';
|
|
29
|
+
}
|
|
30
|
+
/** 12.3 KB / 1.4 MB — byte counter for the detail block. */
|
|
31
|
+
function formatBytes(bytes) {
|
|
32
|
+
if (bytes < 1024)
|
|
33
|
+
return `${bytes} B`;
|
|
34
|
+
if (bytes < 1024 * 1024)
|
|
35
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
36
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
37
|
+
}
|
|
38
|
+
function renderOutputRuns(job) {
|
|
39
|
+
const runs = [];
|
|
40
|
+
let markdown = [];
|
|
41
|
+
const flush = () => {
|
|
42
|
+
if (markdown.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
runs.push({ kind: 'markdown', text: markdown.join('\n') });
|
|
45
|
+
markdown = [];
|
|
46
|
+
};
|
|
47
|
+
for (const line of job.outputLines) {
|
|
48
|
+
if (line.gapBefore === true) {
|
|
49
|
+
flush();
|
|
50
|
+
runs.push({ kind: 'gap' });
|
|
51
|
+
}
|
|
52
|
+
if (line.channel === 'stderr') {
|
|
53
|
+
flush();
|
|
54
|
+
runs.push({ kind: 'stderr', text: line.text });
|
|
55
|
+
}
|
|
56
|
+
else if (line.channel === 'log') {
|
|
57
|
+
flush();
|
|
58
|
+
runs.push({ kind: 'log', text: line.text });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
markdown.push(line.text);
|
|
62
|
+
}
|
|
40
63
|
}
|
|
41
|
-
|
|
64
|
+
flush();
|
|
65
|
+
return runs;
|
|
42
66
|
}
|
|
43
|
-
function JobRowLine({ job, focused }) {
|
|
44
|
-
const { columns } = useTerminalSize();
|
|
67
|
+
function JobRowLine({ job, focused, armed, showProgress, onFocus }) {
|
|
45
68
|
const info = statusInfo(job.status);
|
|
46
69
|
const duration = formatJobDuration(job);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
const live = !isTerminalStatus(job.status);
|
|
71
|
+
const progress = live && job.progress !== undefined && job.progress !== '' ? job.progress : undefined;
|
|
72
|
+
return (_jsxs(Box, { flexDirection: "column", onClick: onFocus, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsxs(Box, { width: 2, flexShrink: 0, children: [_jsx(Text, { color: focused ? 'accent' : undefined, children: focused ? '❯' : ' ' }), _jsx(Text, { color: info.color, children: info.glyph })] }), _jsx(Box, { width: 9, flexShrink: 0, children: _jsx(Text, { bold: focused, color: focused ? 'accent' : undefined, wrap: "truncate-end", children: job.id }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsx(Text, { bold: focused, wrap: "truncate-end", children: job.label }) }), showProgress === true && (_jsx(Box, { width: 11, flexShrink: 0, justifyContent: "flex-end", children: progress !== undefined ? _jsx(JobProgress, { progress: progress }) : _jsx(Text, { children: " " }) })), armed === true ? (_jsx(Text, { bold: true, color: "error", wrap: "truncate-end", children: t('jobs-kill-armed') })) : (_jsxs(_Fragment, { children: [_jsx(Box, { width: 6, flexShrink: 0, justifyContent: "flex-end", children: _jsx(Text, { dimColor: true, children: duration }) }), _jsx(Box, { width: 9, flexShrink: 0, justifyContent: "flex-end", children: _jsx(Text, { color: info.color, wrap: "truncate-end", children: info.label }) })] }))] }), focused && (_jsxs(Box, { flexDirection: "column", paddingLeft: 4, children: [job.command !== undefined && job.command !== '' && job.command !== job.label && (_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Box, { width: 7, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-command') }) }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: job.command })] })), _jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Box, { width: 7, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-started') }) }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: timeOf(job.startedAt)
|
|
73
|
+
+ (job.finishedAt !== undefined ? ` · ${t('jobs-panel-finished')} ${timeOf(job.finishedAt)}` : '')
|
|
74
|
+
+ (job.lastOutputAt !== undefined ? ` · ${t('jobs-panel-output-at')} ${timeOf(job.lastOutputAt)}` : '') })] }), (job.outputTotalBytes !== undefined || job.outputDropped === true) && (_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Box, { width: 7, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-output') }) }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: (job.outputTotalBytes !== undefined ? formatBytes(job.outputTotalBytes) : '')
|
|
75
|
+
+ (job.outputDropped === true
|
|
76
|
+
? `${job.outputTotalBytes !== undefined ? ' · ' : ''}${t('jobs-output-dropped')}`
|
|
77
|
+
: '') })] })), job.spillPaths !== undefined && job.spillPaths.length > 0 && (_jsx(Box, { paddingLeft: 8, children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: t('jobs-output-spill', { path: job.spillPaths[job.spillPaths.length - 1] ?? '' }) }) })), job.outputLines.length > 0 ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: renderOutputRuns(job).map((run, runIndex) => (_jsxs(Box, { flexDirection: "column", marginTop: runIndex === 0 ? 0 : 1, children: [run.kind === 'gap' && (_jsx(Text, { dimColor: true, italic: true, wrap: "truncate-end", children: t('jobs-output-gap') })), run.kind === 'markdown' && (_jsx(Markdown, { cacheTokens: true, children: run.text })), run.kind === 'stderr' && (_jsx(Text, { color: "error", wrap: "truncate-end", children: `│ ${run.text}` })), run.kind === 'log' && (_jsx(Text, { dimColor: true, italic: true, wrap: "truncate-end", children: `│ ${run.text}` }))] }, `${job.id}-run-${runIndex}`))) })) : (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: t('jobs-panel-no-output-yet') }))] }))] }));
|
|
52
78
|
}
|
|
53
79
|
/** HH:MM:SS wall-clock of an epoch ms value (locale-independent). */
|
|
54
80
|
function timeOf(ms) {
|
|
@@ -65,11 +91,21 @@ function timeOf(ms) {
|
|
|
65
91
|
*/
|
|
66
92
|
export function JobsPanel({ jobs, onClose, onKill }) {
|
|
67
93
|
const [focusIndex, setFocusIndex] = React.useState(0);
|
|
94
|
+
/** Armed kill: first `k` primes, second within the window confirms; any
|
|
95
|
+
* navigation or other key disarms. Mirrors the web two-press stop. */
|
|
96
|
+
const [killArmed, setKillArmed] = React.useState(undefined);
|
|
68
97
|
const scrollRef = React.useRef(null);
|
|
69
98
|
const { rows } = useTerminalSize();
|
|
70
99
|
// 1s tick keeps live durations counting while the panel is open.
|
|
71
100
|
const [clockRef] = useAnimationFrame(1000);
|
|
72
101
|
const focus = Math.min(focusIndex, Math.max(0, jobs.length - 1));
|
|
102
|
+
// The armed confirmation decays after 4s so a stray later `k` never kills.
|
|
103
|
+
React.useEffect(() => {
|
|
104
|
+
if (killArmed === undefined)
|
|
105
|
+
return;
|
|
106
|
+
const timer = setTimeout(() => setKillArmed(undefined), 4000);
|
|
107
|
+
return () => clearTimeout(timer);
|
|
108
|
+
}, [killArmed]);
|
|
73
109
|
useInput((input, key, event) => {
|
|
74
110
|
if (key.escape || (key.ctrl && input === 'c')) {
|
|
75
111
|
event.stopImmediatePropagation();
|
|
@@ -78,12 +114,14 @@ export function JobsPanel({ jobs, onClose, onKill }) {
|
|
|
78
114
|
}
|
|
79
115
|
if (key.upArrow) {
|
|
80
116
|
event.stopImmediatePropagation();
|
|
117
|
+
setKillArmed(undefined);
|
|
81
118
|
setFocusIndex(i => Math.max(0, i - 1));
|
|
82
119
|
scrollRef.current?.scrollBy(-1);
|
|
83
120
|
return;
|
|
84
121
|
}
|
|
85
122
|
if (key.downArrow) {
|
|
86
123
|
event.stopImmediatePropagation();
|
|
124
|
+
setKillArmed(undefined);
|
|
87
125
|
setFocusIndex(i => Math.min(jobs.length - 1, i + 1));
|
|
88
126
|
scrollRef.current?.scrollBy(1);
|
|
89
127
|
return;
|
|
@@ -92,7 +130,13 @@ export function JobsPanel({ jobs, onClose, onKill }) {
|
|
|
92
130
|
const selected = jobs[focus];
|
|
93
131
|
if (selected !== undefined && (selected.status === 'running' || selected.status === 'stopping')) {
|
|
94
132
|
event.stopImmediatePropagation();
|
|
95
|
-
|
|
133
|
+
if (killArmed === selected.id) {
|
|
134
|
+
setKillArmed(undefined);
|
|
135
|
+
onKill(selected.id);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
setKillArmed(selected.id);
|
|
139
|
+
}
|
|
96
140
|
}
|
|
97
141
|
return;
|
|
98
142
|
}
|
|
@@ -105,7 +149,10 @@ export function JobsPanel({ jobs, onClose, onKill }) {
|
|
|
105
149
|
event.stopImmediatePropagation();
|
|
106
150
|
});
|
|
107
151
|
const running = jobs.filter(job => job.status === 'running' || job.status === 'stopping').length;
|
|
152
|
+
// One live job with a progress line reserves the column on every row, so the
|
|
153
|
+
// right-hand grid does not shift as jobs start and finish.
|
|
154
|
+
const showProgress = jobs.some(job => (job.status === 'running' || job.status === 'stopping') && job.progress !== undefined && job.progress !== '');
|
|
108
155
|
const completed = jobs.filter(job => job.status === 'completed').length;
|
|
109
156
|
const failed = jobs.filter(job => job.status === 'failed' || job.status === 'killed').length;
|
|
110
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, ref: clockRef, children: [_jsx(Divider, { color: "accent", title: t('jobs-panel-title') }), _jsxs(Box, { flexDirection: "row", gap: 3, marginTop: 1, marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "accent", children: running }), _jsxs(Text, { dimColor: true, children: [" ", t('jobs-panel-count-running')] })] }), _jsxs(Text, { children: [_jsx(Text, { color: "success", children: completed }), _jsxs(Text, { dimColor: true, children: [" ", t('jobs-panel-count-completed')] })] }), failed > 0 && (_jsxs(Text, { children: [_jsx(Text, { color: "error", children: failed }), _jsxs(Text, { dimColor: true, children: [" ", t('jobs-panel-count-failed')] })] })), _jsx(Box, { flexGrow: 1 }), _jsx(ExitButton, { onClick: onClose })] }), _jsx(Box, { flexDirection: "column", maxHeight: Math.max(10, rows - 10), marginTop: 1, children: _jsx(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: jobs.length === 0 ? (_jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: Math.max(2, Math.floor((rows - 16) / 3)), children: [_jsx(Text, { dimColor: true, children: '○' }), _jsx(Text, { dimColor: true, children: t('jobs-panel-empty') }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-empty-hint') }) })] })) : (jobs.map((job, index) => _jsx(JobRowLine, { job: job, focused: index === focus }, job.id))) }) }), _jsx(Divider, { color: "subtle", title: "" }), _jsx(Box, { marginTop: 0, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-hint') }) })] }));
|
|
157
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, ref: clockRef, children: [_jsx(Divider, { color: "accent", title: t('jobs-panel-title') }), _jsxs(Box, { flexDirection: "row", gap: 3, marginTop: 1, marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "accent", children: running }), _jsxs(Text, { dimColor: true, children: [" ", t('jobs-panel-count-running')] })] }), _jsxs(Text, { children: [_jsx(Text, { color: "success", children: completed }), _jsxs(Text, { dimColor: true, children: [" ", t('jobs-panel-count-completed')] })] }), failed > 0 && (_jsxs(Text, { children: [_jsx(Text, { color: "error", children: failed }), _jsxs(Text, { dimColor: true, children: [" ", t('jobs-panel-count-failed')] })] })), _jsx(Box, { flexGrow: 1 }), _jsx(ExitButton, { onClick: onClose })] }), _jsx(Box, { flexDirection: "column", maxHeight: Math.max(10, rows - 10), marginTop: 1, children: _jsx(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: jobs.length === 0 ? (_jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: Math.max(2, Math.floor((rows - 16) / 3)), children: [_jsx(Text, { dimColor: true, children: '○' }), _jsx(Text, { dimColor: true, children: t('jobs-panel-empty') }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-empty-hint') }) })] })) : (jobs.map((job, index) => (_jsx(JobRowLine, { job: job, focused: index === focus, armed: killArmed === job.id, showProgress: showProgress, onFocus: () => { setKillArmed(undefined); setFocusIndex(index); } }, job.id)))) }) }), _jsx(Divider, { color: "subtle", title: "" }), _jsx(Box, { marginTop: 0, children: _jsx(Text, { dimColor: true, children: t('jobs-panel-hint') }) })] }));
|
|
111
158
|
}
|
|
@@ -10,7 +10,7 @@ import { AssistantThinkingMessage } from './messages/AssistantThinkingMessage.js
|
|
|
10
10
|
import { AssistantToolUseMessage } from './messages/AssistantToolUseMessage.js';
|
|
11
11
|
import { SubagentMessage } from './Chat/SubagentMessage.js';
|
|
12
12
|
import { JobCard } from './Chat/JobCard.js';
|
|
13
|
-
import {
|
|
13
|
+
import { isMinimalUiMode } from '../minimalUiMode.js';
|
|
14
14
|
import { noteFrameCause, noteListGeometry } from '../ink/geometry-trace.js';
|
|
15
15
|
import { getTerminalFlushTick } from '../ink/flush-tick.js';
|
|
16
16
|
import { TurnInterruptedRow } from './TurnInterruptedRow.js';
|
|
@@ -1171,9 +1171,9 @@ const MemoRow = React.memo(TranscriptRow);
|
|
|
1171
1171
|
* fills the viewport.
|
|
1172
1172
|
*/
|
|
1173
1173
|
export function LogoHeader({ model, effort, cwd, fontId, whale = true, whaleIdle = true, whaleGirl = false, starred = false, onStarClick, working = false, skipIntro = false, }) {
|
|
1174
|
-
//
|
|
1174
|
+
// The minimal UI drops the whole splash (whale art AND wordmark) — only the
|
|
1175
1175
|
// transcript and a bare status bar remain.
|
|
1176
|
-
if (
|
|
1176
|
+
if (isMinimalUiMode())
|
|
1177
1177
|
return null;
|
|
1178
1178
|
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsx(LogoV2, { model: model, effort: effort, cwd: cwd, fontId: fontId, whale: whale, whaleIdle: whaleIdle, whaleGirl: whaleGirl, starred: starred, onStarClick: onStarClick, working: working, skipIntro: skipIntro }) }));
|
|
1179
1179
|
}
|
|
@@ -8,6 +8,10 @@ import type { PresetOption } from '../dsh-adapter/channel.js';
|
|
|
8
8
|
* `channel.switchPreset`, Esc cancels. Broken presets are listed (the
|
|
9
9
|
* roster's discovery contract) but marked with their reason; the roster
|
|
10
10
|
* default is tagged.
|
|
11
|
+
*
|
|
12
|
+
* The header says "内核 Agent 预设 / Kernel agent preset" (not just "Agent
|
|
13
|
+
* preset"): this screen changes the model-facing tool catalog, and must never
|
|
14
|
+
* be confused with the `/settings → 极简界面` (Minimal UI) display switch.
|
|
11
15
|
*/
|
|
12
16
|
export declare function PresetPicker({ presets, focusIndex, currentPreset, onPick, }: {
|
|
13
17
|
presets: readonly PresetOption[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresetPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PresetPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D
|
|
1
|
+
{"version":3,"file":"PresetPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PresetPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,UAAU,EACV,aAAa,EACb,MAAM,GACP,EAAE;IACD,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC;qDACiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CA4BlB"}
|
|
@@ -12,9 +12,13 @@ import { HintLine } from './design-system/HintLine.js';
|
|
|
12
12
|
* `channel.switchPreset`, Esc cancels. Broken presets are listed (the
|
|
13
13
|
* roster's discovery contract) but marked with their reason; the roster
|
|
14
14
|
* default is tagged.
|
|
15
|
+
*
|
|
16
|
+
* The header says "内核 Agent 预设 / Kernel agent preset" (not just "Agent
|
|
17
|
+
* preset"): this screen changes the model-facing tool catalog, and must never
|
|
18
|
+
* be confused with the `/settings → 极简界面` (Minimal UI) display switch.
|
|
15
19
|
*/
|
|
16
20
|
export function PresetPicker({ presets, focusIndex, currentPreset, onPick, }) {
|
|
17
|
-
return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children:
|
|
21
|
+
return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('preset-picker-title') }) }), _jsx(Select, { options: presets.map(preset => ({
|
|
18
22
|
value: preset.id,
|
|
19
23
|
label: (preset.name ?? preset.id) +
|
|
20
24
|
(preset.isDefault ? t('preset-default-tag') : '') +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2063,7 +2063,18 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2063
2063
|
// indentation arm so the expanded editor participates in the cycle too —
|
|
2064
2064
|
// the parser reports backtab as key.tab + key.shift.
|
|
2065
2065
|
if (key.tab && key.shift) {
|
|
2066
|
-
|
|
2066
|
+
// The key is consumed either way. `cycleMode` is best-effort inside the
|
|
2067
|
+
// channel, but a dropped rejection here would be an unhandledRejection
|
|
2068
|
+
// (the process guard rethrows everything that is not React #185), and
|
|
2069
|
+
// an unhandled rejection kills the TUI with the session still open —
|
|
2070
|
+
// so the caller keeps a catch of its own rather than `void`ing the
|
|
2071
|
+
// promise (the sibling `/permission` entry point does the same).
|
|
2072
|
+
void channel.cycleMode().catch((error) => {
|
|
2073
|
+
channel.notify(t('mode-switch-failed', { err: error instanceof Error ? error.message : String(error) }), {
|
|
2074
|
+
color: 'error',
|
|
2075
|
+
timeoutMs: 8000,
|
|
2076
|
+
});
|
|
2077
|
+
});
|
|
2067
2078
|
return;
|
|
2068
2079
|
}
|
|
2069
2080
|
// Expanded editor: plain Tab inserts indentation; Shift+Tab was handled
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { StarMilestone } from '../usageStats.js';
|
|
3
|
+
import type { WhaleCouponNotice } from '../dsh-adapter/oauth/bonus.js';
|
|
3
4
|
/** What a star attempt came back with (the modal renders each outcome). */
|
|
4
5
|
export type StarAttempt = {
|
|
5
6
|
readonly kind: 'starred';
|
|
@@ -50,4 +51,9 @@ export declare function StarPrompt({ milestone, actions, onClose, initialPhase,
|
|
|
50
51
|
* 走这条(只演感谢,不再问一次)。 */
|
|
51
52
|
readonly initialPhase?: 'ask' | 'done';
|
|
52
53
|
}): React.ReactNode;
|
|
54
|
+
export declare function WhaleCouponPrompt({ notice, onShown, onClose, }: {
|
|
55
|
+
readonly notice: WhaleCouponNotice;
|
|
56
|
+
readonly onShown: (orderId: WhaleCouponNotice['orderId']) => void;
|
|
57
|
+
readonly onClose: () => void;
|
|
58
|
+
}): React.ReactNode;
|
|
53
59
|
//# sourceMappingURL=StarPrompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StarPrompt.d.ts","sourceRoot":"","sources":["../../../src/components/StarPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"StarPrompt.d.ts","sourceRoot":"","sources":["../../../src/components/StarPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAuBtE,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9E;;0DAE0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAChD,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,OAAO,EACP,OAAO,EACP,YAAoB,GACrB,EAAE;IACD,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B;2BACuB;IACvB,QAAQ,CAAC,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CACvC,GAAG,KAAK,CAAC,SAAS,CAsOlB;AAmBD,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,OAAO,EACP,OAAO,GACR,EAAE;IACD,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,KAAK,IAAI,CAAA;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAC7B,GAAG,KAAK,CAAC,SAAS,CA6DlB"}
|
|
@@ -6,6 +6,7 @@ import { Divider } from './design-system/Divider.js';
|
|
|
6
6
|
import { HintLine } from './design-system/HintLine.js';
|
|
7
7
|
import { ListItem } from './design-system/ListItem.js';
|
|
8
8
|
import { MaidPortrait, useMaidPortraits } from './maidPortrait.js';
|
|
9
|
+
import { WhaleGirlHappyArt } from './WhaleGirl.js';
|
|
9
10
|
import { useTerminalBackground } from './design-system/ThemeProvider.js';
|
|
10
11
|
import { STANDARD_FRAME_INDEX, WhaleArt } from './Whale.js';
|
|
11
12
|
import { OPENING_SEQUENCES, WHALE_FRAME_INDEX } from './whaleFrames.js';
|
|
@@ -151,6 +152,50 @@ export function StarPrompt({ milestone, actions, onClose, initialPhase = 'ask',
|
|
|
151
152
|
actions.onOpen();
|
|
152
153
|
}, children: t('star-modal-open') }), phase === 'failed' && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Text, { color: "error", wrap: "wrap", children: failure })] })), phase !== 'failed' && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Divider, { width: textColumns })] })), _jsx(Box, { height: 1 }), _jsx(Text, { dimColor: true, wrap: "wrap", children: _jsx(HintLine, { text: t('star-modal-hint') }) })] }))] })] }) })] }));
|
|
153
154
|
}
|
|
155
|
+
/** The star modal's card and maid art, used only for a confirmed login grant. */
|
|
156
|
+
function couponExpiry(expiresAt) {
|
|
157
|
+
const date = new Date(expiresAt);
|
|
158
|
+
if (Number.isNaN(date.getTime()))
|
|
159
|
+
return null;
|
|
160
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
161
|
+
timeZone: 'Asia/Shanghai', month: 'numeric', day: 'numeric',
|
|
162
|
+
hour: '2-digit', minute: '2-digit', hourCycle: 'h23',
|
|
163
|
+
}).formatToParts(date);
|
|
164
|
+
const part = (type) => parts.find(item => item.type === type)?.value;
|
|
165
|
+
const month = part('month');
|
|
166
|
+
const day = part('day');
|
|
167
|
+
const hour = part('hour');
|
|
168
|
+
const minute = part('minute');
|
|
169
|
+
return month === undefined || day === undefined || hour === undefined || minute === undefined
|
|
170
|
+
? null : { month, day, time: `${hour}:${minute}` };
|
|
171
|
+
}
|
|
172
|
+
export function WhaleCouponPrompt({ notice, onShown, onClose, }) {
|
|
173
|
+
const lang = React.useSyncExternalStore(subscribeLang, getLang);
|
|
174
|
+
const { columns, rows } = useTerminalSize();
|
|
175
|
+
const imagesAvailable = useTerminalImages();
|
|
176
|
+
const portraits = useMaidPortraits(true);
|
|
177
|
+
const background = useTerminalBackground();
|
|
178
|
+
const withArt = columns >= MIN_ART_COLUMNS && rows >= MIN_ART_ROWS;
|
|
179
|
+
const textColumns = withArt ? TEXT_COLUMNS : Math.max(1, Math.min(TEXT_COLUMNS, columns - 6));
|
|
180
|
+
const cardColumns = withArt ? 96 : Math.min(columns, textColumns + 6);
|
|
181
|
+
const cardRows = withArt ? ART_ROWS + 2 : Math.min(rows, 15);
|
|
182
|
+
const left = Math.max(0, Math.floor((columns - cardColumns) / 2));
|
|
183
|
+
const bottom = Math.max(0, Math.min(Math.floor((rows - cardRows) / 2), rows - cardRows));
|
|
184
|
+
const amount = notice.amount.replace(/(\.\d*?)0+$/u, '$1').replace(/\.$/u, '');
|
|
185
|
+
const unit = lang === 'zh' ? notice.currency === 'CNY' ? '元' : '美元' : notice.currency;
|
|
186
|
+
const expiry = couponExpiry(notice.expiresAt);
|
|
187
|
+
React.useEffect(() => {
|
|
188
|
+
const timer = setTimeout(() => onShown(notice.orderId), 0);
|
|
189
|
+
return () => { clearTimeout(timer); };
|
|
190
|
+
}, [notice.orderId, onShown]);
|
|
191
|
+
useInput((_input, key) => {
|
|
192
|
+
if (key.return || key.escape)
|
|
193
|
+
onClose();
|
|
194
|
+
});
|
|
195
|
+
return (_jsxs(_Fragment, { children: [_jsx(Box, { position: "absolute", bottom: 0, left: 0, width: "100%", height: rows, flexShrink: 0, backdrop: "dim", onClick: onClose }), _jsx(Box, { position: "absolute", left: left, bottom: bottom, width: cardColumns, height: cardRows, flexDirection: "column", flexShrink: 0, overflow: "hidden", backgroundColor: background, opaque: true, onClick: event => { event.stopImmediatePropagation(); }, children: _jsxs(Box, { flexDirection: "row", gap: 2, alignItems: "center", justifyContent: "center", borderStyle: "round", borderColor: "inactive", paddingX: 2, backgroundColor: background, children: [withArt && (_jsxs(Box, { width: ART_COLUMNS, height: ART_ROWS, flexShrink: 0, flexDirection: "column", alignItems: "center", justifyContent: "center", backgroundColor: background, opaque: true, children: [_jsx(Confetti, { width: ART_COLUMNS }), imagesAvailable && portraits?.happy !== undefined
|
|
196
|
+
? _jsx(MaidPortrait, { source: portraits.happy, maxColumns: ART_COLUMNS, maxRows: ART_ROWS - CONFETTI_ROWS, presentation: "preview" })
|
|
197
|
+
: _jsx(WhaleGirlHappyArt, { source: portraits?.happy, width: ART_COLUMNS })] })), _jsxs(Box, { flexDirection: "column", width: textColumns, ...(withArt ? { height: ART_ROWS } : {}), children: [_jsx(Text, { color: "accent", bold: true, wrap: "truncate-end", children: t('coupon-modal-title') }), _jsx(Box, { height: 1 }), _jsx(Text, { color: "success", bold: true, wrap: "wrap", children: t('coupon-modal-received', { amount, unit }) }), expiry !== null && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Text, { wrap: "wrap", children: t('coupon-modal-expiry', expiry) })] })), _jsx(Box, { flexGrow: 1 }), _jsx(Divider, { width: textColumns }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: _jsx(HintLine, { text: t('coupon-modal-hint') }) })] })] }) })] }));
|
|
198
|
+
}
|
|
154
199
|
/**
|
|
155
200
|
* The card's art column: the raster maid first, the animated pixel whale
|
|
156
201
|
* otherwise. While celebrating it shows the **happy maid** (raster→raster in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAAG,QAAQ,EAAE,aAAa,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE;AAEpH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAAG,QAAQ,EAAE,aAAa,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE;AAEpH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAsD/F"}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text } from '../ui.js';
|
|
4
4
|
import { t } from '../i18n.js';
|
|
5
|
-
import {
|
|
5
|
+
import { isMinimalUiMode } from '../minimalUiMode.js';
|
|
6
6
|
function formatDuration(ms) {
|
|
7
7
|
const seconds = Math.floor(ms / 1000);
|
|
8
8
|
return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m${seconds % 60}s`;
|
|
@@ -24,16 +24,16 @@ export function SubagentCard({ subagent, focused, onClick }) {
|
|
|
24
24
|
// the card mid-gesture and reshuffle the whole dashboard list (user
|
|
25
25
|
// feedback: hover must never change layout). The hover tint stays.
|
|
26
26
|
const liveLine = running ? subagent.output[subagent.output.length - 1] : undefined;
|
|
27
|
-
const
|
|
28
|
-
const glyph = running ? (
|
|
29
|
-
: subagent.status === 'unknown' ? (
|
|
30
|
-
: subagent.status === 'failed' || subagent.status === 'cancelled' ? (
|
|
31
|
-
: (
|
|
32
|
-
const glyphColor =
|
|
27
|
+
const minimalUi = isMinimalUiMode();
|
|
28
|
+
const glyph = running ? (minimalUi ? '·' : '🟡')
|
|
29
|
+
: subagent.status === 'unknown' ? (minimalUi ? '·' : '⚪')
|
|
30
|
+
: subagent.status === 'failed' || subagent.status === 'cancelled' ? (minimalUi ? '×' : '🔴')
|
|
31
|
+
: (minimalUi ? '✓' : '🟢');
|
|
32
|
+
const glyphColor = minimalUi ? undefined
|
|
33
33
|
: running ? 'warning'
|
|
34
34
|
: subagent.status === 'unknown' ? 'subtle'
|
|
35
35
|
: subagent.status === 'failed' || subagent.status === 'cancelled' ? 'error'
|
|
36
36
|
: 'success';
|
|
37
37
|
const hoverTint = onClick !== undefined && hovered && !focused;
|
|
38
|
-
return _jsxs(Box, { flexDirection: "column", paddingLeft: 1, marginBottom: 1, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hoverTint ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: glyphColor, children: glyph }), _jsx(Text, { bold: true, color: focused ? 'accent' : undefined, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsxs(Text, { dimColor: true, children: [elapsed !== undefined ? ` · ${formatDuration(elapsed)} · ` : ' · ', total || '—', " tok \u00B7 ", subagent.toolCalls.length, " tools"] })] })] }), liveLine && _jsx(Text, { dimColor: true, wrap: "truncate", children: ` │ ${liveLine}` })] });
|
|
38
|
+
return _jsxs(Box, { flexDirection: "column", paddingLeft: 1, marginBottom: 1, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hoverTint ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: glyphColor, children: glyph }), _jsx(Text, { bold: true, color: focused ? 'accent' : undefined, children: `${t('subagent-card-prefix')}${subagent.description}` }), subagent.mode === 'continuable' && (_jsx(Text, { color: focused ? 'accent' : 'warning', children: t('subagent-mode-continuable') })), subagent.mode === 'one-shot' && (_jsx(Text, { dimColor: true, children: t('subagent-mode-one-shot') })), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsxs(Text, { dimColor: true, children: [elapsed !== undefined ? ` · ${formatDuration(elapsed)} · ` : ' · ', total || '—', " tok \u00B7 ", subagent.toolCalls.length, " tools"] })] })] }), liveLine && _jsx(Text, { dimColor: true, wrap: "truncate", children: ` │ ${liveLine}` })] });
|
|
39
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubagentDetailScene.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentDetailScene.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"SubagentDetailScene.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentDetailScene.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAqJpF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,aAAa,CAAA;IACvB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,WAAW,GACZ,EAAE,wBAAwB,GAAG,KAAK,CAAC,SAAS,CA6S5C"}
|