@deepseek-harness-tui/dsh-tui 0.7.2 → 0.8.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 +3 -3
- package/bin/dsh-tui.js +24 -3
- package/cordis.patch.yml +24 -11
- package/cordis.yml +9 -1
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +2 -1
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +6 -1
- package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
- package/lib/types/components/HistorySearchDialog.js +5 -1
- package/lib/types/components/MessageList.d.ts +3 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +9 -5
- package/lib/types/components/PluginSceneBoundary.d.ts +31 -0
- package/lib/types/components/PluginSceneBoundary.d.ts.map +1 -0
- package/lib/types/components/PluginSceneBoundary.js +29 -0
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +52 -74
- package/lib/types/components/SearchBox.d.ts +4 -0
- package/lib/types/components/SearchBox.d.ts.map +1 -1
- package/lib/types/components/SearchBox.js +101 -2
- package/lib/types/components/SkillsPicker.d.ts +18 -0
- package/lib/types/components/SkillsPicker.d.ts.map +1 -0
- package/lib/types/components/SkillsPicker.js +50 -0
- package/lib/types/components/Spinner/SpinnerAnimationRow.d.ts +4 -1
- package/lib/types/components/Spinner/SpinnerAnimationRow.d.ts.map +1 -1
- package/lib/types/components/Spinner/SpinnerAnimationRow.js +10 -5
- package/lib/types/components/SplitDiffView.d.ts +28 -0
- package/lib/types/components/SplitDiffView.d.ts.map +1 -0
- package/lib/types/components/SplitDiffView.js +417 -0
- package/lib/types/components/WorkingSpinner.d.ts +3 -1
- package/lib/types/components/WorkingSpinner.d.ts.map +1 -1
- package/lib/types/components/WorkingSpinner.js +2 -2
- package/lib/types/components/design-system/ThemedText.d.ts +7 -1
- package/lib/types/components/design-system/ThemedText.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemedText.js +2 -2
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +3 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +17 -7
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +52 -8
- package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
- package/lib/types/components/questions/PlanReviewPanel.js +12 -3
- package/lib/types/dsh-adapter/channel.d.ts +78 -0
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +165 -14
- package/lib/types/dsh-adapter/contract.d.ts +1 -1
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +1 -0
- package/lib/types/dsh-adapter/index.d.ts +4 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +1 -0
- package/lib/types/dsh-adapter/packaged-presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/packaged-presets.js +5 -2
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +66 -3
- package/lib/types/dsh-adapter/promptDebug.d.ts +10 -0
- package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -0
- package/lib/types/dsh-adapter/promptDebug.js +148 -0
- package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/providerWizard.js +3 -1
- package/lib/types/dsh-adapter/scenes.d.ts +75 -0
- package/lib/types/dsh-adapter/scenes.d.ts.map +1 -0
- package/lib/types/dsh-adapter/scenes.js +78 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts +116 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -0
- package/lib/types/dsh-adapter/settings-sections.js +63 -0
- package/lib/types/dsh-adapter/settingsEditor.d.ts +128 -0
- package/lib/types/dsh-adapter/settingsEditor.d.ts.map +1 -0
- package/lib/types/dsh-adapter/settingsEditor.js +244 -0
- package/lib/types/i18n.d.ts +169 -18
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +45 -6
- package/lib/types/ink/components/Text.d.ts +9 -1
- package/lib/types/ink/components/Text.d.ts.map +1 -1
- package/lib/types/ink/components/Text.js +7 -6
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +4 -2
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +76 -9
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +4 -1
- package/lib/types/ink/terminal.d.ts +40 -4
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +57 -5
- package/lib/types/ink/termio/tokenize.d.ts +6 -0
- package/lib/types/ink/termio/tokenize.d.ts.map +1 -1
- package/lib/types/ink/termio/tokenize.js +18 -4
- package/lib/types/jsx-runtime.d.ts +2 -0
- package/lib/types/jsx-runtime.d.ts.map +1 -0
- package/lib/types/jsx-runtime.js +13 -0
- package/lib/types/modelRoute.d.ts +10 -2
- package/lib/types/modelRoute.d.ts.map +1 -1
- package/lib/types/modelRoute.js +33 -4
- package/lib/types/scenes.d.ts +3 -0
- package/lib/types/scenes.d.ts.map +1 -0
- package/lib/types/scenes.js +4 -0
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +182 -26
- package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
- package/lib/types/screens/SessionBrowser.js +30 -15
- package/lib/types/screens/Settings.d.ts +20 -0
- package/lib/types/screens/Settings.d.ts.map +1 -0
- package/lib/types/screens/Settings.js +333 -0
- package/lib/types/screens/StatusLine.js +1 -1
- package/lib/types/sessions/view.d.ts.map +1 -1
- package/lib/types/sessions/view.js +13 -1
- package/lib/types/settings-sections.d.ts +3 -0
- package/lib/types/settings-sections.d.ts.map +1 -0
- package/lib/types/settings-sections.js +4 -0
- package/lib/types/theme.d.ts +12 -0
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +36 -0
- package/lib/types/update.d.ts +21 -7
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +66 -16
- package/lib/types/utils/paths.d.ts.map +1 -1
- package/lib/types/utils/paths.js +4 -1
- package/package.json +49 -9
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text, useInput, useTerminalSize } from '../ui.js';
|
|
4
|
+
import { Divider } from '../components/design-system/Divider.js';
|
|
5
|
+
import { HintLine } from '../components/design-system/HintLine.js';
|
|
6
|
+
import { isMod, isPlainReturn } from '../utils/modifiers.js';
|
|
7
|
+
import { truncateWidth } from '../sessions/format.js';
|
|
8
|
+
import { getLang, t } from '../i18n.js';
|
|
9
|
+
import { SettingsForm } from '../dsh-adapter/settingsEditor.js';
|
|
10
|
+
/** Pick the provider-owned translation for the active language. */
|
|
11
|
+
function pick(text, descriptions) {
|
|
12
|
+
return descriptions?.[getLang()] ?? text;
|
|
13
|
+
}
|
|
14
|
+
/** Compact one-line preview of a read-only namespace's resolved value. */
|
|
15
|
+
function valuePreview(value, budget) {
|
|
16
|
+
let raw;
|
|
17
|
+
try {
|
|
18
|
+
raw = JSON.stringify(value) ?? 'undefined';
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
raw = String(value);
|
|
22
|
+
}
|
|
23
|
+
return truncateWidth(raw, Math.max(8, budget));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The settings screen — `/settings` as a screen of its own (issue #165).
|
|
27
|
+
*
|
|
28
|
+
* The TUI owns only presentation here: plugin-declared sections from the
|
|
29
|
+
* `tuiSettingsSections` seam render as editable forms; every write goes back
|
|
30
|
+
* through the dsh settings service (revision-fenced `mutate` path ops) or the
|
|
31
|
+
* credentials seam (secret fields, blank-until-typed). Namespaces no plugin
|
|
32
|
+
* declared a section for stay read-only with a YAML hint — the same fallback
|
|
33
|
+
* the web front door gives namespaces without a card.
|
|
34
|
+
*
|
|
35
|
+
* Edits are staged, never settled live: typing changes a draft, and only the
|
|
36
|
+
* explicit save writes the durable document (see settingsEditor.ts for why).
|
|
37
|
+
*/
|
|
38
|
+
export function Settings({ channel, onClose, }) {
|
|
39
|
+
// Explicit terminal size (not flexGrow) — the same rule SessionBrowser's
|
|
40
|
+
// root follows inside the alternate screen's fixed-height box.
|
|
41
|
+
const { columns, rows } = useTerminalSize();
|
|
42
|
+
// channel caches the host — a fresh object per call would re-fire the
|
|
43
|
+
// host-keyed effects below on every render (an endless render loop).
|
|
44
|
+
const host = channel.settingsHost();
|
|
45
|
+
const [namespaces, setNamespaces] = React.useState(() => host?.listNamespaces() ?? []);
|
|
46
|
+
const [sections, setSections] = React.useState(() => channel.settingsSections());
|
|
47
|
+
const [mode, setMode] = React.useState('list');
|
|
48
|
+
const [editing, setEditing] = React.useState(null);
|
|
49
|
+
const [focusIndex, setFocusIndex] = React.useState(0);
|
|
50
|
+
const [notice, setNotice] = React.useState(undefined);
|
|
51
|
+
/** Configured status of every secret field's credential ref. */
|
|
52
|
+
const [secrets, setSecrets] = React.useState(new Map());
|
|
53
|
+
/** First line of the windowed entry list (focus-follow scrolling). */
|
|
54
|
+
const [windowStart, setWindowStart] = React.useState(0);
|
|
55
|
+
/** Repaint after a form mutation — staged drafts live in the (React-free)
|
|
56
|
+
* SettingsForm, so editing one changes no React state by itself. */
|
|
57
|
+
const [, bump] = React.useReducer((count) => count + 1, 0);
|
|
58
|
+
/** Async save completions must not touch state after the screen closes. */
|
|
59
|
+
const mountedRef = React.useRef(true);
|
|
60
|
+
React.useEffect(() => () => {
|
|
61
|
+
mountedRef.current = false;
|
|
62
|
+
}, []);
|
|
63
|
+
React.useEffect(() => channel.subscribeSettingsSections(() => {
|
|
64
|
+
setSections(channel.settingsSections());
|
|
65
|
+
}), [channel]);
|
|
66
|
+
// One form per section namespace. A fresh namespace view replaces the form
|
|
67
|
+
// only while it holds no edits — replacing a dirty form would discard the
|
|
68
|
+
// drafts the user is still typing.
|
|
69
|
+
const formsRef = React.useRef(new Map());
|
|
70
|
+
const forms = new Map();
|
|
71
|
+
if (host !== undefined) {
|
|
72
|
+
for (const section of sections) {
|
|
73
|
+
const view = namespaces.find(entry => entry.ns === section.ns);
|
|
74
|
+
const kept = formsRef.current.get(section.ns);
|
|
75
|
+
const reuse = kept !== undefined && (kept.namespace === view || kept.shell().dirty);
|
|
76
|
+
const form = reuse ? kept : new SettingsForm(host, view, section.fields);
|
|
77
|
+
forms.set(section.ns, form);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
formsRef.current = forms;
|
|
81
|
+
const refresh = () => {
|
|
82
|
+
setNamespaces(host?.listNamespaces() ?? []);
|
|
83
|
+
};
|
|
84
|
+
// Secret fields report only configured/unconfigured; resolve each ref once
|
|
85
|
+
// per section-list change (and after every save, which may have set one).
|
|
86
|
+
const [secretProbe, setSecretProbe] = React.useState(0);
|
|
87
|
+
React.useEffect(() => {
|
|
88
|
+
if (host === undefined)
|
|
89
|
+
return;
|
|
90
|
+
let stale = false;
|
|
91
|
+
const pending = sections.flatMap(section => section.fields
|
|
92
|
+
.filter((field) => field.secret !== undefined)
|
|
93
|
+
.map(async (field) => [`${section.ns}:${field.path.join('.')}`, await host.credentialConfigured(field.secret.ref)]));
|
|
94
|
+
void Promise.all(pending).then(entries => {
|
|
95
|
+
if (!stale && mountedRef.current)
|
|
96
|
+
setSecrets(new Map(entries));
|
|
97
|
+
});
|
|
98
|
+
return () => {
|
|
99
|
+
stale = true;
|
|
100
|
+
};
|
|
101
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
|
+
}, [host, sections, secretProbe]);
|
|
103
|
+
/** Focusable rows in display order: every field of every section. */
|
|
104
|
+
const focusable = sections.flatMap(section => section.fields.map(field => ({ ns: section.ns, field })));
|
|
105
|
+
const effFocus = Math.min(focusIndex, Math.max(0, focusable.length - 1));
|
|
106
|
+
const focused = focusable.length === 0 ? undefined : focusable[effFocus];
|
|
107
|
+
const focusedForm = focused === undefined ? undefined : forms.get(focused.ns);
|
|
108
|
+
const commitSave = (ns) => {
|
|
109
|
+
const form = forms.get(ns);
|
|
110
|
+
if (form === undefined || form.saving || !form.shell().dirty)
|
|
111
|
+
return;
|
|
112
|
+
void form.save().then(ok => {
|
|
113
|
+
if (!mountedRef.current)
|
|
114
|
+
return;
|
|
115
|
+
if (ok) {
|
|
116
|
+
setNotice({ text: t('settings-saved', { ns }), tone: 'success' });
|
|
117
|
+
refresh();
|
|
118
|
+
setSecretProbe(count => count + 1);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
setNotice({ text: t('settings-save-failed', { ns }), tone: 'error' });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
/** Stage the next choice for a boolean/select field (Enter cycles). */
|
|
126
|
+
const cycleField = (ns, field) => {
|
|
127
|
+
const form = forms.get(ns);
|
|
128
|
+
if (form === undefined || !form.available || form.saving)
|
|
129
|
+
return;
|
|
130
|
+
const current = form.field(field).text;
|
|
131
|
+
if (field.kind === 'boolean') {
|
|
132
|
+
form.edit(field, current === 'true' ? 'false' : 'true');
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const options = field.options ?? [];
|
|
136
|
+
if (options.length === 0)
|
|
137
|
+
return;
|
|
138
|
+
const index = options.findIndex(option => option.value === current);
|
|
139
|
+
form.edit(field, options[(index + 1) % options.length]?.value ?? options[0]?.value ?? '');
|
|
140
|
+
}
|
|
141
|
+
setNotice(undefined);
|
|
142
|
+
bump();
|
|
143
|
+
};
|
|
144
|
+
useInput((input, key) => {
|
|
145
|
+
if (mode === 'edit' && editing !== null) {
|
|
146
|
+
if (isPlainReturn(key)) {
|
|
147
|
+
const form = forms.get(editing.ns);
|
|
148
|
+
form?.edit(editing.field, editing.draft);
|
|
149
|
+
bump();
|
|
150
|
+
setMode('list');
|
|
151
|
+
setEditing(null);
|
|
152
|
+
}
|
|
153
|
+
else if (key.escape) {
|
|
154
|
+
setMode('list');
|
|
155
|
+
setEditing(null);
|
|
156
|
+
}
|
|
157
|
+
else if (key.backspace || key.delete) {
|
|
158
|
+
setEditing(state => state === null ? null : { ...state, draft: state.draft.slice(0, -1) });
|
|
159
|
+
}
|
|
160
|
+
else if (!isMod(key) && !key.meta && !key.super && input && !key.return) {
|
|
161
|
+
// Only real characters reach the draft (see SessionBrowser's query).
|
|
162
|
+
const typed = input.replace(/\p{Cc}/gu, '');
|
|
163
|
+
if (typed.length > 0) {
|
|
164
|
+
setEditing(state => state === null ? null : { ...state, draft: state.draft + typed });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (key.upArrow) {
|
|
170
|
+
setFocusIndex(Math.max(0, effFocus - 1));
|
|
171
|
+
}
|
|
172
|
+
else if (key.downArrow) {
|
|
173
|
+
setFocusIndex(Math.min(Math.max(0, focusable.length - 1), effFocus + 1));
|
|
174
|
+
}
|
|
175
|
+
else if (isPlainReturn(key) && focused !== undefined) {
|
|
176
|
+
// A save in flight owns the section's drafts; starting an edit mid-write
|
|
177
|
+
// is exactly the lost-draft race the staged model exists to prevent.
|
|
178
|
+
if (focusedForm === undefined || !focusedForm.available || focusedForm.saving)
|
|
179
|
+
return;
|
|
180
|
+
if (focused.field.kind === 'boolean' || focused.field.kind === 'select') {
|
|
181
|
+
cycleField(focused.ns, focused.field);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
setEditing({ ns: focused.ns, field: focused.field, draft: focusedForm.field(focused.field).text });
|
|
185
|
+
setMode('edit');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else if (input === 's' && focused !== undefined) {
|
|
189
|
+
commitSave(focused.ns);
|
|
190
|
+
}
|
|
191
|
+
else if (input === 'd' && focused !== undefined) {
|
|
192
|
+
if (focusedForm?.saving)
|
|
193
|
+
return;
|
|
194
|
+
focusedForm?.discard();
|
|
195
|
+
setNotice(undefined);
|
|
196
|
+
bump();
|
|
197
|
+
}
|
|
198
|
+
else if (key.escape) {
|
|
199
|
+
// Esc backs out one layer at a time: staged drafts first — ANY dirty
|
|
200
|
+
// section, not just the focused one, so leaving never silently drops
|
|
201
|
+
// an edit made two sections ago — the screen second. A save in flight
|
|
202
|
+
// cannot be undone from here; let it settle instead of discarding
|
|
203
|
+
// around it.
|
|
204
|
+
const dirty = [...forms.values()].filter(form => form.shell().dirty);
|
|
205
|
+
if (dirty.length > 0) {
|
|
206
|
+
if (dirty.some(form => form.saving))
|
|
207
|
+
return;
|
|
208
|
+
for (const form of dirty)
|
|
209
|
+
form.discard();
|
|
210
|
+
setNotice({ text: t('settings-discarded'), tone: 'success' });
|
|
211
|
+
bump();
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
onClose();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
const renderField = (section, field) => {
|
|
219
|
+
const ns = section.ns;
|
|
220
|
+
const form = forms.get(ns);
|
|
221
|
+
const state = form?.field(field) ?? { text: '', overridden: false, invalid: false };
|
|
222
|
+
const isFocused = focused !== undefined && focused.ns === ns && focused.field === field;
|
|
223
|
+
const isEditing = isFocused && mode === 'edit' && editing !== null;
|
|
224
|
+
const label = pick(field.label, field.descriptions);
|
|
225
|
+
const hint = field.hint !== undefined ? pick(field.hint, field.hintDescriptions) : undefined;
|
|
226
|
+
let value;
|
|
227
|
+
if (field.secret !== undefined) {
|
|
228
|
+
const configured = secrets.get(`${ns}:${field.path.join('.')}`) === true;
|
|
229
|
+
if (isEditing) {
|
|
230
|
+
value = '•'.repeat(editing?.draft.length ?? 0) + '▌';
|
|
231
|
+
}
|
|
232
|
+
else if (state.text !== '') {
|
|
233
|
+
value = `${'•'.repeat(state.text.length)} ${t('settings-secret-staged')}`;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
value = configured ? t('settings-secret-set') : t('settings-secret-unset');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else if (isEditing) {
|
|
240
|
+
value = `${editing?.draft ?? ''}▌`;
|
|
241
|
+
}
|
|
242
|
+
else if (state.text === '') {
|
|
243
|
+
value = t('settings-field-empty');
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
value = state.text;
|
|
247
|
+
}
|
|
248
|
+
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
|
+
};
|
|
250
|
+
// ── Layout: a flat entry list with accounted line heights, windowed so the
|
|
251
|
+
// focused field is always on screen no matter how long the list gets. ────
|
|
252
|
+
const entries = [];
|
|
253
|
+
let focusCursor = 0;
|
|
254
|
+
sections.forEach((section, sectionIndex) => {
|
|
255
|
+
const form = forms.get(section.ns);
|
|
256
|
+
const view = form?.namespace;
|
|
257
|
+
const shell = form?.shell();
|
|
258
|
+
entries.push({
|
|
259
|
+
key: `section:${section.ns}`,
|
|
260
|
+
lines: sectionIndex === 0 ? 1 : 2,
|
|
261
|
+
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'), "]"] })] })] })),
|
|
262
|
+
});
|
|
263
|
+
for (const field of section.fields) {
|
|
264
|
+
const isFocused = focused !== undefined && focused.ns === section.ns && focused.field === field;
|
|
265
|
+
const hasHint = field.hint !== undefined && isFocused;
|
|
266
|
+
const index = focusCursor;
|
|
267
|
+
focusCursor += 1;
|
|
268
|
+
entries.push({
|
|
269
|
+
key: `field:${section.ns}:${field.path.join('.')}`,
|
|
270
|
+
lines: hasHint ? 2 : 1,
|
|
271
|
+
focus: index,
|
|
272
|
+
node: renderField(section, field),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
const registeredNs = new Set(sections.map(section => section.ns));
|
|
277
|
+
const readonlyNamespaces = namespaces.filter(entry => !registeredNs.has(entry.ns));
|
|
278
|
+
if (readonlyNamespaces.length > 0) {
|
|
279
|
+
entries.push({
|
|
280
|
+
key: 'readonly:heading',
|
|
281
|
+
lines: 2,
|
|
282
|
+
node: (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: " " }), _jsx(Text, { bold: true, dimColor: true, children: t('settings-readonly-heading') })] })),
|
|
283
|
+
});
|
|
284
|
+
for (const entry of readonlyNamespaces) {
|
|
285
|
+
entries.push({
|
|
286
|
+
key: `readonly:${entry.ns}`,
|
|
287
|
+
lines: 1,
|
|
288
|
+
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)] })] })),
|
|
289
|
+
});
|
|
290
|
+
}
|
|
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
|
+
}
|
|
304
|
+
// Focus-follow window: keep the focused entry fully inside the viewport.
|
|
305
|
+
let totalLines = 0;
|
|
306
|
+
let focusedOffset = 0;
|
|
307
|
+
let focusedLines = 1;
|
|
308
|
+
for (const entry of entries) {
|
|
309
|
+
if (entry.focus === effFocus) {
|
|
310
|
+
focusedOffset = totalLines;
|
|
311
|
+
focusedLines = entry.lines;
|
|
312
|
+
}
|
|
313
|
+
totalLines += entry.lines;
|
|
314
|
+
}
|
|
315
|
+
// Chrome: title row, top rule, bottom rule, hint row, plus the notice.
|
|
316
|
+
const viewport = Math.max(1, rows - 4 - (notice === undefined ? 0 : 1));
|
|
317
|
+
React.useEffect(() => {
|
|
318
|
+
setWindowStart(start => {
|
|
319
|
+
if (focusedOffset < start)
|
|
320
|
+
return focusedOffset;
|
|
321
|
+
if (focusedOffset + focusedLines > start + viewport)
|
|
322
|
+
return focusedOffset + focusedLines - viewport;
|
|
323
|
+
return start;
|
|
324
|
+
});
|
|
325
|
+
}, [focusedOffset, focusedLines, viewport]);
|
|
326
|
+
let entryOffset = 0;
|
|
327
|
+
const visible = entries.filter(entry => {
|
|
328
|
+
const start = entryOffset;
|
|
329
|
+
entryOffset += entry.lines;
|
|
330
|
+
return start >= windowStart && start + entry.lines <= windowStart + viewport;
|
|
331
|
+
});
|
|
332
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: t('settings-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') : t('settings-hint-list') }) })] }));
|
|
333
|
+
}
|
|
@@ -105,7 +105,7 @@ export function StatusLine({ channel, selectionActive = false, helpOpen = false,
|
|
|
105
105
|
if (channel.contextBarEnabled && barWidth >= 14 && channel.contextWindow !== undefined) {
|
|
106
106
|
bar = renderContextBar(channel.contextSegments, usage !== undefined ? usage.input + usage.cacheRead + usage.cacheWrite : 0, channel.contextWindow, barWidth, barColors);
|
|
107
107
|
}
|
|
108
|
-
return (_jsx(Box, { paddingX:
|
|
108
|
+
return (_jsx(Box, { paddingX: 1, width: columns, flexShrink: 0, children: _jsxs(Box, { flexDirection: "column", width: "100%", children: [bar ? _jsx(Text, { children: bar }) : null, _jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Text, { wrap: "truncate", children: _jsx(Byline, { children: leftParts }) }), _jsx(Box, { justifyContent: "flex-end", flexShrink: 2, children: _jsx(Text, { wrap: "truncate", children: _jsx(Byline, { children: rightParts }) }) })] }), _jsxs(Box, { height: 1, overflow: "hidden", flexDirection: "row", justifyContent: "space-between", 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, wake !== undefined ? (_jsx(MiniWake, { band: wake.band, hint: wake.hint, tick: wake.tick })) : null] })] }) }));
|
|
109
109
|
}
|
|
110
110
|
function basename(path) {
|
|
111
111
|
const parts = path.split(/[\\/]/);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/sessions/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAEtE,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAChC;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,EAAE,cAK7B,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAA;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GACtH,WAAW,
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/sessions/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAEtE,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAChC;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,EAAE,cAK7B,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAA;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GACtH,WAAW,CAmGb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAK9F;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAKhG;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAGhG;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEjD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,MAAM,CAoBR;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAU1F"}
|
|
@@ -85,7 +85,19 @@ export function buildView(sessions, filters, context) {
|
|
|
85
85
|
const rows = [];
|
|
86
86
|
let shown = 0;
|
|
87
87
|
let lastProject;
|
|
88
|
-
|
|
88
|
+
const ordered = visible.sort((left, right) => right.updatedAt - left.updatedAt);
|
|
89
|
+
if (filters.allProjects) {
|
|
90
|
+
// Order project groups by their newest visible session, then keep every
|
|
91
|
+
// session from that project together in MRU order. A global MRU sort alone
|
|
92
|
+
// can interleave A/B/A and emit the same project header more than once.
|
|
93
|
+
const projectOrder = new Map();
|
|
94
|
+
for (const session of ordered) {
|
|
95
|
+
if (!projectOrder.has(session.cwd))
|
|
96
|
+
projectOrder.set(session.cwd, projectOrder.size);
|
|
97
|
+
}
|
|
98
|
+
ordered.sort((left, right) => projectOrder.get(left.cwd) - projectOrder.get(right.cwd) || right.updatedAt - left.updatedAt);
|
|
99
|
+
}
|
|
100
|
+
for (const session of ordered) {
|
|
89
101
|
// Group headers only earn their line when more than one project is in
|
|
90
102
|
// play; inside a single project they would repeat the same path forever.
|
|
91
103
|
if (filters.allProjects && session.cwd !== lastProject) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-sections.d.ts","sourceRoot":"","sources":["../../src/settings-sections.ts"],"names":[],"mappings":"AAEA,cAAc,oCAAoC,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAA"}
|
package/lib/types/theme.d.ts
CHANGED
|
@@ -47,6 +47,18 @@ export type Theme = {
|
|
|
47
47
|
diffRemovedDimmed: string;
|
|
48
48
|
diffAddedWord: string;
|
|
49
49
|
diffRemovedWord: string;
|
|
50
|
+
toolCardBackground: string;
|
|
51
|
+
toolCardBackgroundDim: string;
|
|
52
|
+
syntaxKeyword: string;
|
|
53
|
+
syntaxString: string;
|
|
54
|
+
syntaxComment: string;
|
|
55
|
+
syntaxNumber: string;
|
|
56
|
+
syntaxFunction: string;
|
|
57
|
+
syntaxType: string;
|
|
58
|
+
syntaxVariable: string;
|
|
59
|
+
syntaxOperator: string;
|
|
60
|
+
syntaxPunctuation: string;
|
|
61
|
+
syntaxConstant: string;
|
|
50
62
|
red_FOR_SUBAGENTS_ONLY: string;
|
|
51
63
|
blue_FOR_SUBAGENTS_ONLY: string;
|
|
52
64
|
green_FOR_SUBAGENTS_ONLY: string;
|
package/lib/types/theme.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,KAAK,GAAG;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,6BAA6B,EAAE,MAAM,CAAA;IACrC,oCAAoC,EAAE,MAAM,CAAA;IAC5C,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAElB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IAEtB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/theme.ts"],"names":[],"mappings":"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"}
|
package/lib/types/theme.js
CHANGED
|
@@ -86,6 +86,18 @@ const darkTheme = {
|
|
|
86
86
|
diffRemovedDimmed: rgb('#362B2C'),
|
|
87
87
|
diffAddedWord: rgb('#57956B'),
|
|
88
88
|
diffRemovedWord: rgb('#B26671'),
|
|
89
|
+
toolCardBackground: rgb('#242B3A'), // lighter blue-grey card surface
|
|
90
|
+
toolCardBackgroundDim: rgb('#1C2330'), // deeper blue substrate
|
|
91
|
+
syntaxKeyword: rgb('#8FA8E8'), // mist blue
|
|
92
|
+
syntaxString: rgb('#9FBF8F'), // soft sage
|
|
93
|
+
syntaxComment: rgb('#6B7280'), // neutral grey
|
|
94
|
+
syntaxNumber: rgb('#D9A97E'), // warm tan
|
|
95
|
+
syntaxFunction: rgb('#82B8C7'), // cyan blue
|
|
96
|
+
syntaxType: rgb('#B39DDB'), // soft violet
|
|
97
|
+
syntaxVariable: rgb('#C9D1D9'), // near-text
|
|
98
|
+
syntaxOperator: rgb('#93A1B0'), // blue grey
|
|
99
|
+
syntaxPunctuation: rgb('#7A8694'), // dim blue grey
|
|
100
|
+
syntaxConstant: rgb('#D98C9B'), // soft rose
|
|
89
101
|
red_FOR_SUBAGENTS_ONLY: rgb('#D4685E'),
|
|
90
102
|
blue_FOR_SUBAGENTS_ONLY: rgb('#7496D6'),
|
|
91
103
|
green_FOR_SUBAGENTS_ONLY: rgb('#66B285'),
|
|
@@ -163,6 +175,18 @@ const lightTheme = {
|
|
|
163
175
|
diffRemovedDimmed: rgb('#F5E6E4'),
|
|
164
176
|
diffAddedWord: rgb('#A9D3B4'),
|
|
165
177
|
diffRemovedWord: rgb('#E5B3AE'),
|
|
178
|
+
toolCardBackground: rgb('#E9EFF9'), // cool light blue card
|
|
179
|
+
toolCardBackgroundDim: rgb('#DEE7F4'), // deeper blue-tinted substrate
|
|
180
|
+
syntaxKeyword: rgb('#4A63A8'),
|
|
181
|
+
syntaxString: rgb('#4E7A4E'),
|
|
182
|
+
syntaxComment: rgb('#8A8F98'),
|
|
183
|
+
syntaxNumber: rgb('#A96B32'),
|
|
184
|
+
syntaxFunction: rgb('#3F7E8F'),
|
|
185
|
+
syntaxType: rgb('#7A5CA8'),
|
|
186
|
+
syntaxVariable: rgb('#343945'),
|
|
187
|
+
syntaxOperator: rgb('#5B6672'),
|
|
188
|
+
syntaxPunctuation: rgb('#9AA0A8'),
|
|
189
|
+
syntaxConstant: rgb('#B04A5A'),
|
|
166
190
|
red_FOR_SUBAGENTS_ONLY: rgb('#BE5A52'),
|
|
167
191
|
blue_FOR_SUBAGENTS_ONLY: rgb('#3F6CC4'),
|
|
168
192
|
green_FOR_SUBAGENTS_ONLY: rgb('#4E9675'),
|
|
@@ -242,6 +266,18 @@ const darkAnsiTheme = {
|
|
|
242
266
|
diffRemovedDimmed: 'ansi:red',
|
|
243
267
|
diffAddedWord: 'ansi:greenBright',
|
|
244
268
|
diffRemovedWord: 'ansi:redBright',
|
|
269
|
+
toolCardBackground: 'ansi:blackBright',
|
|
270
|
+
toolCardBackgroundDim: 'ansi:black',
|
|
271
|
+
syntaxKeyword: 'ansi:blueBright',
|
|
272
|
+
syntaxString: 'ansi:greenBright',
|
|
273
|
+
syntaxComment: 'ansi:blackBright',
|
|
274
|
+
syntaxNumber: 'ansi:yellowBright',
|
|
275
|
+
syntaxFunction: 'ansi:cyanBright',
|
|
276
|
+
syntaxType: 'ansi:magentaBright',
|
|
277
|
+
syntaxVariable: 'ansi:white',
|
|
278
|
+
syntaxOperator: 'ansi:white',
|
|
279
|
+
syntaxPunctuation: 'ansi:blackBright',
|
|
280
|
+
syntaxConstant: 'ansi:redBright',
|
|
245
281
|
red_FOR_SUBAGENTS_ONLY: 'ansi:redBright',
|
|
246
282
|
blue_FOR_SUBAGENTS_ONLY: 'ansi:blueBright',
|
|
247
283
|
green_FOR_SUBAGENTS_ONLY: 'ansi:greenBright',
|
package/lib/types/update.d.ts
CHANGED
|
@@ -55,22 +55,36 @@ export declare function resolveTuiUpdateTarget(): Promise<TuiUpdateTarget>;
|
|
|
55
55
|
* or blocks the interactive TUI.
|
|
56
56
|
*/
|
|
57
57
|
export declare function checkForTuiUpdate(): Promise<TuiUpdateInfo | undefined>;
|
|
58
|
+
/** Build the profile-manager command, preferring a preflight-pinned version. */
|
|
59
|
+
export declare function tuiUpdatePluginArgs(profile: string, targetVersion?: string): string[];
|
|
60
|
+
/**
|
|
61
|
+
* The pnpm Windows tmp-rename race signature (issue #225): pnpm swaps a
|
|
62
|
+
* package directory via a `<name>_tmp_<pid>` staging dir, and a file lock or
|
|
63
|
+
* AV scan makes the scandir/rename fail with ENOENT/EPERM/EBUSY. The failure
|
|
64
|
+
* is transient — the identical command succeeds on retry — but the crashed
|
|
65
|
+
* run leaves a half-updated profile (manifest pins the old version while the
|
|
66
|
+
* lockfile already carries the new snapshot), which presents as "update did
|
|
67
|
+
* nothing" (#209). Genuine resolution errors never carry the `_tmp_<pid>`
|
|
68
|
+
* token, so matching both keeps the retry from masking real failures.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isTransientUpdateFailure(stderr: string): boolean;
|
|
58
71
|
/**
|
|
59
72
|
* Update the installed dsh-tui package and restart the same launcher while
|
|
60
73
|
* preserving the active session. The TUI must already be unmounted before
|
|
61
74
|
* this is called so pnpm output cannot corrupt the rendered terminal frame.
|
|
62
75
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* registry still serving the old `latest`).
|
|
76
|
+
* When the preflight registry check resolved an exact target, pass that
|
|
77
|
+
* version to pnpm instead of resolving `latest` a second time. This avoids a
|
|
78
|
+
* stale mirror/dist-tag response between the check and install. If preflight
|
|
79
|
+
* failed, retain the `--latest` fallback: a plain `pnpm update` stays inside
|
|
80
|
+
* the manifest range and can restart unchanged across minor releases.
|
|
69
81
|
*
|
|
70
82
|
* @param sessionId - Session to resume in the replacement process.
|
|
71
83
|
* @param profile - The dsh profile this TUI was launched with; updating any
|
|
72
84
|
* other profile would leave the running install untouched.
|
|
85
|
+
* @param targetVersion - Exact version returned by the preflight registry
|
|
86
|
+
* check, or undefined when that check failed and pnpm should resolve latest.
|
|
73
87
|
* @returns Exit codes for the update run and the replacement process.
|
|
74
88
|
*/
|
|
75
|
-
export declare function updateTuiAndRestart(sessionId: string, profile: string): Promise<TuiUpdateResult>;
|
|
89
|
+
export declare function updateTuiAndRestart(sessionId: string, profile: string, targetVersion?: string): Promise<TuiUpdateResult>;
|
|
76
90
|
//# sourceMappingURL=update.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/update.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAIlD,OAAO,EAAE,UAAU,EAAE,CAAA;AAQrB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAED,4DAA4D;AAC5D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAiBxD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,MAAM,GAAG,SAAS,CAahG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAW5C;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIzE;AA4BD;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CASvE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAG5E;
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/update.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAIlD,OAAO,EAAE,UAAU,EAAE,CAAA;AAQrB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAED,4DAA4D;AAC5D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAiBxD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,MAAM,GAAG,SAAS,CAahG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAW5C;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIzE;AA4BD;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CASvE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAG5E;AA6DD,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,eAAe,CAAC,CAgD1B"}
|