@myrialabs/ptykit 0.0.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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -0
  3. package/dist/client/fit.d.ts +29 -0
  4. package/dist/client/fit.d.ts.map +1 -0
  5. package/dist/client/fit.js +45 -0
  6. package/dist/client/fit.js.map +1 -0
  7. package/dist/client/index.d.ts +10 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +9 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/client/persistence.d.ts +15 -0
  12. package/dist/client/persistence.d.ts.map +1 -0
  13. package/dist/client/persistence.js +47 -0
  14. package/dist/client/persistence.js.map +1 -0
  15. package/dist/client/pty-kit-client.d.ts +122 -0
  16. package/dist/client/pty-kit-client.d.ts.map +1 -0
  17. package/dist/client/pty-kit-client.js +245 -0
  18. package/dist/client/pty-kit-client.js.map +1 -0
  19. package/dist/client/terminal.d.ts +77 -0
  20. package/dist/client/terminal.d.ts.map +1 -0
  21. package/dist/client/terminal.js +112 -0
  22. package/dist/client/terminal.js.map +1 -0
  23. package/dist/client/ws-core.d.ts +88 -0
  24. package/dist/client/ws-core.d.ts.map +1 -0
  25. package/dist/client/ws-core.js +324 -0
  26. package/dist/client/ws-core.js.map +1 -0
  27. package/dist/core/backend.d.ts +52 -0
  28. package/dist/core/backend.d.ts.map +1 -0
  29. package/dist/core/backend.js +11 -0
  30. package/dist/core/backend.js.map +1 -0
  31. package/dist/core/detect.d.ts +21 -0
  32. package/dist/core/detect.d.ts.map +1 -0
  33. package/dist/core/detect.js +82 -0
  34. package/dist/core/detect.js.map +1 -0
  35. package/dist/core/env.d.ts +30 -0
  36. package/dist/core/env.d.ts.map +1 -0
  37. package/dist/core/env.js +68 -0
  38. package/dist/core/env.js.map +1 -0
  39. package/dist/core/index.d.ts +11 -0
  40. package/dist/core/index.d.ts.map +1 -0
  41. package/dist/core/index.js +10 -0
  42. package/dist/core/index.js.map +1 -0
  43. package/dist/core/pty-kit.d.ts +90 -0
  44. package/dist/core/pty-kit.d.ts.map +1 -0
  45. package/dist/core/pty-kit.js +187 -0
  46. package/dist/core/pty-kit.js.map +1 -0
  47. package/dist/core/scrollback.d.ts +43 -0
  48. package/dist/core/scrollback.d.ts.map +1 -0
  49. package/dist/core/scrollback.js +79 -0
  50. package/dist/core/scrollback.js.map +1 -0
  51. package/dist/core/session.d.ts +100 -0
  52. package/dist/core/session.d.ts.map +1 -0
  53. package/dist/core/session.js +264 -0
  54. package/dist/core/session.js.map +1 -0
  55. package/dist/core/shell.d.ts +24 -0
  56. package/dist/core/shell.d.ts.map +1 -0
  57. package/dist/core/shell.js +55 -0
  58. package/dist/core/shell.js.map +1 -0
  59. package/dist/index.d.ts +11 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +11 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/server/connection.d.ts +38 -0
  64. package/dist/server/connection.d.ts.map +1 -0
  65. package/dist/server/connection.js +67 -0
  66. package/dist/server/connection.js.map +1 -0
  67. package/dist/server/ids.d.ts +2 -0
  68. package/dist/server/ids.d.ts.map +1 -0
  69. package/dist/server/ids.js +7 -0
  70. package/dist/server/ids.js.map +1 -0
  71. package/dist/server/index.d.ts +6 -0
  72. package/dist/server/index.d.ts.map +1 -0
  73. package/dist/server/index.js +6 -0
  74. package/dist/server/index.js.map +1 -0
  75. package/dist/server/pty-kit-server.d.ts +101 -0
  76. package/dist/server/pty-kit-server.d.ts.map +1 -0
  77. package/dist/server/pty-kit-server.js +361 -0
  78. package/dist/server/pty-kit-server.js.map +1 -0
  79. package/dist/server/transport-bun.d.ts +26 -0
  80. package/dist/server/transport-bun.d.ts.map +1 -0
  81. package/dist/server/transport-bun.js +79 -0
  82. package/dist/server/transport-bun.js.map +1 -0
  83. package/dist/server/transport-node.d.ts +20 -0
  84. package/dist/server/transport-node.d.ts.map +1 -0
  85. package/dist/server/transport-node.js +77 -0
  86. package/dist/server/transport-node.js.map +1 -0
  87. package/dist/shared/index.d.ts +260 -0
  88. package/dist/shared/index.d.ts.map +1 -0
  89. package/dist/shared/index.js +85 -0
  90. package/dist/shared/index.js.map +1 -0
  91. package/package.json +108 -0
  92. package/src/client/svelte/PtyTerminal.svelte +146 -0
  93. package/src/client/svelte/index.d.ts +84 -0
  94. package/src/client/svelte/index.js +4 -0
  95. package/src/client/svelte/svelte-compile.test.ts +11 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Shared wire-protocol types and primitives used across the core engine, the
3
+ * WebSocket transport, and the browser client.
4
+ *
5
+ * The transport is a single multiplexed WebSocket. Two planes ride it:
6
+ * - **Control plane** — RPC request/response keyed by `requestId`.
7
+ * - **Data plane** — broadcast events fanned out to a room and filtered
8
+ * client-side by `sessionId`.
9
+ */
10
+ /** PtyKit package version. */
11
+ export declare const PTYKIT_VERSION = "0.1.0";
12
+ /**
13
+ * Monotonic sequence number stamped on every output event so clients can
14
+ * deduplicate replayed-vs-live output after a reattach (R5).
15
+ */
16
+ export type Seq = number;
17
+ /**
18
+ * Every WebSocket message is a JSON frame `{ action, payload }`. RPC requests
19
+ * carry `payload = { requestId, data }`; RPC responses use action
20
+ * `${action}:response` with `payload = { requestId, success, data?, error? }`;
21
+ * events carry their event payload directly.
22
+ */
23
+ export interface WireFrame {
24
+ action: string;
25
+ payload: unknown;
26
+ }
27
+ /** RPC request payload. */
28
+ export interface RpcRequest<D = unknown> {
29
+ requestId: string;
30
+ data: D;
31
+ }
32
+ /** RPC response payload. The client unwraps `data` on success, throws on failure. */
33
+ export interface RpcResponse<D = unknown> {
34
+ requestId: string;
35
+ success: boolean;
36
+ data?: D;
37
+ error?: string;
38
+ }
39
+ /** Operation names (control plane). */
40
+ export declare const RPC_ACTIONS: readonly ["create-session", "resize", "cancel", "kill-session", "clear", "check-shell", "pty-status", "list-sessions", "stream-status", "missed-output", "reconnect"];
41
+ export type RpcAction = (typeof RPC_ACTIONS)[number];
42
+ /** Fire-and-forget client→server events (data plane in). */
43
+ export declare const CLIENT_EVENTS: readonly ["input"];
44
+ export type ClientEvent = (typeof CLIENT_EVENTS)[number];
45
+ /** Server→client broadcast events (data plane out). */
46
+ export declare const SERVER_EVENTS: readonly ["ready", "output", "directory", "exit", "error", "tab-created", "tab-closed"];
47
+ export type ServerEvent = (typeof SERVER_EVENTS)[number];
48
+ export interface CreateSessionRequest {
49
+ sessionId: string;
50
+ namespace: string;
51
+ streamId?: string;
52
+ shell?: string;
53
+ cwd?: string;
54
+ cols?: number;
55
+ rows?: number;
56
+ }
57
+ export interface CreateSessionResponse {
58
+ sessionId: string;
59
+ streamId: string;
60
+ pid: number;
61
+ currentDirectory: string;
62
+ cols: number;
63
+ rows: number;
64
+ }
65
+ export interface ResizeRequest {
66
+ sessionId: string;
67
+ cols: number;
68
+ rows: number;
69
+ }
70
+ export interface ResizeResponse {
71
+ sessionId: string;
72
+ cols: number;
73
+ rows: number;
74
+ }
75
+ export interface CancelRequest {
76
+ sessionId: string;
77
+ }
78
+ export interface CancelResponse {
79
+ sessionId: string;
80
+ pid: number;
81
+ }
82
+ export interface KillSessionRequest {
83
+ sessionId: string;
84
+ }
85
+ export interface KillSessionResponse {
86
+ sessionId: string;
87
+ pid?: number;
88
+ }
89
+ export interface ClearRequest {
90
+ sessionId: string;
91
+ }
92
+ export interface ClearResponse {
93
+ sessionId: string;
94
+ }
95
+ export interface CheckShellRequest {
96
+ namespace?: string;
97
+ }
98
+ export interface CheckShellResponse {
99
+ available: boolean;
100
+ path: string | null;
101
+ platform: string;
102
+ isWindows: boolean;
103
+ shellType: string;
104
+ }
105
+ export interface PtyStatusRequest {
106
+ sessionId: string;
107
+ }
108
+ export interface PtyStatusResponse {
109
+ isActive: boolean;
110
+ sessionId: string;
111
+ pid?: number;
112
+ message?: string;
113
+ }
114
+ export interface ListSessionsRequest {
115
+ namespace: string;
116
+ }
117
+ export interface ListedSession {
118
+ sessionId: string;
119
+ pid: number;
120
+ cwd: string;
121
+ createdAt: string;
122
+ lastActivityAt: string;
123
+ }
124
+ export interface ListSessionsResponse {
125
+ sessions: ListedSession[];
126
+ }
127
+ export interface StreamStatusRequest {
128
+ sessionId: string;
129
+ }
130
+ export interface StreamStatusResponse {
131
+ status: string;
132
+ bufferLength: number;
133
+ startedAt: string;
134
+ processId?: number;
135
+ }
136
+ export interface MissedOutputRequest {
137
+ sessionId: string;
138
+ }
139
+ export interface MissedOutputResponse {
140
+ sessionId: string;
141
+ output: string;
142
+ status: string;
143
+ timestamp: string;
144
+ }
145
+ export interface ReconnectRequest {
146
+ sessionId: string;
147
+ }
148
+ export interface ReconnectResponse {
149
+ sessionId: string;
150
+ output: string;
151
+ status: string;
152
+ }
153
+ /** Maps each RPC action to its `{ data, response }` contract. */
154
+ export interface RpcMap {
155
+ 'create-session': {
156
+ data: CreateSessionRequest;
157
+ response: CreateSessionResponse;
158
+ };
159
+ resize: {
160
+ data: ResizeRequest;
161
+ response: ResizeResponse;
162
+ };
163
+ cancel: {
164
+ data: CancelRequest;
165
+ response: CancelResponse;
166
+ };
167
+ 'kill-session': {
168
+ data: KillSessionRequest;
169
+ response: KillSessionResponse;
170
+ };
171
+ clear: {
172
+ data: ClearRequest;
173
+ response: ClearResponse;
174
+ };
175
+ 'check-shell': {
176
+ data: CheckShellRequest;
177
+ response: CheckShellResponse;
178
+ };
179
+ 'pty-status': {
180
+ data: PtyStatusRequest;
181
+ response: PtyStatusResponse;
182
+ };
183
+ 'list-sessions': {
184
+ data: ListSessionsRequest;
185
+ response: ListSessionsResponse;
186
+ };
187
+ 'stream-status': {
188
+ data: StreamStatusRequest;
189
+ response: StreamStatusResponse;
190
+ };
191
+ 'missed-output': {
192
+ data: MissedOutputRequest;
193
+ response: MissedOutputResponse;
194
+ };
195
+ reconnect: {
196
+ data: ReconnectRequest;
197
+ response: ReconnectResponse;
198
+ };
199
+ }
200
+ export interface InputEvent {
201
+ sessionId: string;
202
+ data: string;
203
+ }
204
+ export interface ReadyEvent {
205
+ sessionId: string;
206
+ streamId: string;
207
+ pid: number;
208
+ cols: number;
209
+ rows: number;
210
+ }
211
+ export interface OutputEvent {
212
+ sessionId: string;
213
+ content: string;
214
+ seq?: Seq;
215
+ timestamp: string;
216
+ }
217
+ export interface DirectoryEvent {
218
+ sessionId: string;
219
+ newDirectory: string;
220
+ }
221
+ export interface ExitEvent {
222
+ sessionId: string;
223
+ exitCode: number;
224
+ }
225
+ export interface ErrorEvent {
226
+ sessionId: string;
227
+ error: string;
228
+ }
229
+ export interface TabCreatedEvent {
230
+ sessionId: string;
231
+ streamId: string;
232
+ pid: number;
233
+ currentDirectory: string;
234
+ cols: number;
235
+ rows: number;
236
+ }
237
+ export interface TabClosedEvent {
238
+ sessionId: string;
239
+ }
240
+ /** Maps each server→client event to its payload. */
241
+ export interface ServerEventMap {
242
+ ready: ReadyEvent;
243
+ output: OutputEvent;
244
+ directory: DirectoryEvent;
245
+ exit: ExitEvent;
246
+ error: ErrorEvent;
247
+ 'tab-created': TabCreatedEvent;
248
+ 'tab-closed': TabClosedEvent;
249
+ }
250
+ /** Strip terminal report-request sequences from replayed content (R17). */
251
+ export declare function stripReportRequests(content: string): string;
252
+ /** Minimal logger interface. The library never writes to stdout/stderr itself. */
253
+ export interface Logger {
254
+ log(scope: string, ...args: unknown[]): void;
255
+ warn(scope: string, ...args: unknown[]): void;
256
+ error(scope: string, ...args: unknown[]): void;
257
+ }
258
+ /** A logger that discards everything — the default. */
259
+ export declare const silentLogger: Logger;
260
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Shared wire-protocol types and primitives used across the core engine, the
3
+ * WebSocket transport, and the browser client.
4
+ *
5
+ * The transport is a single multiplexed WebSocket. Two planes ride it:
6
+ * - **Control plane** — RPC request/response keyed by `requestId`.
7
+ * - **Data plane** — broadcast events fanned out to a room and filtered
8
+ * client-side by `sessionId`.
9
+ */
10
+ /** PtyKit package version. */
11
+ export const PTYKIT_VERSION = '0.1.0';
12
+ // ============================================================================
13
+ // Control-plane operations (RPC)
14
+ // ============================================================================
15
+ /** Operation names (control plane). */
16
+ export const RPC_ACTIONS = [
17
+ 'create-session',
18
+ 'resize',
19
+ 'cancel',
20
+ 'kill-session',
21
+ 'clear',
22
+ 'check-shell',
23
+ 'pty-status',
24
+ 'list-sessions',
25
+ 'stream-status',
26
+ 'missed-output',
27
+ 'reconnect',
28
+ ];
29
+ /** Fire-and-forget client→server events (data plane in). */
30
+ export const CLIENT_EVENTS = ['input'];
31
+ /** Server→client broadcast events (data plane out). */
32
+ export const SERVER_EVENTS = [
33
+ 'ready',
34
+ 'output',
35
+ 'directory',
36
+ 'exit',
37
+ 'error',
38
+ 'tab-created',
39
+ 'tab-closed',
40
+ ];
41
+ // ============================================================================
42
+ // Replay hygiene (R17)
43
+ // ============================================================================
44
+ /**
45
+ * Escape sequences that ask the terminal to *report back* (color, cursor
46
+ * position, device attributes, mode/status). They are emitted by shells and
47
+ * TUI apps (powerlevel10k, starship, vim) and get captured raw into stored
48
+ * session output.
49
+ *
50
+ * During live output these must reach xterm so it can answer the program
51
+ * waiting to read the reply. But when REPLAYING stored history no program is
52
+ * waiting — xterm still answers via `onData`, and that answer gets forwarded to
53
+ * the live PTY and printed at the idle shell prompt. So we strip these requests
54
+ * from replayed content only.
55
+ */
56
+ /* eslint-disable no-control-regex -- these patterns deliberately match ANSI escape (ESC) sequences */
57
+ const REPORT_REQUEST_PATTERNS = [
58
+ // OSC color query: ESC ] <ps> ; ? (BEL | ST)
59
+ /\x1b\][0-9;]*\?(?:\x07|\x1b\\)/g,
60
+ // Device Status Report / cursor position request: ESC [ ?? <ps> n
61
+ /\x1b\[\??[0-9;]*n/g,
62
+ // Device Attributes: ESC [ [<=>]? <ps> c
63
+ /\x1b\[[<=>]?[0-9;]*c/g,
64
+ // DECRQM mode query: ESC [ ? <ps> $ p
65
+ /\x1b\[\?[0-9;]*\$p/g,
66
+ // DECRQSS status string request (DCS): ESC P <ps> $ q ... ESC \
67
+ /\x1bP[0-9;]*\$q[\s\S]*?\x1b\\/g,
68
+ ];
69
+ /* eslint-enable no-control-regex */
70
+ /** Strip terminal report-request sequences from replayed content (R17). */
71
+ export function stripReportRequests(content) {
72
+ let result = content;
73
+ for (const pattern of REPORT_REQUEST_PATTERNS) {
74
+ pattern.lastIndex = 0;
75
+ result = result.replace(pattern, '');
76
+ }
77
+ return result;
78
+ }
79
+ /** A logger that discards everything — the default. */
80
+ export const silentLogger = {
81
+ log() { },
82
+ warn() { },
83
+ error() { },
84
+ };
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8BAA8B;AAC9B,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAqCtC,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E,uCAAuC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,gBAAgB;IAChB,QAAQ;IACR,QAAQ;IACR,cAAc;IACd,OAAO;IACP,aAAa;IACb,YAAY;IACZ,eAAe;IACf,eAAe;IACf,eAAe;IACf,WAAW;CACF,CAAC;AAGX,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAAO,CAAU,CAAC;AAGhD,uDAAuD;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,OAAO;IACP,QAAQ;IACR,WAAW;IACX,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY;CACH,CAAC;AA+LX,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;GAWG;AACH,sGAAsG;AACtG,MAAM,uBAAuB,GAAa;IACzC,6CAA6C;IAC7C,iCAAiC;IACjC,kEAAkE;IAClE,oBAAoB;IACpB,yCAAyC;IACzC,uBAAuB;IACvB,sCAAsC;IACtC,qBAAqB;IACrB,gEAAgE;IAChE,gCAAgC;CAChC,CAAC;AACF,oCAAoC;AAEpC,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CAAC,OAAe;IAClD,IAAI,MAAM,GAAG,OAAO,CAAC;IACrB,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;QAC/C,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QACtB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAaD,uDAAuD;AACvD,MAAM,CAAC,MAAM,YAAY,GAAW;IACnC,GAAG,KAAI,CAAC;IACR,IAAI,KAAI,CAAC;IACT,KAAK,KAAI,CAAC;CACV,CAAC"}
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "@myrialabs/ptykit",
3
+ "version": "0.0.1",
4
+ "description": "PTY sessions over WebSocket for Node & Bun — collaborative rooms, serialized-scrollback reattach, and a resilient browser client with one typed API.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ },
11
+ "./client": {
12
+ "types": "./dist/client/index.d.ts",
13
+ "import": "./dist/client/index.js"
14
+ },
15
+ "./svelte": {
16
+ "types": "./src/client/svelte/index.d.ts",
17
+ "svelte": "./src/client/svelte/index.js",
18
+ "default": "./src/client/svelte/index.js"
19
+ }
20
+ },
21
+ "types": "./dist/index.d.ts",
22
+ "main": "./dist/index.js",
23
+ "files": [
24
+ "dist",
25
+ "src/client/svelte",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "sideEffects": false,
33
+ "scripts": {
34
+ "build": "tsc -p tsconfig.json",
35
+ "typecheck": "tsc -p tsconfig.json --noEmit",
36
+ "lint": "eslint .",
37
+ "lint:fix": "eslint . --fix",
38
+ "test": "bun test",
39
+ "clean": "rm -rf dist",
40
+ "prepublishOnly": "bun run clean && bun run build"
41
+ },
42
+ "keywords": [
43
+ "pty",
44
+ "pseudoterminal",
45
+ "terminal",
46
+ "websocket",
47
+ "xterm",
48
+ "bun-pty",
49
+ "node-pty",
50
+ "scrollback",
51
+ "reattach",
52
+ "shell",
53
+ "collaborative",
54
+ "browser-terminal",
55
+ "svelte",
56
+ "bun",
57
+ "node",
58
+ "typescript"
59
+ ],
60
+ "author": "Myria Labs",
61
+ "license": "MIT",
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/myrialabs/ptykit.git"
65
+ },
66
+ "homepage": "https://github.com/myrialabs/ptykit#readme",
67
+ "bugs": {
68
+ "url": "https://github.com/myrialabs/ptykit/issues"
69
+ },
70
+ "dependencies": {
71
+ "@xterm/headless": "^6.0.0",
72
+ "@xterm/addon-serialize": "^0.14.0"
73
+ },
74
+ "optionalDependencies": {
75
+ "bun-pty": "^0.4.10",
76
+ "node-pty": "^1.1.0",
77
+ "ws": "^8.21.0"
78
+ },
79
+ "peerDependencies": {
80
+ "@xterm/xterm": "^6.0.0",
81
+ "@xterm/addon-fit": "^0.11.0",
82
+ "svelte": "^5.0.0"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "@xterm/xterm": {
86
+ "optional": true
87
+ },
88
+ "@xterm/addon-fit": {
89
+ "optional": true
90
+ },
91
+ "svelte": {
92
+ "optional": true
93
+ }
94
+ },
95
+ "devDependencies": {
96
+ "@eslint/js": "^9.31.0",
97
+ "@types/bun": "latest",
98
+ "@types/node": "^22.10.0",
99
+ "@types/ws": "^8.18.1",
100
+ "@xterm/addon-fit": "^0.11.0",
101
+ "@xterm/xterm": "^6.0.0",
102
+ "eslint": "^9.31.0",
103
+ "globals": "^16.3.0",
104
+ "svelte": "^5.0.0",
105
+ "typescript": "^5.7.0",
106
+ "typescript-eslint": "^8.37.0"
107
+ }
108
+ }
@@ -0,0 +1,146 @@
1
+ <!--
2
+ PtyTerminal — official Svelte component for `ptykit/svelte`.
3
+
4
+ A thin reactive shell over `mountTerminal` from `ptykit/client`, which owns all
5
+ the xterm.js + FitAddon + session wiring. xterm is imported dynamically there,
6
+ so the component is SSR-safe (it only touches the DOM in the browser).
7
+
8
+ Peer deps (provided by the consuming app): svelte, @xterm/xterm, @xterm/addon-fit.
9
+ -->
10
+ <script>
11
+ import { mountTerminal } from '@myrialabs/ptykit/client';
12
+
13
+ let {
14
+ // --- connection ---
15
+ sessionId,
16
+ url,
17
+ namespace = undefined,
18
+ create = false,
19
+ client = undefined,
20
+ reconnect = undefined,
21
+ persistence = undefined,
22
+ requestTimeoutMs = undefined,
23
+
24
+ // --- session (used when creating) ---
25
+ cols = undefined,
26
+ rows = undefined,
27
+ cwd = undefined,
28
+ shell = undefined,
29
+
30
+ // --- terminal appearance ---
31
+ scrollback = 5000,
32
+ fontSize = 13,
33
+ fontFamily = 'ui-monospace, SFMono-Regular, Menlo, monospace',
34
+ lineHeight = 1.0,
35
+ cursorBlink = true,
36
+ cursorStyle = 'block',
37
+ theme = undefined,
38
+ terminalOptions = {},
39
+
40
+ // --- behavior ---
41
+ fit = true,
42
+ fitDebounceMs = 100,
43
+ showStatus = true,
44
+
45
+ // --- styling ---
46
+ class: className = '',
47
+
48
+ // --- lifecycle callbacks ---
49
+ onready = undefined,
50
+ ondata = undefined,
51
+ onexit = undefined,
52
+ onstatus = undefined,
53
+ onerror = undefined,
54
+ ondirectory = undefined,
55
+ } = $props();
56
+
57
+ /** @type {'connected' | 'reconnecting' | 'disconnected'} */
58
+ let status = $state('reconnecting');
59
+ /** @type {HTMLDivElement | undefined} */
60
+ let container = $state();
61
+
62
+ $effect(() => {
63
+ if (!container) return;
64
+ let cancelled = false;
65
+ /** @type {import('@myrialabs/ptykit/client').TerminalHandle | undefined} */
66
+ let handle;
67
+
68
+ mountTerminal(container, {
69
+ url,
70
+ sessionId,
71
+ namespace,
72
+ create,
73
+ client,
74
+ reconnect,
75
+ persistence,
76
+ requestTimeoutMs,
77
+ cols,
78
+ rows,
79
+ cwd,
80
+ shell,
81
+ scrollback,
82
+ fontSize,
83
+ fontFamily,
84
+ lineHeight,
85
+ cursorBlink,
86
+ cursorStyle,
87
+ theme,
88
+ terminalOptions,
89
+ fit,
90
+ fitDebounceMs,
91
+ onData: ondata,
92
+ onExit: onexit,
93
+ onError: onerror,
94
+ onDirectory: ondirectory,
95
+ onStatus: (s) => {
96
+ status = s;
97
+ onstatus?.(s);
98
+ },
99
+ })
100
+ .then((h) => {
101
+ if (cancelled) {
102
+ h.dispose();
103
+ return;
104
+ }
105
+ handle = h;
106
+ onready?.({ client: h.client, session: h.session, terminal: h.terminal });
107
+ })
108
+ .catch(() => {
109
+ /* onError (if provided) was already invoked inside mountTerminal */
110
+ });
111
+
112
+ return () => {
113
+ cancelled = true;
114
+ handle?.dispose();
115
+ };
116
+ });
117
+ </script>
118
+
119
+ <div class="ptykit-terminal {className}" data-status={status}>
120
+ {#if showStatus}
121
+ <div class="ptykit-terminal__status">{status}</div>
122
+ {/if}
123
+ <div class="ptykit-terminal__screen" bind:this={container}></div>
124
+ </div>
125
+
126
+ <style>
127
+ .ptykit-terminal {
128
+ position: relative;
129
+ width: 100%;
130
+ height: 100%;
131
+ }
132
+ .ptykit-terminal__screen {
133
+ width: 100%;
134
+ height: 100%;
135
+ }
136
+ .ptykit-terminal__status {
137
+ position: absolute;
138
+ top: 4px;
139
+ right: 8px;
140
+ z-index: 1;
141
+ font: 11px/1.4 ui-monospace, monospace;
142
+ opacity: 0.6;
143
+ pointer-events: none;
144
+ text-transform: uppercase;
145
+ }
146
+ </style>
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Type declarations for `ptykit/svelte`.
3
+ *
4
+ * The component ships as raw `.svelte` source (resolved via the `svelte` export
5
+ * condition by Svelte-aware bundlers). These hand-written types describe its
6
+ * public props.
7
+ */
8
+
9
+ import type { Component } from 'svelte';
10
+ import type {
11
+ ClientSession,
12
+ PtyKitClient,
13
+ ReconnectOptions,
14
+ SessionPersistence,
15
+ } from '../index.js';
16
+
17
+ export interface PtyTerminalReadyContext {
18
+ client: PtyKitClient;
19
+ session: ClientSession;
20
+ /** The xterm `Terminal` instance (typed loosely to avoid a hard xterm dep). */
21
+ terminal: unknown;
22
+ }
23
+
24
+ export interface PtyTerminalProps {
25
+ // connection
26
+ /** Session to attach to / create (created server-side if new). */
27
+ sessionId: string;
28
+ /** WebSocket endpoint, e.g. `/pty`. */
29
+ url: string;
30
+ /** Room/namespace. Required when `create` is true. */
31
+ namespace?: string;
32
+ /** Create instead of attach. Default `false`. */
33
+ create?: boolean;
34
+ /** Reuse an existing client instead of creating one. */
35
+ client?: PtyKitClient;
36
+ /** Reconnect tuning for the internally-created client. */
37
+ reconnect?: ReconnectOptions;
38
+ /** sessionId persistence override. */
39
+ persistence?: SessionPersistence;
40
+ /** RPC timeout (ms). */
41
+ requestTimeoutMs?: number;
42
+
43
+ // session (used when creating)
44
+ cols?: number;
45
+ rows?: number;
46
+ cwd?: string;
47
+ shell?: string;
48
+
49
+ // terminal appearance
50
+ scrollback?: number;
51
+ fontSize?: number;
52
+ fontFamily?: string;
53
+ lineHeight?: number;
54
+ cursorBlink?: boolean;
55
+ cursorStyle?: 'block' | 'underline' | 'bar';
56
+ /** An xterm `ITheme` object. */
57
+ theme?: Record<string, unknown>;
58
+ /** Extra/override xterm `Terminal` options. */
59
+ terminalOptions?: Record<string, unknown>;
60
+
61
+ // behavior
62
+ /** Attach a FitAddon + ResizeObserver. Default `true`. */
63
+ fit?: boolean;
64
+ fitDebounceMs?: number;
65
+ /** Show the built-in connection-status chip. Default `true`. */
66
+ showStatus?: boolean;
67
+
68
+ // styling
69
+ /** Extra class on the root element. */
70
+ class?: string;
71
+
72
+ // lifecycle callbacks
73
+ onready?: (ctx: PtyTerminalReadyContext) => void;
74
+ ondata?: (chunk: string) => void;
75
+ onexit?: (exitCode: number) => void;
76
+ onstatus?: (status: 'connected' | 'reconnecting' | 'disconnected') => void;
77
+ onerror?: (error: unknown) => void;
78
+ ondirectory?: (directory: string) => void;
79
+ }
80
+
81
+ /** `<PtyTerminal sessionId url … />` — the official Svelte terminal component. */
82
+ declare const PtyTerminal: Component<PtyTerminalProps>;
83
+ export { PtyTerminal };
84
+ export default PtyTerminal;