praxis-agent 0.43.0 → 0.44.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 +48 -47
- package/dist/application/native-session-projection.d.ts +4 -0
- package/dist/application/native-session-projection.js +135 -0
- package/dist/application/session-service.d.ts +0 -1
- package/dist/application/session-service.js +9 -170
- package/dist/application/top-level-agent-manager.d.ts +7 -0
- package/dist/application/top-level-agent-manager.js +21 -3
- package/dist/cli/controls.js +4 -0
- package/dist/cli/interactive.js +112 -156
- package/dist/cli/protocol.d.ts +5 -0
- package/dist/cli/protocol.js +45 -0
- package/dist/cli/provider-auth-command.d.ts +32 -0
- package/dist/cli/provider-auth-command.js +249 -0
- package/dist/cli/tui/ansi-frame-renderer.d.ts +2 -0
- package/dist/cli/tui/ansi-frame-renderer.js +109 -21
- package/dist/cli/tui/ansi-surface.d.ts +6 -22
- package/dist/cli/tui/ansi-surface.js +6 -126
- package/dist/cli/tui/ansi-theme.d.ts +3 -2
- package/dist/cli/tui/ansi-theme.js +22 -1
- package/dist/cli/tui/quiet-choice-rows.d.ts +26 -0
- package/dist/cli/tui/quiet-choice-rows.js +302 -0
- package/dist/cli/tui/quiet-frame-adapter.d.ts +18 -0
- package/dist/cli/tui/quiet-frame-adapter.js +90 -0
- package/dist/cli/tui/quiet-frame.d.ts +43 -0
- package/dist/cli/tui/quiet-frame.js +346 -0
- package/dist/cli/tui/quiet-operational-rows.d.ts +17 -0
- package/dist/cli/tui/quiet-operational-rows.js +413 -0
- package/dist/cli/tui/quiet-screen-projector.d.ts +25 -0
- package/dist/cli/tui/quiet-screen-projector.js +110 -0
- package/dist/cli/tui/quiet-settings-rows.d.ts +17 -0
- package/dist/cli/tui/quiet-settings-rows.js +490 -0
- package/dist/cli/tui/status-line.d.ts +15 -9
- package/dist/cli/tui/status-line.js +15 -6
- package/dist/cli/tui/theme.js +20 -20
- package/dist/cli/tui/transcript-viewport.d.ts +5 -0
- package/dist/cli/tui/transcript-viewport.js +213 -78
- package/dist/cli/tui/tui-row-ir.js +4 -4
- package/dist/cli/workspace-trust-prompt.js +2 -2
- package/dist/cli-runtime.d.ts +34 -1
- package/dist/cli-runtime.js +587 -184
- package/dist/maintenance/doctor.js +100 -22
- package/dist/persistence/in-memory-transcript-store.js +1 -7
- package/dist/persistence/native-transcript-store.d.ts +0 -9
- package/dist/persistence/native-transcript-store.js +4 -38
- package/dist/persistence/provider-credential-vault.d.ts +72 -0
- package/dist/persistence/provider-credential-vault.js +498 -0
- package/dist/providers/codex-oauth.d.ts +104 -0
- package/dist/providers/codex-oauth.js +770 -0
- package/dist/providers/codex-subscription.d.ts +33 -0
- package/dist/providers/codex-subscription.js +849 -0
- package/dist/providers/provider-auth.d.ts +71 -0
- package/dist/providers/provider-auth.js +149 -0
- package/dist/providers/provider-registry.d.ts +52 -0
- package/dist/providers/provider-registry.js +187 -0
- package/dist/providers/provider-settings.d.ts +38 -0
- package/dist/providers/provider-settings.js +334 -0
- package/dist/security/workspace-trust.d.ts +4 -3
- package/dist/security/workspace-trust.js +35 -1
- package/package.json +8 -4
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { createQuietFrameRow, } from './quiet-frame.js';
|
|
2
|
+
import { configSettingValue, CLAUDE_2_1_208_CONFIG_SETTINGS, } from './config-settings.js';
|
|
3
|
+
import { formatCostSummary } from './cost-summary.js';
|
|
4
|
+
const full = (d) => d === 'full' || d === 'standard';
|
|
5
|
+
const max = (o) => Number.isInteger(o.maxItems) && (o.maxItems ?? 0) > 0
|
|
6
|
+
? o.maxItems
|
|
7
|
+
: 20;
|
|
8
|
+
const clean = (v) => typeof v === 'string' ? v.slice(0, 32768).replace(/\s+/gu, ' ').trim() : '';
|
|
9
|
+
const excerpt = (v, length = 240) => clean(v).slice(0, length);
|
|
10
|
+
const row = (k, t, role = 'body', a) => createQuietFrameRow(k, t, 'focus', role, a);
|
|
11
|
+
const selected = (yes, text, sr) => sr ? `${yes ? 'Selected' : 'Option'}: ${text}` : `${yes ? '❯ ' : ' '}${text}`;
|
|
12
|
+
const index = (n, i) => n ? Math.max(0, Math.min(n - 1, Number.isFinite(i) ? Math.trunc(i) : 0)) : 0;
|
|
13
|
+
function window(n, i, size) {
|
|
14
|
+
if (!n)
|
|
15
|
+
return [0, 0];
|
|
16
|
+
const x = index(n, i);
|
|
17
|
+
const start = Math.max(0, Math.min(Math.max(0, n - size), x - Math.floor(size / 2)));
|
|
18
|
+
return [start, Math.min(n, start + size)];
|
|
19
|
+
}
|
|
20
|
+
const footer = (visual, accessible, sr) => row('quiet:settings:footer', sr ? accessible : visual, 'muted', accessible);
|
|
21
|
+
const unsupported = (v) => {
|
|
22
|
+
throw new Error(`Unsupported quiet settings surface: ${String(v)}`);
|
|
23
|
+
};
|
|
24
|
+
const statusRole = (s) => /fail|error|denied|invalid/iu.test(s)
|
|
25
|
+
? 'error'
|
|
26
|
+
: /warn|pending|running/iu.test(s)
|
|
27
|
+
? 'warning'
|
|
28
|
+
: /pass|complete|ready|enabled/iu.test(s)
|
|
29
|
+
? 'success'
|
|
30
|
+
: 'muted';
|
|
31
|
+
const marker = (s) => /fail|error|denied/iu.test(s)
|
|
32
|
+
? '!'
|
|
33
|
+
: /warn|pending|running/iu.test(s)
|
|
34
|
+
? '…'
|
|
35
|
+
: /pass|complete|ready|enabled/iu.test(s)
|
|
36
|
+
? '✓'
|
|
37
|
+
: '○';
|
|
38
|
+
const value = (v) => typeof v === 'boolean'
|
|
39
|
+
? v
|
|
40
|
+
? 'On'
|
|
41
|
+
: 'Off'
|
|
42
|
+
: Array.isArray(v)
|
|
43
|
+
? excerpt(v
|
|
44
|
+
.slice(0, 20)
|
|
45
|
+
.map((item) => excerpt(item, 80))
|
|
46
|
+
.join(', ')) || 'none'
|
|
47
|
+
: excerpt(v) || 'Not set';
|
|
48
|
+
const closeFooter = (sr) => footer('Esc close', 'Press Escape to close this surface.', sr);
|
|
49
|
+
function doctor(s, o) {
|
|
50
|
+
const out = [
|
|
51
|
+
row('quiet:doctor:heading', 'Doctor · Diagnostics', 'heading', 'Doctor diagnostics'),
|
|
52
|
+
];
|
|
53
|
+
if (s.loading)
|
|
54
|
+
out.push(row('quiet:doctor:loading', '… Running diagnostics…', 'warning', 'Diagnostics in progress'));
|
|
55
|
+
if (s.error)
|
|
56
|
+
out.push(row('quiet:doctor:error', `! ${clean(s.error)}`, 'error', `Error: ${clean(s.error)}`));
|
|
57
|
+
const report = s.report;
|
|
58
|
+
if (!report) {
|
|
59
|
+
out.push(row('quiet:doctor:empty', '○ No diagnostic report available', 'muted'), closeFooter(!!o.screenReader));
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
out.push(row('quiet:doctor:version', `Praxis ${clean(report.praxisVersion)}`, 'muted'));
|
|
63
|
+
out.push(row('quiet:doctor:summary', `✓ ${report.summary.passed} passed · ! ${report.summary.failed} failed · ${report.summary.warnings} warnings`, report.summary.failed
|
|
64
|
+
? 'error'
|
|
65
|
+
: report.summary.warnings
|
|
66
|
+
? 'warning'
|
|
67
|
+
: 'success'));
|
|
68
|
+
const checks = [...report.checks];
|
|
69
|
+
if (o.density === 'minimal')
|
|
70
|
+
checks.sort((a, b) => (a.status === 'pass' ? 1 : 0) - (b.status === 'pass' ? 1 : 0));
|
|
71
|
+
for (const c of checks.slice(0, max(o)))
|
|
72
|
+
out.push(row(`quiet:doctor:check:${c.id}`, `${marker(c.status)} ${c.id}: ${excerpt(c.summary)}`, statusRole(c.status), `${c.status === 'pass' ? 'Pass' : c.status === 'fail' ? 'Failure' : 'Warning'}: ${c.id}. ${excerpt(c.summary)}`));
|
|
73
|
+
out.push(closeFooter(!!o.screenReader));
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
function memory(s, o) {
|
|
77
|
+
const sr = !!o.screenReader;
|
|
78
|
+
const out = [
|
|
79
|
+
row('quiet:memory:heading', 'Memory · Native data plane', 'heading'),
|
|
80
|
+
];
|
|
81
|
+
out.push(row('quiet:memory:auto', `${s.autoMemoryEnabled ? '✓' : '○'} Auto-memory ${s.autoMemoryEnabled ? 'enabled' : 'disabled'}`, s.autoMemoryEnabled ? 'success' : 'muted'));
|
|
82
|
+
if (s.loading)
|
|
83
|
+
out.push(row('quiet:memory:loading', '… Loading memory files', 'warning'));
|
|
84
|
+
if (!s.entries.length) {
|
|
85
|
+
out.push(row('quiet:memory:empty', '○ No memory entries', 'muted'));
|
|
86
|
+
out.push(closeFooter(sr));
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
if (s.openedIndex !== null) {
|
|
90
|
+
const e = s.entries[index(s.entries.length, s.openedIndex)];
|
|
91
|
+
if (!e)
|
|
92
|
+
return out;
|
|
93
|
+
if (e) {
|
|
94
|
+
out.push(row(`quiet:memory:detail:${e.path}`, `${e.kind === 'folder' ? 'Folder' : 'File'} · ${excerpt(e.displayPath)}`, 'body'));
|
|
95
|
+
if (full(o.density) && e.annotation)
|
|
96
|
+
out.push(row(`quiet:memory:annotation:${e.path}`, excerpt(e.annotation), 'muted'));
|
|
97
|
+
}
|
|
98
|
+
out.push(footer('Esc back', 'Press Escape to go back to memory entries', sr));
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
const [a, b] = window(s.entries.length, s.selectedIndex, max(o));
|
|
102
|
+
for (let i = a; i < b; i++) {
|
|
103
|
+
const e = s.entries[i];
|
|
104
|
+
if (!e)
|
|
105
|
+
continue;
|
|
106
|
+
const text = `${e.kind === 'folder' ? 'Folder' : 'File'} · ${excerpt(e.label || e.displayPath)}${full(o.density) && e.annotation ? ` — ${excerpt(e.annotation)}` : ''}`;
|
|
107
|
+
out.push(row(`quiet:memory:${e.path}`, selected(i === index(s.entries.length, s.selectedIndex), text, sr), i === index(s.entries.length, s.selectedIndex) ? 'selection' : 'body', `${i === index(s.entries.length, s.selectedIndex) ? 'Selected' : 'Option'}: ${text}`));
|
|
108
|
+
}
|
|
109
|
+
out.push(footer('↑/↓ browse Enter open Esc close', 'Use Up and Down to browse. Press Enter to open. Escape closes.', sr));
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
function hooks(s, o) {
|
|
113
|
+
const sr = !!o.screenReader;
|
|
114
|
+
const c = s.configuration;
|
|
115
|
+
const out = [
|
|
116
|
+
row('quiet:hooks:heading', `Hooks · ${s.depth}`, 'heading'),
|
|
117
|
+
row('quiet:hooks:notice', '○ Read-only hook settings', 'muted'),
|
|
118
|
+
];
|
|
119
|
+
const ev = c.events[index(c.events.length, s.eventIndex)];
|
|
120
|
+
if (!ev) {
|
|
121
|
+
out.push(row('quiet:hooks:empty', '○ No hooks configured', 'muted'), closeFooter(sr));
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
if (s.depth === 'events') {
|
|
125
|
+
const [start, end] = window(c.events.length, s.eventIndex, max(o));
|
|
126
|
+
for (let i = start; i < end; i++) {
|
|
127
|
+
const e = c.events[i];
|
|
128
|
+
if (!e)
|
|
129
|
+
continue;
|
|
130
|
+
const isSelected = i === index(c.events.length, s.eventIndex);
|
|
131
|
+
const label = `${e.name}${full(o.density) ? ` — ${excerpt(e.description)}` : ''}`;
|
|
132
|
+
out.push(row(`quiet:hooks:event:${e.name}`, selected(isSelected, label, sr), isSelected ? 'selection' : 'body', `${isSelected ? 'Selected' : 'Option'}: ${label}`));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
out.push(row(`quiet:hooks:event:${ev.name}`, `Event · ${ev.name} — ${excerpt(ev.description)}`, 'muted'));
|
|
137
|
+
const m = ev.matchers[index(ev.matchers.length, s.matcherIndex)];
|
|
138
|
+
if (s.depth === 'matchers') {
|
|
139
|
+
const [start, end] = window(ev.matchers.length, s.matcherIndex, max(o));
|
|
140
|
+
for (let i = start; i < end; i++) {
|
|
141
|
+
const x = ev.matchers[i];
|
|
142
|
+
if (!x)
|
|
143
|
+
continue;
|
|
144
|
+
const isSelected = i === index(ev.matchers.length, s.matcherIndex);
|
|
145
|
+
const label = `${x.scopeLabel}: ${excerpt(x.matcher) || 'All tools'}`;
|
|
146
|
+
out.push(row(`quiet:hooks:matcher:${ev.name}:${x.scope}:${x.matcher}`, selected(isSelected, label, sr), isSelected ? 'selection' : 'body', `${isSelected ? 'Selected' : 'Option'}: ${label}`));
|
|
147
|
+
}
|
|
148
|
+
if (!ev.matchers.length)
|
|
149
|
+
out.push(row('quiet:hooks:matchers:empty', '○ No matchers', 'muted'));
|
|
150
|
+
}
|
|
151
|
+
else if (m) {
|
|
152
|
+
out.push(row(`quiet:hooks:matcher:${ev.name}:${m.scope}:${m.matcher}`, `Matcher · ${m.scopeLabel}: ${excerpt(m.matcher) || 'All tools'}`, 'muted'));
|
|
153
|
+
if (s.depth === 'hooks') {
|
|
154
|
+
const [start, end] = window(m.hooks.length, s.hookIndex, max(o));
|
|
155
|
+
for (let i = start; i < end; i++) {
|
|
156
|
+
const h = m.hooks[i];
|
|
157
|
+
if (!h)
|
|
158
|
+
continue;
|
|
159
|
+
const isSelected = i === index(m.hooks.length, s.hookIndex);
|
|
160
|
+
const label = `${h.type} · ${h.scopeLabel} · ${excerpt(h.path)}`;
|
|
161
|
+
out.push(row(`quiet:hooks:hook:${h.path}:${h.type}`, selected(isSelected, label, sr), isSelected ? 'selection' : 'body', `${isSelected ? 'Selected' : 'Option'}: ${label}`));
|
|
162
|
+
}
|
|
163
|
+
if (!m.hooks.length)
|
|
164
|
+
out.push(row('quiet:hooks:hooks:empty', '○ No hooks', 'muted'));
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const h = m.hooks[index(m.hooks.length, s.hookIndex)];
|
|
168
|
+
if (h)
|
|
169
|
+
out.push(row(`quiet:hooks:hook:${h.path}:${h.type}`, `Hook · ${h.type} · ${h.scopeLabel} · ${excerpt(h.path)}`, 'body'));
|
|
170
|
+
else
|
|
171
|
+
for (const [detailIndex, d] of ev.detail.slice(0, max(o)).entries())
|
|
172
|
+
out.push(row(`quiet:hooks:detail:${ev.name}:${detailIndex}`, excerpt(d), 'muted'));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else
|
|
176
|
+
out.push(row(`quiet:hooks:${s.depth}:empty`, s.depth === 'hooks' ? '○ No hooks' : '○ No hook details', 'muted'));
|
|
177
|
+
}
|
|
178
|
+
out.push(footer('↑/↓ browse Enter open Esc back', 'Use Up and Down to browse. Press Enter to open. Escape goes back or closes.', sr));
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
function config(s, o) {
|
|
182
|
+
const sr = !!o.screenReader;
|
|
183
|
+
const tabLabel = s.tab === 'status' ? 'Status' : s.tab === 'config' ? 'Config' : 'Usage';
|
|
184
|
+
const out = [
|
|
185
|
+
row('quiet:config:heading', `Settings · ${tabLabel}`, 'heading'),
|
|
186
|
+
row('quiet:config:tabs', ['Status', 'Config', 'Usage']
|
|
187
|
+
.map((label) => (label === tabLabel ? `[${label}]` : label))
|
|
188
|
+
.join(' '), 'muted', `Current tab: ${tabLabel}`),
|
|
189
|
+
];
|
|
190
|
+
if (s.tab === 'status') {
|
|
191
|
+
const x = s.status;
|
|
192
|
+
if (!x) {
|
|
193
|
+
out.push(row('quiet:config:status:empty', '○ No status available', 'muted'), footer('←/→ tabs Esc close', 'Use Left and Right to change tabs. Press Escape to close.', sr));
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
const fields = [
|
|
197
|
+
['version', x.version],
|
|
198
|
+
['session', x.sessionName],
|
|
199
|
+
['session-id', x.sessionId],
|
|
200
|
+
['cwd', x.cwd],
|
|
201
|
+
['auth', x.authSource],
|
|
202
|
+
['base-url', x.baseUrl],
|
|
203
|
+
['proxy', x.proxy],
|
|
204
|
+
['mcp', x.mcpSummary],
|
|
205
|
+
['model', x.model],
|
|
206
|
+
['sources', x.settingSources.join(', ')],
|
|
207
|
+
];
|
|
208
|
+
for (const [k, v] of fields.slice(0, max(o)))
|
|
209
|
+
if (v !== undefined)
|
|
210
|
+
out.push(row(`quiet:config:status:${k}`, `${k}: ${value(v)}`, 'body'));
|
|
211
|
+
out.push(footer('←/→ tabs Esc close', 'Use Left and Right to change tabs. Press Escape to close.', sr));
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
if (s.tab === 'usage') {
|
|
215
|
+
if (!s.usage)
|
|
216
|
+
out.push(row('quiet:config:usage:empty', '○ No usage summary available', 'muted'));
|
|
217
|
+
else {
|
|
218
|
+
try {
|
|
219
|
+
const source = formatCostSummary(s.usage).slice(0, 32768);
|
|
220
|
+
const lines = source.split('\n');
|
|
221
|
+
const truncated = lines.length > max(o);
|
|
222
|
+
const visible = lines.slice(0, truncated ? Math.max(0, max(o) - 1) : max(o));
|
|
223
|
+
for (const [i, line] of visible.entries())
|
|
224
|
+
out.push(row(`quiet:config:usage:${i}`, clean(line), 'body'));
|
|
225
|
+
if (truncated)
|
|
226
|
+
out.push(row('quiet:config:usage:truncated', '… Usage truncated', 'muted'));
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
out.push(row('quiet:config:usage:error', '! Usage summary unavailable', 'error'));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
out.push(footer('←/→ tabs Esc close', 'Use Left and Right to change tabs. Press Escape to close.', sr));
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
const q = excerpt(s.query).toLowerCase();
|
|
236
|
+
const defs = CLAUDE_2_1_208_CONFIG_SETTINGS.filter((d) => !q ||
|
|
237
|
+
d.label.toLowerCase().includes(q) ||
|
|
238
|
+
d.nativeKey.toLowerCase().includes(q));
|
|
239
|
+
const [a, b] = window(defs.length, s.selectedIndex, max(o));
|
|
240
|
+
for (let i = a; i < b; i++) {
|
|
241
|
+
const d = defs[i];
|
|
242
|
+
if (!d)
|
|
243
|
+
continue;
|
|
244
|
+
const v = s.effectiveValues?.[d.id] ?? configSettingValue(s.snapshot, d);
|
|
245
|
+
const t = `${d.label}: ${value(v)}`;
|
|
246
|
+
out.push(row(`quiet:config:setting:${d.id}`, selected(i === index(defs.length, s.selectedIndex), t, sr), i === index(defs.length, s.selectedIndex) ? 'selection' : 'body', `${i === index(defs.length, s.selectedIndex) ? 'Selected' : 'Option'}: ${t}`));
|
|
247
|
+
}
|
|
248
|
+
if (!defs.length)
|
|
249
|
+
out.push(row('quiet:config:empty', '○ No matching settings', 'muted'));
|
|
250
|
+
out.push(row('quiet:config:search', `Search: ${excerpt(s.query) || '(all settings)'}`, s.searchFocused ? 'input' : 'muted', s.searchFocused
|
|
251
|
+
? `Search input: ${excerpt(s.query) || 'all settings'}`
|
|
252
|
+
: undefined));
|
|
253
|
+
out.push(footer('←/→ tabs / search ↑/↓ browse Enter change Esc close', 'Use Left and Right to change tabs. Press slash to search. Use Up and Down to browse. Press Enter to change. Press Escape to close.', sr));
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
function sandbox(s, o) {
|
|
257
|
+
const x = s.snapshot;
|
|
258
|
+
const sr = !!o.screenReader;
|
|
259
|
+
const out = [
|
|
260
|
+
row('quiet:sandbox:heading', `Sandbox · ${s.tab}`, 'heading'),
|
|
261
|
+
row('quiet:sandbox:tab', `Current tab: ${s.tab}`, 'muted', `Current tab: ${s.tab}`),
|
|
262
|
+
row('quiet:sandbox:support', `${x.supported ? '✓' : '!'} ${x.supported ? 'Supported' : 'Unavailable'} on ${x.platform}${x.unavailableReason ? `: ${excerpt(x.unavailableReason)}` : ''}`, x.supported ? 'success' : 'error', `${x.supported ? 'Supported' : 'Unavailable'} on ${x.platform}${x.unavailableReason ? `: ${excerpt(x.unavailableReason)}` : ''}`),
|
|
263
|
+
];
|
|
264
|
+
if (s.tab === 'mode') {
|
|
265
|
+
const modes = [
|
|
266
|
+
['auto-allow', 'Auto-allow'],
|
|
267
|
+
['regular', 'Regular permissions'],
|
|
268
|
+
['disabled', 'Disabled'],
|
|
269
|
+
];
|
|
270
|
+
const current = x.settings.enabled
|
|
271
|
+
? x.settings.autoAllowBashIfSandboxed
|
|
272
|
+
? 'auto-allow'
|
|
273
|
+
: 'regular'
|
|
274
|
+
: 'disabled';
|
|
275
|
+
const [start, end] = window(modes.length, s.selectedIndex, max(o));
|
|
276
|
+
for (let i = start; i < end; i++) {
|
|
277
|
+
const candidate = modes[i];
|
|
278
|
+
if (!candidate)
|
|
279
|
+
continue;
|
|
280
|
+
const [id, label] = candidate;
|
|
281
|
+
const isSelected = i === index(modes.length, s.selectedIndex);
|
|
282
|
+
const optionText = `${label}${id === current ? ' (current)' : ''}`;
|
|
283
|
+
out.push(row(`quiet:sandbox:mode:${id}`, selected(isSelected, optionText, sr), isSelected ? 'selection' : 'body', `${isSelected ? 'Selected' : 'Option'}: ${label}${id === current ? ', current mode' : ''}`));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else if (s.tab === 'dependencies') {
|
|
287
|
+
const d = x.dependencies;
|
|
288
|
+
const errors = (Array.isArray(d.errors) ? d.errors : [])
|
|
289
|
+
.map((item) => excerpt(item))
|
|
290
|
+
.filter(Boolean);
|
|
291
|
+
const warnings = (Array.isArray(d.warnings) ? d.warnings : [])
|
|
292
|
+
.map((item) => excerpt(item))
|
|
293
|
+
.filter(Boolean);
|
|
294
|
+
const diagnostics = [
|
|
295
|
+
...errors.map((message, sourceIndex) => ({
|
|
296
|
+
key: `quiet:sandbox:dependency:error:${sourceIndex}`,
|
|
297
|
+
text: `! ${message}`,
|
|
298
|
+
role: 'error',
|
|
299
|
+
accessible: `Dependency error: ${message}`,
|
|
300
|
+
})),
|
|
301
|
+
...warnings.map((message, sourceIndex) => ({
|
|
302
|
+
key: `quiet:sandbox:dependency:warning:${sourceIndex}`,
|
|
303
|
+
text: `… ${message}`,
|
|
304
|
+
role: 'warning',
|
|
305
|
+
accessible: `Dependency warning: ${message}`,
|
|
306
|
+
})),
|
|
307
|
+
];
|
|
308
|
+
for (const item of diagnostics.slice(0, max(o)))
|
|
309
|
+
out.push(row(item.key, item.text, item.role, item.accessible));
|
|
310
|
+
if (!errors.length && !warnings.length && !x.unavailableReason)
|
|
311
|
+
out.push(row('quiet:sandbox:ready', '✓ Sandbox dependencies ready', 'success'));
|
|
312
|
+
}
|
|
313
|
+
else if (s.tab === 'overrides') {
|
|
314
|
+
const items = [
|
|
315
|
+
[
|
|
316
|
+
'unsandboxed',
|
|
317
|
+
'Allow unsandboxed fallback',
|
|
318
|
+
x.settings.allowUnsandboxedCommands,
|
|
319
|
+
],
|
|
320
|
+
['strict', 'Strict sandbox mode', x.settings.failIfUnavailable],
|
|
321
|
+
];
|
|
322
|
+
const [start, end] = window(items.length, s.selectedIndex, max(o));
|
|
323
|
+
for (let i = start; i < end; i++) {
|
|
324
|
+
const candidate = items[i];
|
|
325
|
+
if (!candidate)
|
|
326
|
+
continue;
|
|
327
|
+
const [id, label, on] = candidate;
|
|
328
|
+
const isSelected = i === index(items.length, s.selectedIndex);
|
|
329
|
+
out.push(row(`quiet:sandbox:override:${id}`, selected(isSelected, `${label}${on ? ' (current)' : ''}`, sr), isSelected ? 'selection' : 'body', `${isSelected ? 'Selected' : 'Option'}: ${label}${on ? ', current' : ''}`));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
const runtime = s.snapshot.settings.runtimeConfig;
|
|
334
|
+
const filesystem = (runtime.filesystem ?? {});
|
|
335
|
+
const network = (runtime.network ?? {});
|
|
336
|
+
const fields = [
|
|
337
|
+
['excluded commands', x.settings.excludedCommands],
|
|
338
|
+
['allow write', filesystem.allowWrite],
|
|
339
|
+
['deny write', filesystem.denyWrite],
|
|
340
|
+
['allow read', filesystem.allowRead],
|
|
341
|
+
['deny read', filesystem.denyRead],
|
|
342
|
+
['allow domains', network.allowedDomains],
|
|
343
|
+
['deny domains', network.deniedDomains],
|
|
344
|
+
];
|
|
345
|
+
const warnings = (x.globPatternWarnings ?? []).map((warning, warningIndex) => ({
|
|
346
|
+
key: `quiet:sandbox:warning:${JSON.stringify([warningIndex, excerpt(warning, 120)])}`,
|
|
347
|
+
text: `! Glob warning: ${excerpt(warning)}`,
|
|
348
|
+
role: 'warning',
|
|
349
|
+
accessible: `Glob warning: ${excerpt(warning)}`,
|
|
350
|
+
}));
|
|
351
|
+
const detail = fields.map(([key, fieldValue]) => ({
|
|
352
|
+
key: `quiet:sandbox:config:${key}`,
|
|
353
|
+
text: `${key}: ${Array.isArray(fieldValue) ? fieldValue.slice(0, max(o)).map(excerpt).join(', ') || 'none' : value(fieldValue)}`,
|
|
354
|
+
role: 'body',
|
|
355
|
+
accessible: undefined,
|
|
356
|
+
}));
|
|
357
|
+
const projected = full(o.density) ? [...warnings, ...detail] : warnings;
|
|
358
|
+
for (const item of projected.slice(0, max(o)))
|
|
359
|
+
out.push(row(item.key, item.text, item.role, item.accessible));
|
|
360
|
+
if (projected.length === 0)
|
|
361
|
+
out.push(row('quiet:sandbox:config:empty', '○ No sandbox overrides', 'muted'));
|
|
362
|
+
}
|
|
363
|
+
out.push(footer('←/→ tabs ↑/↓ select Enter confirm Esc close', 'Use Left and Right to change tabs. Use Up and Down to select. Press Enter to confirm. Press Escape to close sandbox settings.', sr));
|
|
364
|
+
return out;
|
|
365
|
+
}
|
|
366
|
+
function optionsSurface(title, options, selectedIndex, o, extra) {
|
|
367
|
+
const sr = !!o.screenReader;
|
|
368
|
+
const out = [
|
|
369
|
+
row(`quiet:${title}:heading`, (title.at(0) ?? '').toUpperCase() + title.slice(1), 'heading'),
|
|
370
|
+
];
|
|
371
|
+
const occurrences = new Map();
|
|
372
|
+
const identities = options.map((option) => {
|
|
373
|
+
const identity = excerpt(option.id || option.model || option.label) || 'option';
|
|
374
|
+
const occurrence = occurrences.get(identity) ?? 0;
|
|
375
|
+
occurrences.set(identity, occurrence + 1);
|
|
376
|
+
return JSON.stringify([identity, occurrence]);
|
|
377
|
+
});
|
|
378
|
+
if (extra)
|
|
379
|
+
out.push(row(`quiet:${title}:state`, excerpt(extra), 'muted'));
|
|
380
|
+
const [a, b] = window(options.length, selectedIndex, max(o));
|
|
381
|
+
for (let i = a; i < b; i++) {
|
|
382
|
+
const x = options[i];
|
|
383
|
+
if (!x)
|
|
384
|
+
continue;
|
|
385
|
+
const identity = identities[i] ?? `option:${i}`;
|
|
386
|
+
const t = `${excerpt(x.label)}${x.selected ? ' (current)' : ''}${full(o.density) && x.description ? ` — ${excerpt(x.description)}` : ''}`;
|
|
387
|
+
out.push(row(`quiet:${title}:option:${identity}`, selected(i === index(options.length, selectedIndex), t, sr), title === 'theme-delete' && x.id === 'delete'
|
|
388
|
+
? 'error'
|
|
389
|
+
: i === index(options.length, selectedIndex)
|
|
390
|
+
? 'selection'
|
|
391
|
+
: 'body', `${i === index(options.length, selectedIndex) ? 'Selected' : 'Option'}: ${t}`));
|
|
392
|
+
}
|
|
393
|
+
if (!options.length)
|
|
394
|
+
out.push(row(`quiet:${title}:empty`, '○ No options available', 'muted'));
|
|
395
|
+
out.push(footer('↑/↓ browse Enter select Esc back', 'Use Up and Down to browse. Press Enter to select. Escape goes back.', sr));
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
398
|
+
function model(s, o) {
|
|
399
|
+
return optionsSurface('model', s.options, s.selectedIndex, o, `Effort: ${clean(s.effort)}`);
|
|
400
|
+
}
|
|
401
|
+
function effort(s, o) {
|
|
402
|
+
return optionsSurface('effort', s.options, s.selectedIndex, o);
|
|
403
|
+
}
|
|
404
|
+
function theme(s, o) {
|
|
405
|
+
if (s.kind === 'theme-panel')
|
|
406
|
+
return optionsSurface('theme', s.options.map((option) => ({
|
|
407
|
+
...option,
|
|
408
|
+
selected: option.current,
|
|
409
|
+
})), s.selectedIndex, o, `${s.currentTheme}${s.syntaxHighlightingDisabled ? ' · Syntax highlighting disabled' : ''}`);
|
|
410
|
+
if (s.kind === 'custom-theme-create')
|
|
411
|
+
return [
|
|
412
|
+
row('quiet:theme:create:heading', 'Create custom theme', 'heading'),
|
|
413
|
+
row('quiet:theme:create:base', `Base: ${s.base}`),
|
|
414
|
+
row('quiet:theme:create:name', `Name: ${excerpt(s.name) || '(enter name)'}`),
|
|
415
|
+
footer('Enter save Esc back', 'Press Enter to save. Escape goes back.', !!o.screenReader),
|
|
416
|
+
];
|
|
417
|
+
if (s.kind === 'custom-theme-editor')
|
|
418
|
+
return optionsSurface('theme-editor', s.tokens.map((token) => ({
|
|
419
|
+
id: token,
|
|
420
|
+
label: token,
|
|
421
|
+
description: s.theme.overrides[token] ?? 'Inherited from base',
|
|
422
|
+
})), s.selectedIndex, o, `Theme: ${s.theme.name}`);
|
|
423
|
+
if (s.kind === 'custom-theme-token')
|
|
424
|
+
return [
|
|
425
|
+
row('quiet:theme:token:heading', `Theme token · ${s.token}`, 'heading'),
|
|
426
|
+
row(`quiet:theme:token:${s.token}:value`, `Value: ${excerpt(s.value) || '(enter value)'}`),
|
|
427
|
+
footer('Enter save Esc back', 'Press Enter to save. Escape goes back.', !!o.screenReader),
|
|
428
|
+
];
|
|
429
|
+
if (s.kind === 'custom-theme-delete')
|
|
430
|
+
return optionsSurface('theme-delete', [
|
|
431
|
+
{
|
|
432
|
+
id: 'delete',
|
|
433
|
+
label: 'Delete theme',
|
|
434
|
+
description: `Warning: permanently delete ${s.theme.name}`,
|
|
435
|
+
},
|
|
436
|
+
{ id: 'cancel', label: 'Cancel', description: 'Keep this theme' },
|
|
437
|
+
], s.selectedIndex, o, '! Destructive action');
|
|
438
|
+
return unsupported(s);
|
|
439
|
+
}
|
|
440
|
+
function leaf(s, o) {
|
|
441
|
+
if (s.kind === 'model-input' || s.kind === 'export-filename')
|
|
442
|
+
return [
|
|
443
|
+
row(`quiet:leaf:${s.kind}:heading`, s.kind === 'model-input' ? 'Model input' : 'Export filename', 'heading'),
|
|
444
|
+
row(`quiet:leaf:${s.kind}:value`, `Input: ${excerpt(s.value)}`, 'input'),
|
|
445
|
+
footer('Enter submit Esc back', 'Press Enter to submit. Escape goes back.', !!o.screenReader),
|
|
446
|
+
];
|
|
447
|
+
if (s.kind === 'compact-progress') {
|
|
448
|
+
const p = Math.max(0, Math.min(100, Number.isFinite(s.progress) ? s.progress : 0));
|
|
449
|
+
return [
|
|
450
|
+
row('quiet:leaf:progress:heading', 'Compaction progress', 'heading'),
|
|
451
|
+
row('quiet:leaf:progress', `${p >= 100 ? '✓' : '…'} ${Math.round(p)}%`, p >= 100 ? 'success' : 'warning'),
|
|
452
|
+
];
|
|
453
|
+
}
|
|
454
|
+
return optionsSurface(s.kind, s.options.map((x) => ({ ...x, id: x.id })), s.selectedIndex, o, s.kind === 'copy' && full(o.density)
|
|
455
|
+
? `Message age: ${Number.isFinite(s.messageAge) ? s.messageAge : 'unknown'}`
|
|
456
|
+
: undefined);
|
|
457
|
+
}
|
|
458
|
+
export function projectQuietSettingsRows(surface, o) {
|
|
459
|
+
switch (surface.kind) {
|
|
460
|
+
case 'doctor-panel':
|
|
461
|
+
return doctor(surface, o);
|
|
462
|
+
case 'memory-panel':
|
|
463
|
+
return memory(surface, o);
|
|
464
|
+
case 'hooks-panel':
|
|
465
|
+
return hooks(surface, o);
|
|
466
|
+
case 'config-panel':
|
|
467
|
+
return config(surface, o);
|
|
468
|
+
case 'sandbox-panel':
|
|
469
|
+
return sandbox(surface, o);
|
|
470
|
+
case 'model-panel':
|
|
471
|
+
return model(surface, o);
|
|
472
|
+
case 'effort-panel':
|
|
473
|
+
return effort(surface, o);
|
|
474
|
+
case 'theme-panel':
|
|
475
|
+
case 'custom-theme-create':
|
|
476
|
+
case 'custom-theme-editor':
|
|
477
|
+
case 'custom-theme-token':
|
|
478
|
+
case 'custom-theme-delete':
|
|
479
|
+
return theme(surface, o);
|
|
480
|
+
case 'model-input':
|
|
481
|
+
case 'export':
|
|
482
|
+
case 'copy':
|
|
483
|
+
case 'export-filename':
|
|
484
|
+
case 'compact-progress':
|
|
485
|
+
return leaf(surface, o);
|
|
486
|
+
default:
|
|
487
|
+
return unsupported(surface);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
//# sourceMappingURL=quiet-settings-rows.js.map
|
|
@@ -82,13 +82,19 @@ export declare function createClaudeStatusLineInput(options: {
|
|
|
82
82
|
vimMode?: 'INSERT' | 'NORMAL';
|
|
83
83
|
dataPlane?: DataPlane;
|
|
84
84
|
}): ClaudeStatusLineInput;
|
|
85
|
-
export
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
export interface ClaudeStatusLineState {
|
|
86
|
+
readonly text?: string;
|
|
87
|
+
readonly padding: number;
|
|
88
|
+
}
|
|
89
|
+
export declare function formatClaudeStatusLineState(state: ClaudeStatusLineState, width?: number): string | undefined;
|
|
90
|
+
export interface UseClaudeStatusLineOptions {
|
|
91
|
+
readonly configRoot: string;
|
|
92
|
+
readonly cwd: string;
|
|
93
|
+
readonly input: ClaudeStatusLineInput;
|
|
94
|
+
readonly refreshKey: string;
|
|
95
|
+
readonly width?: number;
|
|
96
|
+
readonly settingSources?: readonly ResourceScope[];
|
|
97
|
+
readonly dataPlane?: DataPlane;
|
|
98
|
+
}
|
|
99
|
+
export declare function useClaudeStatusLine({ configRoot, cwd, input, refreshKey, width, settingSources, dataPlane: _dataPlane, }: UseClaudeStatusLineOptions): ClaudeStatusLineState;
|
|
94
100
|
//# sourceMappingURL=status-line.d.ts.map
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
1
|
import { spawn } from 'node:child_process';
|
|
3
2
|
import { watchFile, unwatchFile } from 'node:fs';
|
|
4
3
|
import { join, resolve } from 'node:path';
|
|
5
|
-
import { Box, Text } from 'ink';
|
|
6
4
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
7
5
|
import { loadNativeSharedResources } from '../../persistence/native-resources.js';
|
|
8
6
|
import { commandShell, commandShellArguments, } from '../../platform/command-shell.js';
|
|
@@ -172,7 +170,20 @@ export function createClaudeStatusLineInput(options) {
|
|
|
172
170
|
...(options.vimMode ? { vim: { mode: options.vimMode } } : {}),
|
|
173
171
|
};
|
|
174
172
|
}
|
|
175
|
-
export function
|
|
173
|
+
export function formatClaudeStatusLineState(state, width) {
|
|
174
|
+
if (!state.text)
|
|
175
|
+
return undefined;
|
|
176
|
+
const padding = Number.isFinite(state.padding)
|
|
177
|
+
? Math.max(0, Math.trunc(state.padding))
|
|
178
|
+
: 0;
|
|
179
|
+
const maxPadding = width !== undefined && Number.isFinite(width) && width > 0
|
|
180
|
+
? Math.floor((width - 1) / 2)
|
|
181
|
+
: 256;
|
|
182
|
+
const boundedPadding = Math.min(padding, maxPadding);
|
|
183
|
+
const spaces = ' '.repeat(boundedPadding);
|
|
184
|
+
return `${spaces}${state.text}${spaces}`;
|
|
185
|
+
}
|
|
186
|
+
export function useClaudeStatusLine({ configRoot, cwd, input, refreshKey, width, settingSources, dataPlane: _dataPlane = 'native', }) {
|
|
176
187
|
void _dataPlane;
|
|
177
188
|
const [text, setText] = useState();
|
|
178
189
|
const [padding, setPadding] = useState(0);
|
|
@@ -235,8 +246,6 @@ export function StatusLine({ configRoot, cwd, input, refreshKey, width, settingS
|
|
|
235
246
|
clearTimeout(timer.current);
|
|
236
247
|
};
|
|
237
248
|
}, [configRoot, cwd, schedule]);
|
|
238
|
-
|
|
239
|
-
return null;
|
|
240
|
-
return (_jsx(Box, { paddingX: padding, flexShrink: 0, children: _jsx(Text, { dimColor: true, wrap: "truncate", children: text }) }));
|
|
249
|
+
return text === undefined ? { padding } : { text, padding };
|
|
241
250
|
}
|
|
242
251
|
//# sourceMappingURL=status-line.js.map
|
package/dist/cli/tui/theme.js
CHANGED
|
@@ -391,6 +391,7 @@ function resolveRawPalette(profile, syntaxHighlightingDisabled = false, environm
|
|
|
391
391
|
profile === 'dark-daltonized' ||
|
|
392
392
|
profile === 'dark-ansi';
|
|
393
393
|
const ansiOnly = profile.endsWith('-ansi');
|
|
394
|
+
const basicColor = terminalColorCapability(environment) === 'ansi16';
|
|
394
395
|
const daltonized = profile.endsWith('-daltonized');
|
|
395
396
|
const syntaxBase = ansiOnly
|
|
396
397
|
? {
|
|
@@ -442,15 +443,21 @@ function resolveRawPalette(profile, syntaxHighlightingDisabled = false, environm
|
|
|
442
443
|
ansiOnly,
|
|
443
444
|
syntaxHighlightingDisabled,
|
|
444
445
|
sessionColors,
|
|
445
|
-
brand: ansiOnly ? '
|
|
446
|
-
accent: ansiOnly ? '
|
|
447
|
-
info: ansiOnly ? 'cyanBright' : dark ? '#
|
|
448
|
-
link: ansiOnly ? '
|
|
449
|
-
error: ansiOnly ? 'redBright' : dark ? '#
|
|
450
|
-
success: ansiOnly ? 'greenBright' : dark ? '#
|
|
451
|
-
warning: ansiOnly ? 'yellowBright' : dark ? '#
|
|
452
|
-
muted: ansiOnly
|
|
453
|
-
|
|
446
|
+
brand: ansiOnly || basicColor ? 'cyanBright' : dark ? '#5EE6B5' : '#087F5B',
|
|
447
|
+
accent: ansiOnly || basicColor ? 'cyanBright' : dark ? '#5EE6B5' : '#087F5B',
|
|
448
|
+
info: ansiOnly || basicColor ? 'cyanBright' : dark ? '#9AA7B8' : '#475467',
|
|
449
|
+
link: ansiOnly || basicColor ? 'cyanBright' : dark ? '#5EE6B5' : '#087F5B',
|
|
450
|
+
error: ansiOnly || basicColor ? 'redBright' : dark ? '#FF6B6B' : '#C92A2A',
|
|
451
|
+
success: ansiOnly || basicColor ? 'greenBright' : dark ? '#5EE6B5' : '#087F5B',
|
|
452
|
+
warning: ansiOnly || basicColor ? 'yellowBright' : dark ? '#F2C14E' : '#9A6700',
|
|
453
|
+
muted: ansiOnly || basicColor
|
|
454
|
+
? dark
|
|
455
|
+
? 'white'
|
|
456
|
+
: 'black'
|
|
457
|
+
: dark
|
|
458
|
+
? '#8B949E'
|
|
459
|
+
: '#667085',
|
|
460
|
+
selectionText: ansiOnly || basicColor ? 'cyanBright' : dark ? '#5EE6B5' : '#087F5B',
|
|
454
461
|
syntaxTheme: ansiOnly ? 'ansi' : dark ? 'Monokai Extended' : 'GitHub',
|
|
455
462
|
syntax: syntaxBase,
|
|
456
463
|
};
|
|
@@ -538,7 +545,6 @@ function buildSemanticTheme(settings, palette, options = {}, capability = palett
|
|
|
538
545
|
const successColor = palette.success;
|
|
539
546
|
const warningColor = palette.warning;
|
|
540
547
|
const mutedColor = palette.muted;
|
|
541
|
-
const selectionTextColor = palette.selectionText;
|
|
542
548
|
const syntaxPalette = palette.syntax;
|
|
543
549
|
const sessionColors = palette.sessionColors;
|
|
544
550
|
const color = (value) => suppressColor ? undefined : value;
|
|
@@ -551,12 +557,10 @@ function buildSemanticTheme(settings, palette, options = {}, capability = palett
|
|
|
551
557
|
}),
|
|
552
558
|
heading: semanticText(undefined, options, { bold: true }),
|
|
553
559
|
navigation: semanticText(color(focusColor), options, { bold: true }),
|
|
554
|
-
selectedRow: semanticText(color(
|
|
555
|
-
...(suppressColor ? {} : { backgroundColor: focusColor }),
|
|
560
|
+
selectedRow: semanticText(color(focusColor), options, {
|
|
556
561
|
bold: true,
|
|
557
562
|
}),
|
|
558
|
-
selectedTab: semanticText(color(
|
|
559
|
-
...(suppressColor ? {} : { backgroundColor: focusColor }),
|
|
563
|
+
selectedTab: semanticText(color(focusColor), options, {
|
|
560
564
|
bold: true,
|
|
561
565
|
}),
|
|
562
566
|
focusMarker: semanticText(color(focusColor), options, { bold: true }),
|
|
@@ -578,15 +582,11 @@ function buildSemanticTheme(settings, palette, options = {}, capability = palett
|
|
|
578
582
|
const resolved = color(value);
|
|
579
583
|
return resolved === undefined ? {} : { borderColor: resolved };
|
|
580
584
|
};
|
|
581
|
-
const background = (value) => {
|
|
582
|
-
const resolved = color(value);
|
|
583
|
-
return resolved === undefined ? {} : { backgroundColor: resolved };
|
|
584
|
-
};
|
|
585
585
|
const surface = {
|
|
586
586
|
neutralBorder: semanticSurface(border(mutedColor), options),
|
|
587
587
|
separator: semanticSurface(border(mutedColor), options),
|
|
588
|
-
selectedRow: semanticSurface(
|
|
589
|
-
selectedTab: semanticSurface(
|
|
588
|
+
selectedRow: semanticSurface({}, options),
|
|
589
|
+
selectedTab: semanticSurface({}, options),
|
|
590
590
|
input: semanticSurface(border(focusColor), options),
|
|
591
591
|
decision: semanticSurface(border(warningColor), options),
|
|
592
592
|
error: semanticSurface(border(errorColor), options),
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { TranscriptPresentationEntry, TranscriptPresentationMode } from './transcript-presentation.js';
|
|
2
2
|
export declare const FULLSCREEN_TRANSCRIPT_RESERVED_ROWS = 12;
|
|
3
3
|
export declare const TRANSCRIPT_TRUNCATION_MARKER = "\u2026";
|
|
4
|
+
export declare function terminalGraphemes(text: string): readonly string[];
|
|
5
|
+
export declare function terminalGraphemeWidth(cluster: string): number;
|
|
6
|
+
export declare function terminalTextWidth(text: string): number;
|
|
7
|
+
export declare function terminalTextHead(text: string, budget: number): string;
|
|
8
|
+
export declare function terminalTextTail(text: string, budget: number): string;
|
|
4
9
|
export declare function estimateTranscriptEntryLines(entry: TranscriptPresentationEntry, width: number, mode: TranscriptPresentationMode): number;
|
|
5
10
|
export declare function transcriptPresentationLineCount(entries: readonly TranscriptPresentationEntry[], width: number, mode: TranscriptPresentationMode): number;
|
|
6
11
|
export declare function projectTranscriptEntryRows(entry: TranscriptPresentationEntry, width: number, mode: TranscriptPresentationMode): readonly string[] | undefined;
|