@datnguyennnx/localterm-server 0.0.15

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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agent-rpc.d.ts +27 -0
  3. package/dist/agent-rpc.d.ts.map +1 -0
  4. package/dist/agent-rpc.js +213 -0
  5. package/dist/agent-rpc.js.map +1 -0
  6. package/dist/agent-token.d.ts +21 -0
  7. package/dist/agent-token.d.ts.map +1 -0
  8. package/dist/agent-token.js +53 -0
  9. package/dist/agent-token.js.map +1 -0
  10. package/dist/constants.d.ts +54 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/constants.js +106 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/default-shell.d.ts +2 -0
  15. package/dist/default-shell.d.ts.map +1 -0
  16. package/dist/default-shell.js +44 -0
  17. package/dist/default-shell.js.map +1 -0
  18. package/dist/ensure-spawn-helper-executable.d.ts +2 -0
  19. package/dist/ensure-spawn-helper-executable.d.ts.map +1 -0
  20. package/dist/ensure-spawn-helper-executable.js +34 -0
  21. package/dist/ensure-spawn-helper-executable.js.map +1 -0
  22. package/dist/errors.d.ts +64 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +84 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/index.d.ts +25 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +424 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/osc133-chunk-parser.d.ts +8 -0
  31. package/dist/osc133-chunk-parser.d.ts.map +1 -0
  32. package/dist/osc133-chunk-parser.js +29 -0
  33. package/dist/osc133-chunk-parser.js.map +1 -0
  34. package/dist/osc7-chunk-parser.d.ts +7 -0
  35. package/dist/osc7-chunk-parser.d.ts.map +1 -0
  36. package/dist/osc7-chunk-parser.js +29 -0
  37. package/dist/osc7-chunk-parser.js.map +1 -0
  38. package/dist/output-batcher.d.ts +11 -0
  39. package/dist/output-batcher.d.ts.map +1 -0
  40. package/dist/output-batcher.js +47 -0
  41. package/dist/output-batcher.js.map +1 -0
  42. package/dist/protocol.d.ts +5 -0
  43. package/dist/protocol.d.ts.map +1 -0
  44. package/dist/protocol.js +3 -0
  45. package/dist/protocol.js.map +1 -0
  46. package/dist/schemas.d.ts +66 -0
  47. package/dist/schemas.d.ts.map +1 -0
  48. package/dist/schemas.js +118 -0
  49. package/dist/schemas.js.map +1 -0
  50. package/dist/security.d.ts +5 -0
  51. package/dist/security.d.ts.map +1 -0
  52. package/dist/security.js +63 -0
  53. package/dist/security.js.map +1 -0
  54. package/dist/session-registry.d.ts +9 -0
  55. package/dist/session-registry.d.ts.map +1 -0
  56. package/dist/session-registry.js +19 -0
  57. package/dist/session-registry.js.map +1 -0
  58. package/dist/session.d.ts +62 -0
  59. package/dist/session.d.ts.map +1 -0
  60. package/dist/session.js +238 -0
  61. package/dist/session.js.map +1 -0
  62. package/dist/shell-integration/index.d.ts +7 -0
  63. package/dist/shell-integration/index.d.ts.map +1 -0
  64. package/dist/shell-integration/index.js +29 -0
  65. package/dist/shell-integration/index.js.map +1 -0
  66. package/dist/static-resolver.d.ts +7 -0
  67. package/dist/static-resolver.d.ts.map +1 -0
  68. package/dist/static-resolver.js +65 -0
  69. package/dist/static-resolver.js.map +1 -0
  70. package/dist/types.d.ts +13 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +2 -0
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils/format-working-directory-title.d.ts +2 -0
  75. package/dist/utils/format-working-directory-title.d.ts.map +1 -0
  76. package/dist/utils/format-working-directory-title.js +28 -0
  77. package/dist/utils/format-working-directory-title.js.map +1 -0
  78. package/dist/utils/get-heartbeat-action.d.ts +4 -0
  79. package/dist/utils/get-heartbeat-action.d.ts.map +1 -0
  80. package/dist/utils/get-heartbeat-action.js +11 -0
  81. package/dist/utils/get-heartbeat-action.js.map +1 -0
  82. package/dist/utils/parse-osc133-from-chunk.d.ts +10 -0
  83. package/dist/utils/parse-osc133-from-chunk.d.ts.map +1 -0
  84. package/dist/utils/parse-osc133-from-chunk.js +44 -0
  85. package/dist/utils/parse-osc133-from-chunk.js.map +1 -0
  86. package/dist/utils/parse-osc7-from-chunk.d.ts +2 -0
  87. package/dist/utils/parse-osc7-from-chunk.d.ts.map +1 -0
  88. package/dist/utils/parse-osc7-from-chunk.js +32 -0
  89. package/dist/utils/parse-osc7-from-chunk.js.map +1 -0
  90. package/dist/utils/resolve-cwd-for-pid.d.ts +2 -0
  91. package/dist/utils/resolve-cwd-for-pid.d.ts.map +1 -0
  92. package/dist/utils/resolve-cwd-for-pid.js +29 -0
  93. package/dist/utils/resolve-cwd-for-pid.js.map +1 -0
  94. package/dist/utils/strip-ansi.d.ts +13 -0
  95. package/dist/utils/strip-ansi.d.ts.map +1 -0
  96. package/dist/utils/strip-ansi.js +28 -0
  97. package/dist/utils/strip-ansi.js.map +1 -0
  98. package/package.json +69 -0
@@ -0,0 +1,238 @@
1
+ import { EventEmitter } from "node:events";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { spawn } from "node-pty";
5
+ import { COLORTERM_VALUE, CWD_RESOLVE_BACKOFF_MS, CWD_RESOLVE_COOLDOWN_MS, DEFAULT_COLS, DEFAULT_ROWS, PTY_ENV_DENYLIST, TERM_TYPE, TITLE_POLL_INTERVAL_MS, } from "./constants.js";
6
+ // Note: titles are emitted on a dedicated `title` event so they travel as a
7
+ // separate WebSocket frame. We deliberately do NOT splice OSC sequences into
8
+ // the PTY output stream — doing so corrupts in-flight escape sequences from
9
+ // modern TUIs (e.g. Cursor Agent / Claude Code use DECSET 2026 synchronized
10
+ // output mode and any byte landing inside that frame breaks the parser state).
11
+ import { ensureSpawnHelperExecutable } from "./ensure-spawn-helper-executable.js";
12
+ import { getDefaultShell } from "./default-shell.js";
13
+ import { Osc7ChunkParser } from "./osc7-chunk-parser.js";
14
+ import { Osc133ChunkParser } from "./osc133-chunk-parser.js";
15
+ import { formatWorkingDirectoryTitle } from "./utils/format-working-directory-title.js";
16
+ import { resolveCwdForPid } from "./utils/resolve-cwd-for-pid.js";
17
+ export class Session extends EventEmitter {
18
+ shell;
19
+ cwd;
20
+ createdAt;
21
+ mode;
22
+ pty;
23
+ shellName;
24
+ currentCols;
25
+ currentRows;
26
+ exited = false;
27
+ paused = false;
28
+ titlePollTimer = null;
29
+ lastEmittedTitle = "";
30
+ lastEmittedCwd = "";
31
+ nextCwdResolveAt = 0;
32
+ osc7Detected = false;
33
+ osc7ChunkParser = new Osc7ChunkParser();
34
+ osc133ChunkParser = new Osc133ChunkParser();
35
+ constructor(input) {
36
+ super();
37
+ ensureSpawnHelperExecutable();
38
+ this.shell = input.shell ?? getDefaultShell();
39
+ this.shellName = path.basename(this.shell);
40
+ this.cwd = input.cwd ?? os.homedir();
41
+ this.currentCols = input.cols ?? DEFAULT_COLS;
42
+ this.currentRows = input.rows ?? DEFAULT_ROWS;
43
+ this.createdAt = Date.now();
44
+ this.mode = input.mode ?? "human";
45
+ const env = {};
46
+ const denied = new Set(PTY_ENV_DENYLIST);
47
+ for (const [key, value] of Object.entries(process.env)) {
48
+ if (denied.has(key))
49
+ continue;
50
+ if (typeof value === "string")
51
+ env[key] = value;
52
+ }
53
+ if (input.env) {
54
+ for (const [key, value] of Object.entries(input.env)) {
55
+ env[key] = value;
56
+ }
57
+ }
58
+ env.TERM = TERM_TYPE;
59
+ env.COLORTERM = COLORTERM_VALUE;
60
+ this.pty = spawn(this.shell, [], {
61
+ name: TERM_TYPE,
62
+ cols: this.currentCols,
63
+ rows: this.currentRows,
64
+ cwd: this.cwd,
65
+ env,
66
+ });
67
+ this.pty.onData((data) => {
68
+ this.onPtyOutput(data);
69
+ this.emit("output", data);
70
+ });
71
+ this.pty.onExit(({ exitCode }) => {
72
+ this.exited = true;
73
+ this.stopTitlePolling();
74
+ this.emit("exit", exitCode);
75
+ });
76
+ this.scheduleTitlePoll(0);
77
+ }
78
+ get pid() {
79
+ return this.pty.pid;
80
+ }
81
+ get shellBaseName() {
82
+ return this.shellName;
83
+ }
84
+ get cols() {
85
+ return this.currentCols;
86
+ }
87
+ get rows() {
88
+ return this.currentRows;
89
+ }
90
+ get isExited() {
91
+ return this.exited;
92
+ }
93
+ get isPaused() {
94
+ return this.paused;
95
+ }
96
+ write(data) {
97
+ if (this.exited)
98
+ return;
99
+ this.pty.write(data);
100
+ }
101
+ /**
102
+ * Stop reading data from the PTY. node-pty buffers further child output in
103
+ * the OS pipe; once that fills, write() in the child process blocks, which
104
+ * propagates flow control all the way back to the producing program (e.g.
105
+ * `cat large_file`). Used by the WS layer to pause heavy output streams
106
+ * when the outbound socket buffer is filling, so we don't have to kill the
107
+ * connection just to recover memory.
108
+ */
109
+ pause() {
110
+ if (this.exited || this.paused)
111
+ return;
112
+ this.paused = true;
113
+ try {
114
+ this.pty.pause();
115
+ }
116
+ catch {
117
+ /* PTY may have died between the exited check and the call */
118
+ }
119
+ }
120
+ /**
121
+ * Reverse of `pause()`. Buffered child output starts flowing again and the
122
+ * child process unblocks if it was stuck in write().
123
+ */
124
+ resume() {
125
+ if (this.exited || !this.paused)
126
+ return;
127
+ this.paused = false;
128
+ try {
129
+ this.pty.resume();
130
+ }
131
+ catch {
132
+ /* see pause() */
133
+ }
134
+ }
135
+ resize(cols, rows) {
136
+ if (this.exited)
137
+ return;
138
+ if (cols <= 0 || rows <= 0)
139
+ return;
140
+ if (cols === this.currentCols && rows === this.currentRows)
141
+ return;
142
+ this.currentCols = cols;
143
+ this.currentRows = rows;
144
+ try {
145
+ this.pty.resize(cols, rows);
146
+ }
147
+ catch {
148
+ /* PTY may have died between checks */
149
+ }
150
+ }
151
+ kill(signal = "SIGHUP") {
152
+ if (this.exited)
153
+ return;
154
+ try {
155
+ this.pty.kill(signal);
156
+ }
157
+ catch {
158
+ /* already gone */
159
+ }
160
+ }
161
+ dispose() {
162
+ this.kill();
163
+ this.exited = true;
164
+ this.stopTitlePolling();
165
+ this.osc7ChunkParser.reset();
166
+ this.osc133ChunkParser.reset();
167
+ this.removeAllListeners();
168
+ }
169
+ onPtyOutput(data) {
170
+ const osc7Path = this.osc7ChunkParser.push(data);
171
+ if (osc7Path) {
172
+ this.osc7Detected = true;
173
+ if (osc7Path !== this.lastEmittedCwd) {
174
+ this.lastEmittedCwd = osc7Path;
175
+ this.emit("cwd", osc7Path);
176
+ }
177
+ }
178
+ // OSC 133 / FinalTerm command boundary detection.
179
+ const boundary = this.osc133ChunkParser.push(data);
180
+ if (boundary) {
181
+ this.emit("commandBoundary", boundary);
182
+ }
183
+ }
184
+ scheduleTitlePoll(delayMs) {
185
+ if (this.exited)
186
+ return;
187
+ this.titlePollTimer = setTimeout(() => {
188
+ void this.runTitlePoll();
189
+ }, delayMs);
190
+ this.titlePollTimer.unref();
191
+ }
192
+ async runTitlePoll() {
193
+ if (this.exited)
194
+ return;
195
+ try {
196
+ const liveCwd = this.osc7Detected ? this.lastEmittedCwd || null : await this.resolveLiveCwd();
197
+ if (this.exited)
198
+ return;
199
+ if (!this.osc7Detected && liveCwd && liveCwd !== this.lastEmittedCwd) {
200
+ this.lastEmittedCwd = liveCwd;
201
+ this.emit("cwd", liveCwd);
202
+ }
203
+ const nextTitle = this.computeTitle(liveCwd);
204
+ if (nextTitle && nextTitle !== this.lastEmittedTitle) {
205
+ this.lastEmittedTitle = nextTitle;
206
+ this.emit("title", nextTitle);
207
+ }
208
+ }
209
+ catch {
210
+ /* polling errors are non-fatal; the next tick will retry */
211
+ }
212
+ finally {
213
+ this.scheduleTitlePoll(TITLE_POLL_INTERVAL_MS);
214
+ }
215
+ }
216
+ computeTitle(liveCwd) {
217
+ const foreground = this.pty.process?.trim() ?? "";
218
+ if (foreground && foreground !== this.shellName)
219
+ return foreground;
220
+ return formatWorkingDirectoryTitle(liveCwd ?? this.cwd);
221
+ }
222
+ async resolveLiveCwd() {
223
+ const now = Date.now();
224
+ if (now < this.nextCwdResolveAt)
225
+ return null;
226
+ const liveCwd = await resolveCwdForPid(this.pid).catch(() => null);
227
+ this.nextCwdResolveAt =
228
+ now + (liveCwd === null ? CWD_RESOLVE_BACKOFF_MS : CWD_RESOLVE_COOLDOWN_MS);
229
+ return liveCwd;
230
+ }
231
+ stopTitlePolling() {
232
+ if (this.titlePollTimer === null)
233
+ return;
234
+ clearTimeout(this.titlePollTimer);
235
+ this.titlePollTimer = null;
236
+ }
237
+ }
238
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Return the shell integration script for the given shell basename.
3
+ * Returns an empty string for unsupported shells (graceful degradation).
4
+ */
5
+ export declare const getShellIntegrationScript: (shellBaseName: string) => string;
6
+ export declare const SHELL_INTEGRATION_ENV_VAR = "LOCALTERM_SHELL_INTEGRATION";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell-integration/index.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GAAI,eAAe,MAAM,KAAG,MASjE,CAAC;AAEF,eAAO,MAAM,yBAAyB,gCAAgC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const __dirname = join(fileURLToPath(import.meta.url), "..");
5
+ const SCRIPT_CACHE = new Map();
6
+ const loadScript = (name) => {
7
+ const cached = SCRIPT_CACHE.get(name);
8
+ if (cached !== undefined)
9
+ return cached;
10
+ const content = readFileSync(join(__dirname, name), "utf-8");
11
+ SCRIPT_CACHE.set(name, content);
12
+ return content;
13
+ };
14
+ /**
15
+ * Return the shell integration script for the given shell basename.
16
+ * Returns an empty string for unsupported shells (graceful degradation).
17
+ */
18
+ export const getShellIntegrationScript = (shellBaseName) => {
19
+ switch (shellBaseName) {
20
+ case "bash":
21
+ return loadScript("bash.sh");
22
+ case "zsh":
23
+ return loadScript("zsh.sh");
24
+ default:
25
+ return "";
26
+ }
27
+ };
28
+ export const SHELL_INTEGRATION_ENV_VAR = "LOCALTERM_SHELL_INTEGRATION";
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shell-integration/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AAE7D,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE/C,MAAM,UAAU,GAAG,CAAC,IAAY,EAAU,EAAE;IAC1C,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IAC7D,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,aAAqB,EAAU,EAAE;IACzE,QAAQ,aAAa,EAAE,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;QAC/B,KAAK,KAAK;YACR,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC9B;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,6BAA6B,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface StaticAsset {
2
+ body: Buffer;
3
+ contentType: string;
4
+ status: number;
5
+ }
6
+ export declare const resolveStaticAsset: (root: string, urlPath: string) => StaticAsset | null;
7
+ //# sourceMappingURL=static-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-resolver.d.ts","sourceRoot":"","sources":["../src/static-resolver.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAkBD,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,WAAW,GAAG,IAqBhF,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import path from "node:path";
3
+ const MIME = {
4
+ ".html": "text/html; charset=utf-8",
5
+ ".js": "text/javascript; charset=utf-8",
6
+ ".mjs": "text/javascript; charset=utf-8",
7
+ ".css": "text/css; charset=utf-8",
8
+ ".svg": "image/svg+xml",
9
+ ".png": "image/png",
10
+ ".jpg": "image/jpeg",
11
+ ".jpeg": "image/jpeg",
12
+ ".gif": "image/gif",
13
+ ".webp": "image/webp",
14
+ ".ico": "image/x-icon",
15
+ ".json": "application/json; charset=utf-8",
16
+ ".webmanifest": "application/manifest+json; charset=utf-8",
17
+ ".woff": "font/woff",
18
+ ".woff2": "font/woff2",
19
+ ".ttf": "font/ttf",
20
+ ".map": "application/json; charset=utf-8",
21
+ };
22
+ const isContained = (root, resolved) => {
23
+ const relative = path.relative(root, resolved);
24
+ return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
25
+ };
26
+ const readFile = (target) => {
27
+ if (!existsSync(target))
28
+ return null;
29
+ if (!statSync(target).isFile())
30
+ return null;
31
+ const ext = path.extname(target).toLowerCase();
32
+ return {
33
+ body: readFileSync(target),
34
+ contentType: MIME[ext] ?? "application/octet-stream",
35
+ status: 200,
36
+ };
37
+ };
38
+ export const resolveStaticAsset = (root, urlPath) => {
39
+ const normalizedRoot = path.resolve(root);
40
+ let decoded;
41
+ try {
42
+ decoded = decodeURIComponent(urlPath.split("?", 1)[0] ?? "/");
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ const trimmed = decoded.replace(/^[/\\]+/, "");
48
+ const resolvedExact = path.resolve(normalizedRoot, trimmed);
49
+ if (isContained(normalizedRoot, resolvedExact)) {
50
+ const direct = readFile(resolvedExact);
51
+ if (direct)
52
+ return direct;
53
+ const indexed = readFile(path.join(resolvedExact, "index.html"));
54
+ if (indexed)
55
+ return indexed;
56
+ }
57
+ const hasFileExtension = /\.[a-z0-9]+$/i.test(trimmed);
58
+ if (hasFileExtension)
59
+ return null;
60
+ const fallback = readFile(path.join(normalizedRoot, "index.html"));
61
+ if (!fallback)
62
+ return null;
63
+ return { ...fallback, status: 200 };
64
+ };
65
+ //# sourceMappingURL=static-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-resolver.js","sourceRoot":"","sources":["../src/static-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { z } from "zod";
2
+ import type { clientToServerMessageSchema, serverToClientMessageSchema } from "./schemas.js";
3
+ export interface SpawnPtyInput {
4
+ cols?: number;
5
+ rows?: number;
6
+ shell?: string;
7
+ cwd?: string;
8
+ env?: Record<string, string>;
9
+ mode?: "human" | "agent";
10
+ }
11
+ export type ClientToServerMessage = z.infer<typeof clientToServerMessageSchema>;
12
+ export type ServerToClientMessage = z.infer<typeof serverToClientMessageSchema>;
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAE7F,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare const formatWorkingDirectoryTitle: (cwd: string, home?: string) => string;
2
+ //# sourceMappingURL=format-working-directory-title.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-working-directory-title.d.ts","sourceRoot":"","sources":["../../src/utils/format-working-directory-title.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,2BAA2B,GAAI,KAAK,MAAM,EAAE,aAA4B,KAAG,MAQvF,CAAC"}
@@ -0,0 +1,28 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { TITLE_MAX_PATH_SEGMENTS, TITLE_TRUNCATION_PREFIX } from "../constants.js";
4
+ const HOME_PREFIX = "~";
5
+ const PATH_SEPARATOR = "/";
6
+ const CACHED_HOME_DIRECTORY = os.homedir();
7
+ const abbreviateHome = (cwd, home) => {
8
+ const normalizedCwd = path.resolve(cwd);
9
+ const normalizedHome = path.resolve(home);
10
+ if (normalizedCwd === normalizedHome)
11
+ return HOME_PREFIX;
12
+ if (normalizedCwd.startsWith(`${normalizedHome}${PATH_SEPARATOR}`)) {
13
+ return `${HOME_PREFIX}${normalizedCwd.slice(normalizedHome.length)}`;
14
+ }
15
+ return normalizedCwd;
16
+ };
17
+ export const formatWorkingDirectoryTitle = (cwd, home = CACHED_HOME_DIRECTORY) => {
18
+ if (!cwd)
19
+ return cwd;
20
+ const abbreviated = abbreviateHome(cwd, home);
21
+ const segments = abbreviated.split(PATH_SEPARATOR).filter(Boolean);
22
+ if (segments.length <= TITLE_MAX_PATH_SEGMENTS)
23
+ return abbreviated;
24
+ return `${TITLE_TRUNCATION_PREFIX}${PATH_SEPARATOR}${segments
25
+ .slice(-TITLE_MAX_PATH_SEGMENTS)
26
+ .join(PATH_SEPARATOR)}`;
27
+ };
28
+ //# sourceMappingURL=format-working-directory-title.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-working-directory-title.js","sourceRoot":"","sources":["../../src/utils/format-working-directory-title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAEnF,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,MAAM,qBAAqB,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;AAE3C,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,IAAY,EAAU,EAAE;IAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,aAAa,KAAK,cAAc;QAAE,OAAO,WAAW,CAAC;IACzD,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC,EAAE,CAAC;QACnE,OAAO,GAAG,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAW,EAAE,IAAI,GAAG,qBAAqB,EAAU,EAAE;IAC/F,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IACrB,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnE,IAAI,QAAQ,CAAC,MAAM,IAAI,uBAAuB;QAAE,OAAO,WAAW,CAAC;IACnE,OAAO,GAAG,uBAAuB,GAAG,cAAc,GAAG,QAAQ;SAC1D,KAAK,CAAC,CAAC,uBAAuB,CAAC;SAC/B,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;AAC5B,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ type HeartbeatAction = "ping" | "grace-ping" | "wait" | "terminate";
2
+ export declare const getHeartbeatAction: (nowMs: number, lastPongAtMs: number, pendingPingAtMs: number) => HeartbeatAction;
3
+ export {};
4
+ //# sourceMappingURL=get-heartbeat-action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-heartbeat-action.d.ts","sourceRoot":"","sources":["../../src/utils/get-heartbeat-action.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC;AAEpE,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,cAAc,MAAM,EACpB,iBAAiB,MAAM,KACtB,eAKF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { WS_HEARTBEAT_GRACE_MS, WS_HEARTBEAT_TIMEOUT_MS } from "../constants.js";
2
+ export const getHeartbeatAction = (nowMs, lastPongAtMs, pendingPingAtMs) => {
3
+ if (nowMs - lastPongAtMs <= WS_HEARTBEAT_TIMEOUT_MS)
4
+ return "ping";
5
+ if (pendingPingAtMs === 0)
6
+ return "grace-ping";
7
+ if (nowMs - pendingPingAtMs < WS_HEARTBEAT_GRACE_MS)
8
+ return "wait";
9
+ return "terminate";
10
+ };
11
+ //# sourceMappingURL=get-heartbeat-action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-heartbeat-action.js","sourceRoot":"","sources":["../../src/utils/get-heartbeat-action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAIjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAa,EACb,YAAoB,EACpB,eAAuB,EACN,EAAE;IACnB,IAAI,KAAK,GAAG,YAAY,IAAI,uBAAuB;QAAE,OAAO,MAAM,CAAC;IACnE,IAAI,eAAe,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC;IAC/C,IAAI,KAAK,GAAG,eAAe,GAAG,qBAAqB;QAAE,OAAO,MAAM,CAAC;IACnE,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface CommandBoundary {
2
+ phase: "prompt-start" | "command-start" | "output-start" | "command-end";
3
+ exitCode?: number;
4
+ }
5
+ /**
6
+ * Scan a string chunk for OSC 133 FinalTerm sequences and return the last one found.
7
+ * Returns null if no complete OSC 133 sequence is present.
8
+ */
9
+ export declare const parseOsc133FromChunk: (data: string) => CommandBoundary | null;
10
+ //# sourceMappingURL=parse-osc133-from-chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-osc133-from-chunk.d.ts","sourceRoot":"","sources":["../../src/utils/parse-osc133-from-chunk.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,cAAc,GAAG,eAAe,GAAG,cAAc,GAAG,aAAa,CAAC;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAmBD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,eAAe,GAAG,IAqBrE,CAAC"}
@@ -0,0 +1,44 @@
1
+ const OSC133_PREFIX = "\x1b]133;";
2
+ const OSC_BEL_TERMINATOR = "\x07";
3
+ const OSC_ST_TERMINATOR = "\x1b\\";
4
+ const parseOsc133Payload = (payload) => {
5
+ if (payload.length === 0)
6
+ return null;
7
+ const letter = payload[0];
8
+ if (letter === "A")
9
+ return { phase: "prompt-start" };
10
+ if (letter === "B")
11
+ return { phase: "command-start" };
12
+ if (letter === "C")
13
+ return { phase: "output-start" };
14
+ if (letter === "D") {
15
+ const exitCode = payload.length > 2 ? Number(payload.slice(2)) : 0;
16
+ return { phase: "command-end", exitCode: Number.isFinite(exitCode) ? exitCode : 0 };
17
+ }
18
+ return null;
19
+ };
20
+ /**
21
+ * Scan a string chunk for OSC 133 FinalTerm sequences and return the last one found.
22
+ * Returns null if no complete OSC 133 sequence is present.
23
+ */
24
+ export const parseOsc133FromChunk = (data) => {
25
+ let searchFrom = 0;
26
+ let lastBoundary = null;
27
+ while (searchFrom < data.length) {
28
+ const sequenceStart = data.indexOf(OSC133_PREFIX, searchFrom);
29
+ if (sequenceStart === -1)
30
+ break;
31
+ const payloadStart = sequenceStart + OSC133_PREFIX.length;
32
+ const belIndex = data.indexOf(OSC_BEL_TERMINATOR, payloadStart);
33
+ const stIndex = data.indexOf(OSC_ST_TERMINATOR, payloadStart);
34
+ const payloadEnd = belIndex !== -1 && (stIndex === -1 || belIndex < stIndex) ? belIndex : stIndex;
35
+ if (payloadEnd === -1)
36
+ break;
37
+ const boundary = parseOsc133Payload(data.slice(payloadStart, payloadEnd));
38
+ if (boundary)
39
+ lastBoundary = boundary;
40
+ searchFrom = payloadEnd + 1;
41
+ }
42
+ return lastBoundary;
43
+ };
44
+ //# sourceMappingURL=parse-osc133-from-chunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-osc133-from-chunk.js","sourceRoot":"","sources":["../../src/utils/parse-osc133-from-chunk.ts"],"names":[],"mappings":"AAKA,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAEnC,MAAM,kBAAkB,GAAG,CAAC,OAAe,EAA0B,EAAE;IACrE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IACrD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;IACtD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IACrD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAAY,EAA0B,EAAE;IAC3E,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,YAAY,GAA2B,IAAI,CAAC;IAEhD,OAAO,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QAC9D,IAAI,aAAa,KAAK,CAAC,CAAC;YAAE,MAAM;QAEhC,MAAM,YAAY,GAAG,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;QAC9D,MAAM,UAAU,GACd,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;QACjF,IAAI,UAAU,KAAK,CAAC,CAAC;YAAE,MAAM;QAE7B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;QAC1E,IAAI,QAAQ;YAAE,YAAY,GAAG,QAAQ,CAAC;QACtC,UAAU,GAAG,UAAU,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const parseOsc7FromChunk: (data: string) => string | null;
2
+ //# sourceMappingURL=parse-osc7-from-chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-osc7-from-chunk.d.ts","sourceRoot":"","sources":["../../src/utils/parse-osc7-from-chunk.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,IAqB1D,CAAC"}
@@ -0,0 +1,32 @@
1
+ const OSC7_PREFIX = "\x1b]7;";
2
+ const OSC_BEL_TERMINATOR = "\x07";
3
+ const OSC_ST_TERMINATOR = "\x1b\\";
4
+ const extractOsc7Path = (url) => {
5
+ try {
6
+ return decodeURIComponent(new URL(url).pathname);
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ };
12
+ export const parseOsc7FromChunk = (data) => {
13
+ let searchFrom = 0;
14
+ let lastPath = null;
15
+ while (searchFrom < data.length) {
16
+ const sequenceStart = data.indexOf(OSC7_PREFIX, searchFrom);
17
+ if (sequenceStart === -1)
18
+ break;
19
+ const payloadStart = sequenceStart + OSC7_PREFIX.length;
20
+ const belIndex = data.indexOf(OSC_BEL_TERMINATOR, payloadStart);
21
+ const stIndex = data.indexOf(OSC_ST_TERMINATOR, payloadStart);
22
+ const payloadEnd = belIndex !== -1 && (stIndex === -1 || belIndex < stIndex) ? belIndex : stIndex;
23
+ if (payloadEnd === -1)
24
+ break;
25
+ const path = extractOsc7Path(data.slice(payloadStart, payloadEnd));
26
+ if (path)
27
+ lastPath = path;
28
+ searchFrom = payloadEnd + 1;
29
+ }
30
+ return lastPath;
31
+ };
32
+ //# sourceMappingURL=parse-osc7-from-chunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-osc7-from-chunk.js","sourceRoot":"","sources":["../../src/utils/parse-osc7-from-chunk.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,SAAS,CAAC;AAC9B,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAEnC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAiB,EAAE;IACrD,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAiB,EAAE;IAChE,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,QAAQ,GAAkB,IAAI,CAAC;IAEnC,OAAO,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QAC5D,IAAI,aAAa,KAAK,CAAC,CAAC;YAAE,MAAM;QAEhC,MAAM,YAAY,GAAG,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC;QACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;QAC9D,MAAM,UAAU,GACd,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;QACjF,IAAI,UAAU,KAAK,CAAC,CAAC;YAAE,MAAM;QAE7B,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;QACnE,IAAI,IAAI;YAAE,QAAQ,GAAG,IAAI,CAAC;QAC1B,UAAU,GAAG,UAAU,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const resolveCwdForPid: (pid: number) => Promise<string | null>;
2
+ //# sourceMappingURL=resolve-cwd-for-pid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-cwd-for-pid.d.ts","sourceRoot":"","sources":["../../src/utils/resolve-cwd-for-pid.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gBAAgB,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAuBzE,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { execFile } from "node:child_process";
2
+ import { readlink } from "node:fs/promises";
3
+ import { promisify } from "node:util";
4
+ import { CWD_RESOLVE_TIMEOUT_MS } from "../constants.js";
5
+ const execFileAsync = promisify(execFile);
6
+ export const resolveCwdForPid = async (pid) => {
7
+ if (!Number.isFinite(pid) || pid <= 0)
8
+ return null;
9
+ if (process.platform === "linux") {
10
+ try {
11
+ return await readlink(`/proc/${pid}/cwd`);
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ if (process.platform === "darwin") {
18
+ try {
19
+ const { stdout } = await execFileAsync("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], { timeout: CWD_RESOLVE_TIMEOUT_MS, windowsHide: true });
20
+ const cwdLine = stdout.split("\n").find((line) => line.startsWith("n"));
21
+ return cwdLine ? cwdLine.slice(1) : null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ return null;
28
+ };
29
+ //# sourceMappingURL=resolve-cwd-for-pid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-cwd-for-pid.js","sourceRoot":"","sources":["../../src/utils/resolve-cwd-for-pid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,GAAW,EAA0B,EAAE;IAC5E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CACpC,MAAM,EACN,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAC7C,EAAE,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,IAAI,EAAE,CACvD,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;YACxE,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC"}