webtty 1.5.0 → 1.6.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/dist/cli/index.js CHANGED
@@ -387,6 +387,95 @@ function cmdConfig() {
387
387
  const editor = process.env.VISUAL ?? process.env.EDITOR ?? (process.platform === "win32" ? "notepad" : "vi");
388
388
  childProcess2.spawnSync(editor, [configPath], { stdio: "inherit" });
389
389
  }
390
+ function bytesToChars(buf) {
391
+ let out = "";
392
+ for (const b of buf) {
393
+ if (b === 27)
394
+ out += "\\u001b";
395
+ else if (b === 13)
396
+ out += "\\r";
397
+ else if (b === 9)
398
+ out += "\\t";
399
+ else if (b === 10)
400
+ out += "\\n";
401
+ else if (b === 34)
402
+ out += "\\\"";
403
+ else if (b === 92)
404
+ out += "\\\\";
405
+ else if (b >= 32 && b < 127)
406
+ out += String.fromCharCode(b);
407
+ else
408
+ out += `\\u${b.toString(16).padStart(4, "0")}`;
409
+ }
410
+ return `"${out}"`;
411
+ }
412
+ function bytesToDisplay(buf) {
413
+ return Array.from(buf).map((b) => {
414
+ if (b === 27)
415
+ return "ESC";
416
+ if (b === 13)
417
+ return "CR";
418
+ if (b === 9)
419
+ return "TAB";
420
+ if (b === 10)
421
+ return "LF";
422
+ if (b === 32)
423
+ return "SPC";
424
+ if (b === 127)
425
+ return "DEL";
426
+ if (b > 32 && b < 127)
427
+ return String.fromCharCode(b);
428
+ return `\\x${b.toString(16).padStart(2, "0")}`;
429
+ }).join(" ");
430
+ }
431
+ function cmdKey() {
432
+ if (!process.stdin.isTTY) {
433
+ console.error("webtty key: requires an interactive terminal");
434
+ process.exit(1);
435
+ return;
436
+ }
437
+ const dim = "\x1B[2m";
438
+ const bold = "\x1B[1m";
439
+ const reset = "\x1B[0m";
440
+ const restoreTerminal = () => {
441
+ try {
442
+ process.stdin.setRawMode(false);
443
+ } catch {}
444
+ };
445
+ process.once("exit", restoreTerminal);
446
+ process.once("SIGINT", restoreTerminal);
447
+ process.once("SIGTERM", restoreTerminal);
448
+ process.stdin.setRawMode(true);
449
+ process.stdin.resume();
450
+ console.log(`Press any key combo to see its chars value. q to quit.
451
+ `);
452
+ console.log(` ${dim}received${reset} → ${bold}chars${reset}`);
453
+ console.log(` ${"─".repeat(17)}`);
454
+ let buf = Buffer.alloc(0);
455
+ let timer = null;
456
+ const flush = () => {
457
+ if (buf.length === 0)
458
+ return;
459
+ const display = bytesToDisplay(buf).padEnd(8);
460
+ console.log(` ${dim}${display}${reset} → ${bold}${bytesToChars(buf)}${reset}`);
461
+ buf = Buffer.alloc(0);
462
+ };
463
+ process.stdin.on("data", (chunk) => {
464
+ if (chunk.length === 1 && chunk[0] === 113) {
465
+ process.stdin.setRawMode(false);
466
+ process.removeListener("exit", restoreTerminal);
467
+ process.removeListener("SIGINT", restoreTerminal);
468
+ process.removeListener("SIGTERM", restoreTerminal);
469
+ console.log(` ${"─".repeat(17)}
470
+ `);
471
+ process.exit(0);
472
+ }
473
+ buf = Buffer.concat([buf, chunk]);
474
+ if (timer)
475
+ clearTimeout(timer);
476
+ timer = setTimeout(flush, 50);
477
+ });
478
+ }
390
479
 
391
480
  // src/cli/index.ts
392
481
  var GO_ALIASES = new Set(["go", "a", "run", "attach", "open"]);
@@ -409,6 +498,7 @@ function printHelp() {
409
498
  row("stop", "Stop the webtty server"),
410
499
  row("start", "Start the webtty server"),
411
500
  row("config", "Open the config file in $VISUAL, $EDITOR, or a default editor"),
501
+ row("key", "Capture a key combo and print its chars value for keyboardBindings"),
412
502
  row("help", "Show this help message")
413
503
  ].join(`
414
504
  `));
@@ -442,6 +532,9 @@ if (!cmd) {
442
532
  case "config":
443
533
  cmdConfig();
444
534
  break;
535
+ case "key":
536
+ cmdKey();
537
+ break;
445
538
  case "help":
446
539
  case "--help":
447
540
  case "-h":
@@ -454,4 +547,4 @@ Run \`webtty help\` for usage.`);
454
547
  }
455
548
  }
456
549
 
457
- //# debugId=4C1C000D06D317F764756E2164756E21
550
+ //# debugId=C605AEBE349A513364756E2164756E21
@@ -2,12 +2,12 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/cli/commands.ts", "../src/config.ts", "../src/cli/http.ts", "../src/cli/index.ts"],
4
4
  "sourcesContent": [
5
- "import * as childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { configDir } from '../config';\nimport { BASE_URL, isServerRunning, openBrowser, startServer, stopServer } from './http';\n\n/**\n * Opens (or creates) session `id`, starts the server if needed, and opens the URL in the browser.\n *\n * @param id - The session ID to open (default: `'main'`).\n */\nexport async function cmdGo(id = 'main'): Promise<void> {\n if (!(await isServerRunning())) {\n await startServer();\n }\n\n let sessionId: string;\n const check = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`);\n if (check.status === 200) {\n sessionId = id;\n } else {\n const res = await fetch(`${BASE_URL}/api/sessions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id }),\n });\n if (!res.ok) {\n const body = (await res.json()) as { error?: string };\n console.error(`webtty: ${body.error ?? `failed to create session (${res.status})`}`);\n process.exit(1);\n }\n const session = (await res.json()) as { id: string };\n sessionId = session.id;\n }\n\n const url = `${BASE_URL}/s/${sessionId}`;\n console.log(url);\n openBrowser(url);\n}\n\n/**\n * Lists all active sessions, optionally filtered by a substring of the session ID.\n *\n * @param filter - Optional substring to filter session IDs.\n */\nexport async function cmdList(filter?: string): Promise<void> {\n let res: Response;\n try {\n res = await fetch(`${BASE_URL}/api/sessions`);\n } catch {\n console.log('webtty is not running');\n process.exit(1);\n }\n const all = (await res.json()) as Array<{\n id: string;\n connected: boolean;\n createdAt: number;\n }>;\n const sessions = filter ? all.filter((s) => s.id.includes(filter)) : all;\n if (sessions.length === 0) {\n console.log('no sessions');\n return;\n }\n console.log('id\\t\\t\\tconnected\\tcreated');\n for (const s of sessions) {\n const created = new Date(s.createdAt).toLocaleString();\n console.log(`${s.id}\\t\\t\\t${s.connected}\\t\\t${created}`);\n }\n}\n\n/**\n * Removes session `id` and stops the server if no sessions remain.\n *\n * @param id - The session ID to remove.\n */\nexport async function cmdRemove(id?: string): Promise<void> {\n if (!id) {\n console.error('webtty: rm requires a session id');\n process.exit(1);\n }\n let res: Response;\n try {\n res = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n });\n } catch {\n console.log('webtty is not running');\n process.exit(1);\n }\n if (res.status === 204) {\n console.log(`removed ${id}`);\n if (res.headers.get('x-sessions-remaining') === '0') {\n await stopServer();\n console.log('no sessions remaining — webtty stopped');\n }\n } else if (res.status === 404) {\n console.error(`session ${id} not found`);\n process.exit(1);\n } else {\n console.error(`webtty rm failed (status: ${res.status})`);\n process.exit(1);\n }\n}\n\n/**\n * Renames session `id` to `newId`.\n *\n * @param id - The current session ID.\n * @param newId - The new session ID.\n */\nexport async function cmdRename(id?: string, newId?: string): Promise<void> {\n if (!id || !newId) {\n console.error('webtty: rename requires two arguments: [id] [new-id]');\n process.exit(1);\n }\n let res: Response;\n try {\n res = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: newId }),\n });\n } catch {\n console.log('webtty is not running');\n process.exit(1);\n }\n if (res.ok) {\n console.log(`renamed ${id} → ${newId}`);\n } else if (res.status === 404) {\n console.error(`session ${id} not found`);\n process.exit(1);\n } else {\n const body = (await res.json()) as { error?: string };\n console.error(`webtty: ${body.error ?? `rename failed (${res.status})`}`);\n process.exit(1);\n }\n}\n\n/** Stops the server if it is running. */\nexport async function cmdStop(): Promise<void> {\n if (!(await isServerRunning())) {\n console.log('webtty is not running');\n return;\n }\n const ok = await stopServer();\n if (ok) {\n console.log('webtty stopped');\n } else {\n console.error('webtty stop failed');\n process.exit(1);\n }\n}\n\n/** Starts the server if it is not already running. */\nexport async function cmdStart(): Promise<void> {\n if (await isServerRunning()) {\n console.log('webtty is already running');\n return;\n }\n await startServer();\n console.log('webtty started');\n}\n\n/** Opens `~/.config/webtty/config.json` in `$VISUAL` / `$EDITOR`, creating it if absent. */\nexport function cmdConfig(): void {\n const dir = configDir();\n const configPath = path.join(dir, 'config.json');\n fs.mkdirSync(dir, { recursive: true });\n if (!fs.existsSync(configPath)) {\n fs.writeFileSync(configPath, '{}\\n', 'utf8');\n }\n const editor =\n process.env.VISUAL ?? process.env.EDITOR ?? (process.platform === 'win32' ? 'notepad' : 'vi');\n childProcess.spawnSync(editor, [configPath], { stdio: 'inherit' });\n}\n",
5
+ "import * as childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { configDir } from '../config';\nimport { BASE_URL, isServerRunning, openBrowser, startServer, stopServer } from './http';\n\n/**\n * Opens (or creates) session `id`, starts the server if needed, and opens the URL in the browser.\n *\n * @param id - The session ID to open (default: `'main'`).\n */\nexport async function cmdGo(id = 'main'): Promise<void> {\n if (!(await isServerRunning())) {\n await startServer();\n }\n\n let sessionId: string;\n const check = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`);\n if (check.status === 200) {\n sessionId = id;\n } else {\n const res = await fetch(`${BASE_URL}/api/sessions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id }),\n });\n if (!res.ok) {\n const body = (await res.json()) as { error?: string };\n console.error(`webtty: ${body.error ?? `failed to create session (${res.status})`}`);\n process.exit(1);\n }\n const session = (await res.json()) as { id: string };\n sessionId = session.id;\n }\n\n const url = `${BASE_URL}/s/${sessionId}`;\n console.log(url);\n openBrowser(url);\n}\n\n/**\n * Lists all active sessions, optionally filtered by a substring of the session ID.\n *\n * @param filter - Optional substring to filter session IDs.\n */\nexport async function cmdList(filter?: string): Promise<void> {\n let res: Response;\n try {\n res = await fetch(`${BASE_URL}/api/sessions`);\n } catch {\n console.log('webtty is not running');\n process.exit(1);\n }\n const all = (await res.json()) as Array<{\n id: string;\n connected: boolean;\n createdAt: number;\n }>;\n const sessions = filter ? all.filter((s) => s.id.includes(filter)) : all;\n if (sessions.length === 0) {\n console.log('no sessions');\n return;\n }\n console.log('id\\t\\t\\tconnected\\tcreated');\n for (const s of sessions) {\n const created = new Date(s.createdAt).toLocaleString();\n console.log(`${s.id}\\t\\t\\t${s.connected}\\t\\t${created}`);\n }\n}\n\n/**\n * Removes session `id` and stops the server if no sessions remain.\n *\n * @param id - The session ID to remove.\n */\nexport async function cmdRemove(id?: string): Promise<void> {\n if (!id) {\n console.error('webtty: rm requires a session id');\n process.exit(1);\n }\n let res: Response;\n try {\n res = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n });\n } catch {\n console.log('webtty is not running');\n process.exit(1);\n }\n if (res.status === 204) {\n console.log(`removed ${id}`);\n if (res.headers.get('x-sessions-remaining') === '0') {\n await stopServer();\n console.log('no sessions remaining — webtty stopped');\n }\n } else if (res.status === 404) {\n console.error(`session ${id} not found`);\n process.exit(1);\n } else {\n console.error(`webtty rm failed (status: ${res.status})`);\n process.exit(1);\n }\n}\n\n/**\n * Renames session `id` to `newId`.\n *\n * @param id - The current session ID.\n * @param newId - The new session ID.\n */\nexport async function cmdRename(id?: string, newId?: string): Promise<void> {\n if (!id || !newId) {\n console.error('webtty: rename requires two arguments: [id] [new-id]');\n process.exit(1);\n }\n let res: Response;\n try {\n res = await fetch(`${BASE_URL}/api/sessions/${encodeURIComponent(id)}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: newId }),\n });\n } catch {\n console.log('webtty is not running');\n process.exit(1);\n }\n if (res.ok) {\n console.log(`renamed ${id} → ${newId}`);\n } else if (res.status === 404) {\n console.error(`session ${id} not found`);\n process.exit(1);\n } else {\n const body = (await res.json()) as { error?: string };\n console.error(`webtty: ${body.error ?? `rename failed (${res.status})`}`);\n process.exit(1);\n }\n}\n\n/** Stops the server if it is running. */\nexport async function cmdStop(): Promise<void> {\n if (!(await isServerRunning())) {\n console.log('webtty is not running');\n return;\n }\n const ok = await stopServer();\n if (ok) {\n console.log('webtty stopped');\n } else {\n console.error('webtty stop failed');\n process.exit(1);\n }\n}\n\n/** Starts the server if it is not already running. */\nexport async function cmdStart(): Promise<void> {\n if (await isServerRunning()) {\n console.log('webtty is already running');\n return;\n }\n await startServer();\n console.log('webtty started');\n}\n\n/** Opens `~/.config/webtty/config.json` in `$VISUAL` / `$EDITOR`, creating it if absent. */\nexport function cmdConfig(): void {\n const dir = configDir();\n const configPath = path.join(dir, 'config.json');\n fs.mkdirSync(dir, { recursive: true });\n if (!fs.existsSync(configPath)) {\n fs.writeFileSync(configPath, '{}\\n', 'utf8');\n }\n const editor =\n process.env.VISUAL ?? process.env.EDITOR ?? (process.platform === 'win32' ? 'notepad' : 'vi');\n childProcess.spawnSync(editor, [configPath], { stdio: 'inherit' });\n}\n\nexport function bytesToChars(buf: Buffer): string {\n let out = '';\n for (const b of buf) {\n if (b === 0x1b) out += '\\\\u001b';\n else if (b === 0x0d) out += '\\\\r';\n else if (b === 0x09) out += '\\\\t';\n else if (b === 0x0a) out += '\\\\n';\n else if (b === 0x22) out += '\\\\\"';\n else if (b === 0x5c) out += '\\\\\\\\';\n else if (b >= 0x20 && b < 0x7f) out += String.fromCharCode(b);\n else out += `\\\\u${b.toString(16).padStart(4, '0')}`;\n }\n return `\"${out}\"`;\n}\n\nexport function bytesToDisplay(buf: Buffer): string {\n return Array.from(buf)\n .map((b) => {\n if (b === 0x1b) return 'ESC';\n if (b === 0x0d) return 'CR';\n if (b === 0x09) return 'TAB';\n if (b === 0x0a) return 'LF';\n if (b === 0x20) return 'SPC';\n if (b === 0x7f) return 'DEL';\n if (b > 0x20 && b < 0x7f) return String.fromCharCode(b);\n return `\\\\x${b.toString(16).padStart(2, '0')}`;\n })\n .join(' ');\n}\n\nexport function cmdKey(): void {\n if (!process.stdin.isTTY) {\n console.error('webtty key: requires an interactive terminal');\n process.exit(1);\n return;\n }\n\n const dim = '\\x1b[2m';\n const bold = '\\x1b[1m';\n const reset = '\\x1b[0m';\n\n const restoreTerminal = () => {\n try {\n process.stdin.setRawMode(false);\n } catch {}\n };\n process.once('exit', restoreTerminal);\n process.once('SIGINT', restoreTerminal);\n process.once('SIGTERM', restoreTerminal);\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n console.log('Press any key combo to see its chars value. q to quit.\\n');\n console.log(` ${dim}received${reset} → ${bold}chars${reset}`);\n console.log(` ${'─'.repeat(17)}`);\n\n let buf = Buffer.alloc(0);\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const flush = () => {\n if (buf.length === 0) return;\n const display = bytesToDisplay(buf).padEnd(8);\n console.log(` ${dim}${display}${reset} → ${bold}${bytesToChars(buf)}${reset}`);\n buf = Buffer.alloc(0);\n };\n\n process.stdin.on('data', (chunk: Buffer) => {\n if (chunk.length === 1 && chunk[0] === 0x71) {\n process.stdin.setRawMode(false);\n process.removeListener('exit', restoreTerminal);\n process.removeListener('SIGINT', restoreTerminal);\n process.removeListener('SIGTERM', restoreTerminal);\n console.log(` ${'─'.repeat(17)}\\n`);\n process.exit(0);\n }\n buf = Buffer.concat([buf, chunk]);\n if (timer) clearTimeout(timer);\n timer = setTimeout(flush, 50);\n });\n}\n",
6
6
  "import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\n/** A single keyboard binding: intercepts `key`+`mods` and sends `chars` to the PTY. */\nexport interface KeyboardBinding {\n /** Key name matched case-insensitively against `KeyboardEvent.key` (e.g. `\"enter\"`, `\"arrowup\"`, `\"a\"`). */\n key: string;\n /** Modifier keys that must be active — and no others — for this binding to match. Accepted values: `\"shift\"`, `\"ctrl\"`, `\"alt\"`, `\"meta\"`. Order irrelevant. Unknown values are filtered out at config load time. */\n mods?: string[];\n /** Byte sequence sent verbatim to the PTY. Standard JSON escapes apply (`\\r`, `\\uXXXX`, etc.). */\n chars: string;\n}\n\n/** Terminal color palette. All keys are optional; omitted keys fall back to the Campbell defaults. */\nexport interface Theme {\n /** Terminal background. */\n background?: string;\n /** Default text color. */\n foreground?: string;\n /** Cursor color. */\n cursor?: string;\n /** Selection highlight. */\n selection?: string;\n /** ANSI 0. */\n black?: string;\n /** ANSI 1. */\n red?: string;\n /** ANSI 2. */\n green?: string;\n /** ANSI 3. */\n yellow?: string;\n /** ANSI 4. */\n blue?: string;\n /** ANSI 5. */\n purple?: string;\n /** ANSI 6. */\n cyan?: string;\n /** ANSI 7. */\n white?: string;\n /** ANSI 8. */\n brightBlack?: string;\n /** ANSI 9. */\n brightRed?: string;\n /** ANSI 10. */\n brightGreen?: string;\n /** ANSI 11. */\n brightYellow?: string;\n /** ANSI 12. */\n brightBlue?: string;\n /** ANSI 13. */\n brightPurple?: string;\n /** ANSI 14. */\n brightCyan?: string;\n /** ANSI 15. */\n brightWhite?: string;\n}\n\n/** Right-click behavior: `\"copyPaste\"` copies selection + clears it if selection exists, otherwise native menu; `\"default\"` always shows native context menu. */\nexport type RightClickBehavior = 'default' | 'copyPaste';\n\n/** Full webtty configuration. All keys are optional in the config file; missing keys fall back to {@link DEFAULT_CONFIG}. */\nexport interface Config {\n /** HTTP listen port; env `PORT` takes precedence. */\n port: number;\n /** Bind address; use `\"0.0.0.0\"` for remote access. */\n host: string;\n /** Shell for new sessions. */\n shell: string;\n /** `$TERM` env var passed to the shell. Fixed to `xterm-256color` — the PTY child talks to webtty, not to the parent terminal. */\n term: string;\n /** `$COLORTERM` env var passed to the shell. */\n colorTerm: string;\n /** PTY history buffer in bytes; used for server-side replay on reload/reconnect. */\n scrollback: number;\n /** Initial terminal width in columns. */\n cols: number;\n /** Initial terminal height in rows. */\n rows: number;\n /** Font size in px. */\n fontSize: number;\n /** CSS font-family stack. */\n fontFamily: string;\n /** Default cursor shape. Apps override at runtime via DECSCUSR — this is the startup default only. */\n cursorStyle: 'block' | 'bar' | 'underline';\n /** Default blink state. Apps override at runtime via DECSCUSR — this is the startup default only. */\n cursorStyleBlink: boolean;\n /** Auto-copy selection to clipboard on mouseup (kitty / Windows Terminal style). */\n copyOnSelect: boolean;\n /** `\"copyPaste\"` copies selection + clears it on right-click if selection exists; `\"default\"` always shows native context menu. */\n rightClickBehavior: RightClickBehavior;\n /** Mouse wheel scroll speed multiplier for apps with mouse tracking. `1` = one SGR per tick. Values `< 1` reduce rate; values `> 1` send multiple SGRs per tick. Must be `> 0`. */\n mouseScrollSpeed: number;\n /** Write server stdout/stderr to `~/.config/webtty/server.log`. Appends on each start. */\n logs: boolean;\n /** Terminal color palette. */\n theme: Theme;\n /** Custom key-to-sequence bindings. Merged with built-in defaults by `(key, mods)` identity. */\n keyboardBindings: KeyboardBinding[];\n}\n\n/** Returns the webtty config directory: `~/.config/webtty`. */\nexport function configDir(): string {\n return path.join(process.env.HOME ?? os.homedir(), '.config', 'webtty');\n}\n\nfunction getConfigPath(): string {\n return path.join(configDir(), 'config.json');\n}\n\n// NOTE: export for testing only; users should use loadConfig() and initConfig() instead\nexport const DEFAULT_THEME: Theme = {\n background: '#000000',\n foreground: '#CCCCCC',\n cursor: '#FFFFFF',\n selection: '#FFFFFF',\n black: '#0C0C0C',\n red: '#C50F1F',\n green: '#13A10E',\n yellow: '#C19C00',\n blue: '#0037DA',\n purple: '#881798',\n cyan: '#3A96DD',\n white: '#CCCCCC',\n brightBlack: '#767676',\n brightRed: '#E74856',\n brightGreen: '#16C60C',\n brightYellow: '#F9F1A5',\n brightBlue: '#3B78FF',\n brightPurple: '#B4009E',\n brightCyan: '#61D6D6',\n brightWhite: '#F2F2F2',\n};\n\n// NOTE: export for testing only; users should use loadConfig() and initConfig() instead\nexport const DEFAULT_KEYBOARD_BINDINGS: KeyboardBinding[] = [];\n\n// NOTE: export for testing only; users should use loadConfig() and initConfig() instead\nexport const DEFAULT_CONFIG: Config = {\n port: 2346,\n host: '127.0.0.1',\n shell:\n process.platform === 'win32'\n ? (process.env.COMSPEC ?? 'cmd.exe')\n : (process.env.SHELL ?? '/bin/bash'),\n term: 'xterm-256color',\n colorTerm: 'truecolor',\n scrollback: 256 * 1024,\n cols: 80,\n rows: 24,\n fontSize: 13,\n fontFamily: \"Menlo, Consolas, 'DejaVu Sans Mono', monospace\",\n cursorStyle: 'bar',\n cursorStyleBlink: true,\n copyOnSelect: true,\n rightClickBehavior: 'default' as RightClickBehavior,\n mouseScrollSpeed: 1,\n logs: false,\n theme: DEFAULT_THEME,\n keyboardBindings: DEFAULT_KEYBOARD_BINDINGS,\n};\n\nfunction bindingKey(b: KeyboardBinding): string {\n const mods = [...(b.mods ?? [])].sort().join('+');\n return `${b.key.toLowerCase()}|${mods}`;\n}\n\nconst VALID_MODS = new Set(['shift', 'ctrl', 'alt', 'meta']);\n\nfunction isValidBinding(b: unknown): b is KeyboardBinding {\n if (!b || typeof b !== 'object') return false;\n const o = b as Record<string, unknown>;\n if (typeof o.key !== 'string' || typeof o.chars !== 'string') return false;\n if (o.mods !== undefined && !Array.isArray(o.mods)) return false;\n return true;\n}\n\nfunction normalizeBinding(b: KeyboardBinding): KeyboardBinding {\n return {\n ...b,\n key: b.key.toLowerCase(),\n mods: (b.mods ?? []).map((m) => m.toLowerCase()).filter((m) => VALID_MODS.has(m)),\n };\n}\n\n/**\n * Merges user-supplied bindings over a set of defaults by `(key, mods)` identity.\n * User entries replace matching defaults; unmatched user entries are appended.\n *\n * @param defaults - Default bindings to merge over.\n * @param user - User-supplied bindings that override defaults.\n * @returns Merged bindings with user entries replacing matching defaults and new user entries appended.\n */\n// NOTE: export for testing only\nexport function mergeKeyboardBindings(\n defaults: KeyboardBinding[],\n user: KeyboardBinding[],\n): KeyboardBinding[] {\n const deduped = [...new Map(user.map((b) => [bindingKey(b), b])).values()];\n const overrides = new Map(deduped.map((b) => [bindingKey(b), b]));\n const merged = defaults.map((d) => overrides.get(bindingKey(d)) ?? d);\n const defaultKeys = new Set(defaults.map(bindingKey));\n for (const b of deduped) {\n if (!defaultKeys.has(bindingKey(b))) merged.push(b);\n }\n return merged;\n}\n\n/**\n * Load config from `~/.config/webtty/config.json`, merged over `DEFAULT_CONFIG`.\n *\n * On first run (file absent), writes the default port/host stub and returns defaults.\n * Unknown keys and keys with wrong types are silently ignored.\n * Throws if the file exists but cannot be read or contains invalid JSON.\n *\n * @returns The resolved {@link Config}, with all missing keys filled from {@link DEFAULT_CONFIG}.\n */\nexport function loadConfig(): Config {\n if (!fs.existsSync(getConfigPath())) {\n try {\n initConfig();\n } catch (err) {\n console.warn(\n `webtty: failed to write default config to ${getConfigPath()}: ${(err as Error).message}`,\n );\n return { ...DEFAULT_CONFIG };\n }\n }\n\n let raw: string;\n try {\n raw = fs.readFileSync(getConfigPath(), 'utf8');\n } catch (err) {\n throw new Error(\n `webtty: failed to read config at ${getConfigPath()}: ${(err as Error).message}`,\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`webtty: invalid JSON in config file ${getConfigPath()}`);\n }\n\n const p = parsed as Partial<Config>;\n return {\n ...DEFAULT_CONFIG,\n ...(typeof p.port === 'number' && { port: p.port }),\n ...(typeof p.host === 'string' && { host: p.host }),\n ...(typeof p.shell === 'string' && { shell: p.shell }),\n ...(typeof p.term === 'string' && { term: p.term }),\n ...(typeof p.colorTerm === 'string' && { colorTerm: p.colorTerm }),\n ...(typeof p.scrollback === 'number' && { scrollback: p.scrollback }),\n ...(typeof p.cols === 'number' && { cols: p.cols }),\n ...(typeof p.rows === 'number' && { rows: p.rows }),\n ...(typeof p.fontSize === 'number' && { fontSize: p.fontSize }),\n ...(typeof p.fontFamily === 'string' && { fontFamily: p.fontFamily }),\n ...(typeof p.cursorStyle === 'string' &&\n (p.cursorStyle === 'block' || p.cursorStyle === 'bar' || p.cursorStyle === 'underline') && {\n cursorStyle: p.cursorStyle,\n }),\n ...(typeof p.cursorStyleBlink === 'boolean' && { cursorStyleBlink: p.cursorStyleBlink }),\n ...(typeof p.copyOnSelect === 'boolean' && { copyOnSelect: p.copyOnSelect }),\n ...(typeof p.rightClickBehavior === 'string' && {\n rightClickBehavior: (p.rightClickBehavior === 'copyPaste'\n ? 'copyPaste'\n : 'default') as RightClickBehavior,\n }),\n ...(typeof p.mouseScrollSpeed === 'number' &&\n p.mouseScrollSpeed > 0 && { mouseScrollSpeed: p.mouseScrollSpeed }),\n ...(typeof p.logs === 'boolean' && { logs: p.logs }),\n ...(p.theme && typeof p.theme === 'object' && { theme: { ...DEFAULT_THEME, ...p.theme } }),\n ...(Array.isArray(p.keyboardBindings) && {\n keyboardBindings: mergeKeyboardBindings(\n DEFAULT_KEYBOARD_BINDINGS,\n p.keyboardBindings.filter(isValidBinding).map(normalizeBinding),\n ),\n }),\n };\n}\n\n/**\n * Write the initial config stub (`port` + `host` only) to `~/.config/webtty/config.json`.\n *\n * Only writes the two keys that are safe to persist as defaults; all other\n * keys are intentionally omitted so future webtty versions can add new fields\n * without the stub going stale.\n */\nexport function initConfig(): void {\n fs.mkdirSync(path.dirname(getConfigPath()), { recursive: true });\n const content = JSON.stringify(\n {\n port: DEFAULT_CONFIG.port,\n host: DEFAULT_CONFIG.host,\n },\n null,\n 2,\n );\n fs.writeFileSync(getConfigPath(), content, 'utf8');\n}\n",
7
7
  "import * as childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { configDir, loadConfig } from '../config';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/** Active server port, resolved from `PORT` env or config default. */\nexport const PORT = Number(process.env.PORT) || 2346;\n\n/** Base URL for the local server (always 127.0.0.1). */\nexport const BASE_URL = `http://127.0.0.1:${PORT}`;\n\n/** Returns the path to the server log file: `~/.config/webtty/server.log`. */\nexport function logPath(): string {\n return path.join(configDir(), 'server.log');\n}\n\n/** Returns `true` if the webtty server is reachable and responding to API requests. */\nexport async function isServerRunning(): Promise<boolean> {\n try {\n const res = await fetch(`${BASE_URL}/api/sessions`);\n if (!res.ok) return false;\n const body = await res.json();\n return Array.isArray(body);\n } catch {\n return false;\n }\n}\n\n/**\n * Spawns the server process detached, then polls until it is ready or `timeoutMs` expires.\n *\n * @param timeoutMs - Maximum time to wait for the server to start (default: 10000 ms).\n * @param _spawn - Spawn function override for testing (default: childProcess.spawn).\n * @throws Exits the process with code 1 if the server entry is not found or fails to start in time.\n */\nexport async function startServer(timeoutMs = 10000, _spawn = childProcess.spawn): Promise<void> {\n const isBun = typeof (globalThis as Record<string, unknown>).Bun !== 'undefined';\n const isTs = isBun && __filename.endsWith('.ts');\n const serverEntry = path.resolve(__dirname, isTs ? '../server/index.ts' : '../server/index.js');\n if (!fs.existsSync(serverEntry)) {\n console.error(`webtty: server entry not found at ${serverEntry}`);\n process.exit(1);\n }\n\n const config = loadConfig();\n let stdio: childProcess.SpawnOptions['stdio'] = 'ignore';\n let logFd: number | undefined;\n if (config.logs) {\n const log = logPath();\n fs.mkdirSync(path.dirname(log), { recursive: true });\n logFd = fs.openSync(log, 'a');\n stdio = ['ignore', logFd, logFd];\n }\n\n const child = _spawn(process.execPath, [serverEntry], {\n detached: true,\n stdio,\n env: { ...process.env, PORT: String(PORT) },\n });\n child.unref();\n if (logFd !== undefined) fs.closeSync(logFd);\n\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await isServerRunning()) return;\n await new Promise((r) => setTimeout(r, 100));\n }\n console.error('webtty: server did not start in time');\n process.exit(1);\n}\n\n/**\n * Sends `POST /api/server/stop`, then polls until the server is no longer reachable.\n *\n * @param baseUrl - The server base URL (default: BASE_URL).\n * @param timeoutMs - Maximum time to wait for the server to stop (default: 5000 ms).\n * @returns `true` if the server stopped successfully, `false` otherwise.\n */\nexport async function stopServer(baseUrl: string = BASE_URL, timeoutMs = 5000): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl}/api/server/stop`, { method: 'POST' });\n if (!res.ok) return false;\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (!(await isServerRunning())) return true;\n await new Promise((r) => setTimeout(r, 100));\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Opens `url` in the default system browser.\n * No-op in test environments or when `WEBTTY_NO_OPEN=1` is set.\n *\n * @param url - The URL to open.\n * @param _spawn - Spawn function override for testing (default: childProcess.spawn).\n */\nexport function openBrowser(url: string, _spawn = childProcess.spawn): void {\n if (process.env.WEBTTY_NO_OPEN === '1') return;\n if (process.env.NODE_ENV === 'test') return;\n if (process.platform === 'win32') {\n _spawn('cmd.exe', ['/c', 'start', '', url], { detached: true, stdio: 'ignore' }).unref();\n } else {\n const cmd = process.platform === 'darwin' ? 'open' : 'xdg-open';\n _spawn(cmd, [url], { detached: true, stdio: 'ignore' }).unref();\n }\n}\n",
8
- "import { cmdConfig, cmdGo, cmdList, cmdRemove, cmdRename, cmdStart, cmdStop } from './commands';\n\nconst GO_ALIASES = new Set(['go', 'a', 'run', 'attach', 'open']);\n\nfunction printHelp(): void {\n const indent = ' ';\n const col = 18; // width of the widest term: \"mv <id> <new-id>\"\n const row = (term: string, desc: string) => `${indent}${term.padEnd(col)} ${desc}`;\n\n console.log(\n [\n 'Launch Terminal UI in the browser.',\n '',\n 'USAGE',\n row('webtty', 'Open main session in the browser'),\n row('webtty [command]', 'Execute a specific command'),\n '',\n 'COMMANDS',\n row('go [id]', 'Open a new or existing session in the browser'),\n row('ls [id]', 'List all sessions, or filter by id substring'),\n row('rm <id>', 'Destroy a session'),\n row('mv <id> <new-id>', 'Rename a session'),\n row('stop', 'Stop the webtty server'),\n row('start', 'Start the webtty server'),\n row('config', 'Open the config file in $VISUAL, $EDITOR, or a default editor'),\n row('help', 'Show this help message'),\n ].join('\\n'),\n );\n}\n\nconst [, , cmd, ...rest] = process.argv;\n\nif (!cmd) {\n await cmdGo();\n} else if (GO_ALIASES.has(cmd)) {\n await cmdGo(rest[0]);\n} else {\n switch (cmd) {\n case 'ls':\n case 'list':\n await cmdList(rest[0]);\n break;\n case 'rm':\n case 'remove':\n await cmdRemove(rest[0]);\n break;\n case 'mv':\n case 'move':\n case 'rename':\n await cmdRename(rest[0], rest[1]);\n break;\n case 'stop':\n await cmdStop();\n break;\n case 'start':\n await cmdStart();\n break;\n case 'config':\n cmdConfig();\n break;\n case 'help':\n case '--help':\n case '-h':\n printHelp();\n break;\n default:\n console.error(`webtty: unknown command '${cmd}'\\nRun \\`webtty help\\` for usage.`);\n process.exit(1);\n }\n}\n"
8
+ "import {\n cmdConfig,\n cmdGo,\n cmdKey,\n cmdList,\n cmdRemove,\n cmdRename,\n cmdStart,\n cmdStop,\n} from './commands';\n\nconst GO_ALIASES = new Set(['go', 'a', 'run', 'attach', 'open']);\n\nfunction printHelp(): void {\n const indent = ' ';\n const col = 18; // width of the widest term: \"mv <id> <new-id>\"\n const row = (term: string, desc: string) => `${indent}${term.padEnd(col)} ${desc}`;\n\n console.log(\n [\n 'Launch Terminal UI in the browser.',\n '',\n 'USAGE',\n row('webtty', 'Open main session in the browser'),\n row('webtty [command]', 'Execute a specific command'),\n '',\n 'COMMANDS',\n row('go [id]', 'Open a new or existing session in the browser'),\n row('ls [id]', 'List all sessions, or filter by id substring'),\n row('rm <id>', 'Destroy a session'),\n row('mv <id> <new-id>', 'Rename a session'),\n row('stop', 'Stop the webtty server'),\n row('start', 'Start the webtty server'),\n row('config', 'Open the config file in $VISUAL, $EDITOR, or a default editor'),\n row('key', 'Capture a key combo and print its chars value for keyboardBindings'),\n row('help', 'Show this help message'),\n ].join('\\n'),\n );\n}\n\nconst [, , cmd, ...rest] = process.argv;\n\nif (!cmd) {\n await cmdGo();\n} else if (GO_ALIASES.has(cmd)) {\n await cmdGo(rest[0]);\n} else {\n switch (cmd) {\n case 'ls':\n case 'list':\n await cmdList(rest[0]);\n break;\n case 'rm':\n case 'remove':\n await cmdRemove(rest[0]);\n break;\n case 'mv':\n case 'move':\n case 'rename':\n await cmdRename(rest[0], rest[1]);\n break;\n case 'stop':\n await cmdStop();\n break;\n case 'start':\n await cmdStart();\n break;\n case 'config':\n cmdConfig();\n break;\n case 'key':\n cmdKey();\n break;\n case 'help':\n case '--help':\n case '-h':\n printHelp();\n break;\n default:\n console.error(`webtty: unknown command '${cmd}'\\nRun \\`webtty help\\` for usage.`);\n process.exit(1);\n }\n}\n"
9
9
  ],
10
- "mappings": "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",
11
- "debugId": "4C1C000D06D317F764756E2164756E21",
10
+ "mappings": "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",
11
+ "debugId": "C605AEBE349A513364756E2164756E21",
12
12
  "names": []
13
13
  }
@@ -1,3 +1,3 @@
1
- import{FitAddon as L,init as M,Terminal as y}from"/dist/ghostty-web.js";var B=new RegExp("\x1B\\[(\\d*) q","g");function W(j,G){let Q=j.options.cursorStyle,P=j.options.cursorBlink;B.lastIndex=0;let K=B.exec(G);while(K!==null){let J=K[1]===""?0:Number(K[1]);if(!Number.isNaN(J)&&J>=0&&J<=6)j.options.cursorStyle=J===0||J===1||J===2?"block":J===3||J===4?"underline":"bar",j.options.cursorBlink=J===0||J===1||J===3||J===5;K=B.exec(G)}if((j.options.cursorStyle!==Q||j.options.cursorBlink!==P)&&j.renderer&&j.wasmTerm)j.renderer.render(j.wasmTerm,!0,j.viewportY)}var O=window.location.pathname.split("/s/")[1]??"main",N=await fetch("/api/config").then((j)=>j.json());document.title=`${O} | webtty`;await M();var z=new y({cols:N.cols,rows:N.rows,cursorStyle:N.cursorStyle,cursorBlink:N.cursorStyleBlink,fontSize:N.fontSize,fontFamily:N.fontFamily,scrollback:Math.ceil(N.scrollback/80),theme:N.theme}),_=new L;z.loadAddon(_);var $=document.getElementById("terminal");await z.open($);_.fit();_.observeResize();var U=window.location.protocol==="https:"?"wss:":"ws:",H;function q(){let j=`${U}//${window.location.host}/ws/${O}?cols=${z.cols}&rows=${z.rows}`;H=new WebSocket(j);let G="\x1B[2m",Q="\x1B[1;33m",P="\x1B[3m",K="\x1B[0m",J=`${G}[${K} ${Q}webtty${K} ${G}]${K}`,V=(X)=>`\r
2
- ${J} ${G}${P}${X}${K}\r
3
- `;H.onopen=()=>{H.send(JSON.stringify({type:"resize",cols:z.cols,rows:z.rows}))},H.onmessage=(X)=>{W(z,X.data),z.write(X.data)},H.onclose=(X)=>{if(X.code===4001){z.write(V("Session removed.")),setTimeout(()=>window.close(),500);return}if(X.code===1001){z.write(V("Server stopped.")),setTimeout(()=>window.close(),500);return}z.write(V("Connection lost. Reconnecting in 2s...")),setTimeout(q,2000)},H.onerror=()=>{z.write(V("WebSocket error."))}}q();var Z=0,Y=0;z.attachCustomWheelEventHandler((j)=>{if(!z.hasMouseTracking())return!1;let G=z.renderer?.getMetrics();if(!G)return!1;let Q=j.deltaY<0?-1:1;if(Q!==Y)Z=0,Y=Q;Z+=N.mouseScrollSpeed;let P=Math.trunc(Z);if(P===0)return!0;Z-=P;let K=j.target.getBoundingClientRect(),J=Math.max(1,Math.floor((j.clientX-K.left)/G.width)+1),V=Math.max(1,Math.floor((j.clientY-K.top)/G.height)+1),x=`\x1B[<${Q<0?64:65};${J};${V}M`;if(H&&H.readyState===WebSocket.OPEN)for(let F=0;F<P;F++)H.send(x);return!0});$.addEventListener("keydown",(j)=>{let G=j.key.toLowerCase(),Q=new Set([...j.shiftKey?["shift"]:[],...j.ctrlKey?["ctrl"]:[],...j.altKey?["alt"]:[],...j.metaKey?["meta"]:[]]),P=N.keyboardBindings.find((K)=>{if(K.key.toLowerCase()!==G)return!1;let J=new Set((Array.isArray(K.mods)?K.mods:[]).map((V)=>V.toLowerCase()));if(J.size!==Q.size)return!1;for(let V of J)if(!Q.has(V))return!1;return!0});if(!P)return;if(j.preventDefault(),j.stopPropagation(),P.chars&&H.readyState===WebSocket.OPEN)H.send(P.chars)},{capture:!0});z.onData((j)=>{if(H&&H.readyState===WebSocket.OPEN)H.send(j)});z.onResize(({cols:j,rows:G})=>{if(H&&H.readyState===WebSocket.OPEN)H.send(JSON.stringify({type:"resize",cols:j,rows:G}))});window.addEventListener("resize",()=>{_.fit()});if(N.copyOnSelect)z.onSelectionChange(()=>{let j=z.getSelection();if(!j)return;navigator.clipboard.writeText(j).catch(()=>{})});if(N.rightClickBehavior==="copyPaste")$.addEventListener("contextmenu",(j)=>{let G=z.getSelection();if(!G)return;j.preventDefault(),navigator.clipboard.writeText(G).catch(()=>{}),z.clearSelection()});$.addEventListener("paste",(j)=>{let G=j.clipboardData;if(!G)return;if(G.getData("text/plain"))return;if(j.preventDefault(),j.stopImmediatePropagation(),H&&H.readyState===WebSocket.OPEN)H.send("\x16")},{capture:!0});
1
+ import{FitAddon as G,init as y,Terminal as U}from"/dist/ghostty-web.js";var B=new RegExp("\x1B\\[(\\d*) q","g");function W(j,z){let V=j.options.cursorStyle,X=j.options.cursorBlink;B.lastIndex=0;let N=B.exec(z);while(N!==null){let K=N[1]===""?0:Number(N[1]);if(!Number.isNaN(K)&&K>=0&&K<=6)j.options.cursorStyle=K===0||K===1||K===2?"block":K===3||K===4?"underline":"bar",j.options.cursorBlink=K===0||K===1||K===3||K===5;N=B.exec(z)}if((j.options.cursorStyle!==V||j.options.cursorBlink!==X)&&j.renderer&&j.wasmTerm)j.renderer.render(j.wasmTerm,!0,j.viewportY)}var O=window.location.pathname.split("/s/")[1]??"main",P=await fetch("/api/config").then((j)=>j.json());document.title=`${O} | webtty`;await y();var H=new U({cols:P.cols,rows:P.rows,cursorStyle:P.cursorStyle,cursorBlink:P.cursorStyleBlink,fontSize:P.fontSize,fontFamily:P.fontFamily,scrollback:Math.ceil(P.scrollback/80),theme:P.theme}),q=new G;H.loadAddon(q);var Q=document.getElementById("terminal");if(P.theme?.background)Q.style.background=P.theme.background;await H.open(Q);function x(){Q.style.padding="0",q.fit();let j=Q.querySelector("canvas");if(!j)return;let z=Math.max(0,Q.clientWidth-j.offsetWidth),V=Math.max(0,Q.clientHeight-j.offsetHeight);Q.style.paddingLeft=`${Math.floor(z/2)}px`,Q.style.paddingRight=`${Math.ceil(z/2)}px`,Q.style.paddingTop=`${Math.floor(V/2)}px`,Q.style.paddingBottom=`${Math.ceil(V/2)}px`}x();new ResizeObserver(()=>x()).observe(Q,{box:"border-box"});var k=window.location.protocol==="https:"?"wss:":"ws:",J;function L(){let j=`${k}//${window.location.host}/ws/${O}?cols=${H.cols}&rows=${H.rows}`;J=new WebSocket(j);let z="\x1B[2m",V="\x1B[1;33m",X="\x1B[3m",N="\x1B[0m",K=`${z}[${N} ${V}webtty${N} ${z}]${N}`,Z=(_)=>`\r
2
+ ${K} ${z}${X}${_}${N}\r
3
+ `;J.onopen=()=>{J.send(JSON.stringify({type:"resize",cols:H.cols,rows:H.rows}))},J.onmessage=(_)=>{W(H,_.data),H.write(_.data)},J.onclose=(_)=>{if(_.code===4001){H.write(Z("Session removed.")),setTimeout(()=>window.close(),500);return}if(_.code===1001){H.write(Z("Server stopped.")),setTimeout(()=>window.close(),500);return}H.write(Z("Connection lost. Reconnecting in 2s...")),setTimeout(L,2000)},J.onerror=()=>{H.write(Z("WebSocket error."))}}L();var $=0,Y=0;H.attachCustomWheelEventHandler((j)=>{if(!H.hasMouseTracking())return!1;let z=H.renderer?.getMetrics();if(!z)return!1;let V=j.deltaY<0?-1:1;if(V!==Y)$=0,Y=V;$+=P.mouseScrollSpeed;let X=Math.trunc($);if(X===0)return!0;$-=X;let N=j.target.getBoundingClientRect(),K=Math.max(1,Math.floor((j.clientX-N.left)/z.width)+1),Z=Math.max(1,Math.floor((j.clientY-N.top)/z.height)+1),M=`\x1B[<${V<0?64:65};${K};${Z}M`;if(J&&J.readyState===WebSocket.OPEN)for(let F=0;F<X;F++)J.send(M);return!0});Q.addEventListener("keydown",(j)=>{let z=j.key.toLowerCase(),V=new Set([...j.shiftKey?["shift"]:[],...j.ctrlKey?["ctrl"]:[],...j.altKey?["alt"]:[],...j.metaKey?["meta"]:[]]),X=P.keyboardBindings.find((N)=>{if(N.key.toLowerCase()!==z)return!1;let K=new Set((Array.isArray(N.mods)?N.mods:[]).map((Z)=>Z.toLowerCase()));if(K.size!==V.size)return!1;for(let Z of K)if(!V.has(Z))return!1;return!0});if(!X)return;if(j.preventDefault(),j.stopPropagation(),X.chars&&J.readyState===WebSocket.OPEN)J.send(X.chars)},{capture:!0});H.onData((j)=>{if(J&&J.readyState===WebSocket.OPEN)J.send(j)});H.onResize(({cols:j,rows:z})=>{if(J&&J.readyState===WebSocket.OPEN)J.send(JSON.stringify({type:"resize",cols:j,rows:z}))});if(P.copyOnSelect)H.onSelectionChange(()=>{let j=H.getSelection();if(!j)return;navigator.clipboard.writeText(j).catch(()=>{})});if(P.rightClickBehavior==="copyPaste")Q.addEventListener("contextmenu",(j)=>{let z=H.getSelection();if(!z)return;j.preventDefault(),navigator.clipboard.writeText(z).catch(()=>{}),H.clearSelection()});Q.addEventListener("paste",(j)=>{let z=j.clipboardData;if(!z)return;if(z.getData("text/plain"))return;if(j.preventDefault(),j.stopImmediatePropagation(),J&&J.readyState===WebSocket.OPEN)J.send("\x16")},{capture:!0});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webtty",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "description": "Web TTY for running CLI/TUI applications in a browser tab, across platforms",
5
5
  "license": "MIT",
6
6
  "bin": {