@co0ontty/wand 4.36.0 → 4.37.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.
@@ -12,9 +12,9 @@ export function vendorAssetUrl(relPath) {
12
12
  export function renderApp(configPath) {
13
13
  const cssStyles = getCSSStyles();
14
14
  const scriptContent = getScriptContent(configPath);
15
- const wtermSrc = vendorAssetUrl("/vendor/wterm/wterm.bundle.js");
15
+ const xtermSrc = vendorAssetUrl("/vendor/xterm/xterm.bundle.js");
16
16
  const qrcodeSrc = vendorAssetUrl("/vendor/qrcode/qrcode.bundle.js");
17
- const wtermCssHref = vendorAssetUrl("/vendor/wterm/terminal.css");
17
+ const xtermCssHref = vendorAssetUrl("/vendor/xterm/xterm.css");
18
18
  return `<!doctype html>
19
19
  <html lang="zh-CN">
20
20
  <head>
@@ -26,7 +26,7 @@ export function renderApp(configPath) {
26
26
  <meta name="theme-color" content="#1f1b17" media="(prefers-color-scheme: dark)" />
27
27
  <meta name="format-detection" content="telephone=no" />
28
28
  <meta name="msapplication-tap-highlight" content="no" />
29
- <link rel="stylesheet" href="${wtermCssHref}" />
29
+ <link rel="stylesheet" href="${xtermCssHref}" />
30
30
  <style>
31
31
  ${cssStyles}
32
32
  </style>
@@ -34,7 +34,7 @@ ${cssStyles}
34
34
  <body>
35
35
  <div id="app"></div>
36
36
  <div id="overlay-root" data-wand-ui-root></div>
37
- ${scriptOpen} src="${wtermSrc}">${scriptClose}
37
+ ${scriptOpen} src="${xtermSrc}">${scriptClose}
38
38
  ${scriptOpen} src="${qrcodeSrc}">${scriptClose}
39
39
  ${scriptOpen}>
40
40
  ${scriptContent}
@@ -10,7 +10,8 @@ export declare function inferProviderIdFromCommand(value: unknown): ProviderId |
10
10
  export declare function providerDisplayName(value: unknown): string;
11
11
  export declare const CLAUDE_LOGO_PATH = "m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z";
12
12
  export declare const CODEX_LOGO_PATH = "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z";
13
- export declare const PI_LOGO_PATH = "M4 5h16v4h-3v11h-4V9h-2v11H7V9H4Z";
13
+ export declare const PI_LOGO_PATH = "M165.29 165.29H517.36V400H400V517.36H282.65V634.72H165.29ZM282.65 282.65V400H400V282.65Z";
14
+ export declare const PI_LOGO_DOT_PATH = "M517.36 400H634.72V634.72H517.36Z";
14
15
  export declare const GROK_LOGO_PATHS: readonly ["M13.2371 21.0407L24.3186 12.8506C24.8619 12.4491 25.6384 12.6057 25.8973 13.2294C27.2597 16.5185 26.651 20.4712 23.9403 23.1851C21.2297 25.8989 17.4581 26.4941 14.0108 25.1386L10.2449 26.8843C15.6463 30.5806 22.2053 29.6665 26.304 25.5601C29.5551 22.3051 30.562 17.8683 29.6205 13.8673L29.629 13.8758C28.2637 7.99809 29.9647 5.64871 33.449.844576C33.5314.730667 33.6139.616757 33.6964.5L29.1113 5.09055V5.07631L13.2343 21.0436Z", "M10.9503 23.0313C7.07343 19.3235 7.74185 13.5853 11.0498 10.2763C13.4959 7.82722 17.5036 6.82767 21.0021 8.2971L24.7595 6.55998C24.0826 6.07017 23.215 5.54334 22.2195 5.17313C17.7198 3.31926 12.3326 4.24192 8.67479 7.90126C5.15635 11.4239 4.0499 16.8403 5.94992 21.4622C7.36924 24.9165 5.04257 27.3598 2.69884 29.826C1.86829 30.7002 1.0349 31.5745.36364 32.5L10.9474 23.0341Z"];
15
16
  /** Framework-free counterpart used by the legacy Shell rollback path. */
16
17
  export declare function renderProviderLogoMarkup(value: unknown): string;
@@ -64,7 +64,10 @@ export function providerDisplayName(value) {
64
64
  // CC0). Grok uses xAI's mark path already shipped by the Web new-session view.
65
65
  export const CLAUDE_LOGO_PATH = "m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z";
66
66
  export const CODEX_LOGO_PATH = "M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z";
67
- export const PI_LOGO_PATH = "M4 5h16v4h-3v11h-4V9h-2v11H7V9H4Z";
67
+ // Official Pi mark from https://pi.dev/logo-auto.svg. Keep it local so provider
68
+ // logos remain available when Wand is offline.
69
+ export const PI_LOGO_PATH = "M165.29 165.29H517.36V400H400V517.36H282.65V634.72H165.29ZM282.65 282.65V400H400V282.65Z";
70
+ export const PI_LOGO_DOT_PATH = "M517.36 400H634.72V634.72H517.36Z";
68
71
  export const GROK_LOGO_PATHS = [
69
72
  "M13.2371 21.0407L24.3186 12.8506C24.8619 12.4491 25.6384 12.6057 25.8973 13.2294C27.2597 16.5185 26.651 20.4712 23.9403 23.1851C21.2297 25.8989 17.4581 26.4941 14.0108 25.1386L10.2449 26.8843C15.6463 30.5806 22.2053 29.6665 26.304 25.5601C29.5551 22.3051 30.562 17.8683 29.6205 13.8673L29.629 13.8758C28.2637 7.99809 29.9647 5.64871 33.449.844576C33.5314.730667 33.6139.616757 33.6964.5L29.1113 5.09055V5.07631L13.2343 21.0436Z",
70
73
  "M10.9503 23.0313C7.07343 19.3235 7.74185 13.5853 11.0498 10.2763C13.4959 7.82722 17.5036 6.82767 21.0021 8.2971L24.7595 6.55998C24.0826 6.07017 23.215 5.54334 22.2195 5.17313C17.7198 3.31926 12.3326 4.24192 8.67479 7.90126C5.15635 11.4239 4.0499 16.8403 5.94992 21.4622C7.36924 24.9165 5.04257 27.3598 2.69884 29.826C1.86829 30.7002 1.0349 31.5745.36364 32.5L10.9474 23.0341Z",
@@ -84,7 +87,7 @@ export function renderProviderLogoMarkup(value) {
84
87
  return `<svg ${common} viewBox="0 0 34 33" fill="currentColor">${GROK_LOGO_PATHS.map((path) => `<path d="${path}"/>`).join("")}</svg>`;
85
88
  }
86
89
  if (provider === "pi") {
87
- return `<svg ${common} viewBox="0 0 24 24" fill="currentColor"><path d="${PI_LOGO_PATH}"/></svg>`;
90
+ return `<svg ${common} viewBox="0 0 800 800" fill="currentColor"><path d="${PI_LOGO_PATH}" fill-rule="evenodd"/><path d="${PI_LOGO_DOT_PATH}"/></svg>`;
88
91
  }
89
92
  if (provider === "claude" || provider === "codex") {
90
93
  return `<svg ${common} viewBox="0 0 24 24" fill="currentColor"><path d="${provider === "claude" ? CLAUDE_LOGO_PATH : CODEX_LOGO_PATH}"/></svg>`;
@@ -5,13 +5,24 @@
5
5
  import { WebSocketServer } from "ws";
6
6
  import type { CardExpandDefaults, SessionSnapshot, ProcessEvent } from "./types.js";
7
7
  import { type AuthService } from "./auth.js";
8
+ import type { PtyTerminalSnapshot } from "./pty-terminal-state.js";
8
9
  export type { ProcessEvent } from "./types.js";
10
+ export interface WsSessionPort {
11
+ getSession(id: string): SessionSnapshot | null;
12
+ getTerminalState?(id: string): PtyTerminalSnapshot | null;
13
+ sendPtyInput?(id: string, input: string, shortcutKey?: string, userInput?: boolean): void;
14
+ resizePty?(id: string, cols: number, rows: number): void;
15
+ pausePtyOutput?(id: string): void;
16
+ resumePtyOutput?(id: string): void;
17
+ }
9
18
  export declare class WsBroadcastManager {
10
19
  private wss;
11
20
  private clients;
12
21
  private outputDebounceCache;
13
22
  private heartbeatTimer?;
14
23
  private disposed;
24
+ private port?;
25
+ private readonly ptyPauseRefs;
15
26
  private getCardDefaults;
16
27
  private useHttps;
17
28
  private authService?;
@@ -21,7 +32,7 @@ export declare class WsBroadcastManager {
21
32
  /** Stop timers, discard deferred output, and terminate every client. */
22
33
  dispose(): void;
23
34
  /** Set up connection handling. Should be called once during server startup. */
24
- setup(getSession: (id: string) => SessionSnapshot | null): void;
35
+ setup(portOrGetSession: WsSessionPort | ((id: string) => SessionSnapshot | null)): void;
25
36
  /**
26
37
  * 心跳 tick:对每个 client 执行 stale 判定 + 主动 ping。
27
38
  * - 超过 HEARTBEAT_STALE_MS 没消息 → 视为半开 / 死连接,直接 terminate()。
@@ -55,5 +66,8 @@ export declare class WsBroadcastManager {
55
66
  */
56
67
  private resumeAndQueueResyncNotices;
57
68
  private discardClient;
69
+ private acquirePtyPause;
70
+ private releasePtyPause;
71
+ private sendPtyError;
58
72
  private processWsQueue;
59
73
  }
@@ -24,6 +24,9 @@ const HEARTBEAT_INTERVAL_MS = 20_000;
24
24
  * 半开连接并 terminate。45s = 两个心跳周期再加 5s 容忍,可以避开偶发抖动。
25
25
  */
26
26
  const HEARTBEAT_STALE_MS = 45_000;
27
+ const PTY_UNACKED_HIGH_WATER = 512 * 1024;
28
+ const PTY_UNACKED_LOW_WATER = 128 * 1024;
29
+ const MAX_PTY_INPUT_CHARS = 128 * 1024;
27
30
  // ── Manager ──
28
31
  export class WsBroadcastManager {
29
32
  wss;
@@ -31,6 +34,8 @@ export class WsBroadcastManager {
31
34
  outputDebounceCache = new Map();
32
35
  heartbeatTimer;
33
36
  disposed = false;
37
+ port;
38
+ ptyPauseRefs = new Map();
34
39
  getCardDefaults;
35
40
  useHttps;
36
41
  authService;
@@ -62,9 +67,12 @@ export class WsBroadcastManager {
62
67
  this.disconnectAll();
63
68
  }
64
69
  /** Set up connection handling. Should be called once during server startup. */
65
- setup(getSession) {
70
+ setup(portOrGetSession) {
66
71
  if (this.disposed)
67
72
  return;
73
+ this.port = typeof portOrGetSession === "function"
74
+ ? { getSession: portOrGetSession }
75
+ : portOrGetSession;
68
76
  this.wss.on("connection", (ws, req) => {
69
77
  if (this.disposed) {
70
78
  ws.close(1012, "Server shutting down");
@@ -84,10 +92,14 @@ export class WsBroadcastManager {
84
92
  outputSeqBySession: new Map(),
85
93
  pendingResyncSessions: new Set(),
86
94
  lastSeenAt: Date.now(),
95
+ subscribedSessionId: null,
96
+ supportsPtyAck: false,
97
+ unackedPtyBytes: 0,
98
+ ptyPausedSessionId: null,
87
99
  };
88
100
  this.clients.add(client);
89
101
  ws.on("close", () => {
90
- this.clients.delete(client);
102
+ this.discardClient(client, false);
91
103
  });
92
104
  ws.on("error", () => {
93
105
  // Already closed, ignore
@@ -108,7 +120,13 @@ export class WsBroadcastManager {
108
120
  if (Number.isSafeInteger(msg.blockBudget) && msg.blockBudget > 0) {
109
121
  client.blockBudget = Math.min(msg.blockBudget, MAX_BLOCK_BUDGET);
110
122
  }
111
- const snapshot = getSession(msg.sessionId);
123
+ this.releasePtyPause(client);
124
+ client.subscribedSessionId = null;
125
+ client.supportsPtyAck = msg.capabilities?.ptyAck === true;
126
+ this.flushOutput(msg.sessionId);
127
+ client.subscribedSessionId = msg.sessionId;
128
+ client.unackedPtyBytes = 0;
129
+ const snapshot = this.port?.getSession(msg.sessionId) ?? null;
112
130
  if (snapshot) {
113
131
  this.sendInit(client, msg.sessionId, snapshot, false);
114
132
  }
@@ -121,10 +139,41 @@ export class WsBroadcastManager {
121
139
  }
122
140
  }
123
141
  else if (msg.type === "resync" && msg.sessionId) {
124
- const snapshot = getSession(msg.sessionId);
142
+ this.flushOutput(msg.sessionId);
143
+ const snapshot = this.port?.getSession(msg.sessionId) ?? null;
125
144
  if (snapshot)
126
145
  this.sendInit(client, msg.sessionId, snapshot, true);
127
146
  }
147
+ else if (msg.type === "pty_input" && msg.sessionId && typeof msg.data === "string") {
148
+ if (client.subscribedSessionId !== msg.sessionId || msg.data.length > MAX_PTY_INPUT_CHARS)
149
+ return;
150
+ try {
151
+ this.port?.sendPtyInput?.(msg.sessionId, msg.data, typeof msg.shortcutKey === "string" ? msg.shortcutKey : undefined, msg.userInput !== false);
152
+ }
153
+ catch (error) {
154
+ this.sendPtyError(client, msg.sessionId, error);
155
+ }
156
+ }
157
+ else if (msg.type === "pty_resize" && msg.sessionId) {
158
+ if (client.subscribedSessionId !== msg.sessionId)
159
+ return;
160
+ if (!Number.isFinite(msg.cols) || !Number.isFinite(msg.rows))
161
+ return;
162
+ try {
163
+ this.port?.resizePty?.(msg.sessionId, Math.floor(msg.cols), Math.floor(msg.rows));
164
+ }
165
+ catch (error) {
166
+ this.sendPtyError(client, msg.sessionId, error);
167
+ }
168
+ }
169
+ else if (msg.type === "pty_ack" && msg.sessionId && Number.isFinite(msg.bytes)) {
170
+ if (!client.supportsPtyAck || client.subscribedSessionId !== msg.sessionId)
171
+ return;
172
+ client.unackedPtyBytes = Math.max(0, client.unackedPtyBytes - Math.max(0, Math.floor(msg.bytes)));
173
+ if (client.ptyPausedSessionId && client.unackedPtyBytes <= PTY_UNACKED_LOW_WATER) {
174
+ this.releasePtyPause(client);
175
+ }
176
+ }
128
177
  else if (msg.type === "pong") {
129
178
  // 应用层 pong(对我们下发的 {type:"ping"} 的响应)。lastSeenAt
130
179
  // 已经在函数顶部刷新过了,这里不需要再做事;分支留着是为了
@@ -161,15 +210,11 @@ export class WsBroadcastManager {
161
210
  if (client.ws.readyState !== WebSocket.OPEN) {
162
211
  // 已经不是 OPEN 了,close handler 通常会清理;这里兜底防止集合里
163
212
  // 留下僵尸 entry。
164
- this.clients.delete(client);
213
+ this.discardClient(client, false);
165
214
  continue;
166
215
  }
167
216
  if (now - client.lastSeenAt > HEARTBEAT_STALE_MS) {
168
- try {
169
- client.ws.terminate();
170
- }
171
- catch { /* ignore */ }
172
- this.clients.delete(client);
217
+ this.discardClient(client, true);
173
218
  continue;
174
219
  }
175
220
  try {
@@ -238,7 +283,9 @@ export class WsBroadcastManager {
238
283
  this.outputDebounceCache.set(event.sessionId, { event, timer });
239
284
  return;
240
285
  }
241
- // Non-output events are sent immediately
286
+ // Preserve PTY ordering: the final debounced bytes must arrive before an
287
+ // ended/status event for the same session.
288
+ this.flushOutput(event.sessionId);
242
289
  this.broadcast(event);
243
290
  }
244
291
  /** Flush any pending debounced output for a session (e.g., before session close). */
@@ -268,7 +315,10 @@ export class WsBroadcastManager {
268
315
  sessionId,
269
316
  seq,
270
317
  ...(resync ? { resync: true } : {}),
271
- data: toSessionDetailDTO(snapshot, { output: snapshot.output, ...windowed }),
318
+ data: {
319
+ ...toSessionDetailDTO(snapshot, { output: snapshot.output, ...windowed }),
320
+ terminalState: this.port?.getTerminalState?.(sessionId) ?? undefined,
321
+ },
272
322
  }));
273
323
  }
274
324
  /**
@@ -304,6 +354,10 @@ export class WsBroadcastManager {
304
354
  const boundedData = boundSessionEventData(event.data);
305
355
  const boundedEvent = boundedData === event.data ? event : { ...event, data: boundedData };
306
356
  const data = boundedData;
357
+ const isRawPtyOutput = event.type === "output"
358
+ && data?.incremental === true
359
+ && typeof data.chunk === "string";
360
+ const ptyBytes = isRawPtyOutput ? Buffer.byteLength(data.chunk) : 0;
307
361
  const hasFullMessages = !!(data && !data.incremental && Array.isArray(data.messages));
308
362
  const rawMessages = hasFullMessages
309
363
  ? data.messages
@@ -335,6 +389,8 @@ export class WsBroadcastManager {
335
389
  for (const client of this.clients) {
336
390
  if (client.ws.readyState !== WebSocket.OPEN)
337
391
  continue;
392
+ if (isRawPtyOutput && client.subscribedSessionId !== event.sessionId)
393
+ continue;
338
394
  const clientEvent = eventForClient(client);
339
395
  // Stamp output events with a per-(client, session) sequence number so
340
396
  // the client can detect a gap caused by backpressure drops.
@@ -344,10 +400,19 @@ export class WsBroadcastManager {
344
400
  client.outputSeqBySession.set(event.sessionId, seq);
345
401
  outgoing = { ...clientEvent, seq };
346
402
  }
403
+ const usesPtyAckFlowControl = isRawPtyOutput && client.supportsPtyAck;
404
+ if (usesPtyAckFlowControl) {
405
+ outgoing = { ...outgoing, ptyBytes };
406
+ client.unackedPtyBytes += ptyBytes;
407
+ if (client.unackedPtyBytes >= PTY_UNACKED_HIGH_WATER) {
408
+ this.acquirePtyPause(client, event.sessionId);
409
+ }
410
+ }
347
411
  // Backpressure only gates new business messages. The send pump must
348
412
  // keep draining messages that were already accepted; otherwise a queue
349
413
  // at the high-water mark can never reach the low-water mark again.
350
- if (client.backpressurePaused || client.sendQueue.length >= MAX_QUEUE_SIZE) {
414
+ if (!usesPtyAckFlowControl
415
+ && (client.backpressurePaused || client.sendQueue.length >= MAX_QUEUE_SIZE)) {
351
416
  client.backpressurePaused = true;
352
417
  if (event.type === "output")
353
418
  client.pendingResyncSessions.add(event.sessionId);
@@ -386,6 +451,7 @@ export class WsBroadcastManager {
386
451
  }
387
452
  }
388
453
  discardClient(client, terminate) {
454
+ this.releasePtyPause(client);
389
455
  client.sendQueue.length = 0;
390
456
  client.pendingResyncSessions.clear();
391
457
  client.sendInProgress = false;
@@ -398,6 +464,36 @@ export class WsBroadcastManager {
398
464
  catch { /* ignore */ }
399
465
  }
400
466
  }
467
+ acquirePtyPause(client, sessionId) {
468
+ if (client.ptyPausedSessionId === sessionId)
469
+ return;
470
+ this.releasePtyPause(client);
471
+ client.ptyPausedSessionId = sessionId;
472
+ const next = (this.ptyPauseRefs.get(sessionId) ?? 0) + 1;
473
+ this.ptyPauseRefs.set(sessionId, next);
474
+ if (next === 1)
475
+ this.port?.pausePtyOutput?.(sessionId);
476
+ }
477
+ releasePtyPause(client) {
478
+ const sessionId = client.ptyPausedSessionId;
479
+ if (!sessionId)
480
+ return;
481
+ client.ptyPausedSessionId = null;
482
+ const next = Math.max(0, (this.ptyPauseRefs.get(sessionId) ?? 1) - 1);
483
+ if (next === 0) {
484
+ this.ptyPauseRefs.delete(sessionId);
485
+ this.port?.resumePtyOutput?.(sessionId);
486
+ }
487
+ else {
488
+ this.ptyPauseRefs.set(sessionId, next);
489
+ }
490
+ }
491
+ sendPtyError(client, sessionId, error) {
492
+ if (client.ws.readyState !== WebSocket.OPEN)
493
+ return;
494
+ const message = error instanceof Error ? error.message : String(error);
495
+ client.ws.send(JSON.stringify({ type: "pty_error", sessionId, error: message }));
496
+ }
401
497
  processWsQueue(client) {
402
498
  if (this.disposed)
403
499
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "4.36.0",
3
+ "version": "4.37.0",
4
4
  "description": "A web console for Claude Code, Codex, OpenCode, and other local CLI tools.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,10 +18,10 @@
18
18
  "preferGlobal": true,
19
19
  "scripts": {
20
20
  "generate:web-assets": "node scripts/generate-web-assets.js",
21
- "build": "rm -rf dist && node scripts/bundle-wterm.js && node scripts/bundle-qrcode.js && node scripts/bundle-browser.js && npm run generate:web-assets && tsc -p tsconfig.json && npm run build:copy-content && node scripts/stamp-build-info.js && node scripts/fix-dist-permissions.js",
21
+ "build": "rm -rf dist && node scripts/bundle-xterm.js && node scripts/bundle-qrcode.js && node scripts/bundle-browser.js && npm run generate:web-assets && tsc -p tsconfig.json && npm run build:copy-content && node scripts/stamp-build-info.js && node scripts/fix-dist-permissions.js",
22
22
  "build:copy-content": "cp -r src/web-ui/content dist/web-ui/ && node scripts/minify-dist-content.js",
23
- "dev": "node scripts/bundle-browser.js --development && npm run generate:web-assets && tsx src/cli.ts web",
24
- "check": "node scripts/bundle-browser.js && npm run generate:web-assets && tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.browser.json && tsc --noEmit -p tsconfig.react.json",
23
+ "dev": "node scripts/bundle-xterm.js && node scripts/bundle-browser.js --development && npm run generate:web-assets && tsx src/cli.ts web",
24
+ "check": "node scripts/bundle-xterm.js && node scripts/bundle-browser.js && npm run generate:web-assets && tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.browser.json && tsc --noEmit -p tsconfig.react.json",
25
25
  "test": "node --test --import tsx tests/*.test.ts",
26
26
  "test:browser": "npm run build && playwright test",
27
27
  "test:browser:current": "playwright test",
@@ -46,6 +46,11 @@
46
46
  "@radix-ui/react-switch": "^1.3.3",
47
47
  "@radix-ui/react-tabs": "^1.1.17",
48
48
  "@radix-ui/react-toast": "^1.2.19",
49
+ "@xterm/addon-fit": "^0.11.0",
50
+ "@xterm/addon-serialize": "^0.14.0",
51
+ "@xterm/addon-unicode11": "^0.9.0",
52
+ "@xterm/headless": "^6.0.0",
53
+ "@xterm/xterm": "^6.0.0",
49
54
  "compression": "^1.8.1",
50
55
  "express": "^4.21.2",
51
56
  "multer": "^2.1.1",
@@ -66,7 +71,6 @@
66
71
  "@types/react": "^19.2.17",
67
72
  "@types/react-dom": "^19.2.3",
68
73
  "@types/ws": "^8.18.1",
69
- "@wterm/dom": "^0.1.8",
70
74
  "esbuild": "^0.28.0",
71
75
  "qrcode": "^1.5.4",
72
76
  "tsx": "^4.19.3",
@@ -1,162 +0,0 @@
1
- .wterm {
2
- --term-fg: #d4d4d4;
3
- --term-bg: #1e1e1e;
4
- --term-cursor: #aeafad;
5
-
6
- --term-color-0: #1e1e1e;
7
- --term-color-1: #f44747;
8
- --term-color-2: #6a9955;
9
- --term-color-3: #d7ba7d;
10
- --term-color-4: #569cd6;
11
- --term-color-5: #c586c0;
12
- --term-color-6: #4ec9b0;
13
- --term-color-7: #d4d4d4;
14
- --term-color-8: #808080;
15
- --term-color-9: #f44747;
16
- --term-color-10: #6a9955;
17
- --term-color-11: #d7ba7d;
18
- --term-color-12: #569cd6;
19
- --term-color-13: #c586c0;
20
- --term-color-14: #4ec9b0;
21
- --term-color-15: #ffffff;
22
-
23
- --term-font-family: 'Menlo', 'Consolas', 'DejaVu Sans Mono', 'Courier New', monospace;
24
- --term-font-size: 14px;
25
- --term-line-height: 1.2;
26
- --term-row-height: 17px;
27
-
28
- position: relative;
29
- background: var(--term-bg);
30
- color: var(--term-fg);
31
- font-family: var(--term-font-family);
32
- font-size: var(--term-font-size);
33
- line-height: var(--term-line-height);
34
- padding: 12px;
35
- border-radius: 8px;
36
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
37
- outline: none;
38
- overflow: hidden;
39
- }
40
-
41
- .wterm:focus,
42
- .wterm:focus-visible {
43
- outline: none;
44
- }
45
-
46
- .term-grid {
47
- display: block;
48
- white-space: pre;
49
- contain: layout paint style;
50
- will-change: contents;
51
- }
52
-
53
- .term-row {
54
- display: block;
55
- height: var(--term-row-height);
56
- contain: content;
57
- }
58
-
59
- .term-block {
60
- display: inline-block;
61
- width: 1ch;
62
- height: var(--term-row-height);
63
- vertical-align: top;
64
- overflow: hidden;
65
- }
66
-
67
- .term-cursor {
68
- outline: 1px solid var(--term-cursor);
69
- outline-offset: -1px;
70
- }
71
-
72
- .wterm.focused .term-cursor {
73
- background: var(--term-cursor);
74
- color: var(--term-bg);
75
- outline: none;
76
- }
77
-
78
- .wterm.focused.cursor-blink .term-cursor {
79
- animation: cursor-blink 1s step-end infinite;
80
- }
81
-
82
- @keyframes cursor-blink {
83
- 0%, 100% { background: var(--term-cursor); color: var(--term-bg); }
84
- 50% { background: transparent; color: inherit; }
85
- }
86
-
87
- .wterm.has-scrollback {
88
- overflow-y: auto;
89
- }
90
-
91
- .wterm ::selection {
92
- background: rgba(86, 156, 214, 0.3);
93
- }
94
-
95
- /* Solarized Dark */
96
- .wterm.theme-solarized-dark {
97
- --term-fg: #839496;
98
- --term-bg: #002b36;
99
- --term-cursor: #93a1a1;
100
- --term-color-0: #073642;
101
- --term-color-1: #dc322f;
102
- --term-color-2: #859900;
103
- --term-color-3: #b58900;
104
- --term-color-4: #268bd2;
105
- --term-color-5: #d33682;
106
- --term-color-6: #2aa198;
107
- --term-color-7: #eee8d5;
108
- --term-color-8: #586e75;
109
- --term-color-9: #cb4b16;
110
- --term-color-10: #586e75;
111
- --term-color-11: #657b83;
112
- --term-color-12: #839496;
113
- --term-color-13: #6c71c4;
114
- --term-color-14: #93a1a1;
115
- --term-color-15: #fdf6e3;
116
- }
117
-
118
- /* Monokai */
119
- .wterm.theme-monokai {
120
- --term-fg: #f8f8f2;
121
- --term-bg: #272822;
122
- --term-cursor: #f8f8f0;
123
- --term-color-0: #272822;
124
- --term-color-1: #f92672;
125
- --term-color-2: #a6e22e;
126
- --term-color-3: #f4bf75;
127
- --term-color-4: #66d9ef;
128
- --term-color-5: #ae81ff;
129
- --term-color-6: #a1efe4;
130
- --term-color-7: #f8f8f2;
131
- --term-color-8: #75715e;
132
- --term-color-9: #f92672;
133
- --term-color-10: #a6e22e;
134
- --term-color-11: #f4bf75;
135
- --term-color-12: #66d9ef;
136
- --term-color-13: #ae81ff;
137
- --term-color-14: #a1efe4;
138
- --term-color-15: #f9f8f5;
139
- }
140
-
141
- /* Light */
142
- .wterm.theme-light {
143
- --term-fg: #383a42;
144
- --term-bg: #fafafa;
145
- --term-cursor: #526eff;
146
- --term-color-0: #383a42;
147
- --term-color-1: #e45649;
148
- --term-color-2: #50a14f;
149
- --term-color-3: #c18401;
150
- --term-color-4: #4078f2;
151
- --term-color-5: #a626a4;
152
- --term-color-6: #0184bc;
153
- --term-color-7: #fafafa;
154
- --term-color-8: #a0a1a7;
155
- --term-color-9: #e45649;
156
- --term-color-10: #50a14f;
157
- --term-color-11: #c18401;
158
- --term-color-12: #4078f2;
159
- --term-color-13: #a626a4;
160
- --term-color-14: #0184bc;
161
- --term-color-15: #ffffff;
162
- }
@@ -1 +0,0 @@
1
- "use strict";var WTermLib=(()=>{var f=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var v=(r,A)=>{for(var t in A)f(r,t,{get:A[t],enumerable:!0})},m=(r,A,t,e)=>{if(A&&typeof A=="object"||typeof A=="function")for(let s of x(A))!p.call(r,s)&&s!==t&&f(r,s,{get:()=>A[s],enumerable:!(e=F(A,s))||e.enumerable});return r};var k=r=>m(f({},"__esModule",{value:!0}),r);var O={};v(O,{InputHandler:()=>l,Renderer:()=>c,WTerm:()=>b,WasmBridge:()=>a,WebSocketTransport:()=>d});var G="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";function y(r){let A=atob(r),t=new Uint8Array(A.length);for(let e=0;e<A.length;e++)t[e]=A.charCodeAt(e);return t.buffer}var a=class r{constructor(A){this.gridPtr=0,this.dirtyPtr=0,this.writeBufferPtr=0,this.cellSize=12,this.maxCols=256,this.encoder=new TextEncoder,this.decoder=new TextDecoder,this.exports=A.exports,this.memory=this.exports.memory}static async load(A){let t;if(A){let s=await fetch(A);if(!s.ok)throw new Error(`[wterm] Failed to load WASM from ${A}: ${s.status} ${s.statusText}`);t=await s.arrayBuffer()}else t=y(G);let{instance:e}=await WebAssembly.instantiate(t);return new r(e)}init(A,t){this.exports.init(A,t),this._updatePointers()}_updatePointers(){this.gridPtr=this.exports.getGridPtr(),this.dirtyPtr=this.exports.getDirtyPtr(),this.writeBufferPtr=this.exports.getWriteBuffer(),this.cellSize=this.exports.getCellSize(),this.maxCols=this.exports.getMaxCols(),this._dv=new DataView(this.memory.buffer)}writeString(A){let t=this.encoder.encode(A);this.writeRaw(t)}writeRaw(A){let t=new Uint8Array(this.memory.buffer,this.writeBufferPtr,8192),e=0;for(;e<A.length;){let s=Math.min(A.length-e,8192);t.set(A.subarray(e,e+s)),this.exports.writeBytes(s),e+=s}}getCell(A,t){let e=this.gridPtr+(A*this.maxCols+t)*this.cellSize,s=this._dv;return{char:s.getUint32(e,!0),fg:s.getUint16(e+4,!0),bg:s.getUint16(e+6,!0),flags:s.getUint8(e+8)}}isDirtyRow(A){return new Uint8Array(this.memory.buffer,this.dirtyPtr,256)[A]!==0}clearDirty(){this.exports.clearDirty()}getCursor(){return{row:this.exports.getCursorRow(),col:this.exports.getCursorCol(),visible:this.exports.getCursorVisible()!==0}}getCols(){return this.exports.getCols()}getRows(){return this.exports.getRows()}cursorKeysApp(){return this.exports.getCursorKeysApp()!==0}bracketedPaste(){return this.exports.getBracketedPaste()!==0}usingAltScreen(){return this.exports.getUsingAltScreen()!==0}getTitle(){if(this.exports.getTitleChanged()===0)return null;let A=this.exports.getTitlePtr(),t=this.exports.getTitleLen(),e=new Uint8Array(this.memory.buffer,A,t);return this.decoder.decode(e)}getResponse(){let A=this.exports.getResponseLen();if(A===0)return null;let t=this.exports.getResponsePtr(),e=new Uint8Array(this.memory.buffer,t,A),s=this.decoder.decode(e);return this.exports.clearResponse(),s}getScrollbackCount(){return this.exports.getScrollbackCount()}getScrollbackCell(A,t){let s=this.exports.getScrollbackLine(A)+t*this.cellSize,i=this._dv;return{char:i.getUint32(s,!0),fg:i.getUint16(s+4,!0),bg:i.getUint16(s+6,!0),flags:i.getUint8(s+8)}}getScrollbackLineLen(A){return this.exports.getScrollbackLineLen(A)}resize(A,t){this.exports.resizeTerminal(A,t),this._updatePointers()}};var d=class{constructor(A={}){this._ws=null,this._reconnectTimer=null,this._reconnectDelay=1e3,this._closed=!1,this._buffer=[],this.url=A.url??null,this.reconnect=A.reconnect!==!1,this.maxReconnectDelay=A.maxReconnectDelay??3e4,this.onData=A.onData??null,this.onOpen=A.onOpen??null,this.onClose=A.onClose??null,this.onError=A.onError??null}connect(A){if(A&&(this.url=A),!this.url)throw new Error("No WebSocket URL provided");this._closed=!1,this._ws=new WebSocket(this.url),this._ws.binaryType="arraybuffer",this._ws.onopen=()=>{this._reconnectDelay=1e3,this._flushBuffer(),this.onOpen&&this.onOpen()},this._ws.onmessage=t=>{this.onData&&(t.data instanceof ArrayBuffer?this.onData(new Uint8Array(t.data)):this.onData(t.data))},this._ws.onclose=()=>{this.onClose&&this.onClose(),this.reconnect&&!this._closed&&this._scheduleReconnect()},this._ws.onerror=t=>{this.onError&&this.onError(t),this._ws?.close()}}send(A){this._ws&&this._ws.readyState===WebSocket.OPEN?typeof A=="string"?this._ws.send(new TextEncoder().encode(A)):this._ws.send(A):this._buffer.push(A)}close(){this._closed=!0,this._reconnectTimer&&clearTimeout(this._reconnectTimer),this._ws&&this._ws.close()}get connected(){return this._ws!==null&&this._ws.readyState===WebSocket.OPEN}_flushBuffer(){let A=this._buffer.splice(0);for(let t of A)this.send(t)}_scheduleReconnect(){this._reconnectTimer=setTimeout(()=>{this.connect()},this._reconnectDelay),this._reconnectDelay=Math.min(this._reconnectDelay*2,this.maxReconnectDelay)}};function u(r){if(r===256)return null;if(r<16)return`var(--term-color-${r})`;if(r<232){let t=r-16,e=Math.floor(t/36)*51,s=Math.floor(t/6)%6*51,i=t%6*51;return`rgb(${e},${s},${i})`}let A=(r-232)*10+8;return`rgb(${A},${A},${A})`}function S(r,A,t){let e=r,s=A;if(t&32){let Q=e;e=s,s=Q,e===256&&(e=0),s===256&&(s=7)}let i=u(e),o=u(s),B="";i&&(B+=`color:${i};`),o&&(B+=`background:${o};`),t&1&&(B+="font-weight:bold;"),t&2&&(B+="opacity:0.5;"),t&4&&(B+="font-style:italic;");let E=[];return t&128&&E.push("line-through"),E.length&&(B+=`text-decoration:${E.join(" ")};`),t&64&&(B+="visibility:hidden;"),B}function D(r,A,t){if(t){let e=document.createElement("span");e.style.cssText=t,e.textContent=A,r.appendChild(e)}else r.appendChild(document.createTextNode(A))}function R(r,A,t){let e=r,s=A;return t&32&&([e,s]=[s,e],e===256&&(e=0),s===256&&(s=7)),{fg:u(e)||"var(--term-fg)",bg:u(s)||"var(--term-bg)"}}function H(r,A,t){switch(r){case 9600:return`linear-gradient(${A} 50%,${t} 50%)`;case 9601:return`linear-gradient(${t} 87.5%,${A} 87.5%)`;case 9602:return`linear-gradient(${t} 75%,${A} 75%)`;case 9603:return`linear-gradient(${t} 62.5%,${A} 62.5%)`;case 9604:return`linear-gradient(${t} 50%,${A} 50%)`;case 9605:return`linear-gradient(${t} 37.5%,${A} 37.5%)`;case 9606:return`linear-gradient(${t} 25%,${A} 25%)`;case 9607:return`linear-gradient(${t} 12.5%,${A} 12.5%)`;case 9608:return A;case 9609:return`linear-gradient(to right,${A} 87.5%,${t} 87.5%)`;case 9610:return`linear-gradient(to right,${A} 75%,${t} 75%)`;case 9611:return`linear-gradient(to right,${A} 62.5%,${t} 62.5%)`;case 9612:return`linear-gradient(to right,${A} 50%,${t} 50%)`;case 9613:return`linear-gradient(to right,${A} 37.5%,${t} 37.5%)`;case 9614:return`linear-gradient(to right,${A} 25%,${t} 25%)`;case 9615:return`linear-gradient(to right,${A} 12.5%,${t} 12.5%)`;case 9616:return`linear-gradient(to right,${t} 50%,${A} 50%)`;case 9617:return`color-mix(in srgb,${A} 25%,${t})`;case 9618:return`color-mix(in srgb,${A} 50%,${t})`;case 9619:return`color-mix(in srgb,${A} 75%,${t})`;case 9620:return`linear-gradient(${A} 12.5%,${t} 12.5%)`;case 9621:return`linear-gradient(to right,${t} 87.5%,${A} 87.5%)`;default:{let s={9622:[!1,!1,!0,!1],9623:[!1,!1,!1,!0],9624:[!0,!1,!1,!1],9625:[!0,!1,!0,!0],9626:[!0,!1,!1,!0],9627:[!0,!0,!0,!1],9628:[!0,!0,!1,!0],9629:[!1,!0,!1,!1],9630:[!1,!0,!0,!1],9631:[!1,!0,!0,!0]}[r];if(!s)return A;let[i,o,B,E]=s;if(i&&o&&B&&E)return A;let Q=[],C=["0 0","100% 0","0 100%","100% 100%"];return s.forEach((n,I)=>{n&&Q.push(`linear-gradient(${A},${A}) ${C[I]}/50% 50% no-repeat`)}),Q.push(t),Q.join(",")}}}var c=class{constructor(A){this.rows=0,this.cols=0,this.rowEls=[],this.prevCursorRow=-1,this.prevCursorCol=-1,this._scrollbackRowEls=[],this._renderedScrollbackCount=0,this.container=A}setup(A,t){this.cols=A,this.rows=t,this.container.innerHTML="",this.rowEls=[],this._scrollbackRowEls=[],this._renderedScrollbackCount=0;let e=document.createDocumentFragment();for(let s=0;s<t;s++){let i=document.createElement("div");i.className="term-row",e.appendChild(i),this.rowEls.push(i)}this.container.appendChild(e),this.prevCursorRow=-1,this.prevCursorCol=-1}_buildRowContent(A,t,e,s){A.textContent="";let i="",o="",B=0,E=Q=>{if(o)if(s>=B&&s<Q){let C=s-B,n=o.slice(0,C),I=o[C],h=o.slice(C+1);n&&D(A,n,i);let g=document.createElement("span");g.className="term-cursor",i&&(g.style.cssText=i),g.textContent=I,A.appendChild(g),h&&D(A,h,i)}else D(A,o,i)};for(let Q=0;Q<this.cols;Q++){let C=t(Q),n=Q<e,I=n?C.char:0;if(n&&I>=9600&&I<=9631){E(Q);let h=R(C.fg,C.bg,C.flags),g=document.createElement("span");g.className=Q===s?"term-block term-cursor":"term-block",g.style.background=H(I,h.fg,h.bg),C.flags&2&&(g.style.opacity="0.5"),A.appendChild(g),i="",o="",B=Q+1}else{let h=n&&I>=32?String.fromCodePoint(I):" ",g=n?S(C.fg,C.bg,C.flags):"";g!==i?(E(Q),i=g,o=h,B=Q):o+=h}}E(this.cols)}_buildScrollbackRowEl(A,t){let e=document.createElement("div");e.className="term-row term-scrollback-row";let s=A.getScrollbackLineLen(t);return this._buildRowContent(e,i=>A.getScrollbackCell(t,i),s,-1),e}syncScrollback(A){let t=A.getScrollbackCount();if(t!==this._renderedScrollbackCount){if(t>this._renderedScrollbackCount){let e=t-this._renderedScrollbackCount,s=this.rowEls[0]??null,i=document.createDocumentFragment();for(let o=e-1;o>=0;o--){let B=this._buildScrollbackRowEl(A,o);i.appendChild(B),this._scrollbackRowEls.push(B)}this.container.insertBefore(i,s)}else{let e=this._renderedScrollbackCount-t;for(let s=0;s<e;s++){let i=this._scrollbackRowEls.shift();i&&i.remove()}}this._renderedScrollbackCount=t}}render(A){let t=A.getRows(),e=A.getCols(),s=!1;(t!==this.rows||e!==this.cols)&&(this.setup(e,t),s=!0),this.syncScrollback(A);let i=A.getCursor(),o=i.visible,B=i.row!==this.prevCursorRow||i.col!==this.prevCursorCol;for(let E=0;E<this.rows;E++){let Q=s||A.isDirtyRow(E),C=E===this.prevCursorRow&&B,n=E===i.row;if(Q||C||n&&B){let I=n&&o?i.col:-1;this._buildRowContent(this.rowEls[E],h=>A.getCell(E,h),this.cols,I)}}this.prevCursorRow=i.row,this.prevCursorCol=i.col,A.clearDirty()}};var U={ArrowUp:"\x1B[A",ArrowDown:"\x1B[B",ArrowRight:"\x1B[C",ArrowLeft:"\x1B[D",Home:"\x1B[H",End:"\x1B[F"},M={ArrowUp:"\x1BOA",ArrowDown:"\x1BOB",ArrowRight:"\x1BOC",ArrowLeft:"\x1BOD",Home:"\x1BOH",End:"\x1BOF"},_={Enter:"\r",Backspace:"\x7F",Tab:" ",Escape:"\x1B",Insert:"\x1B[2~",Delete:"\x1B[3~",PageUp:"\x1B[5~",PageDown:"\x1B[6~",F1:"\x1BOP",F2:"\x1BOQ",F3:"\x1BOR",F4:"\x1BOS",F5:"\x1B[15~",F6:"\x1B[17~",F7:"\x1B[18~",F8:"\x1B[19~",F9:"\x1B[20~",F10:"\x1B[21~",F11:"\x1B[23~",F12:"\x1B[24~"},l=class{constructor(A,t,e){this.composing=!1,this.element=A,this.onData=t,this.getBridge=e,this.textarea=document.createElement("textarea"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("autocomplete","off"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.setAttribute("enterkeyhint","send"),this.textarea.setAttribute("tabindex","0"),this.textarea.setAttribute("aria-label","terminal input");let s=this.textarea.style;s.position="absolute",s.left="-9999px",s.top="0",s.width="1px",s.height="1px",s.opacity="0",s.overflow="hidden",s.border="0",s.padding="0",s.margin="0",s.outline="none",s.resize="none",s.pointerEvents="none",s.caretColor="transparent",s.color="transparent",s.background="transparent",A.appendChild(this.textarea),this._onKeyDown=this.handleKeyDown.bind(this),this._onPaste=this.handlePaste.bind(this),this._onCompositionStart=this.handleCompositionStart.bind(this),this._onCompositionEnd=this.handleCompositionEnd.bind(this),this._onInput=this.handleInput.bind(this),this._onFocus=()=>this.element.classList.add("focused"),this._onBlur=()=>this.element.classList.remove("focused"),this.textarea.addEventListener("keydown",this._onKeyDown),this.textarea.addEventListener("paste",this._onPaste),this.textarea.addEventListener("compositionstart",this._onCompositionStart),this.textarea.addEventListener("compositionend",this._onCompositionEnd),this.textarea.addEventListener("input",this._onInput),this.textarea.addEventListener("focus",this._onFocus),this.textarea.addEventListener("blur",this._onBlur)}focus(){this.textarea.focus({preventScroll:!0})}destroy(){this.textarea.removeEventListener("keydown",this._onKeyDown),this.textarea.removeEventListener("paste",this._onPaste),this.textarea.removeEventListener("compositionstart",this._onCompositionStart),this.textarea.removeEventListener("compositionend",this._onCompositionEnd),this.textarea.removeEventListener("input",this._onInput),this.textarea.removeEventListener("focus",this._onFocus),this.textarea.removeEventListener("blur",this._onBlur),this.element.classList.remove("focused"),this.textarea.remove()}handleKeyDown(A){if(this.composing)return;if((A.metaKey||A.ctrlKey)&&A.key==="c"){let e=window.getSelection();if(e&&e.toString().length>0)return}if((A.metaKey||A.ctrlKey)&&A.key==="v"){this.textarea.focus();return}if(A.metaKey&&!A.ctrlKey){if(A.key==="Backspace")A.preventDefault(),this.onData("");else if(A.key==="a"){A.preventDefault();let e=window.getSelection();if(e){let s=document.createRange();s.selectNodeContents(this.element),e.removeAllRanges(),e.addRange(s)}}return}A.preventDefault();let t=this.keyToSequence(A);t&&this.onData(t)}handlePaste(A){A.preventDefault();let t=A.clipboardData?.getData("text");if(!t)return;let e=this.getBridge();e&&e.bracketedPaste()?this.onData("\x1B[200~"+t+"\x1B[201~"):this.onData(t)}handleCompositionStart(){this.composing=!0}handleCompositionEnd(A){this.composing=!1,A.data&&this.onData(A.data),this.textarea.value=""}handleInput(){if(this.composing)return;let A=this.textarea.value;A&&(this.onData(A),this.textarea.value="")}keyToSequence(A){if(A.ctrlKey&&!A.altKey&&!A.metaKey){if(A.key.length===1){let B=A.key.toLowerCase().charCodeAt(0);if(B>=97&&B<=122)return String.fromCharCode(B-96)}if(A.key==="[")return"\x1B";if(A.key==="\\")return"";if(A.key==="]")return"";if(A.key==="^")return"";if(A.key==="_")return""}if(A.key==="Enter"&&A.shiftKey)return"\x1B[13;2u";if(A.key==="Tab"&&A.shiftKey)return"\x1B[Z";let t=_[A.key];if(t)return A.altKey?"\x1B"+t:t;let e=this.getBridge(),o=(e&&e.cursorKeysApp()?M:U)[A.key];return o?A.altKey?"\x1B"+o:o:A.key.length===1&&!A.ctrlKey&&!A.metaKey?A.altKey?"\x1B"+A.key:A.key:null}};var w=class{constructor(A,t={}){this.bridge=null,this.renderer=null,this.input=null,this.rafId=null,this.resizeObserver=null,this._destroyed=!1,this._shouldScrollToBottom=!1,this.element=A,this.wasmUrl=t.wasmUrl,this.cols=t.cols||80,this.rows=t.rows||24,this.autoResize=t.autoResize!==!1,this.onData=t.onData||null,this.onTitle=t.onTitle||null,this.onResize=t.onResize||null,this._container=document.createElement("div"),this._container.className="term-grid",this.element.appendChild(this._container),this.element.classList.add("wterm"),t.cursorBlink&&this.element.classList.add("cursor-blink"),this._onClickFocus=()=>{let e=window.getSelection();(!e||e.isCollapsed)&&this.input?.focus()},this.element.addEventListener("click",this._onClickFocus)}async init(){try{if(this.bridge=await a.load(this.wasmUrl),this._destroyed)return this;this.bridge.init(this.cols,this.rows),this.renderer=new c(this._container),this.renderer.setup(this.cols,this.rows),this.input=new l(this.element,A=>{this.onData?this.onData(A):this.write(A)},()=>this.bridge),this.autoResize?this._setupResizeObserver():this._lockHeight(),this.input.focus(),this._initialRender()}catch(A){throw this.destroy(),new Error(`wterm: failed to initialize: ${A instanceof Error?A.message:A}`)}return this}_isScrolledToBottom(){let A=this.element;return A.scrollHeight-A.scrollTop-A.clientHeight<5}_scrollToBottom(){this.element.scrollTop=this.element.scrollHeight}write(A){this.bridge&&(this._shouldScrollToBottom=this._isScrolledToBottom(),typeof A=="string"?this.bridge.writeString(A):this.bridge.writeRaw(A),this._scheduleRender())}resize(A,t){this.bridge&&(this._shouldScrollToBottom=this._isScrolledToBottom(),this.cols=A,this.rows=t,this.bridge.resize(A,t),this.renderer?.setup(A,t),this._scheduleRender(),this.onResize&&this.onResize(A,t))}focus(){this.input?this.input.focus():this.element.focus()}_scheduleRender(){this.rafId==null&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null,this._doRender()}))}_initialRender(){this._doRender()}_doRender(){if(!this.bridge||!this.renderer)return;this.renderer.render(this.bridge);let A=this.bridge.getScrollbackCount()>0;this.element.classList.toggle("has-scrollback",A),this._shouldScrollToBottom&&this._scrollToBottom();let t=this.bridge.getTitle();t!==null&&this.onTitle&&this.onTitle(t);let e=this.bridge.getResponse();e!==null&&this.onData&&this.onData(e)}_lockHeight(){let A=getComputedStyle(this.element),t=parseFloat(A.getPropertyValue("--term-row-height"))||17,e=this.rows*t,s=(parseFloat(A.paddingTop)||0)+(parseFloat(A.paddingBottom)||0);A.boxSizing==="border-box"&&(s+=(parseFloat(A.borderTopWidth)||0)+(parseFloat(A.borderBottomWidth)||0)),this.element.style.height=`${e+s}px`}_measureCharSize(){let A=document.createElement("span");A.className="term-cell",A.textContent="W",A.style.position="absolute",A.style.visibility="hidden",this._container.appendChild(A);let t=A.getBoundingClientRect(),e=t.width,s=t.height;return A.remove(),e===0||s===0?null:{width:e,height:s}}_setupResizeObserver(){let A=this._measureCharSize();if(!A)return;let t=A.width,e=A.height;this.resizeObserver=new ResizeObserver(s=>{let i=this._measureCharSize();i&&(t=i.width,e=i.height);for(let o of s){let{width:B,height:E}=o.contentRect,Q=Math.max(1,Math.floor(B/t)),C=Math.max(1,Math.floor(E/e));(Q!==this.cols||C!==this.rows)&&this.resize(Q,C)}}),this.resizeObserver.observe(this.element)}destroy(){this._destroyed=!0,this.rafId!=null&&cancelAnimationFrame(this.rafId),this.resizeObserver&&this.resizeObserver.disconnect(),this.input&&this.input.destroy(),this.element.removeEventListener("click",this._onClickFocus),this.element.innerHTML=""}};var J=/\x1b\[([0-9;]*)m/g,L=256;function N(r){if(!r)return null;let A=r.split(";"),t=[];for(let e=0;e<A.length;e++){let s=A[e];if((s==="38"||s==="48")&&A[e+1]==="5"){t.push(A[e],A[e+1],A[e+2]??""),e+=2;continue}if((s==="38"||s==="48")&&A[e+1]==="2"){t.push(A[e],A[e+1],A[e+2]??"",A[e+3]??"",A[e+4]??""),e+=4;continue}s==="4"||s==="24"||t.push(s)}return t.length?"\x1B["+t.join(";")+"m":""}var b=class extends w{resize(A,t){super.resize(Math.min(A,L),t)}write(A){typeof A=="string"&&(A=A.replace(J,(t,e)=>{let s=N(e);return s===null?t:s})),super.write(A)}reset(){!this.bridge||!this.renderer||(this.bridge.init(this.cols,this.rows),this.renderer.setup(this.cols,this.rows),this._scheduleRender())}async init(){return this._calibrateInitialSize(),await super.init(),this.autoResize&&!this.resizeObserver&&!this._destroyed&&this._scheduleObserverSetup(),this}_calibrateInitialSize(){if(!this.element||!this._container||!this.element.isConnected)return;this.element.offsetHeight;let A=document.createElement("span");A.className="term-cell",A.style.cssText="position:absolute;visibility:hidden;left:-9999px;top:0;",A.textContent="W",this._container.appendChild(A);let t=A.getBoundingClientRect(),e=t.width,s=t.height;if(A.remove(),e<=0||s<=0)return;let i=getComputedStyle(this.element),o=(parseFloat(i.paddingLeft)||0)+(parseFloat(i.paddingRight)||0),B=(parseFloat(i.paddingTop)||0)+(parseFloat(i.paddingBottom)||0),E=this.element.clientWidth-o,Q=this.element.clientHeight-B;if(E<=0||Q<=0)return;let C=Math.min(Math.max(1,Math.floor(E/e)),L),n=Math.max(1,Math.floor(Q/s));this.cols=C,this.rows=n}_scheduleObserverSetup(){if(this._observerSetupPending)return;this._observerSetupPending=!0;let A=0,t=120,e=()=>{if(this._destroyed||this.resizeObserver){this._observerSetupPending=!1;return}if(this.element.offsetHeight,this._measureCharSize()&&this.element.clientWidth>0&&this.element.clientHeight>0){this._setupResizeObserver(),this._observerSetupPending=!1;return}if(++A>=t){this._observerSetupPending=!1;return}A<=8?requestAnimationFrame(e):setTimeout(e,50)};requestAnimationFrame(e)}remeasure(){if(!this.bridge||!this.renderer)return;this.autoResize&&!this.resizeObserver&&!this._destroyed&&(this._measureCharSize()&&this.element.clientWidth>0&&this.element.clientHeight>0?this._setupResizeObserver():this._scheduleObserverSetup());let A=this._measureCharSize();if(!A)return;let t=getComputedStyle(this.element),e=this.element.clientWidth-(parseFloat(t.paddingLeft)||0)-(parseFloat(t.paddingRight)||0),s=this.element.clientHeight-(parseFloat(t.paddingTop)||0)-(parseFloat(t.paddingBottom)||0);if(e<=0||s<=0)return;let i=Math.min(Math.max(1,Math.floor(e/A.width)),L),o=Math.max(1,Math.floor(s/A.height));i!==this.cols||o!==this.rows?this.resize(i,o):this._scheduleRender()}};return k(O);})();