@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.
@@ -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-session-relay-v1
33
- function dscodeVisibleRelay(message) {
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 EffortPanel({ row, current, select, back, onExit }) {
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({ resumed, cwd = "", branch = "", title = "" }) {
31770
- const columns = useStdout().stdout?.columns ?? 80;
31771
- const width = Math.max(1, columns - 4);
31772
- const project = singleLineText(cwd).split(/[\\/]/).filter(Boolean).at(-1) || "workspace";
31773
- const identity = "DSCODE · " + project + (branch ? " / " + singleLineText(branch) : "");
31774
- const subtitle = title ? singleLineText(title) : resumed ? "Session resumed · /help" : "New session · /help";
31775
- return (0, import_react.createElement)(Box, { flexDirection: "column", paddingX: 2, marginBottom: 1 },
31776
- (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright), bold: true, wrap: "truncate-end" }, truncateColumns(identity, width)),
31777
- (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim), wrap: "truncate-end" }, truncateColumns(subtitle, width)));
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 MENU_RESERVE_ROWS = 5;
35379
- const dynamicRows = Math.max(1, terminalRows - 8 - MENU_RESERVE_ROWS - composerGutterRows - (composerRows - 1) - Math.max(0, menuRows - MENU_RESERVE_ROWS));
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
- const transcriptVisible = !modelOpen && !helpOpen && !modeOpen && !permissionOpen && !resumeOpen && !pluginOpen && !jobsOpen && !statuslineOpen && !themeOpen && !historyOpen && !agentsOpen && !subagentOpen && !todosOpen && !verboseOpen && diffView === void 0 && !approvalPending && !questionPending;
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 === "login" && props.beginProviderAuthorization !== void 0 && props.cancelProviderAuthorization !== void 0 && props.openAuthorizationUrl !== void 0 && props.copyTextValue !== void 0) modelSurface = (0, import_react.createElement)(ProviderAuthorizationPanel, {
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: () => setEffortFor(void 0),
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" }, (0, import_react.createElement)(MemoStaticTranscript, {
35656
- key: refreshEpoch,
35657
- items: settledRows
35658
- }), 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, {
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
- openModel: () => {
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.write((keyboardEnhanced ? KEYBOARD_ENHANCE_ENABLE : "") + BRACKETED_PASTE_ENABLE + (focusReporting ? TERMINAL_FOCUS_REPORT_ENABLE : ""));
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,