@toddzheng024/dscode-bundle 0.2.0 → 0.4.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/bin/apply_patch +5 -0
- package/cordis.patch.yml +27 -44
- package/package.json +9 -1
- package/plugins/credentials/index.mjs +50 -0
- package/plugins/email/cli.mjs +32 -0
- package/plugins/email/contacts.mjs +36 -0
- package/plugins/email/gmail-oauth.mjs +69 -0
- package/plugins/email/gmail-store.mjs +2 -0
- package/plugins/email/gmail.mjs +194 -0
- package/plugins/email/imap.mjs +136 -0
- package/plugins/email/inbox.d.mts +25 -0
- package/plugins/email/inbox.mjs +76 -0
- package/plugins/email/smtp.mjs +69 -0
- package/plugins/email/store.mjs +32 -0
- package/plugins/email-tools/index.mjs +44 -0
- package/plugins/memory/index.mjs +3 -0
- package/plugins/session-bridge/communication.mjs +30 -11
- package/plugins/tui-tools/index.mjs +13 -9
- package/presets/dscode/agent.cordis.yml +16 -0
- package/vendor/tui/.dscode-viewport-probe-78546.mjs +39239 -0
- package/vendor/tui/dscode-email/cli.mjs +32 -0
- package/vendor/tui/dscode-email/contacts.mjs +36 -0
- package/vendor/tui/dscode-email/gmail-oauth.mjs +69 -0
- package/vendor/tui/dscode-email/gmail-store.mjs +2 -0
- package/vendor/tui/dscode-email/gmail.mjs +194 -0
- package/vendor/tui/dscode-email/imap.mjs +136 -0
- package/vendor/tui/dscode-email/inbox.d.mts +25 -0
- package/vendor/tui/dscode-email/inbox.mjs +76 -0
- package/vendor/tui/dscode-email/smtp.mjs +69 -0
- package/vendor/tui/dscode-email/store.mjs +32 -0
- package/vendor/tui/dscode-email.mjs +69 -0
- package/vendor/tui/index.mjs +483 -60
package/vendor/tui/index.mjs
CHANGED
|
@@ -1,3 +1,162 @@
|
|
|
1
|
+
// dscode-email-v4
|
|
2
|
+
import { createImapConnector as dscodeCreateImapConnector } from "./dscode-email/imap.mjs";
|
|
3
|
+
import { createGmailConnector as dscodeCreateGmailConnector } from "./dscode-email/gmail.mjs";
|
|
4
|
+
import { createEmailInbox as dscodeCreateEmailInbox, emailKey as dscodeEmailKey, emailPrompt as dscodeEmailPrompt, emailText as dscodeEmailText } from "./dscode-email/inbox.mjs";
|
|
5
|
+
function DscodeImapSetup({ connector, back, done }) {
|
|
6
|
+
const [values, setValues] = (0, import_react.useState)(() => {
|
|
7
|
+
const saved = connector.status();
|
|
8
|
+
return [saved.account || '', saved.host || 'imap.gmail.com', String(saved.port || 993), saved.mailbox || 'INBOX', ''];
|
|
9
|
+
});
|
|
10
|
+
const [step, setStep] = (0, import_react.useState)(0);
|
|
11
|
+
const [error, setError] = (0, import_react.useState)('');
|
|
12
|
+
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
13
|
+
const operation = (0, import_react.useRef)(null);
|
|
14
|
+
(0, import_react.useEffect)(() => () => operation.current?.abort(), []);
|
|
15
|
+
const names = ['Email address', 'IMAP host', 'TLS port', 'Mailbox folder', 'Application password'];
|
|
16
|
+
useStableInput((input, key) => {
|
|
17
|
+
if (key.escape || key.ctrl && input === 'c') { operation.current?.abort(); setValues([]); back(); return; }
|
|
18
|
+
if (operation.current) return;
|
|
19
|
+
if (key.return) {
|
|
20
|
+
if (!values[step]?.trim()) { setError('This field is required.'); return; }
|
|
21
|
+
if (step < 4) { setStep(step + 1); setError(''); return; }
|
|
22
|
+
const [account, host, port, mailbox, password] = values;
|
|
23
|
+
const controller = new AbortController(); operation.current = controller;
|
|
24
|
+
setValues(current => current.map((value, index) => index === 4 ? '' : value)); setBusy(true); setError('');
|
|
25
|
+
Promise.resolve().then(() => connector.connect({ account, host, port, mailbox, password }, { signal: controller.signal })).then(result => {
|
|
26
|
+
if (controller.signal.aborted) return;
|
|
27
|
+
if (result.busy) { setError('Another session is syncing. Retry shortly.'); return; }
|
|
28
|
+
done();
|
|
29
|
+
}, reason => { if (!controller.signal.aborted) setError(reason.message); }).finally(() => {
|
|
30
|
+
operation.current = null; if (!controller.signal.aborted) setBusy(false);
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (key.tab) { setStep(current => (current + (key.shift ? 4 : 1)) % 5); setError(''); return; }
|
|
35
|
+
if (key.ctrl && input === 'u') { setValues(current => current.map((value, index) => index === step ? '' : value)); return; }
|
|
36
|
+
if (key.backspace || key.delete) { setValues(current => current.map((value, index) => index === step ? [...value].slice(0, -1).join('') : value)); return; }
|
|
37
|
+
if (key.ctrl || key.meta || !input) return;
|
|
38
|
+
const pasted = stripPasteMarkers(input).replace(/[\x00-\x1f\x7f]/g, '');
|
|
39
|
+
setValues(current => current.map((value, index) => index === step ? (value + pasted).slice(0, 1024) : value));
|
|
40
|
+
});
|
|
41
|
+
const text = (value, props = {}) => (0, import_react.createElement)(Text, { wrap: 'truncate-end', ...props }, value);
|
|
42
|
+
return (0, import_react.createElement)(Box, { flexDirection: 'column' },
|
|
43
|
+
text('Connect IMAP · ' + (step + 1) + '/5', { bold: true }),
|
|
44
|
+
text(busy ? 'Connecting securely…' : names[step] + ' › ' + (step === 4 ? values[step] ? '••••••••' : '' : values[step])),
|
|
45
|
+
text(error || (step === 4 ? 'Gmail: use an app password from 2-Step Verification.' : 'Enter keeps defaults · Ctrl+U clears'), { dimColor: !error, color: error ? 'red' : undefined }),
|
|
46
|
+
text('Enter next/connect · Tab edit · Esc cancel', { dimColor: true }));
|
|
47
|
+
}
|
|
48
|
+
function DscodeEmailPanel({ columns, rows, pick, close, gmail, imap }) {
|
|
49
|
+
const [snapshot, setSnapshot] = (0, import_react.useState)({ emails: [], rejected: 0 });
|
|
50
|
+
const [error, setError] = (0, import_react.useState)('');
|
|
51
|
+
const [selected, setSelected] = (0, import_react.useState)(null);
|
|
52
|
+
const [offset, setOffset] = (0, import_react.useState)(0);
|
|
53
|
+
const [preview, setPreview] = (0, import_react.useState)(false);
|
|
54
|
+
const [gmailStatus, setGmailStatus] = (0, import_react.useState)(() => gmail.status());
|
|
55
|
+
const [imapStatus, setImapStatus] = (0, import_react.useState)(() => imap.status());
|
|
56
|
+
const [setup, setSetup] = (0, import_react.useState)(false);
|
|
57
|
+
const [connecting, setConnecting] = (0, import_react.useState)(false);
|
|
58
|
+
const operation = (0, import_react.useRef)(null);
|
|
59
|
+
(0, import_react.useEffect)(() => () => operation.current?.abort(), []);
|
|
60
|
+
const inbox = (0, import_react.useMemo)(() => dscodeCreateEmailInbox(), []);
|
|
61
|
+
const refresh = () => {
|
|
62
|
+
try { setSnapshot(inbox.list()); setGmailStatus(gmail.status()); setImapStatus(imap.status()); }
|
|
63
|
+
catch { setError('Could not read inbox. Press r to retry.'); }
|
|
64
|
+
};
|
|
65
|
+
(0, import_react.useEffect)(() => {
|
|
66
|
+
refresh();
|
|
67
|
+
const timer = setInterval(refresh, 2000);
|
|
68
|
+
return () => clearInterval(timer);
|
|
69
|
+
}, [inbox]);
|
|
70
|
+
const emails = snapshot.emails;
|
|
71
|
+
const index = Math.max(0, emails.findIndex(mail => dscodeEmailKey(mail) === selected));
|
|
72
|
+
const mail = emails[index];
|
|
73
|
+
(0, import_react.useEffect)(() => {
|
|
74
|
+
if (mail) setSelected(dscodeEmailKey(mail));
|
|
75
|
+
}, [mail && dscodeEmailKey(mail)]);
|
|
76
|
+
const height = Math.max(3, rows);
|
|
77
|
+
const contentRows = Math.max(1, height - 4);
|
|
78
|
+
const wide = columns >= 64;
|
|
79
|
+
const listWidth = wide ? Math.max(26, Math.floor(columns * 0.4)) : columns;
|
|
80
|
+
const previewWidth = wide ? Math.max(1, columns - listWidth - 1) : columns;
|
|
81
|
+
const clean = value => dscodeEmailText(value).replace(/\n/g, ' ');
|
|
82
|
+
const bodyLines = mail ? wrapText(dscodeEmailText(mail.body), Math.max(1, previewWidth - 2), 'wrap').split('\n') : [];
|
|
83
|
+
useStableInput((input, key) => {
|
|
84
|
+
if (setup) return;
|
|
85
|
+
if (key.escape || key.ctrl && input === 'c') { close(); return; }
|
|
86
|
+
if (input === 'i' && !operation.current) { setSetup(true); setError(''); return; }
|
|
87
|
+
if (input === 'g' || input === 'r') {
|
|
88
|
+
if (operation.current) return;
|
|
89
|
+
const controller = new AbortController(); operation.current = controller;
|
|
90
|
+
setError(''); setConnecting(input === 'g');
|
|
91
|
+
const action = input === 'g' ? gmail.connect({ signal: controller.signal }) : (imapStatus.connected ? imap : gmail).sync({ force: true, signal: controller.signal });
|
|
92
|
+
Promise.resolve(action).then(result => {
|
|
93
|
+
if (!controller.signal.aborted) { if (result.busy) setError('Gmail is busy in another session. Retry shortly.'); refresh(); }
|
|
94
|
+
}, reason => { if (!controller.signal.aborted) setError(reason.message); }).finally(() => {
|
|
95
|
+
operation.current = null;
|
|
96
|
+
if (!controller.signal.aborted) setConnecting(false);
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (key.tab) { setPreview(current => !current); return; }
|
|
101
|
+
if (!mail) return;
|
|
102
|
+
if (key.upArrow || key.downArrow) {
|
|
103
|
+
const next = Math.max(0, Math.min(emails.length - 1, index + (key.upArrow ? -1 : 1)));
|
|
104
|
+
setSelected(dscodeEmailKey(emails[next])); setOffset(0); return;
|
|
105
|
+
}
|
|
106
|
+
if (key.pageDown || key.pageUp) {
|
|
107
|
+
setOffset(current => Math.max(0, Math.min(Math.max(0, bodyLines.length - contentRows + 2), current + (key.pageUp ? -1 : 1) * Math.max(1, contentRows - 2)))); return;
|
|
108
|
+
}
|
|
109
|
+
if (key.return) pick(mail);
|
|
110
|
+
});
|
|
111
|
+
if (setup) return (0, import_react.createElement)(Box, { height, overflow: 'hidden', flexDirection: 'column' },
|
|
112
|
+
(0, import_react.createElement)(DscodeImapSetup, { connector: imap, back: () => setSetup(false), done: () => { setSetup(false); refresh(); } }));
|
|
113
|
+
const text = (value, extra = {}) => (0, import_react.createElement)(Text, { wrap: 'truncate-end', ...extra }, value);
|
|
114
|
+
const start = Math.max(0, index - contentRows + 1);
|
|
115
|
+
const list = (0, import_react.createElement)(Box, { width: listWidth, flexDirection: 'column', overflow: 'hidden' },
|
|
116
|
+
text('Email · newest updates first', { bold: true }),
|
|
117
|
+
...emails.slice(start, start + contentRows).map((entry, i) => text(
|
|
118
|
+
(start + i === index ? '› ' : ' ') + entry.updatedAt.slice(5, 16).replace('T', ' ') + ' ' + clean(entry.subject),
|
|
119
|
+
{ key: dscodeEmailKey(entry), color: start + i === index ? 'cyan' : undefined })),
|
|
120
|
+
!mail ? text(error || 'No emails received.') : null);
|
|
121
|
+
return (0, import_react.createElement)(Box, { flexDirection: 'column', height, overflow: 'hidden' },
|
|
122
|
+
text(imapStatus.connected ? imapStatus.error || 'IMAP · ' + clean(imapStatus.account) + ' · ' + clean(imapStatus.mailbox) : connecting ? 'Gmail · Complete Google login in your browser · Esc cancels' : gmailStatus.error || (gmailStatus.connected ? 'Gmail · ' + clean(gmailStatus.account) + (gmailStatus.lastSyncAt ? ' · synced ' + new Date(gmailStatus.lastSyncAt).toLocaleTimeString() : ' · waiting for new mail') : 'Email not connected · i IMAP · g Google OAuth'), { dimColor: true }),
|
|
123
|
+
(0, import_react.createElement)(Box, { flexDirection: 'row', height: Math.max(1, height - 2) },
|
|
124
|
+
wide || preview ? (0, import_react.createElement)(Box, { width: previewWidth, marginRight: wide ? 1 : 0, flexDirection: 'column', overflow: 'hidden' },
|
|
125
|
+
text(mail ? clean(mail.subject) : 'Email preview', { bold: true }),
|
|
126
|
+
text(mail ? 'From: ' + clean(mail.from) : 'Waiting for a connector', { dimColor: true }),
|
|
127
|
+
...bodyLines.slice(offset, offset + Math.max(1, contentRows - 1)).map((line, i) => text(line, { key: i }))) : null,
|
|
128
|
+
wide || !preview ? list : null),
|
|
129
|
+
text(error || (snapshot.rejected ? snapshot.rejected + ' invalid records skipped · ' : '') + (wide ? '↑↓ select · Enter steer · Esc · PgUp/Dn · i IMAP · g OAuth · r sync' : '↑↓ Enter · Tab · i IMAP · r sync'), { dimColor: true }));
|
|
130
|
+
}
|
|
131
|
+
// dscode-effort-bar-v6
|
|
132
|
+
// dscode-welcome-v1
|
|
133
|
+
function welcomePath(path, width) {
|
|
134
|
+
const full = singleLineText(path || '');
|
|
135
|
+
if (visibleColumns(full) <= width) return full;
|
|
136
|
+
const segments = full.split(/[\\/]/).filter(Boolean);
|
|
137
|
+
let suffix = '';
|
|
138
|
+
for (let index = segments.length - 1; index >= 0; index--) {
|
|
139
|
+
const candidate = '/' + segments[index] + suffix;
|
|
140
|
+
if (visibleColumns('…' + candidate) > width) break;
|
|
141
|
+
suffix = candidate;
|
|
142
|
+
}
|
|
143
|
+
return suffix ? '…' + suffix : '…' + truncateColumns(segments.at(-1) || full, Math.max(1, width - 1));
|
|
144
|
+
}
|
|
145
|
+
// dscode-viewport-v1
|
|
146
|
+
function visibleSettledLines(entries, settled, budget, columns, showReasoning, renderEntry) {
|
|
147
|
+
if (budget <= 0) return [];
|
|
148
|
+
const chunks = [];
|
|
149
|
+
let remaining = budget;
|
|
150
|
+
for (let index = settled - 1; index >= 0 && remaining > 0; index--) {
|
|
151
|
+
const lines = renderEntry(entries[index], Math.max(10, columns - 2), showReasoning);
|
|
152
|
+
const kept = lines.slice(-remaining);
|
|
153
|
+
if (kept.length) {
|
|
154
|
+
chunks.unshift(kept);
|
|
155
|
+
remaining -= kept.length;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return chunks.flat();
|
|
159
|
+
}
|
|
1
160
|
// dscode-style-v1
|
|
2
161
|
|
|
3
162
|
function dscodeActivity(entries, streaming) {
|
|
@@ -29,10 +188,8 @@ function DscodeActivityLine({ entries, streaming, since, animated = true }) {
|
|
|
29
188
|
(0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, suffix)));
|
|
30
189
|
}
|
|
31
190
|
|
|
32
|
-
// dscode-
|
|
33
|
-
|
|
34
|
-
return message.source.kind === "plugin" && message.source.plugin === "dscode-session-bridge" && message.source.form === "relay";
|
|
35
|
-
}
|
|
191
|
+
// dscode-footer-v1
|
|
192
|
+
import { footerFor as dscodeFooterFor } from "../../plugins/session-metrics/view.mjs";
|
|
36
193
|
// dscode-ime-v1
|
|
37
194
|
const dscodeImeAnchors = new WeakMap();
|
|
38
195
|
function imePosition(anchor, height, columns) {
|
|
@@ -72,6 +229,10 @@ function imeWriter(stream, anchors) {
|
|
|
72
229
|
}
|
|
73
230
|
};
|
|
74
231
|
}
|
|
232
|
+
// dscode-session-relay-v1
|
|
233
|
+
function dscodeVisibleRelay(message) {
|
|
234
|
+
return message.source.kind === "plugin" && message.source.plugin === "dscode-session-bridge" && message.source.form === "relay";
|
|
235
|
+
}
|
|
75
236
|
// dscode-interaction-v1
|
|
76
237
|
function dscodeChatLines(entry, columns) {
|
|
77
238
|
if (entry.kind === "tool") return [];
|
|
@@ -81,8 +242,6 @@ function dscodeChatLines(entry, columns) {
|
|
|
81
242
|
}
|
|
82
243
|
return transcriptEntryLines(entry, columns, false, false, false);
|
|
83
244
|
}
|
|
84
|
-
// dscode-footer-v1
|
|
85
|
-
import { footerFor as dscodeFooterFor } from "../../plugins/session-metrics/view.mjs";
|
|
86
245
|
import { n as __require, r as __toESM, t as __commonJSMin } from "./rolldown-runtime-CMFfr-1z.mjs";
|
|
87
246
|
import { a as inkColor, c as chalk, i as getTheme, n as dim, o as parseThemeName, r as getPalette, s as setTheme } from "./theme-DCT8Y2xf.mjs";
|
|
88
247
|
import { randomUUID } from "node:crypto";
|
|
@@ -30325,7 +30484,7 @@ function StatuslinePanel({ enabled, change, close }) {
|
|
|
30325
30484
|
* instead of a bare failure notice. Enter applies one level; Esc returns to
|
|
30326
30485
|
* the model list without applying.
|
|
30327
30486
|
*/
|
|
30328
|
-
function
|
|
30487
|
+
function NativeEffortPanel({ row, current, select, back, onExit }) {
|
|
30329
30488
|
const advertised = row.reasoning?.efforts ?? [];
|
|
30330
30489
|
const empty = row.reasoning === void 0 || advertised.length === 0;
|
|
30331
30490
|
const hasDefaultRow = row.reasoning !== void 0 && row.reasoning.defaultEffort === void 0;
|
|
@@ -30385,6 +30544,142 @@ function EffortPanel({ row, current, select, back, onExit }) {
|
|
|
30385
30544
|
footer: empty ? "esc back" : "↑↓ choose · enter apply · esc/q back"
|
|
30386
30545
|
});
|
|
30387
30546
|
}
|
|
30547
|
+
function dscodeEffortCenter(label, width) {
|
|
30548
|
+
const left = Math.floor((width - label.length) / 2);
|
|
30549
|
+
return ' '.repeat(left) + label + ' '.repeat(width - left - label.length);
|
|
30550
|
+
}
|
|
30551
|
+
function dscodeRippleTone(position, center, frame, palette) {
|
|
30552
|
+
const distance = Math.abs(position - center);
|
|
30553
|
+
const radius = frame * 3;
|
|
30554
|
+
return Math.abs(distance - radius) < 3 ? palette.brandBright : distance < radius ? palette.brandMid : palette.brandDeep;
|
|
30555
|
+
}
|
|
30556
|
+
function DscodeUltraRipple({ columns }) {
|
|
30557
|
+
const palette = getPalette();
|
|
30558
|
+
const width = Math.max(1, columns - 5);
|
|
30559
|
+
const tick = useFrames(55, true);
|
|
30560
|
+
const center = (width - 1) / 2;
|
|
30561
|
+
const settled = tick > Math.ceil(width / 6) + 2;
|
|
30562
|
+
const label = dscodeEffortCenter(truncateColumns('✦ ULTRA · max reasoning + focused collaboration', width), width);
|
|
30563
|
+
const rippleLine = (lag) => {
|
|
30564
|
+
const frame = Math.max(0, tick - lag);
|
|
30565
|
+
return (0, import_react.createElement)(Text, { wrap: 'truncate-end' },
|
|
30566
|
+
...Array.from({ length: width }, (_, index) => (0, import_react.createElement)(Text, {
|
|
30567
|
+
key: index,
|
|
30568
|
+
color: inkColor(settled ? palette.brandDeep : dscodeRippleTone(index, center, frame, palette))
|
|
30569
|
+
}, !settled && (index === Math.floor(center - frame * 3) || index === Math.ceil(center + frame * 3)) ? '✦' : '─')));
|
|
30570
|
+
};
|
|
30571
|
+
return (0, import_react.createElement)(Box, {
|
|
30572
|
+
width: Math.max(1, columns - 1), paddingX: 2, flexDirection: 'column'
|
|
30573
|
+
}, rippleLine(0), (0, import_react.createElement)(Text, { wrap: 'truncate-end' },
|
|
30574
|
+
...Array.from(label, (letter, index) => (0, import_react.createElement)(Text, {
|
|
30575
|
+
key: index,
|
|
30576
|
+
color: inkColor(settled ? palette.brandBright : dscodeRippleTone(index, center, Math.max(0, tick - 1), palette)),
|
|
30577
|
+
bold: settled || Math.abs(Math.abs(index - center) - Math.max(0, tick - 1) * 3) < 3
|
|
30578
|
+
}, letter))), rippleLine(2));
|
|
30579
|
+
}
|
|
30580
|
+
function DscodeEffortBar({ row, current, select, back, onExit, animations = true }) {
|
|
30581
|
+
const ids = ['low', 'high', 'max', 'ultra'];
|
|
30582
|
+
const advertised = row.reasoning.efforts;
|
|
30583
|
+
const defaultEffort = row.reasoning.defaultEffort;
|
|
30584
|
+
const initial = current || defaultEffort;
|
|
30585
|
+
const [cursor, setCursor] = (0, import_react.useState)(Math.max(0, ids.indexOf(initial)));
|
|
30586
|
+
useStableInput((input, key) => {
|
|
30587
|
+
if (key.ctrl && input === 'c') return onExit();
|
|
30588
|
+
if (key.escape || input === 'q') return back();
|
|
30589
|
+
if (key.leftArrow || key.upArrow) return setCursor(value => Math.max(0, value - 1));
|
|
30590
|
+
if (key.rightArrow || key.downArrow) return setCursor(value => Math.min(3, value + 1));
|
|
30591
|
+
if (input === 'g') return setCursor(0);
|
|
30592
|
+
if (input === 'G') return setCursor(3);
|
|
30593
|
+
if (input === 'o' && advertised.some(effort => effort.id === 'off')) return select('off');
|
|
30594
|
+
if (key.return) return select(ids[cursor]);
|
|
30595
|
+
}, true);
|
|
30596
|
+
const stdout = useStdout().stdout;
|
|
30597
|
+
const columns = stdout?.columns ?? 80;
|
|
30598
|
+
const rows = stdout?.rows ?? 30;
|
|
30599
|
+
const contentWidth = Math.max(1, columns - 5);
|
|
30600
|
+
const palette = getPalette();
|
|
30601
|
+
const selected = ids[cursor];
|
|
30602
|
+
const slot = Math.max(5, Math.min(14, Math.floor(contentWidth / 4)));
|
|
30603
|
+
const width = slot * 4;
|
|
30604
|
+
const barIndent = Math.max(0, Math.floor((contentWidth - width) / 2));
|
|
30605
|
+
const compact = rows < 16 || contentWidth < 24;
|
|
30606
|
+
const hasOff = advertised.some(effort => effort.id === 'off');
|
|
30607
|
+
if (compact) return (0, import_react.createElement)(Box, { flexDirection: 'column', paddingX: 2 },
|
|
30608
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.brandBright), wrap: 'truncate-end' },
|
|
30609
|
+
truncateColumns(ids.map(id => id === selected ? '[' + id + ']' : id).join(' '), contentWidth)),
|
|
30610
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.dim), wrap: 'truncate-end' },
|
|
30611
|
+
truncateColumns('←→ adjust · enter confirm · esc cancel', contentWidth)));
|
|
30612
|
+
const description = advertised.find(effort => effort.id === selected)?.description ?? '';
|
|
30613
|
+
const currentLabel = current || defaultEffort || 'default';
|
|
30614
|
+
const footer = '←/→ adjust · Enter confirm · Esc cancel' + (hasOff ? ' · o off' : '');
|
|
30615
|
+
const trackNode = Math.floor((slot - 1) / 2);
|
|
30616
|
+
const pointerColumn = barIndent + cursor * slot + trackNode;
|
|
30617
|
+
return (0, import_react.createElement)(Box, {
|
|
30618
|
+
width: Math.max(1, columns - 1),
|
|
30619
|
+
flexDirection: 'column',
|
|
30620
|
+
paddingX: 2
|
|
30621
|
+
},
|
|
30622
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.brandDeep) }, '─'.repeat(contentWidth)),
|
|
30623
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.dim) },
|
|
30624
|
+
'Faster' + ' '.repeat(Math.max(1, contentWidth - 6 - 7)) + 'Smarter'),
|
|
30625
|
+
(0, import_react.createElement)(Box, { flexDirection: 'row', width, marginLeft: barIndent }, ...ids.map((id, index) => {
|
|
30626
|
+
const node = index === cursor ? id === 'ultra' ? '✦' : '◆' : '●';
|
|
30627
|
+
const track = '━'.repeat(trackNode) + node + '━'.repeat(slot - trackNode - 1);
|
|
30628
|
+
const tone = index === cursor ? palette.brandBright : index < cursor ? palette.brandMid : palette.dim;
|
|
30629
|
+
return (0, import_react.createElement)(Text, { key: id, color: inkColor(tone) }, track);
|
|
30630
|
+
})),
|
|
30631
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.brandBright) }, ' '.repeat(pointerColumn) + '▲'),
|
|
30632
|
+
(0, import_react.createElement)(Box, { flexDirection: 'row', width, marginLeft: barIndent }, ...ids.map((id, index) =>
|
|
30633
|
+
(0, import_react.createElement)(Text, {
|
|
30634
|
+
key: id,
|
|
30635
|
+
color: inkColor(index === cursor ? palette.brandBright : palette.dim),
|
|
30636
|
+
bold: index === cursor
|
|
30637
|
+
}, dscodeEffortCenter(id, slot)))),
|
|
30638
|
+
selected === 'ultra' ? (0, import_react.createElement)(DscodeUltraFocus, { width: contentWidth, animations }) :
|
|
30639
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.text), wrap: 'truncate-end' },
|
|
30640
|
+
truncateColumns('current ' + currentLabel + ' · ' + description, contentWidth)),
|
|
30641
|
+
(0, import_react.createElement)(Text, { color: inkColor(palette.dim), wrap: 'truncate-end' },
|
|
30642
|
+
truncateColumns(footer, contentWidth)));
|
|
30643
|
+
}
|
|
30644
|
+
function DscodeUltraFocus({ width, animations }) {
|
|
30645
|
+
const palette = getPalette();
|
|
30646
|
+
const [frame, setFrame] = (0, import_react.useState)(0);
|
|
30647
|
+
const lastFrame = Math.ceil(width / 6) + 2;
|
|
30648
|
+
(0, import_react.useEffect)(() => {
|
|
30649
|
+
if (!animations) return;
|
|
30650
|
+
let step = 0;
|
|
30651
|
+
const timer = setInterval(() => {
|
|
30652
|
+
step++;
|
|
30653
|
+
setFrame(step);
|
|
30654
|
+
if (step >= lastFrame) clearInterval(timer);
|
|
30655
|
+
}, 55);
|
|
30656
|
+
return () => clearInterval(timer);
|
|
30657
|
+
}, [animations, lastFrame]);
|
|
30658
|
+
const label = dscodeEffortCenter(truncateColumns('✦ ULTRA ✦', width), width);
|
|
30659
|
+
const center = (width - 1) / 2;
|
|
30660
|
+
const settled = !animations || frame >= lastFrame;
|
|
30661
|
+
const first = label.length - label.trimStart().length;
|
|
30662
|
+
const last = label.trimEnd().length - 1;
|
|
30663
|
+
return (0, import_react.createElement)(Text, { wrap: 'truncate-end' },
|
|
30664
|
+
...Array.from(label, (letter, index) => {
|
|
30665
|
+
const outer = index < first || index > last;
|
|
30666
|
+
const burst = animations && !settled && outer &&
|
|
30667
|
+
(index === Math.floor(center - frame * 3) || index === Math.ceil(center + frame * 3));
|
|
30668
|
+
return (0, import_react.createElement)(Text, {
|
|
30669
|
+
key: index,
|
|
30670
|
+
color: inkColor(settled ? outer ? palette.brandDeep : palette.brandBright : dscodeRippleTone(index, center, frame, palette)),
|
|
30671
|
+
bold: burst || letter !== ' ' && (settled || Math.abs(Math.abs(index - center) - frame * 3) < 3)
|
|
30672
|
+
}, burst ? '✦' : outer ? '─' : letter);
|
|
30673
|
+
}));
|
|
30674
|
+
}
|
|
30675
|
+
function EffortPanel(props) {
|
|
30676
|
+
const reasoning = props.row.reasoning;
|
|
30677
|
+
const ids = reasoning?.efforts.map(effort => effort.id) ?? [];
|
|
30678
|
+
const barIds = ['low', 'high', 'max', 'ultra'];
|
|
30679
|
+
const barCatalog = reasoning?.defaultEffort !== undefined &&
|
|
30680
|
+
barIds.every(id => ids.includes(id)) && ids.every(id => id === 'off' || barIds.includes(id));
|
|
30681
|
+
return (0, import_react.createElement)(barCatalog ? DscodeEffortBar : NativeEffortPanel, props);
|
|
30682
|
+
}
|
|
30388
30683
|
/**
|
|
30389
30684
|
* The /agents panel (the Codex agent-picker contract, read-only): this
|
|
30390
30685
|
* conversation's subagent conversations — live rows from the activity feed
|
|
@@ -31357,6 +31652,8 @@ function readSettledRowCap() {
|
|
|
31357
31652
|
const SYNCHRONIZED_UPDATE_END = "\x1B[?2026l";
|
|
31358
31653
|
/** One source of truth for TUI-owned slash commands in completion and `/help`. */
|
|
31359
31654
|
const LOCAL_COMMANDS = [
|
|
31655
|
+
{ label: "/email", description: "browse email and steer into this session" },
|
|
31656
|
+
{ label: "/login", description: "save a DeepSeek API key locally" },
|
|
31360
31657
|
// dscode: startup command discovery
|
|
31361
31658
|
{"label":"/status","description":"session, model, permissions and usage"},
|
|
31362
31659
|
{"label":"/doctor","description":"read-only runtime diagnostics"},
|
|
@@ -31766,20 +32063,45 @@ function PanelGap({ visible }) {
|
|
|
31766
32063
|
* keeps its historical three lines. Short or narrow terminals keep a one-line
|
|
31767
32064
|
* form without the kernel line.
|
|
31768
32065
|
*/
|
|
31769
|
-
function Header({
|
|
31770
|
-
const
|
|
31771
|
-
const
|
|
31772
|
-
const
|
|
31773
|
-
const
|
|
31774
|
-
const
|
|
31775
|
-
|
|
31776
|
-
|
|
31777
|
-
|
|
32066
|
+
function Header({ cwd = "", model = "", effort = "" }) {
|
|
32067
|
+
const stdout = useStdout().stdout;
|
|
32068
|
+
const columns = stdout?.columns ?? 80;
|
|
32069
|
+
const full = (stdout?.rows ?? 30) >= 24 && columns >= 64;
|
|
32070
|
+
const width = Math.max(1, full ? Math.min(columns - 2, 84) : columns - 4);
|
|
32071
|
+
const contentWidth = Math.max(1, width - (full ? 4 : 0));
|
|
32072
|
+
const detailsWidth = Math.max(1, contentWidth - (full ? 28 : 0));
|
|
32073
|
+
const modelName = singleLineText(model).split("/").at(-1) || "unknown";
|
|
32074
|
+
const effortName = singleLineText(effort) || "default";
|
|
32075
|
+
const project = welcomePath(cwd, detailsWidth);
|
|
32076
|
+
if (!full) return (0, import_react.createElement)(Box, { flexDirection: "column", paddingX: 2, marginBottom: 1 },
|
|
32077
|
+
(0, import_react.createElement)(Text, { wrap: "truncate-end" },
|
|
32078
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright), bold: true }, "❄ DSCODE"),
|
|
32079
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, " v0.4.0")),
|
|
32080
|
+
(0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(modelName + " · " + effortName, width)),
|
|
32081
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().dim), wrap: "truncate-end" }, welcomePath(cwd, width)));
|
|
32082
|
+
return (0, import_react.createElement)(Box, { flexDirection: "column", width, borderStyle: "round", borderColor: inkColor(getPalette().brand), paddingX: 1, marginBottom: 1 },
|
|
32083
|
+
(0, import_react.createElement)(Box, { flexDirection: "row" },
|
|
32084
|
+
(0, import_react.createElement)(Box, { flexDirection: "column", width: 28 },
|
|
32085
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▄"),
|
|
32086
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " █▄▄█ █▄█▄█ █▄▄█"),
|
|
32087
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▄███▄ ▀█▀ ▄███▄"),
|
|
32088
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▀██▄ █ ▄██▀"),
|
|
32089
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▄███▄"),
|
|
32090
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▀███▀"),
|
|
32091
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▄██▀ █ ▀██▄"),
|
|
32092
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▀███▀ ▄█▄ ▀███▀"),
|
|
32093
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " █▀▀█ █▀█▀█ █▀▀█"),
|
|
32094
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, " ▀")),
|
|
32095
|
+
(0, import_react.createElement)(Box, { flexDirection: "column", width: detailsWidth, marginTop: 2 },
|
|
32096
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().text), bold: true }, "DSCODE"),
|
|
32097
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().brandDeep) }, "────────────"),
|
|
32098
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, "v0.4.0"),
|
|
32099
|
+
(0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns("model " + modelName, detailsWidth)),
|
|
32100
|
+
(0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns("effort " + effortName, detailsWidth)),
|
|
32101
|
+
(0, import_react.createElement)(Text, null, " "),
|
|
32102
|
+
(0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, "project"),
|
|
32103
|
+
(0, import_react.createElement)(Text, { wrap: "truncate-end" }, project))));
|
|
31778
32104
|
}
|
|
31779
|
-
/** Todo status glyph: web TodoPanel's three-state marker. */
|
|
31780
|
-
function todoMark(status) {
|
|
31781
|
-
return status === "completed" ? "✓" : status === "in_progress" ? "●" : "○";
|
|
31782
|
-
}
|
|
31783
32105
|
/**
|
|
31784
32106
|
* One-row live subagent summary (the Codex agent status feed, compressed to
|
|
31785
32107
|
* the transcript's budget): running count, the observed total (the row cap
|
|
@@ -32841,6 +33163,56 @@ function ProviderPanel({ directory, error, authorizations, authorizationError, o
|
|
|
32841
33163
|
wrap: "truncate-end"
|
|
32842
33164
|
}, truncateColumns("↑↓ move · enter configure · l login · o logout · d remove key · x remove provider · r retry · esc back", viewport.contentColumns)));
|
|
32843
33165
|
}
|
|
33166
|
+
// dscode-login-v1
|
|
33167
|
+
function DscodeLoginPanel({ load, save, done, back }) {
|
|
33168
|
+
const [draft, setDraft] = (0, import_react.useState)("");
|
|
33169
|
+
const [target, setTarget] = (0, import_react.useState)(void 0);
|
|
33170
|
+
const [error, setError] = (0, import_react.useState)("");
|
|
33171
|
+
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
33172
|
+
const saving = (0, import_react.useRef)(false);
|
|
33173
|
+
(0, import_react.useEffect)(() => {
|
|
33174
|
+
let active = true;
|
|
33175
|
+
Promise.resolve().then(() => load()).then(directory => {
|
|
33176
|
+
if (!active) return;
|
|
33177
|
+
const row = directory.rows.find(row => row.provider === "deepseek-official");
|
|
33178
|
+
if (!row || !save) { setError("DeepSeek credential storage is unavailable."); return; }
|
|
33179
|
+
if (row.credential?.kind !== "facts") { setError("Could not read credential status. Check local file permissions."); return; }
|
|
33180
|
+
if (!row.credential.writable) { setError("DEEPSEEK_API_KEY is set by your environment. Remove it and restart to use /login."); return; }
|
|
33181
|
+
setTarget(row);
|
|
33182
|
+
}, () => { if (active) setError("Could not load DeepSeek credential settings."); });
|
|
33183
|
+
return () => { active = false; };
|
|
33184
|
+
}, [load, save]);
|
|
33185
|
+
useStableInput((input, key) => {
|
|
33186
|
+
if (saving.current) return;
|
|
33187
|
+
if (key.escape || key.ctrl && input === "c") { setDraft(""); back(); return; }
|
|
33188
|
+
if (!target) return;
|
|
33189
|
+
if (key.return) {
|
|
33190
|
+
const raw = draft.trim();
|
|
33191
|
+
if (!raw || /[\s\x00-\x1f\x7f-\uffff]/.test(raw) || ENV_ASSIGNMENT.test(raw) || hasWrappingQuotes(raw)) {
|
|
33192
|
+
setError("Paste only the API key, without quotes, spaces or an environment-variable name."); return;
|
|
33193
|
+
}
|
|
33194
|
+
saving.current = true; setBusy(true); setError(""); setDraft("");
|
|
33195
|
+
Promise.resolve().then(() => save(target, raw)).then(done, () => {
|
|
33196
|
+
saving.current = false; setBusy(false);
|
|
33197
|
+
setError("Could not save the API key. Check file permissions and available disk space, then paste again.");
|
|
33198
|
+
});
|
|
33199
|
+
return;
|
|
33200
|
+
}
|
|
33201
|
+
if (key.ctrl && input === "u") { setDraft(""); setError(""); return; }
|
|
33202
|
+
if (key.backspace || key.delete) { setDraft(current => [...current].slice(0, -1).join("")); return; }
|
|
33203
|
+
if (key.ctrl || key.meta || !input) return;
|
|
33204
|
+
const pasted = stripPasteMarkers(input);
|
|
33205
|
+
setDraft(current => (current + pasted).slice(0, 4096));
|
|
33206
|
+
setError("");
|
|
33207
|
+
});
|
|
33208
|
+
return (0, import_react.createElement)(Box, { flexDirection: "column", paddingX: 2 },
|
|
33209
|
+
(0, import_react.createElement)(Text, { bold: true }, "DeepSeek login"),
|
|
33210
|
+
(0, import_react.createElement)(Text, { dimColor: true }, "Saved on this Mac in ~/.dscode/credentials.yaml"),
|
|
33211
|
+
(0, import_react.createElement)(Text, null, busy ? "Saving…" : target ? "API key › " + (draft ? "••••••••" : "paste your key") : error ? "" : "Loading…"),
|
|
33212
|
+
error ? (0, import_react.createElement)(Text, { color: "red" }, error) : void 0,
|
|
33213
|
+
(0, import_react.createElement)(Text, { dimColor: true }, "Enter save · Esc cancel · Ctrl+U clear"));
|
|
33214
|
+
}
|
|
33215
|
+
|
|
32844
33216
|
function ProviderSetupPanel({ target, save, saveCredential, discover, effortDonors, done, back, onExit }) {
|
|
32845
33217
|
const stdout = useStdout().stdout;
|
|
32846
33218
|
const viewport = panelViewport(stdout?.columns ?? 80, stdout?.rows ?? 30);
|
|
@@ -33968,7 +34340,7 @@ function CompletionMenu({ active, mention, index, rows, error }) {
|
|
|
33968
34340
|
* While a modal (approval / question / model panel) owns the keys, the
|
|
33969
34341
|
* box passes every key through untouched.
|
|
33970
34342
|
*/
|
|
33971
|
-
function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, interrupt, quit, openModel, openEffort, openHelp, openMode, openPermission, openResume, openPlugin, openJobs, openStatusline, openTheme, openHistory, openAgents, openSubagent, openTodos, openDelete, openDiff, reviewChanges, deleteConfirm, confirmDelete, cancelDelete, createSession, forkSession, cancelSessionSwitch, notify, applyEditorKeys, hasNotice, dismissNotice, toggleReasoning, openVerbose, clearView, refresh, loadMentions, inspectImages, prepareImages, inspectFiles, prepareFiles, cyclePermission, exportTranscript, renameTitle, copyLastResponse, recallSpace, recordLocal, recordHistory, queued, cancelQueued, historyFill, historyConsumed, animations, applyAnimations, waveTier, waveStyle, maxRows, onEditorRows, onMenuRows, sessionKey }) {
|
|
34343
|
+
function Input({ effortSurface, ultraPulse, active, frozen, busy, descriptors, skills, dispatch, steer, interrupt, quit, openEmail, emailFill, emailConsumed, openLogin, openModel, openEffort, openHelp, openMode, openPermission, openResume, openPlugin, openJobs, openStatusline, openTheme, openHistory, openAgents, openSubagent, openTodos, openDelete, openDiff, reviewChanges, deleteConfirm, confirmDelete, cancelDelete, createSession, forkSession, cancelSessionSwitch, notify, applyEditorKeys, hasNotice, dismissNotice, toggleReasoning, openVerbose, clearView, refresh, loadMentions, inspectImages, prepareImages, inspectFiles, prepareFiles, cyclePermission, exportTranscript, renameTitle, copyLastResponse, recallSpace, recordLocal, recordHistory, queued, cancelQueued, historyFill, historyConsumed, animations, applyAnimations, waveTier, waveStyle, maxRows, onEditorRows, onMenuRows, sessionKey }) {
|
|
33972
34344
|
const columns = useStdout().stdout?.columns ?? 80;
|
|
33973
34345
|
const inputTerminalRows = useStdout().stdout?.rows ?? 30;
|
|
33974
34346
|
const dscodeImeStdout = useStdout().stdout;
|
|
@@ -34001,6 +34373,16 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
34001
34373
|
prepareEpochRef.current += 1;
|
|
34002
34374
|
prepareAbortRef.current?.abort();
|
|
34003
34375
|
}, []);
|
|
34376
|
+
|
|
34377
|
+
(0, import_react.useEffect)(() => {
|
|
34378
|
+
if (!emailFill) return;
|
|
34379
|
+
if (emailFill.sessionKey === sessionKey) {
|
|
34380
|
+
const next = valueRef.current + (valueRef.current ? "\n\n" : "") + sanitizeDraftText(emailFill.text);
|
|
34381
|
+
valueRef.current = next; cursorRef.current = next.length;
|
|
34382
|
+
setValue(next); setCursor(next.length); setDismissedMenuValue(void 0);
|
|
34383
|
+
}
|
|
34384
|
+
emailConsumed();
|
|
34385
|
+
}, [emailFill, sessionKey, emailConsumed]);
|
|
34004
34386
|
const killRef = (0, import_react.useRef)("");
|
|
34005
34387
|
const preferredColumnRef = (0, import_react.useRef)(null);
|
|
34006
34388
|
const editorScrollRef = (0, import_react.useRef)(0);
|
|
@@ -34493,6 +34875,21 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
34493
34875
|
}
|
|
34494
34876
|
const trimmed = liveValue.trim();
|
|
34495
34877
|
const text = submissionPayload(liveValue);
|
|
34878
|
+
if (/^\/email(?:\s|$)/.test(trimmed)) {
|
|
34879
|
+
if (trimmed !== "/email") { notify("Use /email to open the inbox.", "warning"); return; }
|
|
34880
|
+
valueRef.current = ""; cursorRef.current = 0;
|
|
34881
|
+
setValue(""); setCursor(0); setCompletionIndex(0); setDismissedMenuValue(void 0);
|
|
34882
|
+
recall.current = beginRecall(recallSpace, "");
|
|
34883
|
+
openEmail(); return;
|
|
34884
|
+
}
|
|
34885
|
+
if (/^\/login(?:\s|$)/.test(trimmed)) {
|
|
34886
|
+
valueRef.current = ""; cursorRef.current = 0;
|
|
34887
|
+
setValue(""); setCursor(0); setCompletionIndex(0); setDismissedMenuValue(void 0);
|
|
34888
|
+
recall.current = beginRecall(recallSpace, "");
|
|
34889
|
+
if (trimmed !== "/login") { notify("Use /login alone, then paste the key in the private input.", "warning"); return; }
|
|
34890
|
+
if (busy) { notify("Stop the running turn before /login.", "warning"); return; }
|
|
34891
|
+
openLogin(); return;
|
|
34892
|
+
}
|
|
34496
34893
|
if (draftImagesRef.current.length > 0 || draftFilesRef.current.length > 0) {
|
|
34497
34894
|
if (isSlashLine(text)) notify("commands cannot carry attachments; the line will be sent to the model as a prompt", "warning");
|
|
34498
34895
|
const originSession = sessionKey;
|
|
@@ -34835,6 +35232,8 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
34835
35232
|
flexDirection: "column",
|
|
34836
35233
|
width: bandWidth
|
|
34837
35234
|
}, (0, import_react.createElement)(Text, { backgroundColor: bandBg }, " ".repeat(bandWidth)), content, (0, import_react.createElement)(Text, { backgroundColor: bandBg }, " ".repeat(bandWidth)));
|
|
35235
|
+
if (effortSurface !== void 0) return effortSurface;
|
|
35236
|
+
if (ultraPulse !== 0 && animations) return (0, import_react.createElement)(DscodeUltraRipple, { key: ultraPulse, columns });
|
|
34838
35237
|
if (frozen) {
|
|
34839
35238
|
if (deleteConfirm !== void 0) {
|
|
34840
35239
|
const warning = "y delete · any other key cancels";
|
|
@@ -35066,6 +35465,18 @@ function computeSettledRows(previous, entries, settled, showReasoning, resumed,
|
|
|
35066
35465
|
}
|
|
35067
35466
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
35068
35467
|
function App(props) {
|
|
35468
|
+
const gmail = (0, import_react.useMemo)(() => dscodeCreateGmailConnector(), []);
|
|
35469
|
+
const imap = (0, import_react.useMemo)(() => dscodeCreateImapConnector(), []);
|
|
35470
|
+
(0, import_react.useEffect)(() => {
|
|
35471
|
+
const controller = new AbortController();
|
|
35472
|
+
const sync = () => (imap.status().connected ? imap : gmail).sync({ signal: controller.signal }).catch(() => {});
|
|
35473
|
+
sync(); const timer = setInterval(sync, 30000);
|
|
35474
|
+
return () => { clearInterval(timer); controller.abort(); };
|
|
35475
|
+
}, [gmail, imap]);
|
|
35476
|
+
const [emailOpen, setEmailOpen] = (0, import_react.useState)(false);
|
|
35477
|
+
const [emailFill, setEmailFill] = (0, import_react.useState)(void 0);
|
|
35478
|
+
const emailConsumed = (0, import_react.useCallback)(() => setEmailFill(void 0), []);
|
|
35479
|
+
(0, import_react.useEffect)(() => { setEmailOpen(false); setEmailFill(void 0); }, [props.sessionKey]);
|
|
35069
35480
|
const view = (0, import_react.useSyncExternalStore)(props.store.subscribe, props.store.getView);
|
|
35070
35481
|
useStableInput(() => {}, true);
|
|
35071
35482
|
const readDescriptors = (0, import_react.useCallback)(() => props.commands.descriptors, [props.commands]);
|
|
@@ -35097,6 +35508,12 @@ function App(props) {
|
|
|
35097
35508
|
const [waveTier, setWaveTier] = (0, import_react.useState)(null);
|
|
35098
35509
|
const [waveStyle, setWaveStyle] = (0, import_react.useState)(null);
|
|
35099
35510
|
const [animations, setAnimations] = (0, import_react.useState)(props.animations ?? true);
|
|
35511
|
+
const [ultraPulse, setUltraPulse] = (0, import_react.useState)(0);
|
|
35512
|
+
(0, import_react.useEffect)(() => {
|
|
35513
|
+
if (ultraPulse === 0) return;
|
|
35514
|
+
const timer = setTimeout(() => setUltraPulse(0), 1100);
|
|
35515
|
+
return () => clearTimeout(timer);
|
|
35516
|
+
}, [ultraPulse]);
|
|
35100
35517
|
const applyAnimations = (enabled) => {
|
|
35101
35518
|
setAnimations(enabled);
|
|
35102
35519
|
props.saveAnimations?.(enabled);
|
|
@@ -35297,9 +35714,10 @@ function App(props) {
|
|
|
35297
35714
|
const agentRows = (0, import_react.useSyncExternalStore)(props.subagents.subscribe, props.subagents.getSnapshot);
|
|
35298
35715
|
const approvalPending = approvalSnapshot.pending !== void 0;
|
|
35299
35716
|
const questionPending = questionSnapshot.pending !== void 0;
|
|
35300
|
-
const inputActive = deleteConfirmId !== void 0 ? !approvalPending && !questionPending : !modelOpen && !helpOpen && !modeOpen && !permissionOpen && !resumeOpen && !pluginOpen && !jobsOpen && !statuslineOpen && !themeOpen && !historyOpen && !agentsOpen && !subagentOpen && !todosOpen && !verboseOpen && diffView === void 0 && !approvalPending && !questionPending;
|
|
35717
|
+
const inputActive = deleteConfirmId !== void 0 ? !approvalPending && !questionPending : !emailOpen && !modelOpen && !helpOpen && !modeOpen && !permissionOpen && !resumeOpen && !pluginOpen && !jobsOpen && !statuslineOpen && !themeOpen && !historyOpen && !agentsOpen && !subagentOpen && !todosOpen && !verboseOpen && diffView === void 0 && !approvalPending && !questionPending;
|
|
35301
35718
|
(0, import_react.useEffect)(() => {
|
|
35302
35719
|
if (!approvalPending && !questionPending) return;
|
|
35720
|
+
setEmailOpen(false);
|
|
35303
35721
|
setModelOpen(false);
|
|
35304
35722
|
setProviderOpen(false);
|
|
35305
35723
|
setProviderAction(void 0);
|
|
@@ -35325,19 +35743,6 @@ function App(props) {
|
|
|
35325
35743
|
rows: appStdout?.rows ?? 30
|
|
35326
35744
|
}));
|
|
35327
35745
|
const terminalSizeRef = (0, import_react.useRef)(terminalSize);
|
|
35328
|
-
const settledRowsCache = (0, import_react.useRef)(void 0);
|
|
35329
|
-
const settledRows = (0, import_react.useMemo)(() => {
|
|
35330
|
-
const result = computeSettledRows(settledRowsCache.current, view.entries, settled, showReasoning, props.resumed, refreshEpoch, terminalSize.columns, SETTLED_ROW_CAP, { cwd: props.cwd, branch: props.branch, title: view.title });
|
|
35331
|
-
settledRowsCache.current = result.cache;
|
|
35332
|
-
return result.cache.flat;
|
|
35333
|
-
}, [
|
|
35334
|
-
view.entries,
|
|
35335
|
-
settled,
|
|
35336
|
-
showReasoning,
|
|
35337
|
-
props.resumed,
|
|
35338
|
-
refreshEpoch,
|
|
35339
|
-
terminalSize.columns
|
|
35340
|
-
]);
|
|
35341
35746
|
const synchronizedReplayPending = (0, import_react.useRef)(false);
|
|
35342
35747
|
(0, import_react.useEffect)(() => {
|
|
35343
35748
|
if (appStdout === void 0) return;
|
|
@@ -35375,8 +35780,13 @@ function App(props) {
|
|
|
35375
35780
|
setMenuRows((current) => current === rows ? current : rows);
|
|
35376
35781
|
}, []);
|
|
35377
35782
|
const composerEditorCap = composerMaxRows(terminalRows);
|
|
35378
|
-
const
|
|
35379
|
-
const
|
|
35783
|
+
const transcriptVisible = !emailOpen && !modelOpen && !helpOpen && !modeOpen && !permissionOpen && !resumeOpen && !pluginOpen && !jobsOpen && !statuslineOpen && !themeOpen && !historyOpen && !agentsOpen && !subagentOpen && !todosOpen && !verboseOpen && diffView === void 0 && !approvalPending && !questionPending;
|
|
35784
|
+
const welcomeFull = terminalRows >= 24 && terminalColumns >= 64;
|
|
35785
|
+
const welcomeChromeRows = welcomeFull ? 22 : terminalRows >= 10 ? 13 : 10;
|
|
35786
|
+
const settledBudget = transcriptVisible ? Math.max(0, terminalRows - welcomeChromeRows - composerGutterRows - (composerRows - 1) - menuRows) : 0;
|
|
35787
|
+
const settledViewportRows = busy || view.streaming !== "" ? Math.floor(settledBudget / 3) : settledBudget;
|
|
35788
|
+
const renderedSettled = (0, import_react.useMemo)(() => visibleSettledLines(view.entries, settled, settledViewportRows, terminalColumns, showReasoning, settledEntryLines), [settled, view.entries[settled - 1], settledViewportRows, terminalColumns, showReasoning]);
|
|
35789
|
+
const dynamicRows = Math.max(0, settledBudget - settledViewportRows);
|
|
35380
35790
|
const streamingActive = view.streaming !== "";
|
|
35381
35791
|
const deepDivingVisible = busy;
|
|
35382
35792
|
const allLiveLines = (0, import_react.useMemo)(() => view.entries.slice(settled).flatMap((entry) => dscodeChatLines(entry, Math.max(1, terminalColumns - 2))), [
|
|
@@ -35385,11 +35795,11 @@ function App(props) {
|
|
|
35385
35795
|
terminalColumns,
|
|
35386
35796
|
showReasoning
|
|
35387
35797
|
]);
|
|
35388
|
-
const liveBudget = busy || streamingActive ? Math.max(1, Math.floor(dynamicRows / 3)) : Math.max(0, dynamicRows - (deepDivingVisible ? 1 : 0));
|
|
35798
|
+
const liveBudget = dynamicRows === 0 ? 0 : busy || streamingActive ? Math.max(1, Math.floor(dynamicRows / 3)) : Math.max(0, dynamicRows - (deepDivingVisible ? 1 : 0));
|
|
35389
35799
|
const visibleLiveLines = liveBudget === 0 ? [] : allLiveLines.slice(-liveBudget);
|
|
35390
35800
|
const streamRows = Math.max(1, dynamicRows - visibleLiveLines.length);
|
|
35391
35801
|
const reasoningRows = 0;
|
|
35392
|
-
const answerRows = view.streaming === "" ? 0 : Math.max(1, streamRows - reasoningRows);
|
|
35802
|
+
const answerRows = view.streaming === "" || dynamicRows === 0 ? 0 : Math.max(1, streamRows - reasoningRows);
|
|
35393
35803
|
const liveAudit = clampLiveAllocation({
|
|
35394
35804
|
live: visibleLiveLines.length,
|
|
35395
35805
|
reasoning: reasoningRows,
|
|
@@ -35402,8 +35812,8 @@ function App(props) {
|
|
|
35402
35812
|
const auditedLiveLines = liveAudit.allocation.live === visibleLiveLines.length ? visibleLiveLines : visibleLiveLines.slice(-liveAudit.allocation.live);
|
|
35403
35813
|
const auditedReasoningRows = liveAudit.allocation.reasoning;
|
|
35404
35814
|
const auditedAnswerRows = liveAudit.allocation.answer;
|
|
35405
|
-
|
|
35406
|
-
const modalVisible = modelOpen || helpOpen || modeOpen || permissionOpen || resumeOpen || pluginOpen || jobsOpen || statuslineOpen || themeOpen || historyOpen || agentsOpen || subagentOpen || todosOpen || verboseOpen && !approvalPending && !questionPending || diffView !== void 0 || approvalPending || questionPending;
|
|
35815
|
+
|
|
35816
|
+
const modalVisible = emailOpen || modelOpen || helpOpen || modeOpen || permissionOpen || resumeOpen || pluginOpen || jobsOpen || statuslineOpen || themeOpen || historyOpen || agentsOpen || subagentOpen || todosOpen || verboseOpen && !approvalPending && !questionPending || diffView !== void 0 || approvalPending || questionPending;
|
|
35407
35817
|
const closeInspector = (0, import_react.useCallback)(() => {
|
|
35408
35818
|
setVerboseOpen(false);
|
|
35409
35819
|
}, []);
|
|
@@ -35419,15 +35829,6 @@ function App(props) {
|
|
|
35419
35829
|
synchronizedReplayPending.current = false;
|
|
35420
35830
|
appStdout.write(SYNCHRONIZED_UPDATE_END);
|
|
35421
35831
|
}, [appStdout, refreshEpoch]);
|
|
35422
|
-
const settledNeedsTrim = settledRowsCache.current?.needsTrim === true;
|
|
35423
|
-
(0, import_react.useEffect)(() => {
|
|
35424
|
-
if (!settledNeedsTrim || busy || streamingActive) return;
|
|
35425
|
-
refreshScreen();
|
|
35426
|
-
}, [
|
|
35427
|
-
settledNeedsTrim,
|
|
35428
|
-
busy,
|
|
35429
|
-
streamingActive
|
|
35430
|
-
]);
|
|
35431
35832
|
const sessionHasImages = (0, import_react.useMemo)(() => view.entries.some((entry) => (entry.kind === "user" || entry.kind === "pending") && (entry.images?.length ?? 0) > 0), [view.entries]);
|
|
35432
35833
|
/** Apply one /model pick: record the selection, close the panel, report via notice. */
|
|
35433
35834
|
const applyModel = (row, effortId) => {
|
|
@@ -35435,6 +35836,7 @@ function App(props) {
|
|
|
35435
35836
|
const label = props.selectModel(row, effortId);
|
|
35436
35837
|
setModelLabel(label);
|
|
35437
35838
|
setEffortLabel(effortId);
|
|
35839
|
+
setUltraPulse(effortId === "ultra" && animations ? Date.now() : 0);
|
|
35438
35840
|
const selected = `${label}${effortId === void 0 || effortId === "" ? "" : `@${effortId}`}`;
|
|
35439
35841
|
if (sessionHasImages && row.inputModalities !== void 0 && !row.inputModalities.includes("image")) notify(`model → ${selected} · image history will be sent as text placeholders`, "warning");
|
|
35440
35842
|
else notify(`model → next step uses ${selected}`);
|
|
@@ -35488,7 +35890,13 @@ function App(props) {
|
|
|
35488
35890
|
}, [providerDirectory, directory]);
|
|
35489
35891
|
let modelSurface;
|
|
35490
35892
|
if (modelOpen && !approvalPending && !questionPending) {
|
|
35491
|
-
if (providerAction?.kind === "
|
|
35893
|
+
if (providerAction?.kind === "dscode-key") modelSurface = (0, import_react.createElement)(DscodeLoginPanel, {
|
|
35894
|
+
load: props.loadModelProviders,
|
|
35895
|
+
save: props.saveModelProviderCredential,
|
|
35896
|
+
done: () => { closeModelSurface(); reloadModelSurfaces(); notify("DeepSeek API key saved locally; ready to use."); },
|
|
35897
|
+
back: closeModelSurface
|
|
35898
|
+
});
|
|
35899
|
+
else if (providerAction?.kind === "login" && props.beginProviderAuthorization !== void 0 && props.cancelProviderAuthorization !== void 0 && props.openAuthorizationUrl !== void 0 && props.copyTextValue !== void 0) modelSurface = (0, import_react.createElement)(ProviderAuthorizationPanel, {
|
|
35492
35900
|
row: providerAction.authorization,
|
|
35493
35901
|
begin: props.beginProviderAuthorization,
|
|
35494
35902
|
cancel: () => props.cancelProviderAuthorization(providerAction.authorization),
|
|
@@ -35631,8 +36039,9 @@ function App(props) {
|
|
|
35631
36039
|
key: `${effortFor.provider}/${effortFor.model}`,
|
|
35632
36040
|
row: effortFor,
|
|
35633
36041
|
current: effortLabel,
|
|
36042
|
+
animations,
|
|
35634
36043
|
select: (effortId) => applyModel(effortFor, effortId),
|
|
35635
|
-
back:
|
|
36044
|
+
back: closeModelSurface,
|
|
35636
36045
|
onExit: closeModelSurface
|
|
35637
36046
|
});
|
|
35638
36047
|
else modelSurface = (0, import_react.createElement)(ModelPanel, {
|
|
@@ -35652,10 +36061,15 @@ function App(props) {
|
|
|
35652
36061
|
onClose: closeModelSurface
|
|
35653
36062
|
});
|
|
35654
36063
|
}
|
|
35655
|
-
return (0, import_react.createElement)(Box, { flexDirection: "column"
|
|
35656
|
-
|
|
35657
|
-
|
|
35658
|
-
|
|
36064
|
+
return (0, import_react.createElement)(Box, { flexDirection: "column", height: Math.max(1, terminalRows - 1) },
|
|
36065
|
+
!emailOpen && terminalRows >= 10 ? (0, import_react.createElement)(Header, { cwd: props.workspaceRoot ?? props.cwd, model: modelLabel, effort: effortLabel }) : (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright), bold: true }, "DSCODE"),
|
|
36066
|
+
emailOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(DscodeEmailPanel, {
|
|
36067
|
+
gmail, imap, columns: terminalColumns, rows: Math.max(3, terminalRows - 8 - composerGutterRows - composerRows),
|
|
36068
|
+
close: () => setEmailOpen(false),
|
|
36069
|
+
pick: mail => { props.steer(dscodeEmailPrompt(mail), [], props.sessionKey); setEmailOpen(false); }
|
|
36070
|
+
}) : void 0,
|
|
36071
|
+
transcriptVisible && settledViewportRows > 0 ? (0, import_react.createElement)(StyledRows, { lines: renderedSettled }) : void 0,
|
|
36072
|
+
transcriptVisible ? (0, import_react.createElement)(Box, { flexDirection: "column" }, auditedLiveLines.length === 0 ? void 0 : (0, import_react.createElement)(StyledRows, { lines: auditedLiveLines }), view.streamingReasoning !== "" && auditedReasoningRows > 0 ? showReasoning ? (0, import_react.createElement)(StreamTail, {
|
|
35659
36073
|
text: view.streamingReasoning,
|
|
35660
36074
|
prefix: "✻ ",
|
|
35661
36075
|
continuationPrefix: " ",
|
|
@@ -35693,7 +36107,7 @@ function App(props) {
|
|
|
35693
36107
|
notify,
|
|
35694
36108
|
interrupt: props.interrupt,
|
|
35695
36109
|
summarize: questionPending
|
|
35696
|
-
}), modelSurface, helpOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(HelpPanel, {
|
|
36110
|
+
}), effortFor !== void 0 ? void 0 : modelSurface, helpOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(HelpPanel, {
|
|
35697
36111
|
descriptors,
|
|
35698
36112
|
skills,
|
|
35699
36113
|
commandError: props.commands.error,
|
|
@@ -35799,7 +36213,7 @@ function App(props) {
|
|
|
35799
36213
|
setSubagentOpen(false);
|
|
35800
36214
|
},
|
|
35801
36215
|
close: () => setSubagentOpen(false)
|
|
35802
|
-
}) : void 0, notice === void 0 ? void 0 : (0, import_react.createElement)(NoticeLine, {
|
|
36216
|
+
}) : void 0, (0, import_react.createElement)(Box, { flexGrow: 1 }), notice === void 0 ? void 0 : (0, import_react.createElement)(NoticeLine, {
|
|
35803
36217
|
text: notice.text,
|
|
35804
36218
|
tone: notice.tone,
|
|
35805
36219
|
columns: terminalColumns
|
|
@@ -35807,6 +36221,8 @@ function App(props) {
|
|
|
35807
36221
|
flexDirection: "column",
|
|
35808
36222
|
marginTop: composerGutterRows
|
|
35809
36223
|
}, (0, import_react.createElement)(Input, {
|
|
36224
|
+
effortSurface: modelOpen && effortFor !== void 0 ? modelSurface : void 0,
|
|
36225
|
+
ultraPulse,
|
|
35810
36226
|
active: inputActive,
|
|
35811
36227
|
frozen: modalVisible,
|
|
35812
36228
|
busy,
|
|
@@ -35817,7 +36233,13 @@ function App(props) {
|
|
|
35817
36233
|
steer: props.steer,
|
|
35818
36234
|
interrupt: props.interrupt,
|
|
35819
36235
|
quit: props.quit,
|
|
35820
|
-
|
|
36236
|
+
openEmail: () => setEmailOpen(true),
|
|
36237
|
+
emailFill, emailConsumed,
|
|
36238
|
+
openLogin: () => {
|
|
36239
|
+
setProviderOpen(false); setEffortFor(void 0);
|
|
36240
|
+
setProviderAction({ kind: "dscode-key" }); setModelOpen(true);
|
|
36241
|
+
},
|
|
36242
|
+
openModel: () => {
|
|
35821
36243
|
setDirectory(void 0);
|
|
35822
36244
|
setModelError(void 0);
|
|
35823
36245
|
setProviderDirectory(void 0);
|
|
@@ -36210,7 +36632,8 @@ const internals = {
|
|
|
36210
36632
|
const focusReporting = isVsCodeTerminalEnv();
|
|
36211
36633
|
if (process.stdin.isTTY === true) process.stdin.setRawMode?.(true);
|
|
36212
36634
|
try {
|
|
36213
|
-
process.stdout.
|
|
36635
|
+
if (process.stdout.isTTY === true) process.stdout.write("\x1B[r\x1B[0m\x1B[H\x1B[2J\x1B[3J\x1B[H");
|
|
36636
|
+
process.stdout.write((keyboardEnhanced ? KEYBOARD_ENHANCE_ENABLE : "") + BRACKETED_PASTE_ENABLE + (focusReporting ? TERMINAL_FOCUS_REPORT_ENABLE : ""));
|
|
36214
36637
|
const tuiStdin = createSplitStdin(process.stdin);
|
|
36215
36638
|
const instance = render(element, {
|
|
36216
36639
|
exitOnCtrlC: false,
|