@deepseek-harness-tui/dsh-tui 0.8.4 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/types/activityPrefs.d.ts +10 -0
- package/lib/types/activityPrefs.d.ts.map +1 -1
- package/lib/types/activityPrefs.js +17 -0
- package/lib/types/cc/figures.d.ts +7 -0
- package/lib/types/cc/figures.d.ts.map +1 -1
- package/lib/types/cc/figures.js +23 -0
- package/lib/types/cc/markdown.d.ts.map +1 -1
- package/lib/types/cc/markdown.js +47 -14
- package/lib/types/cc/syntaxTheme.d.ts +12 -0
- package/lib/types/cc/syntaxTheme.d.ts.map +1 -0
- package/lib/types/cc/syntaxTheme.js +76 -0
- package/lib/types/components/EffortChargeGlyph.d.ts +26 -0
- package/lib/types/components/EffortChargeGlyph.d.ts.map +1 -0
- package/lib/types/components/EffortChargeGlyph.js +70 -0
- package/lib/types/components/EffortInputBorder.d.ts +36 -0
- package/lib/types/components/EffortInputBorder.d.ts.map +1 -0
- package/lib/types/components/EffortInputBorder.js +73 -0
- package/lib/types/components/EffortTierBadge.d.ts +26 -0
- package/lib/types/components/EffortTierBadge.d.ts.map +1 -0
- package/lib/types/components/EffortTierBadge.js +97 -0
- package/lib/types/components/LoadedContextPanel.js +1 -1
- package/lib/types/components/MessageList.d.ts +4 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +9 -11
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +8 -3
- package/lib/types/components/SplitDiffView.d.ts +4 -5
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +18 -65
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +10 -2
- package/lib/types/components/activityFrames.d.ts +7 -28
- package/lib/types/components/activityFrames.d.ts.map +1 -1
- package/lib/types/components/activityFrames.js +7 -94
- package/lib/types/components/design-system/ThemedBox.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemedBox.js +4 -1
- package/lib/types/components/design-system/ThemedText.js +2 -2
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +12 -6
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +25 -9
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +4 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +45 -17
- package/lib/types/components/messages/UserPromptMessage.d.ts +4 -6
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +5 -9
- package/lib/types/dsh-adapter/channel.d.ts +22 -0
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +204 -19
- package/lib/types/dsh-adapter/index.d.ts +5 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +19 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +176 -4
- package/lib/types/dsh-adapter/settings-sections.d.ts +13 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +31 -6
- package/lib/types/ink/ink.d.ts +9 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +24 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +35 -6
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +109 -50
- package/lib/types/screens/StatusLine.d.ts +8 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +62 -39
- package/lib/types/settings-sections.d.ts +1 -1
- package/lib/types/settings-sections.d.ts.map +1 -1
- package/lib/types/theme.d.ts +12 -0
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +51 -21
- package/lib/types/tips.js +2 -2
- package/lib/types/trajectory/effortIgnition.d.ts +66 -0
- package/lib/types/trajectory/effortIgnition.d.ts.map +1 -0
- package/lib/types/trajectory/effortIgnition.js +142 -0
- package/lib/types/tuiDisplayPrefs.d.ts +47 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -0
- package/lib/types/tuiDisplayPrefs.js +60 -0
- package/package.json +6 -3
|
@@ -46,6 +46,7 @@ export function Settings({ channel, onClose, }) {
|
|
|
46
46
|
const [sections, setSections] = React.useState(() => channel.settingsSections());
|
|
47
47
|
const [mode, setMode] = React.useState('list');
|
|
48
48
|
const [editing, setEditing] = React.useState(null);
|
|
49
|
+
const [activeGroup, setActiveGroup] = React.useState(null);
|
|
49
50
|
const [focusIndex, setFocusIndex] = React.useState(0);
|
|
50
51
|
const [notice, setNotice] = React.useState(undefined);
|
|
51
52
|
/** Configured status of every secret field's credential ref. */
|
|
@@ -100,8 +101,26 @@ export function Settings({ channel, onClose, }) {
|
|
|
100
101
|
};
|
|
101
102
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
103
|
}, [host, sections, secretProbe]);
|
|
103
|
-
|
|
104
|
-
const
|
|
104
|
+
const activeSection = activeGroup === null ? undefined : sections.find(section => section.ns === activeGroup.ns);
|
|
105
|
+
const activeGroupSpec = activeSection?.groups?.find(group => group.id === activeGroup?.id);
|
|
106
|
+
React.useEffect(() => {
|
|
107
|
+
if (activeGroup !== null && activeGroupSpec === undefined) {
|
|
108
|
+
setActiveGroup(null);
|
|
109
|
+
setFocusIndex(0);
|
|
110
|
+
setWindowStart(0);
|
|
111
|
+
}
|
|
112
|
+
}, [activeGroup, activeGroupSpec]);
|
|
113
|
+
/** Focusable rows in display order for the current page. */
|
|
114
|
+
const focusable = activeSection !== undefined && activeGroupSpec !== undefined
|
|
115
|
+
? activeSection.fields
|
|
116
|
+
.filter(field => field.group === activeGroupSpec.id)
|
|
117
|
+
.map(field => ({ kind: 'field', ns: activeSection.ns, field }))
|
|
118
|
+
: sections.flatMap(section => [
|
|
119
|
+
...section.fields
|
|
120
|
+
.filter(field => field.group === undefined)
|
|
121
|
+
.map(field => ({ kind: 'field', ns: section.ns, field })),
|
|
122
|
+
...(section.groups ?? []).map(group => ({ kind: 'group', ns: section.ns, group })),
|
|
123
|
+
]);
|
|
105
124
|
const effFocus = Math.min(focusIndex, Math.max(0, focusable.length - 1));
|
|
106
125
|
const focused = focusable.length === 0 ? undefined : focusable[effFocus];
|
|
107
126
|
const focusedForm = focused === undefined ? undefined : forms.get(focused.ns);
|
|
@@ -173,6 +192,12 @@ export function Settings({ channel, onClose, }) {
|
|
|
173
192
|
setFocusIndex(Math.min(Math.max(0, focusable.length - 1), effFocus + 1));
|
|
174
193
|
}
|
|
175
194
|
else if (isPlainReturn(key) && focused !== undefined) {
|
|
195
|
+
if (focused.kind === 'group') {
|
|
196
|
+
setActiveGroup({ ns: focused.ns, id: focused.group.id });
|
|
197
|
+
setFocusIndex(0);
|
|
198
|
+
setWindowStart(0);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
176
201
|
// A save in flight owns the section's drafts; starting an edit mid-write
|
|
177
202
|
// is exactly the lost-draft race the staged model exists to prevent.
|
|
178
203
|
if (focusedForm === undefined || !focusedForm.available || focusedForm.saving)
|
|
@@ -196,11 +221,17 @@ export function Settings({ channel, onClose, }) {
|
|
|
196
221
|
bump();
|
|
197
222
|
}
|
|
198
223
|
else if (key.escape) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
224
|
+
if (activeGroupSpec !== undefined) {
|
|
225
|
+
// Group navigation never settles drafts; the root page owns discard/exit.
|
|
226
|
+
setActiveGroup(null);
|
|
227
|
+
setFocusIndex(0);
|
|
228
|
+
setWindowStart(0);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// At the root, Esc backs out one layer at a time: staged drafts first —
|
|
232
|
+
// ANY dirty section, not just the focused one — then the screen itself.
|
|
233
|
+
// A save in flight cannot be undone from here; let it settle instead of
|
|
234
|
+
// discarding around it.
|
|
204
235
|
const dirty = [...forms.values()].filter(form => form.shell().dirty);
|
|
205
236
|
if (dirty.length > 0) {
|
|
206
237
|
if (dirty.some(form => form.saving))
|
|
@@ -219,7 +250,7 @@ export function Settings({ channel, onClose, }) {
|
|
|
219
250
|
const ns = section.ns;
|
|
220
251
|
const form = forms.get(ns);
|
|
221
252
|
const state = form?.field(field) ?? { text: '', overridden: false, invalid: false };
|
|
222
|
-
const isFocused = focused
|
|
253
|
+
const isFocused = focused?.kind === 'field' && focused.ns === ns && focused.field === field;
|
|
223
254
|
const isEditing = isFocused && mode === 'edit' && editing !== null;
|
|
224
255
|
const label = pick(field.label, field.descriptions);
|
|
225
256
|
const hint = field.hint !== undefined ? pick(field.hint, field.hintDescriptions) : undefined;
|
|
@@ -248,58 +279,82 @@ export function Settings({ channel, onClose, }) {
|
|
|
248
279
|
return (_jsxs(Box, { children: [_jsx(Text, { color: isFocused ? 'suggestion' : undefined, children: isFocused ? '❯ ' : ' ' }), _jsx(Text, { bold: isFocused, children: label }), _jsx(Box, { flexGrow: 1 }), state.invalid && _jsxs(Text, { color: "error", children: [t('settings-field-invalid'), " "] }), state.overridden && _jsxs(Text, { dimColor: true, children: ["[", t('settings-badge-override'), "] "] }), form?.isStaged(field) === true && !isEditing && _jsx(Text, { color: "suggestion", children: "* " }), _jsx(Text, { color: isEditing || isFocused ? 'suggestion' : undefined, dimColor: !isFocused && !isEditing && state.text === '', children: value }), hint !== undefined && isFocused && (_jsxs(Text, { dimColor: true, children: ['\n ', hint] }))] }));
|
|
249
280
|
};
|
|
250
281
|
// ── Layout: a flat entry list with accounted line heights, windowed so the
|
|
251
|
-
// focused
|
|
282
|
+
// focused row is always on screen no matter how long the current page gets. ─
|
|
252
283
|
const entries = [];
|
|
253
284
|
let focusCursor = 0;
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
|
|
285
|
+
const addField = (section, field) => {
|
|
286
|
+
const isFocused = focused?.kind === 'field' && focused.ns === section.ns && focused.field === field;
|
|
287
|
+
const index = focusCursor;
|
|
288
|
+
focusCursor += 1;
|
|
258
289
|
entries.push({
|
|
259
|
-
key: `
|
|
260
|
-
lines:
|
|
261
|
-
|
|
290
|
+
key: `field:${section.ns}:${field.path.join('.')}`,
|
|
291
|
+
lines: field.hint !== undefined && isFocused ? 2 : 1,
|
|
292
|
+
focus: index,
|
|
293
|
+
node: renderField(section, field),
|
|
262
294
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
295
|
+
};
|
|
296
|
+
if (activeSection !== undefined && activeGroupSpec !== undefined) {
|
|
297
|
+
const groupFields = activeSection.fields.filter(field => field.group === activeGroupSpec.id);
|
|
298
|
+
for (const field of groupFields)
|
|
299
|
+
addField(activeSection, field);
|
|
300
|
+
if (groupFields.length === 0) {
|
|
301
|
+
entries.push({ key: 'group:empty', lines: 1, node: _jsx(Text, { dimColor: true, children: t('settings-group-empty') }) });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
sections.forEach((section, sectionIndex) => {
|
|
306
|
+
const form = forms.get(section.ns);
|
|
307
|
+
const view = form?.namespace;
|
|
308
|
+
const shell = form?.shell();
|
|
268
309
|
entries.push({
|
|
269
|
-
key: `
|
|
270
|
-
lines:
|
|
271
|
-
|
|
272
|
-
node: renderField(section, field),
|
|
310
|
+
key: `section:${section.ns}`,
|
|
311
|
+
lines: sectionIndex === 0 ? 1 : 2,
|
|
312
|
+
node: (_jsxs(Box, { flexDirection: "column", children: [sectionIndex > 0 && _jsx(Text, { children: " " }), _jsxs(Box, { children: [_jsx(Text, { bold: true, color: "permission", children: pick(section.title, section.descriptions) }), _jsxs(Text, { dimColor: true, children: [" (", section.ns, ")"] }), view?.applies === 'restart' && _jsxs(Text, { color: "warning", children: [" [", t('settings-badge-restart'), "]"] }), view === undefined && _jsxs(Text, { color: "warning", children: [" [", t('settings-section-unavailable'), "]"] }), shell?.dirty === true && _jsxs(Text, { color: "suggestion", children: [" [", t('settings-badge-dirty'), "]"] }), shell?.saving === true && _jsxs(Text, { dimColor: true, children: [" [", t('settings-badge-saving'), "]"] }), shell?.failed === true && _jsxs(Text, { color: "error", children: [" [", t('settings-badge-failed'), "]"] })] })] })),
|
|
273
313
|
});
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
314
|
+
for (const field of section.fields) {
|
|
315
|
+
if (field.group === undefined)
|
|
316
|
+
addField(section, field);
|
|
317
|
+
}
|
|
318
|
+
for (const group of section.groups ?? []) {
|
|
319
|
+
const isFocused = focused?.kind === 'group' && focused.ns === section.ns && focused.group === group;
|
|
320
|
+
const index = focusCursor;
|
|
321
|
+
focusCursor += 1;
|
|
322
|
+
entries.push({
|
|
323
|
+
key: `group:${section.ns}:${group.id}`,
|
|
324
|
+
lines: 1,
|
|
325
|
+
focus: index,
|
|
326
|
+
node: (_jsxs(Box, { children: [_jsx(Text, { color: isFocused ? 'suggestion' : undefined, children: isFocused ? '❯ ' : ' ' }), _jsx(Text, { bold: isFocused, children: pick(group.title, group.descriptions) }), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { color: isFocused ? 'suggestion' : undefined, children: "\u203A" })] })),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
283
329
|
});
|
|
284
|
-
|
|
330
|
+
const registeredNs = new Set(sections.map(section => section.ns));
|
|
331
|
+
const readonlyNamespaces = namespaces.filter(entry => !registeredNs.has(entry.ns));
|
|
332
|
+
if (readonlyNamespaces.length > 0) {
|
|
333
|
+
entries.push({
|
|
334
|
+
key: 'readonly:heading',
|
|
335
|
+
lines: 2,
|
|
336
|
+
node: (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: " " }), _jsx(Text, { bold: true, dimColor: true, children: t('settings-readonly-heading') })] })),
|
|
337
|
+
});
|
|
338
|
+
for (const entry of readonlyNamespaces) {
|
|
339
|
+
entries.push({
|
|
340
|
+
key: `readonly:${entry.ns}`,
|
|
341
|
+
lines: 1,
|
|
342
|
+
node: (_jsxs(Box, { children: [_jsxs(Text, { children: [' ', entry.ns] }), entry.applies === 'restart' && _jsxs(Text, { color: "warning", children: [" [", t('settings-badge-restart'), "]"] }), _jsxs(Text, { dimColor: true, children: [' ', valuePreview(entry.value, 60)] })] })),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
285
345
|
entries.push({
|
|
286
|
-
key:
|
|
346
|
+
key: 'readonly:hint',
|
|
287
347
|
lines: 1,
|
|
288
|
-
node:
|
|
348
|
+
node: _jsxs(Text, { dimColor: true, children: [' ', t('settings-readonly-hint', { path: '~/.dsh/settings.yaml' })] }),
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
if (sections.length === 0 && readonlyNamespaces.length === 0) {
|
|
352
|
+
entries.push({
|
|
353
|
+
key: 'empty',
|
|
354
|
+
lines: 1,
|
|
355
|
+
node: _jsx(Text, { dimColor: true, children: t('settings-empty') }),
|
|
289
356
|
});
|
|
290
357
|
}
|
|
291
|
-
entries.push({
|
|
292
|
-
key: 'readonly:hint',
|
|
293
|
-
lines: 1,
|
|
294
|
-
node: _jsxs(Text, { dimColor: true, children: [' ', t('settings-readonly-hint', { path: '~/.dsh/settings.yaml' })] }),
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
if (sections.length === 0 && readonlyNamespaces.length === 0) {
|
|
298
|
-
entries.push({
|
|
299
|
-
key: 'empty',
|
|
300
|
-
lines: 1,
|
|
301
|
-
node: _jsx(Text, { dimColor: true, children: t('settings-empty') }),
|
|
302
|
-
});
|
|
303
358
|
}
|
|
304
359
|
// Focus-follow window: keep the focused entry fully inside the viewport.
|
|
305
360
|
let totalLines = 0;
|
|
@@ -329,5 +384,9 @@ export function Settings({ channel, onClose, }) {
|
|
|
329
384
|
entryOffset += entry.lines;
|
|
330
385
|
return start >= windowStart && start + entry.lines <= windowStart + viewport;
|
|
331
386
|
});
|
|
332
|
-
|
|
387
|
+
const title = activeSection !== undefined && activeGroupSpec !== undefined
|
|
388
|
+
? `${t('settings-title')} › ${pick(activeSection.title, activeSection.descriptions)} › ${pick(activeGroupSpec.title, activeGroupSpec.descriptions)}`
|
|
389
|
+
: t('settings-title');
|
|
390
|
+
const navigationHint = activeGroupSpec === undefined ? t('settings-hint-list') : t('settings-hint-group');
|
|
391
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: title }), _jsx(Box, { flexGrow: 1 }), host === undefined && _jsx(Text, { color: "warning", children: t('settings-unavailable') })] }), _jsx(Divider, {}), visible.map(entry => (_jsx(React.Fragment, { children: entry.node }, entry.key))), _jsx(Box, { flexGrow: 1 }), notice !== undefined && (_jsx(Text, { color: notice.tone === 'error' ? 'error' : 'success', children: notice.text })), _jsx(Divider, {}), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: mode === 'edit' ? t('settings-hint-edit') : navigationHint }) })] }));
|
|
333
392
|
}
|
|
@@ -28,4 +28,12 @@ export declare function StatusLine({ channel, selectionActive, helpOpen, wake, }
|
|
|
28
28
|
tick: number;
|
|
29
29
|
};
|
|
30
30
|
}): React.JSX.Element;
|
|
31
|
+
type UsageSnapshot = {
|
|
32
|
+
input: number;
|
|
33
|
+
cacheRead: number;
|
|
34
|
+
cacheWrite: number;
|
|
35
|
+
};
|
|
36
|
+
/** Return the prompt-cache hit rate, or nothing when usage is unavailable. */
|
|
37
|
+
export declare function formatCacheHitRate(usage: UsageSnapshot | undefined): string | undefined;
|
|
38
|
+
export {};
|
|
31
39
|
//# sourceMappingURL=StatusLine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAQvD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,GACL,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD,
|
|
1
|
+
{"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAQvD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,GACL,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD,qBAsPA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF"}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Text, useTerminalSize, useTheme } from '../ui.js';
|
|
3
3
|
import { formatTokens } from '../cc/format.js';
|
|
4
4
|
import { t } from '../i18n.js';
|
|
5
|
+
import { formatContextUsage, normalizeStatusBar } from '../tuiDisplayPrefs.js';
|
|
5
6
|
import { Byline } from '../components/design-system/Byline.js';
|
|
6
7
|
import { ActivityLine, contextPressurePct } from '../components/ActivityLine.js';
|
|
7
8
|
import { modeDisplayName } from '../sessionModes.js';
|
|
@@ -18,30 +19,32 @@ import { renderContextBar, renderTpsGauge, renderTpsSparkline, speedColor, } fro
|
|
|
18
19
|
export function StatusLine({ channel, selectionActive = false, helpOpen = false, wake, }) {
|
|
19
20
|
const { columns } = useTerminalSize();
|
|
20
21
|
const [themeName] = useTheme();
|
|
22
|
+
const statusBar = normalizeStatusBar(channel.statusBar);
|
|
21
23
|
const usage = channel.lastUsage;
|
|
24
|
+
const contextUsed = usage === undefined
|
|
25
|
+
? undefined
|
|
26
|
+
: usage.input + usage.cacheRead + usage.cacheWrite;
|
|
22
27
|
const contextParts = [];
|
|
23
|
-
|
|
24
|
-
// mode (index 0); sage while a plan-declaring mode is in force.
|
|
25
|
-
if (channel.modeIndex > 0) {
|
|
26
|
-
contextParts.push(_jsx(Text, { color: channel.mode.plan === true ? 'planMode' : 'warning', children: modeDisplayName(channel.mode) }, "mode"));
|
|
27
|
-
}
|
|
28
|
-
if (channel.reasoningEffort !== undefined) {
|
|
28
|
+
if (statusBar.thinking && channel.reasoningEffort !== undefined) {
|
|
29
29
|
contextParts.push(_jsx(Text, { color: "inactiveShimmer", children: channel.reasoningEffort }, "effort"));
|
|
30
30
|
}
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
if (statusBar.mode && channel.modeIndex > 0) {
|
|
32
|
+
contextParts.push(_jsx(Text, { color: channel.mode.plan === true ? 'planMode' : 'warning', children: modeDisplayName(channel.mode) }, "mode"));
|
|
33
|
+
}
|
|
34
|
+
const formattedContext = statusBar.contextUsage
|
|
35
|
+
? formatContextUsage(contextUsed, channel.contextWindow, statusBar.compact)
|
|
36
|
+
: undefined;
|
|
37
|
+
const contextUsagePart = formattedContext === undefined
|
|
38
|
+
? undefined
|
|
39
|
+
: (_jsxs(Text, { color: "inactiveShimmer", children: [_jsx(Text, { dimColor: true, children: "ctx " }), formattedContext] }, "context"));
|
|
40
|
+
if (statusBar.cache) {
|
|
41
|
+
const cacheRate = formatCacheHitRate(usage);
|
|
42
|
+
if (cacheRate !== undefined) {
|
|
43
|
+
contextParts.push(_jsxs(Text, { color: "inactiveShimmer", children: [_jsx(Text, { dimColor: true, children: t('status-cache-label') }), cacheRate] }, "cache"));
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
|
-
// TPS readout sits right after the model so a crowded footer truncates
|
|
40
|
-
// the trailing fields (tokens/think/cache), never the speedometer. One
|
|
41
|
-
// number only: the live value (gauge while streaming, sparkline of past
|
|
42
|
-
// turns once samples exist) — no μ/p95 clutter.
|
|
43
46
|
const tpsParts = [];
|
|
44
|
-
if (channel.tps !== undefined) {
|
|
47
|
+
if (statusBar.tps && channel.tps !== undefined) {
|
|
45
48
|
if (channel.working && channel.tpsSamples.length === 0) {
|
|
46
49
|
tpsParts.push(_jsxs(Text, { children: [renderTpsGauge(channel.tps, channel.tps), ' ', _jsxs(Text, { dimColor: true, children: [Math.round(channel.tps), " tps"] })] }, "tps"));
|
|
47
50
|
}
|
|
@@ -55,57 +58,77 @@ export function StatusLine({ channel, selectionActive = false, helpOpen = false,
|
|
|
55
58
|
tpsParts.push(_jsxs(Text, { dimColor: true, children: [Math.round(channel.tps), " t/s"] }, "tps"));
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
|
-
// Left group: every field sits at soft white (inactiveShimmer) instead of
|
|
59
|
-
// the previous uniform dim grey — readable against dark terminals.
|
|
60
61
|
const leftParts = [
|
|
61
|
-
|
|
62
|
+
...(statusBar.model
|
|
63
|
+
? [_jsx(Text, { color: "inactiveShimmer", children: channel.model }, "model")]
|
|
64
|
+
: []),
|
|
62
65
|
...tpsParts,
|
|
63
66
|
...contextParts,
|
|
64
|
-
|
|
67
|
+
...(statusBar.tokens
|
|
68
|
+
? [
|
|
69
|
+
_jsxs(Text, { color: "inactiveShimmer", children: [formatTokens(channel.tokens.input), "\u2192", formatTokens(channel.tokens.output)] }, "tokens"),
|
|
70
|
+
]
|
|
71
|
+
: []),
|
|
65
72
|
];
|
|
66
|
-
// Right group: git branch in muted steel blue, cwd a soft white, the
|
|
67
|
-
// session title dimmest (it truncates first anyway).
|
|
68
73
|
const rightParts = [
|
|
69
|
-
...(channel.gitBranch
|
|
74
|
+
...(statusBar.gitBranch && channel.gitBranch
|
|
70
75
|
? [
|
|
71
76
|
_jsx(Text, { color: "professionalBlue", children: channel.gitBranch }, "git"),
|
|
72
77
|
]
|
|
73
78
|
: []),
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
...(statusBar.cwd
|
|
80
|
+
? [
|
|
81
|
+
_jsx(Text, { color: "inactiveShimmer", children: statusBar.compact ? basename(channel.displayCwd) : channel.displayCwd }, "cwd"),
|
|
82
|
+
]
|
|
83
|
+
: []),
|
|
84
|
+
...(statusBar.sessionTitle && channel.sessionTitle
|
|
76
85
|
? [
|
|
77
86
|
_jsx(Text, { dimColor: true, children: channel.sessionTitle }, "title"),
|
|
78
87
|
]
|
|
79
88
|
: []),
|
|
80
89
|
];
|
|
81
|
-
// Row 3: the mode hint — and, while idle, the working-activity turn
|
|
82
|
-
// summary (the live working line itself moves to the spinner slot above
|
|
83
|
-
// the input while a turn runs, so the two never duplicate).
|
|
84
90
|
const hint = selectionActive
|
|
85
91
|
? t('statusline-hint-select')
|
|
86
92
|
: channel.working
|
|
87
93
|
? t('statusline-hint-working')
|
|
88
|
-
: !helpOpen
|
|
94
|
+
: statusBar.shortcutHint && !helpOpen
|
|
89
95
|
? t('statusline-hint-shortcuts')
|
|
90
96
|
: '';
|
|
91
97
|
const activity = channel.workingActivity;
|
|
92
|
-
const showActivity =
|
|
98
|
+
const showActivity = statusBar.activity &&
|
|
99
|
+
!channel.working &&
|
|
93
100
|
activity !== undefined &&
|
|
94
101
|
activity.line !== '' &&
|
|
95
102
|
activity.phase !== 'idle';
|
|
103
|
+
const showTrajectory = statusBar.trajectory && wake !== undefined;
|
|
96
104
|
const barWidth = columns - 4;
|
|
97
105
|
let bar = null;
|
|
98
|
-
// Theme-aware free segment: the light palette's near-white fill (#E8E8E8)
|
|
99
|
-
// reads as a glaring white band on dark terminals — swap it for a deep
|
|
100
|
-
// blue-gray there while keeping the light palette as-is (dark-ansi carries
|
|
101
|
-
// `ansi:` color names, so map by theme name rather than palette tokens).
|
|
102
106
|
const barColors = themeName === 'light'
|
|
103
107
|
? undefined
|
|
104
108
|
: { freeFill: '#2E3440', freeText: '#8D95A6' };
|
|
105
|
-
if (
|
|
106
|
-
|
|
109
|
+
if (statusBar.contextBar &&
|
|
110
|
+
channel.contextBarEnabled &&
|
|
111
|
+
barWidth >= 14 &&
|
|
112
|
+
usage !== undefined &&
|
|
113
|
+
channel.contextWindow !== undefined) {
|
|
114
|
+
bar = renderContextBar(channel.contextSegments, contextUsed ?? 0, channel.contextWindow, barWidth, barColors);
|
|
107
115
|
}
|
|
108
|
-
|
|
116
|
+
const compactLeftParts = [...leftParts, ...rightParts];
|
|
117
|
+
const fullLeftParts = contextUsagePart === undefined
|
|
118
|
+
? leftParts
|
|
119
|
+
: [...leftParts, contextUsagePart];
|
|
120
|
+
const hasStatusFields = compactLeftParts.length > 0 || contextUsagePart !== undefined;
|
|
121
|
+
const showSupplementalRow = hint !== '' || showActivity || showTrajectory;
|
|
122
|
+
return (_jsx(Box, { paddingX: 1, width: columns, flexShrink: 0, children: _jsxs(Box, { flexDirection: "column", width: "100%", children: [bar ? _jsx(Text, { children: bar }) : null, hasStatusFields ? statusBar.compact ? (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsx(Text, { wrap: "truncate", children: _jsx(Byline, { children: compactLeftParts }) }) }), contextUsagePart ? (_jsx(Box, { flexShrink: 0, children: _jsx(Text, { wrap: "truncate", children: _jsx(Byline, { children: [contextUsagePart] }) }) })) : null] })) : (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsx(Text, { wrap: "truncate", children: _jsx(Byline, { children: fullLeftParts }) }) }), _jsx(Box, { justifyContent: "flex-end", flexShrink: 2, children: _jsx(Text, { wrap: "truncate", children: _jsx(Byline, { children: rightParts }) }) })] })) : null, showSupplementalRow ? _jsxs(Box, { height: 1, overflow: "hidden", flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsxs(Box, { flexDirection: "row", flexGrow: 1, justifyContent: showActivity && hint ? 'space-between' : 'flex-start', gap: 2, children: [showActivity && activity !== undefined ? (_jsx(ActivityLine, { activity: activity, activityFrames: channel.activityFrames, warnPct: contextPressurePct(usage, channel.contextWindow), warnDanger: (contextPressurePct(usage, channel.contextWindow) ?? 0) >= 95 })) : hint ? (_jsx(Text, { color: "inactiveShimmer", children: hint })) : null, showActivity && hint ? (_jsx(Text, { color: "inactiveShimmer", wrap: "truncate", children: hint })) : null] }), showTrajectory && wake !== undefined ? (_jsx(MiniWake, { band: wake.band, hint: wake.hint, tick: wake.tick })) : null] }) : null] }) }));
|
|
123
|
+
}
|
|
124
|
+
/** Return the prompt-cache hit rate, or nothing when usage is unavailable. */
|
|
125
|
+
export function formatCacheHitRate(usage) {
|
|
126
|
+
if (usage === undefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
const total = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
129
|
+
if (!Number.isFinite(total) || total <= 0)
|
|
130
|
+
return undefined;
|
|
131
|
+
return `${((usage.cacheRead / total) * 100).toFixed(1)}%`;
|
|
109
132
|
}
|
|
110
133
|
function basename(path) {
|
|
111
134
|
const parts = path.split(/[\\/]/);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { name, TuiSettingsSectionsRuntime } from './dsh-adapter/settings-sections.js';
|
|
2
|
-
export type { TuiSettingsFieldKind, TuiSettingsFieldOption, TuiSettingsFieldWrite, TuiSettingsField, TuiSettingsSection, } from './dsh-adapter/settings-sections.js';
|
|
2
|
+
export type { TuiSettingsFieldKind, TuiSettingsFieldOption, TuiSettingsGroup, TuiSettingsFieldWrite, TuiSettingsField, TuiSettingsSection, } from './dsh-adapter/settings-sections.js';
|
|
3
3
|
export { default } from './dsh-adapter/settings-sections.js';
|
|
4
4
|
//# sourceMappingURL=settings-sections.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-sections.d.ts","sourceRoot":"","sources":["../../src/settings-sections.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AACrF,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAA"}
|
|
1
|
+
{"version":3,"file":"settings-sections.d.ts","sourceRoot":"","sources":["../../src/settings-sections.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AACrF,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAA"}
|
package/lib/types/theme.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export type Theme = {
|
|
|
19
19
|
autoAccept: string;
|
|
20
20
|
bashBorder: string;
|
|
21
21
|
claude: string;
|
|
22
|
+
toolNameMutate: string;
|
|
23
|
+
toolNameExec: string;
|
|
22
24
|
claudeShimmer: string;
|
|
23
25
|
claudeBlue_FOR_SYSTEM_SPINNER: string;
|
|
24
26
|
claudeBlueShimmer_FOR_SYSTEM_SPINNER: string;
|
|
@@ -135,6 +137,16 @@ export type ThemeName = string;
|
|
|
135
137
|
* (light/dark), unknown names fall back to `dark`.
|
|
136
138
|
*/
|
|
137
139
|
export declare function getTheme(themeName: ThemeName): Theme;
|
|
140
|
+
/**
|
|
141
|
+
* Whether the active theme's RESOLVED palette renders on a light background.
|
|
142
|
+
* Keyed off the resolved palette's IDENTITY for the built-ins (auto resolves
|
|
143
|
+
* to the shared light/dark instance, so this covers auto-with-light-terminal
|
|
144
|
+
* that theme-NAME comparisons miss) and off the ink-text luminance for
|
|
145
|
+
* custom themes (light palettes pair with dark ink). The palette's
|
|
146
|
+
* `background` field is a badge fill, not the terminal background — never a
|
|
147
|
+
* lightness signal. Colour-pair variants (effort ignition hues) consume this.
|
|
148
|
+
*/
|
|
149
|
+
export declare function isLightThemeActive(themeName: ThemeName): boolean;
|
|
138
150
|
/**
|
|
139
151
|
* Register the custom-theme resolver. Called once by ThemeProvider; the
|
|
140
152
|
* resolver must return `undefined` for names it does not know so getTheme
|
package/lib/types/theme.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/theme.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/theme.ts"],"names":[],"mappings":"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"}
|
package/lib/types/theme.js
CHANGED
|
@@ -58,6 +58,8 @@ const darkTheme = {
|
|
|
58
58
|
autoAccept: rgb('#B3A0D4'), // Soft violet
|
|
59
59
|
bashBorder: rgb('#D194AE'), // Mist rose
|
|
60
60
|
claude: rgb('#7DA1DE'), // Accent Soft — mist brand blue
|
|
61
|
+
toolNameMutate: rgb('#E5C07B'), // soft gold — Edit/Write (warm accent)
|
|
62
|
+
toolNameExec: rgb('#56B6C2'), // mist cyan — Bash/exec tools
|
|
61
63
|
claudeShimmer: rgb('#ABC2EC'), // Border Blue for shimmer effect
|
|
62
64
|
claudeBlue_FOR_SYSTEM_SPINNER: rgb('#7DA1DE'),
|
|
63
65
|
claudeBlueShimmer_FOR_SYSTEM_SPINNER: rgb('#ABC2EC'),
|
|
@@ -93,16 +95,16 @@ const darkTheme = {
|
|
|
93
95
|
toolDotWrite: rgb('#B3A0D4'), // soft violet — edit/write
|
|
94
96
|
toolDotWeb: rgb('#7DA1DE'), // mist blue — web search/fetch
|
|
95
97
|
toolDotTask: rgb('#D194AE'), // mist rose — subagent/jobs
|
|
96
|
-
syntaxKeyword: rgb('#
|
|
97
|
-
syntaxString: rgb('#
|
|
98
|
+
syntaxKeyword: rgb('#82AAFF'), // vivid blue (theme anchor)
|
|
99
|
+
syntaxString: rgb('#E5C07B'), // gold - echoes the user-message gold accent
|
|
98
100
|
syntaxComment: rgb('#6B7280'), // neutral grey
|
|
99
|
-
syntaxNumber: rgb('#
|
|
100
|
-
syntaxFunction: rgb('#
|
|
101
|
-
syntaxType: rgb('#
|
|
101
|
+
syntaxNumber: rgb('#D19A66'), // warm orange
|
|
102
|
+
syntaxFunction: rgb('#56B6C2'), // vivid cyan
|
|
103
|
+
syntaxType: rgb('#C678DD'), // vivid violet
|
|
102
104
|
syntaxVariable: rgb('#C9D1D9'), // near-text
|
|
103
105
|
syntaxOperator: rgb('#93A1B0'), // blue grey
|
|
104
106
|
syntaxPunctuation: rgb('#7A8694'), // dim blue grey
|
|
105
|
-
syntaxConstant: rgb('#
|
|
107
|
+
syntaxConstant: rgb('#E48A9B'), // soft rose
|
|
106
108
|
red_FOR_SUBAGENTS_ONLY: rgb('#D4685E'),
|
|
107
109
|
blue_FOR_SUBAGENTS_ONLY: rgb('#7496D6'),
|
|
108
110
|
green_FOR_SUBAGENTS_ONLY: rgb('#66B285'),
|
|
@@ -115,8 +117,8 @@ const darkTheme = {
|
|
|
115
117
|
chromeYellow: rgb('#D8B270'),
|
|
116
118
|
clawd_body: rgb('#D98A63'), // Warm mascot orange
|
|
117
119
|
clawd_background: rgb('#000000'),
|
|
118
|
-
userMessageBackground:
|
|
119
|
-
userMessageBackgroundHover: rgb('#
|
|
120
|
+
userMessageBackground: '', // user turn: no fill, gold bold text only (Kimi style)
|
|
121
|
+
userMessageBackgroundHover: rgb('#3B5BDB'), // hover/expand: blue block with gold text
|
|
120
122
|
messageActionsBackground: rgb('#2E333D'),
|
|
121
123
|
selectionBg: rgb('#3B4A66'), // Mist-blue tint on dark
|
|
122
124
|
bashMessageBackgroundColor: rgb('#2C3038'),
|
|
@@ -125,7 +127,7 @@ const darkTheme = {
|
|
|
125
127
|
rate_limit_empty: rgb('#3C414B'),
|
|
126
128
|
fastMode: rgb('#E09A58'),
|
|
127
129
|
fastModeShimmer: rgb('#EAB478'),
|
|
128
|
-
briefLabelYou: rgb('#
|
|
130
|
+
briefLabelYou: rgb('#FFDF80'),
|
|
129
131
|
briefLabelClaude: rgb('#7DA1DE'),
|
|
130
132
|
rainbow_red: rgb('#D98F8A'),
|
|
131
133
|
rainbow_orange: rgb('#D9A97E'),
|
|
@@ -152,6 +154,8 @@ const lightTheme = {
|
|
|
152
154
|
autoAccept: rgb('#9B86B8'), // Muted violet (from surface-alt pink-mist)
|
|
153
155
|
bashBorder: rgb('#C07A93'), // Muted rose (from surface-alt pink-mist)
|
|
154
156
|
claude: rgb('#3F6CC4'), // Primary Blue — brand
|
|
157
|
+
toolNameMutate: rgb('#8A6A00'), // deep gold - Edit/Write (warm accent)
|
|
158
|
+
toolNameExec: rgb('#0F7A8A'), // deep cyan - Bash/exec tools
|
|
155
159
|
claudeShimmer: rgb('#5E88CC'), // Accent Blue for shimmer effect
|
|
156
160
|
claudeBlue_FOR_SYSTEM_SPINNER: rgb('#3F6CC4'),
|
|
157
161
|
claudeBlueShimmer_FOR_SYSTEM_SPINNER: rgb('#5E88CC'),
|
|
@@ -187,16 +191,16 @@ const lightTheme = {
|
|
|
187
191
|
toolDotWrite: rgb('#7A5CA8'),
|
|
188
192
|
toolDotWeb: rgb('#4A63A8'),
|
|
189
193
|
toolDotTask: rgb('#B04A5A'),
|
|
190
|
-
syntaxKeyword: rgb('#
|
|
191
|
-
syntaxString: rgb('#
|
|
194
|
+
syntaxKeyword: rgb('#2557C7'),
|
|
195
|
+
syntaxString: rgb('#8A6A00'),
|
|
192
196
|
syntaxComment: rgb('#8A8F98'),
|
|
193
|
-
syntaxNumber: rgb('#
|
|
194
|
-
syntaxFunction: rgb('#
|
|
195
|
-
syntaxType: rgb('#
|
|
197
|
+
syntaxNumber: rgb('#B25E1E'),
|
|
198
|
+
syntaxFunction: rgb('#0F7A8A'),
|
|
199
|
+
syntaxType: rgb('#8A3FC7'),
|
|
196
200
|
syntaxVariable: rgb('#343945'),
|
|
197
201
|
syntaxOperator: rgb('#5B6672'),
|
|
198
202
|
syntaxPunctuation: rgb('#9AA0A8'),
|
|
199
|
-
syntaxConstant: rgb('#
|
|
203
|
+
syntaxConstant: rgb('#C2186B'),
|
|
200
204
|
red_FOR_SUBAGENTS_ONLY: rgb('#BE5A52'),
|
|
201
205
|
blue_FOR_SUBAGENTS_ONLY: rgb('#3F6CC4'),
|
|
202
206
|
green_FOR_SUBAGENTS_ONLY: rgb('#4E9675'),
|
|
@@ -209,8 +213,8 @@ const lightTheme = {
|
|
|
209
213
|
chromeYellow: rgb('#C99A3F'),
|
|
210
214
|
clawd_body: rgb('#D98A63'), // Warm mascot orange
|
|
211
215
|
clawd_background: rgb('#F6F3ED'),
|
|
212
|
-
userMessageBackground:
|
|
213
|
-
userMessageBackgroundHover: rgb('#
|
|
216
|
+
userMessageBackground: '', // user turn: no fill in light mode, gold text only
|
|
217
|
+
userMessageBackgroundHover: rgb('#DCE4FB'), // subtle blue tint on hover/expand
|
|
214
218
|
messageActionsBackground: rgb('#E4D9E5'),
|
|
215
219
|
selectionBg: rgb('#D5DEF2'), // Mist-blue tint on warm white
|
|
216
220
|
bashMessageBackgroundColor: rgb('#EAE1D3'),
|
|
@@ -219,7 +223,7 @@ const lightTheme = {
|
|
|
219
223
|
rate_limit_empty: rgb('#DDD5C7'),
|
|
220
224
|
fastMode: rgb('#D98E4A'),
|
|
221
225
|
fastModeShimmer: rgb('#E2A465'),
|
|
222
|
-
briefLabelYou: rgb('#
|
|
226
|
+
briefLabelYou: rgb('#A67600'),
|
|
223
227
|
briefLabelClaude: rgb('#3F6CC4'),
|
|
224
228
|
rainbow_red: rgb('#D98888'),
|
|
225
229
|
rainbow_orange: rgb('#D9A276'),
|
|
@@ -248,6 +252,8 @@ const darkAnsiTheme = {
|
|
|
248
252
|
autoAccept: 'ansi:magentaBright',
|
|
249
253
|
bashBorder: 'ansi:magentaBright',
|
|
250
254
|
claude: 'ansi:blueBright',
|
|
255
|
+
toolNameMutate: 'ansi:yellowBright',
|
|
256
|
+
toolNameExec: 'ansi:cyanBright',
|
|
251
257
|
claudeShimmer: 'ansi:blueBright',
|
|
252
258
|
claudeBlue_FOR_SYSTEM_SPINNER: 'ansi:blueBright',
|
|
253
259
|
claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'ansi:blueBright',
|
|
@@ -305,8 +311,8 @@ const darkAnsiTheme = {
|
|
|
305
311
|
chromeYellow: 'ansi:yellowBright',
|
|
306
312
|
clawd_body: 'ansi:redBright',
|
|
307
313
|
clawd_background: 'ansi:black',
|
|
308
|
-
userMessageBackground: '
|
|
309
|
-
userMessageBackgroundHover: 'ansi:
|
|
314
|
+
userMessageBackground: '',
|
|
315
|
+
userMessageBackgroundHover: 'ansi:blue',
|
|
310
316
|
messageActionsBackground: 'ansi:blackBright',
|
|
311
317
|
selectionBg: 'ansi:blue',
|
|
312
318
|
bashMessageBackgroundColor: 'ansi:black',
|
|
@@ -315,7 +321,7 @@ const darkAnsiTheme = {
|
|
|
315
321
|
rate_limit_empty: 'ansi:white',
|
|
316
322
|
fastMode: 'ansi:redBright',
|
|
317
323
|
fastModeShimmer: 'ansi:redBright',
|
|
318
|
-
briefLabelYou: 'ansi:
|
|
324
|
+
briefLabelYou: 'ansi:yellowBright',
|
|
319
325
|
briefLabelClaude: 'ansi:blueBright',
|
|
320
326
|
rainbow_red: 'ansi:red',
|
|
321
327
|
rainbow_orange: 'ansi:redBright',
|
|
@@ -363,6 +369,30 @@ export function getTheme(themeName) {
|
|
|
363
369
|
* (markdown inline code) resolves user themes through getActiveTheme().
|
|
364
370
|
*/
|
|
365
371
|
let customThemeResolver;
|
|
372
|
+
/**
|
|
373
|
+
* Whether the active theme's RESOLVED palette renders on a light background.
|
|
374
|
+
* Keyed off the resolved palette's IDENTITY for the built-ins (auto resolves
|
|
375
|
+
* to the shared light/dark instance, so this covers auto-with-light-terminal
|
|
376
|
+
* that theme-NAME comparisons miss) and off the ink-text luminance for
|
|
377
|
+
* custom themes (light palettes pair with dark ink). The palette's
|
|
378
|
+
* `background` field is a badge fill, not the terminal background — never a
|
|
379
|
+
* lightness signal. Colour-pair variants (effort ignition hues) consume this.
|
|
380
|
+
*/
|
|
381
|
+
export function isLightThemeActive(themeName) {
|
|
382
|
+
const theme = getTheme(themeName);
|
|
383
|
+
if (theme === lightTheme)
|
|
384
|
+
return true;
|
|
385
|
+
if (theme === darkTheme || theme === darkAnsiTheme)
|
|
386
|
+
return false;
|
|
387
|
+
// 自定义主题:按文本墨色亮度判定——浅底配深墨(ink)、深底配亮墨。
|
|
388
|
+
// 调色板的 background 字段是徽标填充色而非终端背景,不能作判据。
|
|
389
|
+
const ink = theme.text;
|
|
390
|
+
const rgb = /^rgb\((\d+),(\d+),(\d+)\)$/.exec(ink);
|
|
391
|
+
if (rgb === null)
|
|
392
|
+
return false;
|
|
393
|
+
const [r, g, b] = [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];
|
|
394
|
+
return 0.299 * r + 0.587 * g + 0.114 * b < 140;
|
|
395
|
+
}
|
|
366
396
|
/**
|
|
367
397
|
* Register the custom-theme resolver. Called once by ThemeProvider; the
|
|
368
398
|
* resolver must return `undefined` for names it does not know so getTheme
|