@toddzheng024/dscode-bundle 0.7.12 → 0.7.14
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/THIRD_PARTY_NOTICES.md +3 -3
- package/cordis.patch.yml +6 -2
- package/package.json +7 -5
- package/plugins/code-review/index.mjs +5 -2
- package/plugins/compaction/threshold.mjs +12 -0
- package/plugins/credentials/index.mjs +13 -0
- package/plugins/grok/adapter.mjs +114 -0
- package/plugins/grok/auth.mjs +76 -0
- package/plugins/grok/billing.mjs +146 -0
- package/plugins/grok/index.mjs +118 -0
- package/plugins/grok/models.mjs +129 -0
- package/plugins/grok/status.mjs +28 -0
- package/plugins/grok/wire.mjs +268 -0
- package/plugins/i18n/messages.mjs +6 -6
- package/plugins/providers/catalog.mjs +2 -0
- package/plugins/session-metrics/view.mjs +34 -3
- package/vendor/compaction-basic/index.js +91 -1
- package/vendor/persistent/index.js +10 -9
- package/vendor/terminal/index.js +5 -0
- package/vendor/tui/lib/app.mjs +6711 -0
- package/vendor/tui/lib/approval.mjs +122 -0
- package/vendor/tui/lib/attachments.mjs +218 -0
- package/vendor/tui/lib/authorization-panel.mjs +242 -0
- package/vendor/tui/lib/authorization.mjs +111 -0
- package/vendor/tui/lib/commands.mjs +123 -0
- package/vendor/tui/lib/dscode/chat.mjs +84 -0
- package/vendor/tui/lib/dscode/flags.mjs +32 -0
- package/vendor/tui/lib/dscode/model-search.mjs +68 -0
- package/vendor/tui/lib/dscode/paste.mjs +87 -0
- package/vendor/tui/lib/dscode/telemetry.mjs +82 -0
- package/vendor/tui/lib/dscode/welcome.mjs +100 -0
- package/vendor/tui/lib/editor-keys.mjs +346 -0
- package/vendor/tui/lib/editor.mjs +50 -0
- package/vendor/tui/lib/fork.mjs +24 -0
- package/vendor/tui/lib/git-workflow.mjs +278 -0
- package/vendor/tui/{types/history.d.ts → lib/history.mjs} +69 -26
- package/vendor/tui/{types/i18n.d.ts → lib/i18n.mjs} +23 -15
- package/vendor/tui/lib/index.mjs +2200 -0
- package/vendor/tui/lib/input-split.mjs +170 -0
- package/vendor/tui/lib/internals.mjs +90 -0
- package/vendor/tui/lib/invariant.mjs +22 -0
- package/vendor/tui/lib/kernel-panels.mjs +1265 -0
- package/vendor/tui/lib/keyboard.mjs +283 -0
- package/vendor/tui/lib/language-panel.mjs +41 -0
- package/vendor/tui/lib/locales/en.mjs +495 -0
- package/vendor/tui/lib/locales/zh.mjs +495 -0
- package/vendor/tui/lib/mentions.mjs +150 -0
- package/vendor/tui/lib/model-capabilities.mjs +245 -0
- package/vendor/tui/lib/models.mjs +215 -0
- package/vendor/tui/{types/panel-accent.d.ts → lib/panel-accent.mjs} +11 -7
- package/vendor/tui/lib/permissions.mjs +45 -0
- package/vendor/tui/lib/plugin-inventory.mjs +27 -0
- package/vendor/tui/lib/presets.mjs +46 -0
- package/vendor/tui/lib/provider-settings.mjs +600 -0
- package/vendor/tui/lib/questions.mjs +116 -0
- package/vendor/tui/lib/rainbow.mjs +181 -0
- package/vendor/tui/lib/render/animations.mjs +665 -0
- package/vendor/tui/lib/render/editor.mjs +437 -0
- package/vendor/tui/lib/render/export.mjs +119 -0
- package/vendor/tui/lib/render/fuzzy.mjs +79 -0
- package/vendor/tui/lib/render/ime-cursor.mjs +135 -0
- package/vendor/tui/lib/render/inspector.mjs +93 -0
- package/vendor/tui/lib/render/lines.mjs +538 -0
- package/vendor/tui/lib/render/markdown.mjs +592 -0
- package/vendor/tui/lib/render/projection.mjs +1864 -0
- package/vendor/tui/lib/render/status.mjs +591 -0
- package/vendor/tui/lib/render/text.mjs +157 -0
- package/vendor/tui/lib/render/tool-detail.mjs +187 -0
- package/vendor/tui/lib/render/tool-preview.mjs +79 -0
- package/vendor/tui/lib/render/usage.mjs +336 -0
- package/vendor/tui/lib/render/width.mjs +191 -0
- package/vendor/tui/lib/session-directory.mjs +329 -0
- package/vendor/tui/lib/session-query.mjs +184 -0
- package/vendor/tui/lib/session-switch.mjs +51 -0
- package/vendor/tui/lib/settings-file.mjs +75 -0
- package/vendor/tui/lib/skills.mjs +119 -0
- package/vendor/tui/lib/startup.mjs +111 -0
- package/vendor/tui/lib/store.mjs +129 -0
- package/vendor/tui/lib/subagents.mjs +200 -0
- package/vendor/tui/lib/terminal-title.mjs +186 -0
- package/vendor/tui/lib/theme-panel.mjs +60 -0
- package/vendor/tui/lib/theme.mjs +379 -0
- package/vendor/tui/lib/update-panel.mjs +239 -0
- package/vendor/tui/lib/update.mjs +101 -0
- package/vendor/tui/lib/version.mjs +105 -0
- package/vendor/tui/lib/whale-glyph.mjs +20 -0
- package/vendor/tui/LICENSE +0 -21
- package/vendor/tui/devtools-CdTl3MNy.mjs +0 -3643
- package/vendor/tui/dscode-email/cli.mjs +0 -32
- package/vendor/tui/dscode-email/contacts.mjs +0 -36
- package/vendor/tui/dscode-email/gmail-oauth.mjs +0 -69
- package/vendor/tui/dscode-email/gmail-store.mjs +0 -2
- package/vendor/tui/dscode-email/gmail.mjs +0 -194
- package/vendor/tui/dscode-email/imap.mjs +0 -136
- package/vendor/tui/dscode-email/inbox.d.mts +0 -25
- package/vendor/tui/dscode-email/inbox.mjs +0 -76
- package/vendor/tui/dscode-email/smtp.mjs +0 -69
- package/vendor/tui/dscode-email/store.mjs +0 -32
- package/vendor/tui/dscode-providers/catalog.mjs +0 -136
- package/vendor/tui/dscode-providers/effort.mjs +0 -35
- package/vendor/tui/dscode-providers/openrouter-account.mjs +0 -171
- package/vendor/tui/index.mjs +0 -44441
- package/vendor/tui/invariant.mjs +0 -21
- package/vendor/tui/rolldown-runtime-CMFfr-1z.mjs +0 -26
- package/vendor/tui/session-query.mjs +0 -150
- package/vendor/tui/startup.mjs +0 -109
- package/vendor/tui/theme-7u5Qo3dF.mjs +0 -1265
- package/vendor/tui/types/app.d.ts +0 -348
- package/vendor/tui/types/approval.d.ts +0 -59
- package/vendor/tui/types/attachments.d.ts +0 -52
- package/vendor/tui/types/authorization-panel.d.ts +0 -22
- package/vendor/tui/types/authorization.d.ts +0 -36
- package/vendor/tui/types/commands.d.ts +0 -52
- package/vendor/tui/types/editor-keys.d.ts +0 -105
- package/vendor/tui/types/editor.d.ts +0 -6
- package/vendor/tui/types/fork.d.ts +0 -8
- package/vendor/tui/types/git-workflow.d.ts +0 -121
- package/vendor/tui/types/index.d.ts +0 -223
- package/vendor/tui/types/input-split.d.ts +0 -54
- package/vendor/tui/types/internals.d.ts +0 -26
- package/vendor/tui/types/invariant.d.ts +0 -15
- package/vendor/tui/types/kernel-panels.d.ts +0 -245
- package/vendor/tui/types/keyboard.d.ts +0 -80
- package/vendor/tui/types/language-panel.d.ts +0 -12
- package/vendor/tui/types/locales/en.d.ts +0 -450
- package/vendor/tui/types/locales/zh.d.ts +0 -9
- package/vendor/tui/types/mentions.d.ts +0 -85
- package/vendor/tui/types/model-capabilities.d.ts +0 -82
- package/vendor/tui/types/models.d.ts +0 -133
- package/vendor/tui/types/permissions.d.ts +0 -27
- package/vendor/tui/types/plugin-inventory.d.ts +0 -11
- package/vendor/tui/types/presets.d.ts +0 -22
- package/vendor/tui/types/provider-settings.d.ts +0 -239
- package/vendor/tui/types/questions.d.ts +0 -54
- package/vendor/tui/types/rainbow.d.ts +0 -69
- package/vendor/tui/types/render/animations.d.ts +0 -307
- package/vendor/tui/types/render/editor.d.ts +0 -163
- package/vendor/tui/types/render/export.d.ts +0 -9
- package/vendor/tui/types/render/fuzzy.d.ts +0 -21
- package/vendor/tui/types/render/ime-cursor.d.ts +0 -60
- package/vendor/tui/types/render/inspector.d.ts +0 -62
- package/vendor/tui/types/render/lines.d.ts +0 -86
- package/vendor/tui/types/render/markdown.d.ts +0 -29
- package/vendor/tui/types/render/projection.d.ts +0 -587
- package/vendor/tui/types/render/status.d.ts +0 -196
- package/vendor/tui/types/render/text.d.ts +0 -64
- package/vendor/tui/types/render/tool-detail.d.ts +0 -94
- package/vendor/tui/types/render/tool-preview.d.ts +0 -28
- package/vendor/tui/types/render/usage.d.ts +0 -113
- package/vendor/tui/types/render/width.d.ts +0 -29
- package/vendor/tui/types/session-directory.d.ts +0 -190
- package/vendor/tui/types/session-query.d.ts +0 -92
- package/vendor/tui/types/session-switch.d.ts +0 -17
- package/vendor/tui/types/settings-file.d.ts +0 -41
- package/vendor/tui/types/skills.d.ts +0 -47
- package/vendor/tui/types/startup.d.ts +0 -65
- package/vendor/tui/types/store.d.ts +0 -58
- package/vendor/tui/types/subagents.d.ts +0 -70
- package/vendor/tui/types/terminal-title.d.ts +0 -66
- package/vendor/tui/types/theme-panel.d.ts +0 -24
- package/vendor/tui/types/theme.d.ts +0 -434
- package/vendor/tui/types/update-panel.d.ts +0 -49
- package/vendor/tui/types/update.d.ts +0 -75
- package/vendor/tui/types/version.d.ts +0 -19
- package/vendor/tui/types/whale-glyph.d.ts +0 -6
- /package/vendor/tui/{dscode-clipboard-image → lib/dscode/clipboard-image}/clipboard-image.swift +0 -0
- /package/vendor/tui/{dscode-clipboard-image → lib/dscode/clipboard-image}/index.mjs +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal input arrives as byte chunks, and one chunk can carry several
|
|
3
|
+
* keypresses: a fast space-then-enter, a bridged stdin that batches reads, a
|
|
4
|
+
* middle-click paste. Ink parses each chunk as exactly one keypress —
|
|
5
|
+
* `parseKeypress(' \r')` matches neither member, so both keys silently
|
|
6
|
+
* vanish (a multi-select question answered with an empty set). The splitter
|
|
7
|
+
* below cuts every chunk into the individual keypress units Ink's parser
|
|
8
|
+
* expects, keeping escape sequences and bracketed-paste blocks intact, and
|
|
9
|
+
* the stdin proxy feeds the split stream to the Ink mount.
|
|
10
|
+
*
|
|
11
|
+
* @module @deepseek-ai/dsh-tui/input-split
|
|
12
|
+
*/
|
|
13
|
+
import { PassThrough } from 'node:stream';
|
|
14
|
+
import { PASTE_BRACKET_TIMEOUT_MS } from './keyboard.mjs';
|
|
15
|
+
/** Bracketed-paste wrapper bytes; the whole block travels as one unit. */
|
|
16
|
+
const PASTE_START = '\x1b[200~';
|
|
17
|
+
const PASTE_END = '\x1b[201~';
|
|
18
|
+
/** Final byte of a CSI sequence (\x40-\x7e per ECMA-48). */
|
|
19
|
+
const isCsiFinal = (char) => char >= '@' && char <= '~';
|
|
20
|
+
/**
|
|
21
|
+
* Build a stateful chunk splitter. A partial unit at the end of one chunk
|
|
22
|
+
* (a cut CSI sequence, an open paste block) waits in the buffer for the
|
|
23
|
+
* rest. A chunk-trailing lone ESC emits as the Escape key right away:
|
|
24
|
+
* terminals send Escape as its own chunk, and holding it hostage for a
|
|
25
|
+
* sequence that may never continue would break every Esc cancel.
|
|
26
|
+
*/
|
|
27
|
+
export function createKeypressSplitter() {
|
|
28
|
+
let buffer = '';
|
|
29
|
+
const push = (chunk) => {
|
|
30
|
+
buffer += chunk;
|
|
31
|
+
const units = [];
|
|
32
|
+
while (buffer !== '') {
|
|
33
|
+
// A bracketed paste block is display text, not keypresses: keep the
|
|
34
|
+
// whole wrapper plus its payload as the single unit the composer
|
|
35
|
+
// expects, even when the payload contains ESC-looking bytes.
|
|
36
|
+
if (buffer.startsWith(PASTE_START)) {
|
|
37
|
+
const end = buffer.indexOf(PASTE_END, PASTE_START.length);
|
|
38
|
+
if (end < 0)
|
|
39
|
+
break;
|
|
40
|
+
const stop = end + PASTE_END.length;
|
|
41
|
+
units.push(buffer.slice(0, stop));
|
|
42
|
+
buffer = buffer.slice(stop);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const head = buffer[0];
|
|
46
|
+
if (head !== '\x1b') {
|
|
47
|
+
// Plain bytes key one at a time; a surrogate pair is one grapheme
|
|
48
|
+
// and must not split into two lone surrogates.
|
|
49
|
+
const pair = head >= '\uD800' && head <= '\uDBFF' && buffer[1] !== undefined;
|
|
50
|
+
const take = pair ? 2 : 1;
|
|
51
|
+
units.push(buffer.slice(0, take));
|
|
52
|
+
buffer = buffer.slice(take);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// CSI (\x1b[…final) and SS3 (\x1bO<char): hold until complete.
|
|
56
|
+
if (buffer[1] === '[') {
|
|
57
|
+
let end = -1;
|
|
58
|
+
for (let at = 2; at < buffer.length; at += 1) {
|
|
59
|
+
if (isCsiFinal(buffer[at])) {
|
|
60
|
+
end = at;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (end < 0)
|
|
65
|
+
break;
|
|
66
|
+
units.push(buffer.slice(0, end + 1));
|
|
67
|
+
buffer = buffer.slice(end + 1);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (buffer[1] === 'O') {
|
|
71
|
+
if (buffer[2] === undefined)
|
|
72
|
+
break;
|
|
73
|
+
units.push(buffer.slice(0, 3));
|
|
74
|
+
buffer = buffer.slice(3);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (buffer[1] === undefined) {
|
|
78
|
+
// Lone ESC: Escape key (see the tradeoff above).
|
|
79
|
+
units.push(buffer);
|
|
80
|
+
buffer = '';
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// Alt+key: ESC glued to one more byte travels as one unit.
|
|
84
|
+
units.push(buffer.slice(0, 2));
|
|
85
|
+
buffer = buffer.slice(2);
|
|
86
|
+
}
|
|
87
|
+
return units;
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
push,
|
|
91
|
+
openPaste() {
|
|
92
|
+
return buffer.startsWith(PASTE_START);
|
|
93
|
+
},
|
|
94
|
+
releaseStalePaste() {
|
|
95
|
+
if (!buffer.startsWith(PASTE_START))
|
|
96
|
+
return [];
|
|
97
|
+
// Strip the unterminated start marker, then re-run the unit loop: the
|
|
98
|
+
// held bytes flow as ordinary keypresses under all the normal rules.
|
|
99
|
+
buffer = buffer.slice(PASTE_START.length);
|
|
100
|
+
return push('');
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Wrap one real stdin in the splitting proxy: keypress units flow into a
|
|
106
|
+
* PassThrough Ink reads, while raw-mode/ref calls forward to the source.
|
|
107
|
+
* @param source - the process (or harness) input stream in raw mode.
|
|
108
|
+
* @returns the proxy stream plus a dispose that detaches the tap.
|
|
109
|
+
*/
|
|
110
|
+
export function createSplitStdin(source) {
|
|
111
|
+
// Object mode matters: a plain stream's read() without a size drains the
|
|
112
|
+
// whole buffer as one chunk, which would re-coalesce the units this module
|
|
113
|
+
// exists to separate. In object mode every pushed unit reads back alone.
|
|
114
|
+
const stream = new PassThrough({ objectMode: true });
|
|
115
|
+
const splitter = createKeypressSplitter();
|
|
116
|
+
let stalePasteTimer;
|
|
117
|
+
const disarmStalePasteTimer = () => {
|
|
118
|
+
if (stalePasteTimer === undefined)
|
|
119
|
+
return;
|
|
120
|
+
clearTimeout(stalePasteTimer);
|
|
121
|
+
stalePasteTimer = undefined;
|
|
122
|
+
};
|
|
123
|
+
// A terminal that drops the end marker must not swallow every following
|
|
124
|
+
// keypress forever: past the shared paste window the held block is released
|
|
125
|
+
// as plain text, keeping Esc/Ctrl+C reachable. The App-level paste flag has
|
|
126
|
+
// its own reset net with the same window, but it can only see markers that
|
|
127
|
+
// reach Ink — this one guards the bytes that never do.
|
|
128
|
+
const armStalePasteTimer = () => {
|
|
129
|
+
if (stalePasteTimer !== undefined || !splitter.openPaste())
|
|
130
|
+
return;
|
|
131
|
+
stalePasteTimer = setTimeout(() => {
|
|
132
|
+
stalePasteTimer = undefined;
|
|
133
|
+
for (const unit of splitter.releaseStalePaste())
|
|
134
|
+
stream.write(unit);
|
|
135
|
+
armStalePasteTimer();
|
|
136
|
+
}, PASTE_BRACKET_TIMEOUT_MS);
|
|
137
|
+
stalePasteTimer.unref?.();
|
|
138
|
+
};
|
|
139
|
+
const onChunk = (chunk) => {
|
|
140
|
+
for (const unit of splitter.push(String(chunk)))
|
|
141
|
+
stream.write(unit);
|
|
142
|
+
if (splitter.openPaste())
|
|
143
|
+
armStalePasteTimer();
|
|
144
|
+
else
|
|
145
|
+
disarmStalePasteTimer();
|
|
146
|
+
};
|
|
147
|
+
const proxy = Object.assign(stream, {
|
|
148
|
+
isTTY: source.isTTY === true,
|
|
149
|
+
setRawMode(value) {
|
|
150
|
+
source.setRawMode?.(value);
|
|
151
|
+
return stream;
|
|
152
|
+
},
|
|
153
|
+
ref() {
|
|
154
|
+
source.ref?.();
|
|
155
|
+
},
|
|
156
|
+
unref() {
|
|
157
|
+
source.unref?.();
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
source.setEncoding('utf8');
|
|
161
|
+
source.on('data', onChunk);
|
|
162
|
+
return {
|
|
163
|
+
stdin: proxy,
|
|
164
|
+
dispose() {
|
|
165
|
+
disarmStalePasteTimer();
|
|
166
|
+
source.removeListener('data', onChunk);
|
|
167
|
+
source.pause();
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injectable process-facing effects for the TUI runner. Tests substitute the
|
|
3
|
+
* Ink mount with a capturing fake and the streams with string sinks, keeping
|
|
4
|
+
* the runner's lifecycle testable without a terminal.
|
|
5
|
+
*
|
|
6
|
+
* @module @deepseek-ai/dsh-tui/internals
|
|
7
|
+
*/
|
|
8
|
+
import { render } from 'ink';
|
|
9
|
+
import { BRACKETED_PASTE_DISABLE, BRACKETED_PASTE_ENABLE, KEYBOARD_ENHANCE_DISABLE, KEYBOARD_ENHANCE_ENABLE, TERMINAL_FOCUS_REPORT_DISABLE, TERMINAL_FOCUS_REPORT_ENABLE, isVsCodeTerminalEnv, shouldEnableKeyboardEnhancement, } from './keyboard.mjs';
|
|
10
|
+
import { createSplitStdin } from './input-split.mjs';
|
|
11
|
+
import { ensureVsCodeTabTitleSetting } from './terminal-title.mjs';
|
|
12
|
+
/** Substitutable runner effects; production values write to the real terminal. */
|
|
13
|
+
export const internals = {
|
|
14
|
+
mount: (element) => {
|
|
15
|
+
// VS Code's integrated terminal can route Tab to the workbench when Kitty
|
|
16
|
+
// enhancement is enabled. Keep bracketed paste everywhere, but only push
|
|
17
|
+
// the keyboard protocol on terminals that can safely own those key events.
|
|
18
|
+
const keyboardEnhanced = shouldEnableKeyboardEnhancement();
|
|
19
|
+
const focusReporting = isVsCodeTerminalEnv();
|
|
20
|
+
// Enter raw mode BEFORE pushing any protocol: xterm.js answers `?1004h`
|
|
21
|
+
// with an immediate focus report (ESC[I), and while the tty still carries
|
|
22
|
+
// the shell's cooked+ECHO settings that report is echoed to the screen as
|
|
23
|
+
// a literal `^[[I`. Ink only takes raw mode after its first commit, so
|
|
24
|
+
// this mount owns the window; the call is idempotent with Ink's later one.
|
|
25
|
+
if (process.stdin.isTTY === true)
|
|
26
|
+
process.stdin.setRawMode?.(true);
|
|
27
|
+
try {
|
|
28
|
+
process.stdout.write((keyboardEnhanced ? KEYBOARD_ENHANCE_ENABLE : '')
|
|
29
|
+
+ BRACKETED_PASTE_ENABLE
|
|
30
|
+
+ (focusReporting ? TERMINAL_FOCUS_REPORT_ENABLE : ''));
|
|
31
|
+
// Cosmetic best effort: inside a VS Code integrated terminal the tab
|
|
32
|
+
// shows the process name ("node") unless the user settings map it to
|
|
33
|
+
// the sequence title; align them once. Total function, never throws.
|
|
34
|
+
ensureVsCodeTabTitleSetting();
|
|
35
|
+
// App owns Ctrl+C's deliberate three-state contract (interrupt, clear
|
|
36
|
+
// draft, quit). Ink's default `exitOnCtrlC: true` would intercept the
|
|
37
|
+
// normalized control byte first, unmount only its renderer, and leave the
|
|
38
|
+
// Harness runner plus the pushed keyboard protocol alive.
|
|
39
|
+
// stdin travels through the keypress splitter: Ink parses one chunk as
|
|
40
|
+
// one keypress, so a coalesced space-then-enter would drop both keys.
|
|
41
|
+
const tuiStdin = createSplitStdin(process.stdin);
|
|
42
|
+
// Ink only touches isTTY/setRawMode/ref/read on stdin; the object-mode
|
|
43
|
+
// proxy satisfies that contract without the full ReadStream surface.
|
|
44
|
+
const instance = render(element, {
|
|
45
|
+
exitOnCtrlC: false,
|
|
46
|
+
stdin: tuiStdin.stdin,
|
|
47
|
+
stdout: process.stdout,
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
rerender(element) {
|
|
51
|
+
instance.rerender(element);
|
|
52
|
+
},
|
|
53
|
+
unmount() {
|
|
54
|
+
// The cleanup below must run even when Ink's unmount throws (a
|
|
55
|
+
// render-teardown failure): a stdin tap or pushed terminal-protocol
|
|
56
|
+
// stack outliving the app wedges the terminal for whatever runs
|
|
57
|
+
// next, and a stray exception here must not skip the exit sequence.
|
|
58
|
+
// Pop the stack while raw mode still hides echo — xterm.js keeps
|
|
59
|
+
// reporting focus changes until `?1004l` lands, and one arriving
|
|
60
|
+
// after Ink restores the cooked tty would print as `^[[I`.
|
|
61
|
+
try {
|
|
62
|
+
process.stdout.write((keyboardEnhanced ? KEYBOARD_ENHANCE_DISABLE : '')
|
|
63
|
+
+ BRACKETED_PASTE_DISABLE
|
|
64
|
+
+ (focusReporting ? TERMINAL_FOCUS_REPORT_DISABLE : ''));
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
try {
|
|
68
|
+
instance.unmount();
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
tuiStdin.dispose();
|
|
72
|
+
// Belt and braces: give the tty back its cooked mode even when
|
|
73
|
+
// Ink never took raw mode over (idempotent at the termios level).
|
|
74
|
+
if (process.stdin.isTTY === true)
|
|
75
|
+
process.stdin.setRawMode?.(false);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
// The synchronous mount path failed before Ink could own the terminal:
|
|
83
|
+
// undo the raw mode entered above so the shell keeps its echo.
|
|
84
|
+
if (process.stdin.isTTY === true)
|
|
85
|
+
process.stdin.setRawMode?.(false);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
stderr: process.stderr,
|
|
90
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `dsh-code`.
|
|
3
|
+
* @module dsh-code/invariant
|
|
4
|
+
*/
|
|
5
|
+
const PACKAGE_NAME = 'dsh-code';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export const name = 'tui-invariant';
|
|
8
|
+
/** Service required before the companion can register. */
|
|
9
|
+
export const inject = ['invariants'];
|
|
10
|
+
/**
|
|
11
|
+
* No runtime invariant beyond the projection's own contract: the TUI renders
|
|
12
|
+
* only from `session/event` (model-visible means logged), so the display
|
|
13
|
+
* relation the renderer could desync from is already asserted by the session
|
|
14
|
+
* log's projection invariants; this companion registers nothing.
|
|
15
|
+
*/
|
|
16
|
+
const install = () => { };
|
|
17
|
+
/**
|
|
18
|
+
* Register this package's invariant companion.
|
|
19
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
20
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
21
|
+
*/
|
|
22
|
+
export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|