silvery 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -145
- package/dist/chalk.js +3 -0
- package/dist/chalk.js.map +11 -0
- package/dist/index.js +340 -0
- package/dist/index.js.map +282 -0
- package/dist/ink.js +129 -0
- package/dist/ink.js.map +140 -0
- package/dist/runtime.js +394 -0
- package/dist/runtime.js.map +286 -0
- package/dist/theme.js +343 -0
- package/dist/theme.js.map +286 -0
- package/dist/ui/animation.js +3 -0
- package/dist/ui/animation.js.map +15 -0
- package/dist/ui/ansi.js +3 -0
- package/dist/ui/ansi.js.map +10 -0
- package/dist/ui/cli.js +8 -0
- package/dist/ui/cli.js.map +14 -0
- package/dist/ui/display.js +4 -0
- package/dist/ui/display.js.map +10 -0
- package/dist/ui/image.js +4 -0
- package/dist/ui/image.js.map +15 -0
- package/dist/ui/input.js +3 -0
- package/dist/ui/input.js.map +11 -0
- package/dist/ui/progress.js +8 -0
- package/dist/ui/progress.js.map +20 -0
- package/dist/ui/react.js +3 -0
- package/dist/ui/react.js.map +15 -0
- package/dist/ui/utils.js +3 -0
- package/dist/ui/utils.js.map +10 -0
- package/dist/ui/wrappers.js +14 -0
- package/dist/ui/wrappers.js.map +19 -0
- package/dist/ui.js +17 -0
- package/dist/ui.js.map +20 -0
- package/package.json +67 -15
- package/src/index.ts +67 -1
- package/src/runtime.ts +4 -0
- package/src/theme.ts +4 -0
- package/src/ui/animation.ts +2 -0
- package/src/ui/ansi.ts +2 -0
- package/src/ui/cli.ts +2 -0
- package/src/ui/display.ts +2 -0
- package/src/ui/image.ts +2 -0
- package/src/ui/input.ts +2 -0
- package/src/ui/progress.ts +2 -0
- package/src/ui/react.ts +2 -0
- package/src/ui/utils.ts +2 -0
- package/src/ui/wrappers.ts +2 -0
- package/src/ui.ts +4 -0
- package/examples/CLAUDE.md +0 -75
- package/examples/_banner.tsx +0 -60
- package/examples/cli.ts +0 -228
- package/examples/index.md +0 -101
- package/examples/inline/inline-nontty.tsx +0 -98
- package/examples/inline/inline-progress.tsx +0 -79
- package/examples/inline/inline-simple.tsx +0 -63
- package/examples/inline/scrollback.tsx +0 -185
- package/examples/interactive/_input-debug.tsx +0 -110
- package/examples/interactive/_stdin-test.ts +0 -71
- package/examples/interactive/_textarea-bare.tsx +0 -45
- package/examples/interactive/aichat/components.tsx +0 -468
- package/examples/interactive/aichat/index.tsx +0 -207
- package/examples/interactive/aichat/script.ts +0 -460
- package/examples/interactive/aichat/state.ts +0 -326
- package/examples/interactive/aichat/types.ts +0 -19
- package/examples/interactive/app-todo.tsx +0 -198
- package/examples/interactive/async-data.tsx +0 -208
- package/examples/interactive/cli-wizard.tsx +0 -332
- package/examples/interactive/clipboard.tsx +0 -183
- package/examples/interactive/components.tsx +0 -463
- package/examples/interactive/data-explorer.tsx +0 -506
- package/examples/interactive/dev-tools.tsx +0 -379
- package/examples/interactive/explorer.tsx +0 -747
- package/examples/interactive/gallery.tsx +0 -652
- package/examples/interactive/inline-bench.tsx +0 -136
- package/examples/interactive/kanban.tsx +0 -267
- package/examples/interactive/layout-ref.tsx +0 -185
- package/examples/interactive/outline.tsx +0 -171
- package/examples/interactive/paste-demo.tsx +0 -198
- package/examples/interactive/scroll.tsx +0 -77
- package/examples/interactive/search-filter.tsx +0 -240
- package/examples/interactive/task-list.tsx +0 -279
- package/examples/interactive/terminal.tsx +0 -798
- package/examples/interactive/textarea.tsx +0 -103
- package/examples/interactive/theme.tsx +0 -336
- package/examples/interactive/transform.tsx +0 -256
- package/examples/interactive/virtual-10k.tsx +0 -413
- package/examples/kitty/canvas.tsx +0 -519
- package/examples/kitty/generate-samples.ts +0 -236
- package/examples/kitty/image-component.tsx +0 -273
- package/examples/kitty/images.tsx +0 -604
- package/examples/kitty/input.tsx +0 -371
- package/examples/kitty/keys.tsx +0 -378
- package/examples/kitty/paint.tsx +0 -1017
- package/examples/layout/dashboard.tsx +0 -551
- package/examples/layout/live-resize.tsx +0 -290
- package/examples/layout/overflow.tsx +0 -51
- package/examples/playground/README.md +0 -69
- package/examples/playground/build.ts +0 -61
- package/examples/playground/index.html +0 -420
- package/examples/playground/playground-app.tsx +0 -416
- package/examples/runtime/elm-counter.tsx +0 -206
- package/examples/runtime/hello-runtime.tsx +0 -73
- package/examples/runtime/pipe-composition.tsx +0 -184
- package/examples/runtime/run-counter.tsx +0 -78
- package/examples/runtime/runtime-counter.tsx +0 -197
- package/examples/screenshots/generate.tsx +0 -563
- package/examples/scrollback-perf.tsx +0 -230
- package/examples/viewer.tsx +0 -654
- package/examples/web/build.ts +0 -365
- package/examples/web/canvas-app.tsx +0 -80
- package/examples/web/canvas.html +0 -89
- package/examples/web/dom-app.tsx +0 -81
- package/examples/web/dom.html +0 -113
- package/examples/web/showcase-app.tsx +0 -107
- package/examples/web/showcase.html +0 -34
- package/examples/web/showcases/index.tsx +0 -56
- package/examples/web/viewer-app.tsx +0 -555
- package/examples/web/viewer.html +0 -30
- package/examples/web/xterm-app.tsx +0 -105
- package/examples/web/xterm.html +0 -118
package/examples/kitty/keys.tsx
DELETED
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Key Explorer
|
|
3
|
-
*
|
|
4
|
-
* Interactive key chord tester — press any key combination to see exactly
|
|
5
|
-
* how the terminal reports it. Color-coded modifiers, live event log,
|
|
6
|
-
* and a visual modifier dashboard make it easy to understand what your
|
|
7
|
-
* terminal can do.
|
|
8
|
-
*
|
|
9
|
-
* Features:
|
|
10
|
-
* - Legacy vs Kitty parsing differences
|
|
11
|
-
* - All modifier fields (ctrl, alt, shift, super, hyper, capsLock, numLock)
|
|
12
|
-
* - Event types (press/repeat/release)
|
|
13
|
-
* - shiftedKey, baseLayoutKey, associatedText
|
|
14
|
-
* - macOS symbols in the display (⌘ ⌥ ⌃ ⇧ ✦)
|
|
15
|
-
* - Kitty auto-detection on startup
|
|
16
|
-
*
|
|
17
|
-
* Run: bun vendor/silvery/examples/kitty/key-explorer.tsx
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import React, { useState, useRef, useEffect } from "react"
|
|
21
|
-
import {
|
|
22
|
-
render,
|
|
23
|
-
Box,
|
|
24
|
-
Text,
|
|
25
|
-
useInput,
|
|
26
|
-
useApp,
|
|
27
|
-
createTerm,
|
|
28
|
-
parseKeypress,
|
|
29
|
-
KittyFlags,
|
|
30
|
-
enableKittyKeyboard,
|
|
31
|
-
disableKittyKeyboard,
|
|
32
|
-
detectKittyFromStdio,
|
|
33
|
-
type Key,
|
|
34
|
-
type ParsedKeypress,
|
|
35
|
-
} from "../../src/index.js"
|
|
36
|
-
import { ExampleBanner, type ExampleMeta } from "../_banner.js"
|
|
37
|
-
|
|
38
|
-
export const meta: ExampleMeta = {
|
|
39
|
-
name: "Key Events",
|
|
40
|
-
description: "Interactive key chord tester with color-coded modifiers",
|
|
41
|
-
features: ["parseKeypress()", "detectKittySupport()", "⌘ ⌥ ⌃ ⇧ ✦ symbols", "KittyFlags"],
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// eventType is already a string ("press" | "repeat" | "release")
|
|
45
|
-
|
|
46
|
-
interface KeyEvent {
|
|
47
|
-
index: number
|
|
48
|
-
input: string
|
|
49
|
-
key: Key
|
|
50
|
-
parsed: ParsedKeypress
|
|
51
|
-
raw: string
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Modifier definition with display name, symbol, and color */
|
|
55
|
-
interface ModDef {
|
|
56
|
-
symbol: string
|
|
57
|
-
label: string
|
|
58
|
-
color: string
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const MODIFIER_DEFS: ModDef[] = [
|
|
62
|
-
{ symbol: "⌃", label: "Ctrl", color: "red" },
|
|
63
|
-
{ symbol: "⇧", label: "Shift", color: "yellow" },
|
|
64
|
-
{ symbol: "⌥", label: "Alt", color: "blue" },
|
|
65
|
-
{ symbol: "⌘", label: "Super", color: "green" },
|
|
66
|
-
{ symbol: "✦", label: "Hyper", color: "magenta" },
|
|
67
|
-
]
|
|
68
|
-
|
|
69
|
-
function KeyExplorer({ kittySupported }: { kittySupported: boolean }): JSX.Element {
|
|
70
|
-
const { exit } = useApp()
|
|
71
|
-
const [events, setEvents] = useState<KeyEvent[]>([])
|
|
72
|
-
const [latest, setLatest] = useState<KeyEvent | null>(null)
|
|
73
|
-
const counterRef = useRef(0)
|
|
74
|
-
const stdin = process.stdin
|
|
75
|
-
|
|
76
|
-
// Listen to raw stdin for full ParsedKeypress info
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
const onData = (data: Buffer) => {
|
|
79
|
-
const raw = data.toString()
|
|
80
|
-
// Skip mouse sequences
|
|
81
|
-
if (raw.startsWith("\x1b[<")) return
|
|
82
|
-
|
|
83
|
-
const parsed = parseKeypress(raw)
|
|
84
|
-
// Don't log the quit key
|
|
85
|
-
if (parsed.name === "escape" || (raw === "q" && !parsed.ctrl && !parsed.meta)) return
|
|
86
|
-
|
|
87
|
-
counterRef.current++
|
|
88
|
-
const [input, key] = parseInputKey(raw)
|
|
89
|
-
const event: KeyEvent = {
|
|
90
|
-
index: counterRef.current,
|
|
91
|
-
input,
|
|
92
|
-
key,
|
|
93
|
-
parsed,
|
|
94
|
-
raw,
|
|
95
|
-
}
|
|
96
|
-
setLatest(event)
|
|
97
|
-
setEvents((prev) => [...prev.slice(-14), event])
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
stdin.on("data", onData)
|
|
101
|
-
return () => {
|
|
102
|
-
stdin.off("data", onData)
|
|
103
|
-
}
|
|
104
|
-
}, [stdin])
|
|
105
|
-
|
|
106
|
-
useInput((input: string, key: Key) => {
|
|
107
|
-
if (input === "q" || key.escape) {
|
|
108
|
-
exit()
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<Box flexDirection="column" padding={1}>
|
|
114
|
-
{/* Status bar */}
|
|
115
|
-
<Box gap={2} marginBottom={1}>
|
|
116
|
-
<Text>
|
|
117
|
-
<Text bold color="cyan">
|
|
118
|
-
Protocol:
|
|
119
|
-
</Text>{" "}
|
|
120
|
-
{kittySupported ? (
|
|
121
|
-
<Text color="green">Kitty keyboard enabled</Text>
|
|
122
|
-
) : (
|
|
123
|
-
<Text color="yellow">Legacy mode (terminal does not support Kitty)</Text>
|
|
124
|
-
)}
|
|
125
|
-
</Text>
|
|
126
|
-
</Box>
|
|
127
|
-
|
|
128
|
-
<Box gap={4}>
|
|
129
|
-
{/* Left panel: Current key details */}
|
|
130
|
-
<Box flexDirection="column" width={50}>
|
|
131
|
-
<Text bold color="cyan">
|
|
132
|
-
Last Key Pressed
|
|
133
|
-
</Text>
|
|
134
|
-
<Box height={1} />
|
|
135
|
-
{latest ? (
|
|
136
|
-
<KeyDetails event={latest} />
|
|
137
|
-
) : (
|
|
138
|
-
<Box flexDirection="column">
|
|
139
|
-
<Text color="cyan">Try pressing some key combinations:</Text>
|
|
140
|
-
<Box height={1} />
|
|
141
|
-
<Text> Ctrl+A, Shift+Tab, Alt+Enter...</Text>
|
|
142
|
-
{kittySupported && <Text> Cmd+S, Hyper+X (Kitty-only)</Text>}
|
|
143
|
-
<Box height={1} />
|
|
144
|
-
<Text dim>Each keypress shows its full breakdown here.</Text>
|
|
145
|
-
</Box>
|
|
146
|
-
)}
|
|
147
|
-
</Box>
|
|
148
|
-
|
|
149
|
-
{/* Right panel: Event log */}
|
|
150
|
-
<Box flexDirection="column" width={42}>
|
|
151
|
-
<Text bold color="cyan">
|
|
152
|
-
Event Log
|
|
153
|
-
</Text>
|
|
154
|
-
<Text dim>
|
|
155
|
-
{counterRef.current} {counterRef.current === 1 ? "event" : "events"} captured
|
|
156
|
-
</Text>
|
|
157
|
-
<Box height={1} />
|
|
158
|
-
{events.length === 0 ? (
|
|
159
|
-
<Text dim>Waiting for input...</Text>
|
|
160
|
-
) : (
|
|
161
|
-
events.map((e, i) => (
|
|
162
|
-
<Text key={i} dimColor={i < events.length - 1}>
|
|
163
|
-
<Text dim>#{String(e.index).padStart(3)}</Text> {formatEventSummary(e)}
|
|
164
|
-
</Text>
|
|
165
|
-
))
|
|
166
|
-
)}
|
|
167
|
-
</Box>
|
|
168
|
-
</Box>
|
|
169
|
-
</Box>
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function KeyDetails({ event }: { event: KeyEvent }): JSX.Element {
|
|
174
|
-
const { parsed, raw } = event
|
|
175
|
-
|
|
176
|
-
// Determine which modifiers are active
|
|
177
|
-
const modActive: boolean[] = [parsed.ctrl, parsed.shift, parsed.meta || parsed.option, parsed.super, parsed.hyper]
|
|
178
|
-
|
|
179
|
-
return (
|
|
180
|
-
<Box flexDirection="column">
|
|
181
|
-
{/* Key name - big and prominent */}
|
|
182
|
-
<Text>
|
|
183
|
-
<Text bold>Name:</Text>{" "}
|
|
184
|
-
<Text bold color="white">
|
|
185
|
-
{parsed.name || "(none)"}
|
|
186
|
-
</Text>
|
|
187
|
-
</Text>
|
|
188
|
-
<Text>
|
|
189
|
-
<Text bold>Input:</Text> {JSON.stringify(event.input)}
|
|
190
|
-
</Text>
|
|
191
|
-
|
|
192
|
-
{/* Color-coded modifier dashboard */}
|
|
193
|
-
<Box marginTop={1}>
|
|
194
|
-
<Box gap={1}>
|
|
195
|
-
{MODIFIER_DEFS.map((mod, i) => (
|
|
196
|
-
<ModBadge key={mod.symbol} mod={mod} active={modActive[i]!} />
|
|
197
|
-
))}
|
|
198
|
-
</Box>
|
|
199
|
-
</Box>
|
|
200
|
-
|
|
201
|
-
{/* Event type (Kitty-only) */}
|
|
202
|
-
{parsed.eventType && (
|
|
203
|
-
<Box marginTop={1}>
|
|
204
|
-
<Text>
|
|
205
|
-
<Text bold>Event type:</Text> <Text color="magenta">{parsed.eventType}</Text>
|
|
206
|
-
</Text>
|
|
207
|
-
</Box>
|
|
208
|
-
)}
|
|
209
|
-
|
|
210
|
-
{/* Kitty-specific fields */}
|
|
211
|
-
<Box flexDirection="column" marginTop={1}>
|
|
212
|
-
<Text bold dim>
|
|
213
|
-
Kitty Extensions
|
|
214
|
-
</Text>
|
|
215
|
-
<KeyField label="shiftedKey" value={parsed.shiftedKey} />
|
|
216
|
-
<KeyField label="baseLayoutKey" value={parsed.baseLayoutKey} />
|
|
217
|
-
<KeyField label="associatedText" value={parsed.associatedText} />
|
|
218
|
-
<KeyField label="capsLock" value={parsed.capsLock} />
|
|
219
|
-
<KeyField label="numLock" value={parsed.numLock} />
|
|
220
|
-
</Box>
|
|
221
|
-
|
|
222
|
-
{/* Raw sequence */}
|
|
223
|
-
<Box marginTop={1}>
|
|
224
|
-
<Text>
|
|
225
|
-
<Text bold>Raw:</Text>{" "}
|
|
226
|
-
<Text dim>
|
|
227
|
-
{[...raw]
|
|
228
|
-
.map((c) =>
|
|
229
|
-
c.charCodeAt(0) < 32 || c.charCodeAt(0) === 127
|
|
230
|
-
? `\\x${c.charCodeAt(0).toString(16).padStart(2, "0")}`
|
|
231
|
-
: c,
|
|
232
|
-
)
|
|
233
|
-
.join("")}
|
|
234
|
-
</Text>
|
|
235
|
-
</Text>
|
|
236
|
-
</Box>
|
|
237
|
-
<Text>
|
|
238
|
-
<Text bold>Sequence:</Text> <Text dim>{JSON.stringify(parsed.sequence)}</Text>
|
|
239
|
-
</Text>
|
|
240
|
-
</Box>
|
|
241
|
-
)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function ModBadge({ mod, active }: { mod: ModDef; active: boolean }): JSX.Element {
|
|
245
|
-
if (active) {
|
|
246
|
-
return (
|
|
247
|
-
<Text backgroundColor={mod.color as any} color="white" bold>
|
|
248
|
-
{` ${mod.symbol} ${mod.label} `}
|
|
249
|
-
</Text>
|
|
250
|
-
)
|
|
251
|
-
}
|
|
252
|
-
return (
|
|
253
|
-
<Text dim color="gray">
|
|
254
|
-
{` ${mod.symbol} `}
|
|
255
|
-
</Text>
|
|
256
|
-
)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function KeyField({ label, value }: { label: string; value: string | boolean | undefined }): JSX.Element {
|
|
260
|
-
if (value === undefined) {
|
|
261
|
-
return <Text dim>{label}: --</Text>
|
|
262
|
-
}
|
|
263
|
-
return (
|
|
264
|
-
<Text>
|
|
265
|
-
{label}: <Text color="yellow">{String(value)}</Text>
|
|
266
|
-
</Text>
|
|
267
|
-
)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function formatEventSummary(event: KeyEvent): string {
|
|
271
|
-
const parts: string[] = []
|
|
272
|
-
const { parsed } = event
|
|
273
|
-
if (parsed.ctrl) parts.push("⌃")
|
|
274
|
-
if (parsed.shift) parts.push("⇧")
|
|
275
|
-
if (parsed.meta || parsed.option) parts.push("⌥")
|
|
276
|
-
if (parsed.super) parts.push("⌘")
|
|
277
|
-
if (parsed.hyper) parts.push("✦")
|
|
278
|
-
parts.push(parsed.name || JSON.stringify(event.input))
|
|
279
|
-
if (parsed.eventType) parts.push(`(${parsed.eventType})`)
|
|
280
|
-
return parts.join("")
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/** Parse raw input into [input, Key] using the same logic as the runtime */
|
|
284
|
-
function parseInputKey(raw: string): [string, Key] {
|
|
285
|
-
const parsed = parseKeypress(raw)
|
|
286
|
-
const key: Key = {
|
|
287
|
-
upArrow: parsed.name === "up",
|
|
288
|
-
downArrow: parsed.name === "down",
|
|
289
|
-
leftArrow: parsed.name === "left",
|
|
290
|
-
rightArrow: parsed.name === "right",
|
|
291
|
-
pageDown: parsed.name === "pagedown",
|
|
292
|
-
pageUp: parsed.name === "pageup",
|
|
293
|
-
home: parsed.name === "home",
|
|
294
|
-
end: parsed.name === "end",
|
|
295
|
-
return: parsed.name === "return",
|
|
296
|
-
escape: parsed.name === "escape",
|
|
297
|
-
ctrl: parsed.ctrl,
|
|
298
|
-
shift: parsed.shift,
|
|
299
|
-
tab: parsed.name === "tab",
|
|
300
|
-
backspace: parsed.name === "backspace",
|
|
301
|
-
delete: parsed.name === "delete",
|
|
302
|
-
meta: parsed.meta || parsed.option,
|
|
303
|
-
super: parsed.super,
|
|
304
|
-
hyper: parsed.hyper,
|
|
305
|
-
eventType: parsed.eventType,
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// For printable chars, input is the character itself
|
|
309
|
-
const input = parsed.name.length === 1 ? parsed.name : ""
|
|
310
|
-
return [input, key]
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
async function main() {
|
|
314
|
-
const cleanup = () => {
|
|
315
|
-
const stdout = process.stdout
|
|
316
|
-
stdout.write("\x1b[?1003l\x1b[?1006l") // Disable mouse
|
|
317
|
-
stdout.write("\x1b[?25h") // Show cursor
|
|
318
|
-
stdout.write("\x1b[?1049l") // Exit alternate screen
|
|
319
|
-
stdout.write("\x1b[0m") // Reset colors
|
|
320
|
-
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
321
|
-
try {
|
|
322
|
-
process.stdin.setRawMode(false)
|
|
323
|
-
} catch {}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
process.on("uncaughtException", (err) => {
|
|
327
|
-
cleanup()
|
|
328
|
-
throw err
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
// Detect Kitty support before starting the app
|
|
332
|
-
const kittyResult = await detectKittyFromStdio(process.stdout, process.stdin)
|
|
333
|
-
|
|
334
|
-
// Enable Kitty with all reporting flags if supported
|
|
335
|
-
if (kittyResult.supported) {
|
|
336
|
-
const flags =
|
|
337
|
-
KittyFlags.DISAMBIGUATE |
|
|
338
|
-
KittyFlags.REPORT_EVENTS |
|
|
339
|
-
KittyFlags.REPORT_ALTERNATE |
|
|
340
|
-
KittyFlags.REPORT_ALL_KEYS |
|
|
341
|
-
KittyFlags.REPORT_TEXT
|
|
342
|
-
process.stdout.write(enableKittyKeyboard(flags))
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
using term = createTerm()
|
|
346
|
-
const { waitUntilExit } = await render(
|
|
347
|
-
<ExampleBanner meta={meta} controls="q/Esc quit">
|
|
348
|
-
<KeyExplorer kittySupported={kittyResult.supported} />
|
|
349
|
-
</ExampleBanner>,
|
|
350
|
-
term,
|
|
351
|
-
)
|
|
352
|
-
await waitUntilExit()
|
|
353
|
-
|
|
354
|
-
// Cleanup: disable Kitty protocol
|
|
355
|
-
if (kittyResult.supported) {
|
|
356
|
-
process.stdout.write(disableKittyKeyboard())
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (import.meta.main) {
|
|
361
|
-
try {
|
|
362
|
-
await main()
|
|
363
|
-
} catch (err) {
|
|
364
|
-
// Restore terminal on crash
|
|
365
|
-
const stdout = process.stdout
|
|
366
|
-
stdout.write("\x1b[?1003l\x1b[?1006l") // Disable mouse
|
|
367
|
-
stdout.write("\x1b[?25h") // Show cursor
|
|
368
|
-
stdout.write("\x1b[?1049l") // Exit alternate screen
|
|
369
|
-
stdout.write("\x1b[0m") // Reset colors
|
|
370
|
-
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
371
|
-
try {
|
|
372
|
-
process.stdin.setRawMode(false)
|
|
373
|
-
} catch {}
|
|
374
|
-
}
|
|
375
|
-
console.error(err)
|
|
376
|
-
process.exit(1)
|
|
377
|
-
}
|
|
378
|
-
}
|