@moejay/wrightty 0.0.0 → 0.1.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.
Files changed (92) hide show
  1. package/dist/client.d.ts +14 -0
  2. package/dist/client.js +83 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +8 -0
  5. package/dist/terminal.d.ts +48 -0
  6. package/dist/terminal.js +210 -0
  7. package/dist/types.d.ts +90 -0
  8. package/dist/types.js +3 -0
  9. package/package.json +35 -15
  10. package/.github/workflows/ci.yml +0 -90
  11. package/.github/workflows/release.yml +0 -177
  12. package/Cargo.lock +0 -2662
  13. package/Cargo.toml +0 -38
  14. package/PROTOCOL.md +0 -1351
  15. package/README.md +0 -386
  16. package/agents/ceo/AGENTS.md +0 -24
  17. package/agents/ceo/HEARTBEAT.md +0 -72
  18. package/agents/ceo/SOUL.md +0 -33
  19. package/agents/ceo/TOOLS.md +0 -3
  20. package/agents/founding-engineer/AGENTS.md +0 -44
  21. package/crates/wrightty/Cargo.toml +0 -43
  22. package/crates/wrightty/src/client_cmds.rs +0 -366
  23. package/crates/wrightty/src/discover.rs +0 -78
  24. package/crates/wrightty/src/main.rs +0 -100
  25. package/crates/wrightty/src/server.rs +0 -100
  26. package/crates/wrightty/src/term.rs +0 -338
  27. package/crates/wrightty-bridge-ghostty/Cargo.toml +0 -27
  28. package/crates/wrightty-bridge-ghostty/src/ghostty.rs +0 -422
  29. package/crates/wrightty-bridge-ghostty/src/lib.rs +0 -2
  30. package/crates/wrightty-bridge-ghostty/src/main.rs +0 -146
  31. package/crates/wrightty-bridge-ghostty/src/rpc.rs +0 -307
  32. package/crates/wrightty-bridge-kitty/Cargo.toml +0 -26
  33. package/crates/wrightty-bridge-kitty/src/kitty.rs +0 -269
  34. package/crates/wrightty-bridge-kitty/src/lib.rs +0 -2
  35. package/crates/wrightty-bridge-kitty/src/main.rs +0 -124
  36. package/crates/wrightty-bridge-kitty/src/rpc.rs +0 -304
  37. package/crates/wrightty-bridge-tmux/Cargo.toml +0 -26
  38. package/crates/wrightty-bridge-tmux/src/lib.rs +0 -2
  39. package/crates/wrightty-bridge-tmux/src/main.rs +0 -119
  40. package/crates/wrightty-bridge-tmux/src/rpc.rs +0 -291
  41. package/crates/wrightty-bridge-tmux/src/tmux.rs +0 -215
  42. package/crates/wrightty-bridge-wezterm/Cargo.toml +0 -26
  43. package/crates/wrightty-bridge-wezterm/src/lib.rs +0 -2
  44. package/crates/wrightty-bridge-wezterm/src/main.rs +0 -119
  45. package/crates/wrightty-bridge-wezterm/src/rpc.rs +0 -339
  46. package/crates/wrightty-bridge-wezterm/src/wezterm.rs +0 -190
  47. package/crates/wrightty-bridge-zellij/Cargo.toml +0 -27
  48. package/crates/wrightty-bridge-zellij/src/lib.rs +0 -2
  49. package/crates/wrightty-bridge-zellij/src/main.rs +0 -125
  50. package/crates/wrightty-bridge-zellij/src/rpc.rs +0 -328
  51. package/crates/wrightty-bridge-zellij/src/zellij.rs +0 -199
  52. package/crates/wrightty-client/Cargo.toml +0 -16
  53. package/crates/wrightty-client/src/client.rs +0 -254
  54. package/crates/wrightty-client/src/lib.rs +0 -2
  55. package/crates/wrightty-core/Cargo.toml +0 -21
  56. package/crates/wrightty-core/src/input.rs +0 -212
  57. package/crates/wrightty-core/src/lib.rs +0 -4
  58. package/crates/wrightty-core/src/screen.rs +0 -325
  59. package/crates/wrightty-core/src/session.rs +0 -249
  60. package/crates/wrightty-core/src/session_manager.rs +0 -77
  61. package/crates/wrightty-protocol/Cargo.toml +0 -13
  62. package/crates/wrightty-protocol/src/error.rs +0 -8
  63. package/crates/wrightty-protocol/src/events.rs +0 -138
  64. package/crates/wrightty-protocol/src/lib.rs +0 -4
  65. package/crates/wrightty-protocol/src/methods.rs +0 -321
  66. package/crates/wrightty-protocol/src/types.rs +0 -201
  67. package/crates/wrightty-server/Cargo.toml +0 -23
  68. package/crates/wrightty-server/src/lib.rs +0 -2
  69. package/crates/wrightty-server/src/main.rs +0 -65
  70. package/crates/wrightty-server/src/rpc.rs +0 -455
  71. package/crates/wrightty-server/src/state.rs +0 -39
  72. package/examples/basic_command.py +0 -53
  73. package/examples/interactive_tui.py +0 -86
  74. package/examples/record_session.py +0 -96
  75. package/install.sh +0 -81
  76. package/sdks/node/package-lock.json +0 -85
  77. package/sdks/node/package.json +0 -44
  78. package/sdks/node/src/client.ts +0 -94
  79. package/sdks/node/src/index.ts +0 -19
  80. package/sdks/node/src/terminal.ts +0 -258
  81. package/sdks/node/src/types.ts +0 -105
  82. package/sdks/node/tsconfig.json +0 -17
  83. package/sdks/python/README.md +0 -96
  84. package/sdks/python/pyproject.toml +0 -42
  85. package/sdks/python/wrightty/__init__.py +0 -6
  86. package/sdks/python/wrightty/cli.py +0 -210
  87. package/sdks/python/wrightty/client.py +0 -136
  88. package/sdks/python/wrightty/mcp_server.py +0 -434
  89. package/sdks/python/wrightty/terminal.py +0 -333
  90. package/skills/wrightty/SKILL.md +0 -261
  91. package/src/lib.rs +0 -1
  92. package/tests/integration_test.rs +0 -618
package/PROTOCOL.md DELETED
@@ -1,1351 +0,0 @@
1
- # Wrightty Protocol Specification
2
-
3
- **Version:** 0.1.0-draft
4
- **Transport:** WebSocket + JSON-RPC 2.0
5
- **Default endpoint:** `ws://127.0.0.1:9420`
6
-
7
- ---
8
-
9
- ## 1. Transport
10
-
11
- All communication happens over a single WebSocket connection using [JSON-RPC 2.0](https://www.jsonrpc.org/specification).
12
-
13
- - **Requests** flow client → server
14
- - **Responses** flow server → client (matched by `id`)
15
- - **Notifications/Events** flow server → client (no `id`, triggered by subscriptions)
16
- - **Batching** is supported per JSON-RPC 2.0 spec
17
-
18
- ### 1.1 Connection Lifecycle
19
-
20
- ```
21
- Client Server
22
- │ │
23
- ├── WebSocket connect ─────────►│
24
- │ │
25
- ├── Wrightty.getInfo ──────────►│ (optional handshake)
26
- │◄── { version, capabilities } ─┤
27
- │ │
28
- ├── Session.create ────────────►│
29
- │◄── { sessionId } ─────────────┤
30
- │ │
31
- ├── Events.subscribe ──────────►│ (start receiving events)
32
- │◄── subscription confirmed ────┤
33
- │ │
34
- │ ... interact ... │
35
- │ │
36
- ├── Session.destroy ───────────►│
37
- │◄── ok ─────────────────────────┤
38
- │ │
39
- └── WebSocket close ───────────►│
40
- ```
41
-
42
- ### 1.2 Discovery
43
-
44
- When an emulator or daemon starts with wrightty support enabled, it sets:
45
-
46
- ```
47
- WRIGHTTY_SOCKET=ws://127.0.0.1:9420
48
- ```
49
-
50
- Clients check this env var to auto-connect. If multiple sessions exist (e.g., emulator with tabs), the client uses `Session.list` to enumerate them.
51
-
52
- ---
53
-
54
- ## 2. Domains
55
-
56
- Methods are namespaced as `Domain.methodName`.
57
-
58
- ### 2.1 Wrightty (meta)
59
-
60
- | Method | Description |
61
- |--------|-------------|
62
- | `Wrightty.getInfo` | Server metadata and capability negotiation |
63
-
64
- #### `Wrightty.getInfo`
65
-
66
- **Params:** none
67
-
68
- **Result:**
69
- ```json
70
- {
71
- "version": "0.1.0",
72
- "implementation": "wrightty-server",
73
- "capabilities": {
74
- "screenshot": ["text", "ansi", "json", "svg", "png"],
75
- "maxSessions": 64,
76
- "supportsResize": true,
77
- "supportsScrollback": true,
78
- "supportsMouse": false,
79
- "supportsSessionCreate": true,
80
- "supportsColorPalette": true,
81
- "supportsRawOutput": true,
82
- "supportsShellIntegration": true,
83
- "events": [
84
- "Screen.updated", "Session.output", "Session.exited",
85
- "Terminal.bell", "Terminal.titleChanged", "Terminal.cwdChanged",
86
- "Terminal.alternateScreen", "Terminal.cursorChanged",
87
- "Shell.promptStart", "Shell.commandStart", "Shell.outputStart",
88
- "Shell.commandFinished", "Terminal.notification",
89
- "Terminal.clipboardSet", "Terminal.modeChanged",
90
- "Terminal.progressChanged"
91
- ]
92
- }
93
- }
94
- ```
95
-
96
- The `capabilities.events` array advertises which event types this implementation can emit. Clients should check this before subscribing.
97
-
98
- ---
99
-
100
- ### 2.2 Session
101
-
102
- Manages terminal session lifecycle. In daemon mode, each session is a PTY + shell process. In native emulator mode, sessions map to tabs/panes.
103
-
104
- | Method | Description |
105
- |--------|-------------|
106
- | `Session.create` | Spawn a new terminal session |
107
- | `Session.destroy` | Kill a session |
108
- | `Session.list` | List active sessions |
109
- | `Session.getInfo` | Get info about a specific session |
110
-
111
- #### `Session.create`
112
-
113
- **Params:**
114
- ```json
115
- {
116
- "shell": "/bin/bash", // optional, default: user's $SHELL or /bin/sh
117
- "args": ["--norc"], // optional, shell arguments
118
- "cols": 80, // optional, default: 80
119
- "rows": 24, // optional, default: 24
120
- "env": { // optional, additional env vars (merged with inherited env)
121
- "TERM": "xterm-256color",
122
- "LANG": "en_US.UTF-8"
123
- },
124
- "cwd": "/home/user/project" // optional, working directory
125
- }
126
- ```
127
-
128
- **Result:**
129
- ```json
130
- {
131
- "sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
132
- }
133
- ```
134
-
135
- **Notes:**
136
- - `TERM` defaults to `xterm-256color` if not specified
137
- - In native emulator mode, `shell`/`args`/`env`/`cwd` may be ignored (session already exists)
138
- - The session is ready for input immediately after this returns
139
-
140
- #### `Session.destroy`
141
-
142
- **Params:**
143
- ```json
144
- {
145
- "sessionId": "a1b2c3d4...",
146
- "signal": "SIGTERM" // optional, default: SIGTERM then SIGKILL after 5s
147
- }
148
- ```
149
-
150
- **Result:**
151
- ```json
152
- {
153
- "exitCode": 0 // null if process was killed
154
- }
155
- ```
156
-
157
- #### `Session.list`
158
-
159
- **Params:** none
160
-
161
- **Result:**
162
- ```json
163
- {
164
- "sessions": [
165
- {
166
- "sessionId": "a1b2c3d4...",
167
- "title": "bash",
168
- "cwd": "/home/user/project",
169
- "cols": 80,
170
- "rows": 24,
171
- "pid": 12345,
172
- "running": true,
173
- "alternateScreen": false
174
- }
175
- ]
176
- }
177
- ```
178
-
179
- #### `Session.getInfo`
180
-
181
- **Params:**
182
- ```json
183
- {
184
- "sessionId": "a1b2c3d4..."
185
- }
186
- ```
187
-
188
- **Result:** Same shape as one entry in `Session.list.sessions`.
189
-
190
- ---
191
-
192
- ### 2.3 Input
193
-
194
- Send keystrokes and text to a session.
195
-
196
- | Method | Description |
197
- |--------|-------------|
198
- | `Input.sendKeys` | Send structured key events |
199
- | `Input.sendText` | Send raw text (no key interpretation) |
200
- | `Input.sendMouse` | Send mouse events (if supported) |
201
-
202
- #### `Input.sendKeys`
203
-
204
- **Params:**
205
- ```json
206
- {
207
- "sessionId": "a1b2c3d4...",
208
- "keys": [
209
- { "key": "Char", "char": "l", "modifiers": [] },
210
- { "key": "Char", "char": "s", "modifiers": [] },
211
- { "key": "Enter" }
212
- ]
213
- }
214
- ```
215
-
216
- **Result:** `{}`
217
-
218
- **Key types:**
219
-
220
- | key | Additional fields | Example |
221
- |-----|-------------------|---------|
222
- | `"Char"` | `char`: single character | `{ "key": "Char", "char": "a" }` |
223
- | `"Enter"` | — | `{ "key": "Enter" }` |
224
- | `"Tab"` | — | `{ "key": "Tab" }` |
225
- | `"Backspace"` | — | |
226
- | `"Delete"` | — | |
227
- | `"Escape"` | — | |
228
- | `"ArrowUp"` | — | |
229
- | `"ArrowDown"` | — | |
230
- | `"ArrowLeft"` | — | |
231
- | `"ArrowRight"` | — | |
232
- | `"Home"` | — | |
233
- | `"End"` | — | |
234
- | `"PageUp"` | — | |
235
- | `"PageDown"` | — | |
236
- | `"Insert"` | — | |
237
- | `"F"` | `n`: 1-24 | `{ "key": "F", "n": 5 }` |
238
-
239
- **Modifiers** (optional array on any key):
240
- ```json
241
- { "key": "Char", "char": "c", "modifiers": ["Ctrl"] }
242
- { "key": "ArrowUp", "modifiers": ["Shift", "Alt"] }
243
- ```
244
-
245
- Valid modifiers: `"Ctrl"`, `"Alt"`, `"Shift"`, `"Meta"`
246
-
247
- **Shorthand:** For simple cases, a string shorthand is accepted in the `keys` array:
248
-
249
- ```json
250
- {
251
- "keys": ["h", "e", "l", "l", "o", "Enter", "Ctrl+c"]
252
- }
253
- ```
254
-
255
- Where:
256
- - Single character → `Char` key
257
- - Named key → looked up from the key type table
258
- - `Mod+key` → modifier combination
259
-
260
- #### `Input.sendText`
261
-
262
- Sends raw text bytes to the PTY. No key interpretation — newlines are `\n`, not Enter key sequences. Useful for pasting.
263
-
264
- **Params:**
265
- ```json
266
- {
267
- "sessionId": "a1b2c3d4...",
268
- "text": "echo hello world\n"
269
- }
270
- ```
271
-
272
- **Result:** `{}`
273
-
274
- #### `Input.sendMouse`
275
-
276
- **Params:**
277
- ```json
278
- {
279
- "sessionId": "a1b2c3d4...",
280
- "event": "press", // "press", "release", "move", "scroll"
281
- "button": "left", // "left", "right", "middle", "none" (for move)
282
- "row": 5,
283
- "col": 12,
284
- "modifiers": [] // optional
285
- }
286
- ```
287
-
288
- For scroll: `"button"` is `"scrollUp"` or `"scrollDown"`.
289
-
290
- **Result:** `{}`
291
-
292
- ---
293
-
294
- ### 2.4 Screen
295
-
296
- Read terminal screen state.
297
-
298
- | Method | Description |
299
- |--------|-------------|
300
- | `Screen.getContents` | Full cell grid with attributes |
301
- | `Screen.getText` | Plain text extraction |
302
- | `Screen.getScrollback` | Read scrollback buffer |
303
- | `Screen.screenshot` | Render to various formats |
304
- | `Screen.waitForText` | Block until text appears |
305
- | `Screen.waitForCursor` | Block until cursor at position |
306
-
307
- #### `Screen.getContents`
308
-
309
- Returns the full cell grid with styling attributes.
310
-
311
- **Params:**
312
- ```json
313
- {
314
- "sessionId": "a1b2c3d4...",
315
- "region": { // optional, default: entire visible screen
316
- "top": 0,
317
- "left": 0,
318
- "bottom": 23, // inclusive
319
- "right": 79 // inclusive
320
- }
321
- }
322
- ```
323
-
324
- **Result:**
325
- ```json
326
- {
327
- "rows": 24,
328
- "cols": 80,
329
- "cursor": {
330
- "row": 5,
331
- "col": 12,
332
- "visible": true,
333
- "shape": "block" // "block", "underline", "bar"
334
- },
335
- "cells": [
336
- [
337
- {
338
- "char": "$",
339
- "width": 1, // 1 for normal, 2 for wide (CJK), 0 for continuation
340
- "fg": { "r": 255, "g": 255, "b": 255 },
341
- "bg": { "r": 0, "g": 0, "b": 0 },
342
- "attrs": {
343
- "bold": false,
344
- "italic": false,
345
- "underline": "none", // "none", "single", "double", "curly", "dotted", "dashed"
346
- "underlineColor": null, // optional RGB, null = use fg
347
- "strikethrough": false,
348
- "dim": false,
349
- "blink": false,
350
- "reverse": false,
351
- "hidden": false
352
- },
353
- "hyperlink": null // URL string if OSC 8 hyperlink
354
- }
355
- ]
356
- ],
357
- "alternateScreen": false
358
- }
359
- ```
360
-
361
- **Notes:**
362
- - `cells` is a 2D array: `cells[row][col]`
363
- - Wide characters: the first cell has `width: 2`, the next cell has `width: 0` (continuation/spacer)
364
- - Colors are always resolved to RGB (indexed/named colors resolved against the active palette)
365
-
366
- #### `Screen.getText`
367
-
368
- **Params:**
369
- ```json
370
- {
371
- "sessionId": "a1b2c3d4...",
372
- "region": null, // optional, same as getContents
373
- "trimTrailingWhitespace": true // optional, default: true
374
- }
375
- ```
376
-
377
- **Result:**
378
- ```json
379
- {
380
- "text": "$ echo hello\nhello\n$ _"
381
- }
382
- ```
383
-
384
- Rows separated by `\n`. Trailing whitespace on each row is trimmed by default.
385
-
386
- #### `Screen.getScrollback`
387
-
388
- **Params:**
389
- ```json
390
- {
391
- "sessionId": "a1b2c3d4...",
392
- "lines": 100, // number of scrollback lines to retrieve
393
- "offset": 0 // optional, 0 = most recent scrollback line
394
- }
395
- ```
396
-
397
- **Result:**
398
- ```json
399
- {
400
- "lines": [
401
- { "text": "previous output line 1", "lineNumber": -100 },
402
- { "text": "previous output line 2", "lineNumber": -99 }
403
- ],
404
- "totalScrollback": 5000
405
- }
406
- ```
407
-
408
- `lineNumber` is negative, counting up toward 0 (the first visible row).
409
-
410
- #### `Screen.screenshot`
411
-
412
- **Params:**
413
- ```json
414
- {
415
- "sessionId": "a1b2c3d4...",
416
- "format": "png", // "text", "ansi", "json", "svg", "png"
417
- "theme": null, // optional, color theme override
418
- "font": { // optional, for svg/png
419
- "family": "JetBrains Mono",
420
- "size": 14
421
- }
422
- }
423
- ```
424
-
425
- **Result:**
426
- ```json
427
- {
428
- "format": "png",
429
- "data": "iVBORw0KGgo...", // base64 for png, raw string for text/ansi/svg/json
430
- "width": 960, // pixels, only for png/svg
431
- "height": 480
432
- }
433
- ```
434
-
435
- **Format details:**
436
- - `text` — plain text, same as `Screen.getText`
437
- - `ansi` — text with ANSI escape codes preserved (can be printed to another terminal)
438
- - `json` — same as `Screen.getContents` response
439
- - `svg` — terminal rendered as SVG with colors, font, background
440
- - `png` — rasterized SVG
441
-
442
- #### `Screen.waitForText`
443
-
444
- Blocks until the specified text/pattern appears on screen, or timeout.
445
-
446
- **Params:**
447
- ```json
448
- {
449
- "sessionId": "a1b2c3d4...",
450
- "pattern": "\\$\\s*$", // text or regex
451
- "isRegex": true, // default: false (plain text match)
452
- "region": null, // optional, limit search to region
453
- "timeout": 5000, // milliseconds, default: 30000
454
- "interval": 100 // optional, polling interval in ms, default: 100
455
- }
456
- ```
457
-
458
- **Result:**
459
- ```json
460
- {
461
- "found": true,
462
- "matches": [
463
- {
464
- "text": "$ ",
465
- "row": 5,
466
- "col": 0,
467
- "length": 2
468
- }
469
- ],
470
- "elapsed": 1234 // ms waited
471
- }
472
- ```
473
-
474
- If `found` is `false`, the method returns (not an error) after timeout with an empty `matches` array.
475
-
476
- #### `Screen.waitForCursor`
477
-
478
- **Params:**
479
- ```json
480
- {
481
- "sessionId": "a1b2c3d4...",
482
- "row": 5, // optional, null = any row
483
- "col": 12, // optional, null = any col
484
- "timeout": 5000
485
- }
486
- ```
487
-
488
- **Result:**
489
- ```json
490
- {
491
- "cursor": { "row": 5, "col": 12, "visible": true, "shape": "block" },
492
- "elapsed": 500
493
- }
494
- ```
495
-
496
- ---
497
-
498
- ### 2.5 Terminal
499
-
500
- Control terminal properties.
501
-
502
- | Method | Description |
503
- |--------|-------------|
504
- | `Terminal.resize` | Change dimensions |
505
- | `Terminal.getSize` | Query dimensions |
506
- | `Terminal.setColorPalette` | Override color palette |
507
- | `Terminal.getColorPalette` | Read current palette |
508
- | `Terminal.getModes` | Query active terminal modes |
509
-
510
- #### `Terminal.resize`
511
-
512
- **Params:**
513
- ```json
514
- {
515
- "sessionId": "a1b2c3d4...",
516
- "cols": 120,
517
- "rows": 40
518
- }
519
- ```
520
-
521
- **Result:** `{}`
522
-
523
- The underlying PTY and process receive `SIGWINCH`.
524
-
525
- #### `Terminal.getSize`
526
-
527
- **Params:**
528
- ```json
529
- {
530
- "sessionId": "a1b2c3d4..."
531
- }
532
- ```
533
-
534
- **Result:**
535
- ```json
536
- {
537
- "cols": 120,
538
- "rows": 40
539
- }
540
- ```
541
-
542
- #### `Terminal.setColorPalette`
543
-
544
- Override the 256-color palette used for color resolution.
545
-
546
- **Params:**
547
- ```json
548
- {
549
- "sessionId": "a1b2c3d4...",
550
- "palette": {
551
- "0": { "r": 0, "g": 0, "b": 0 },
552
- "1": { "r": 204, "g": 0, "b": 0 },
553
- "15": { "r": 255, "g": 255, "b": 255 },
554
- "foreground": { "r": 200, "g": 200, "b": 200 },
555
- "background": { "r": 30, "g": 30, "b": 30 },
556
- "cursor": { "r": 255, "g": 255, "b": 0 }
557
- }
558
- }
559
- ```
560
-
561
- Only specified entries are overridden; unspecified entries keep their defaults. Affects `Screen.getContents` color resolution and screenshots.
562
-
563
- **Result:** `{}`
564
-
565
- #### `Terminal.getModes`
566
-
567
- Query the active terminal modes. Useful for understanding what the running application has configured.
568
-
569
- **Params:**
570
- ```json
571
- {
572
- "sessionId": "a1b2c3d4..."
573
- }
574
- ```
575
-
576
- **Result:**
577
- ```json
578
- {
579
- "cursorKeyMode": "normal", // "normal" or "application" (DECCKM)
580
- "keypadMode": "numeric", // "numeric" or "application" (DECKPAM/DECKPNM)
581
- "alternateScreen": false, // modes 47/1047/1049
582
- "bracketedPaste": true, // mode 2004
583
- "mouseTracking": "none", // "none", "x10", "normal", "cellMotion", "allMotion"
584
- "mouseEncoding": "sgr", // "default", "utf8", "sgr", "urxvt", "sgrPixel"
585
- "focusReporting": false, // mode 1004
586
- "cursorVisible": true, // DECTCEM, mode 25
587
- "cursorStyle": "block", // "block", "underline", "bar" (and blinking variants)
588
- "autoWrap": true, // DECAWM, mode 7
589
- "reverseVideo": false, // DECSCNM, mode 5
590
- "originMode": false, // DECOM, mode 6
591
- "synchronizedOutput": false // mode 2026
592
- }
593
- ```
594
-
595
- ---
596
-
597
- ### 2.6 Recording (experimental)
598
-
599
- > **Status:** Experimental. Recording methods may change between versions. Implementations advertise recording support via `capabilities.recording` in `Wrightty.getInfo`.
600
-
601
- Record terminal sessions, actions, and video.
602
-
603
- | Method | Description |
604
- |--------|-------------|
605
- | `Recording.startSession` | Start recording raw PTY I/O (asciicast format) |
606
- | `Recording.stopSession` | Stop session recording and return the data |
607
- | `Recording.startActions` | Start recording wrightty API calls as a replayable script |
608
- | `Recording.stopActions` | Stop action recording and return the script |
609
- | `Recording.captureScreen` | Capture a single screen frame |
610
- | `Recording.startVideo` | Start framebuffer video recording (native emulators only) |
611
- | `Recording.stopVideo` | Stop video recording and return the file |
612
-
613
- Recording tiers (implementations advertise which they support):
614
-
615
- | Tier | What | How | Overhead |
616
- |------|------|-----|----------|
617
- | **1 — Session** | PTY byte stream + timestamps | Tap into PTY event loop | Near zero |
618
- | **2 — Video** | Pixel-perfect framebuffer capture | `glReadPixels` after render, pipe to ffmpeg | Low-medium |
619
- | **3 — Actions** | API call log → replayable script | Intercept JSON-RPC methods | Near zero |
620
-
621
- #### `Recording.startSession`
622
-
623
- Begin recording all PTY output bytes with timestamps. Compatible with [asciicast v2](https://docs.asciinema.org/manual/asciicast/v2/) format — can be played back with `asciinema play`.
624
-
625
- **Params:**
626
- ```json
627
- {
628
- "sessionId": "a1b2c3d4...",
629
- "includeInput": true // optional, also record input events (default: false)
630
- }
631
- ```
632
-
633
- **Result:**
634
- ```json
635
- {
636
- "recordingId": "rec_001"
637
- }
638
- ```
639
-
640
- #### `Recording.stopSession`
641
-
642
- Stop a session recording and return the asciicast data.
643
-
644
- **Params:**
645
- ```json
646
- {
647
- "recordingId": "rec_001"
648
- }
649
- ```
650
-
651
- **Result:**
652
- ```json
653
- {
654
- "format": "asciicast-v2",
655
- "data": "{\"version\":2,\"width\":80,\"height\":24,...}\n[0.5,\"o\",\"$ \"]\n[1.2,\"o\",\"hello\\r\\n\"]\n",
656
- "duration": 12.5,
657
- "events": 42
658
- }
659
- ```
660
-
661
- The `data` field contains the full asciicast v2 file as a string. Each line after the header is `[timestamp, type, data]`:
662
- - `"o"` = output (PTY → screen)
663
- - `"i"` = input (user → PTY, only if `includeInput` was true)
664
-
665
- #### `Recording.startActions`
666
-
667
- Begin recording all wrightty API calls (sendKeys, sendText, etc.) as a replayable script. Like Playwright's codegen.
668
-
669
- **Params:**
670
- ```json
671
- {
672
- "sessionId": "a1b2c3d4...",
673
- "format": "python" // "python", "json", or "cli"
674
- }
675
- ```
676
-
677
- **Result:**
678
- ```json
679
- {
680
- "recordingId": "rec_002"
681
- }
682
- ```
683
-
684
- #### `Recording.stopActions`
685
-
686
- Stop action recording and return the generated script.
687
-
688
- **Params:**
689
- ```json
690
- {
691
- "recordingId": "rec_002"
692
- }
693
- ```
694
-
695
- **Result (format=python):**
696
- ```json
697
- {
698
- "format": "python",
699
- "data": "from wrightty import Terminal\n\nterm = Terminal.connect()\nterm.send_text('ls -la\\n')\nterm.wait_for('$')\nterm.send_keys('Ctrl+c')\nterm.close()\n",
700
- "actions": 3,
701
- "duration": 8.2
702
- }
703
- ```
704
-
705
- **Result (format=json):**
706
- ```json
707
- {
708
- "format": "json",
709
- "data": [
710
- { "time": 0.0, "method": "Input.sendText", "params": { "text": "ls -la\n" } },
711
- { "time": 2.1, "method": "Screen.waitForText", "params": { "pattern": "$" } },
712
- { "time": 5.5, "method": "Input.sendKeys", "params": { "keys": ["Ctrl+c"] } }
713
- ],
714
- "actions": 3,
715
- "duration": 8.2
716
- }
717
- ```
718
-
719
- **Result (format=cli):**
720
- ```json
721
- {
722
- "format": "cli",
723
- "data": "wrightty send-text 'ls -la\\n'\nwrightty wait-for '$'\nwrightty send-keys Ctrl+c\n",
724
- "actions": 3,
725
- "duration": 8.2
726
- }
727
- ```
728
-
729
- #### `Recording.captureScreen`
730
-
731
- Capture a single screen frame. Can be called at any time. Frames can be collected into a GIF/video later.
732
-
733
- **Params:**
734
- ```json
735
- {
736
- "sessionId": "a1b2c3d4...",
737
- "format": "svg" // "svg", "text", or "png"
738
- }
739
- ```
740
-
741
- **Result:**
742
- ```json
743
- {
744
- "frameId": 0,
745
- "timestamp": 1679000000000,
746
- "format": "svg",
747
- "data": "<svg ...>"
748
- }
749
- ```
750
-
751
- #### `Recording.startVideo`
752
-
753
- Start recording the terminal as a video. Captures the actual rendered framebuffer at the specified FPS. Only available on native emulators with GPU rendering (Tier 2). Requires `ffmpeg` on the system.
754
-
755
- **Params:**
756
- ```json
757
- {
758
- "sessionId": "a1b2c3d4...",
759
- "fps": 30, // frames per second (default: 30)
760
- "format": "mp4" // "mp4", "webm", or "gif"
761
- }
762
- ```
763
-
764
- **Result:**
765
- ```json
766
- {
767
- "recordingId": "rec_003"
768
- }
769
- ```
770
-
771
- #### `Recording.stopVideo`
772
-
773
- Stop video recording. The server finishes encoding and returns the video file.
774
-
775
- **Params:**
776
- ```json
777
- {
778
- "recordingId": "rec_003"
779
- }
780
- ```
781
-
782
- **Result:**
783
- ```json
784
- {
785
- "format": "mp4",
786
- "path": "/tmp/wrightty-rec_003.mp4",
787
- "duration": 12.5,
788
- "frames": 375,
789
- "width": 1920,
790
- "height": 1080,
791
- "size": 2458624
792
- }
793
- ```
794
-
795
- The video is saved to a temp file. The `path` field contains the absolute path. For large videos, the file is not base64-encoded in the response — the client reads it from disk.
796
-
797
- ---
798
-
799
- ### 2.7 Events
800
-
801
- Events use a unified subscription model. Instead of per-event subscribe/unsubscribe methods, clients use a single `Events.subscribe` method and specify which event types they want.
802
-
803
- #### `Events.subscribe`
804
-
805
- **Params:**
806
- ```json
807
- {
808
- "sessionId": "a1b2c3d4...",
809
- "events": ["Screen.updated", "Session.exited", "Shell.commandFinished"],
810
- "options": {
811
- "screenDebounceMs": 16 // optional, debounce for Screen.updated, default: 16
812
- }
813
- }
814
- ```
815
-
816
- `events` accepts `"*"` as a wildcard to subscribe to all available events:
817
- ```json
818
- { "sessionId": "abc123", "events": ["*"] }
819
- ```
820
-
821
- **Result:**
822
- ```json
823
- {
824
- "subscriptionId": "sub_001",
825
- "subscribedEvents": ["Screen.updated", "Session.exited", "Shell.commandFinished"]
826
- }
827
- ```
828
-
829
- `subscribedEvents` confirms which events were actually subscribed (may be a subset if some are not supported).
830
-
831
- #### `Events.unsubscribe`
832
-
833
- **Params:**
834
- ```json
835
- {
836
- "subscriptionId": "sub_001"
837
- }
838
- ```
839
-
840
- **Result:** `{}`
841
-
842
- ---
843
-
844
- ## 3. Event Catalog
845
-
846
- All events share a common envelope:
847
-
848
- ```json
849
- {
850
- "jsonrpc": "2.0",
851
- "method": "Events.event",
852
- "params": {
853
- "subscriptionId": "sub_001",
854
- "event": "<EventType>",
855
- "sessionId": "a1b2c3d4...",
856
- "timestamp": 1679000000000,
857
- "data": { ... }
858
- }
859
- }
860
- ```
861
-
862
- Events are organized into tiers. Tier 1 events MUST be supported by all implementations. Tier 2 and 3 are optional and advertised via `capabilities.events`.
863
-
864
- ---
865
-
866
- ### Tier 1 — Core Events (required)
867
-
868
- #### `Screen.updated`
869
-
870
- Screen content changed. Debounced to avoid flooding (default 16ms / 60fps).
871
-
872
- ```json
873
- {
874
- "dirtyRegion": { // bounding box of changed area, null if unknown
875
- "top": 0, "left": 0, "bottom": 5, "right": 79
876
- }
877
- }
878
- ```
879
-
880
- The event does NOT include screen contents. Clients call `Screen.getText` or `Screen.getContents` if they need the data.
881
-
882
- #### `Session.exited`
883
-
884
- The shell/process in this session has exited.
885
-
886
- ```json
887
- {
888
- "exitCode": 0, // null if killed by signal
889
- "signal": null // e.g., "SIGTERM", "SIGKILL"
890
- }
891
- ```
892
-
893
- #### `Session.output`
894
-
895
- Raw PTY output bytes, base64-encoded. Useful for session recording/replay (asciicast format, etc.).
896
-
897
- ```json
898
- {
899
- "data": "G1szMW1oZWxsbw==" // base64-encoded bytes
900
- }
901
- ```
902
-
903
- #### `Terminal.bell`
904
-
905
- BEL character (0x07) received.
906
-
907
- ```json
908
- {}
909
- ```
910
-
911
- #### `Terminal.titleChanged`
912
-
913
- Window title changed via OSC 0 or OSC 2.
914
-
915
- ```json
916
- {
917
- "title": "vim README.md",
918
- "iconName": null // OSC 1 icon name, if set separately
919
- }
920
- ```
921
-
922
- #### `Terminal.cwdChanged`
923
-
924
- Working directory changed. Detected via OSC 7 (`file://host/path`), OSC 9;9, or OSC 1337;CurrentDir.
925
-
926
- ```json
927
- {
928
- "cwd": "/home/user/project",
929
- "uri": "file://hostname/home/user/project" // original OSC 7 URI if available
930
- }
931
- ```
932
-
933
- #### `Terminal.alternateScreen`
934
-
935
- Application entered or exited the alternate screen buffer (modes 47/1047/1049). Critical for detecting TUI app launch/exit.
936
-
937
- ```json
938
- {
939
- "active": true // true = entered, false = exited
940
- }
941
- ```
942
-
943
- #### `Terminal.cursorChanged`
944
-
945
- Cursor visibility or style changed (DECTCEM mode 25, CSI N SP q).
946
-
947
- ```json
948
- {
949
- "visible": true,
950
- "shape": "bar", // "block", "underline", "bar"
951
- "blinking": true
952
- }
953
- ```
954
-
955
- ---
956
-
957
- ### Tier 2 — Shell Integration Events (optional, requires OSC 133)
958
-
959
- These events require the shell to emit OSC 133 sequences (bash, zsh, fish with shell integration enabled). They provide semantic understanding of what's happening in the terminal.
960
-
961
- #### `Shell.promptStart`
962
-
963
- Shell has begun rendering its prompt (OSC 133;A).
964
-
965
- ```json
966
- {}
967
- ```
968
-
969
- #### `Shell.commandStart`
970
-
971
- User has finished the prompt; command input area begins (OSC 133;B).
972
-
973
- ```json
974
- {}
975
- ```
976
-
977
- #### `Shell.outputStart`
978
-
979
- Shell is executing the command; output begins (OSC 133;C).
980
-
981
- ```json
982
- {
983
- "command": null // the command text, if extractable from the screen between promptStart and outputStart
984
- }
985
- ```
986
-
987
- #### `Shell.commandFinished`
988
-
989
- Command has completed (OSC 133;D).
990
-
991
- ```json
992
- {
993
- "exitCode": 0
994
- }
995
- ```
996
-
997
- **Why these matter:** An AI agent can use `Shell.commandFinished` to know when a command is done instead of fragile heuristics like "wait for the prompt pattern." A test framework can assert on exit codes without parsing output.
998
-
999
- ---
1000
-
1001
- ### Tier 2 — Terminal Notifications
1002
-
1003
- #### `Terminal.notification`
1004
-
1005
- A desktop notification was requested by the application. Covers:
1006
- - OSC 9 (iTerm2-style simple notification)
1007
- - OSC 99 (kitty rich notifications with buttons, icons, urgency)
1008
- - OSC 777 (rxvt-unicode notifications)
1009
-
1010
- ```json
1011
- {
1012
- "title": "Build complete",
1013
- "body": "Project compiled successfully",
1014
- "urgency": "normal", // "low", "normal", "critical"
1015
- "source": "osc9" // "osc9", "osc99", "osc777"
1016
- }
1017
- ```
1018
-
1019
- #### `Terminal.clipboardSet`
1020
-
1021
- Application set clipboard content via OSC 52.
1022
-
1023
- ```json
1024
- {
1025
- "selection": "clipboard", // "clipboard", "primary", "secondary", "select"
1026
- "text": "copied text", // decoded content (NOT base64)
1027
- "base64": "Y29waWVkIHRleHQ=" // raw base64 as sent by app
1028
- }
1029
- ```
1030
-
1031
- **Security note:** In daemon mode, wrightty intercepts OSC 52 and emits this event instead of modifying the system clipboard. The client decides whether to honor it.
1032
-
1033
- #### `Terminal.progressChanged`
1034
-
1035
- Taskbar/tab progress indicator changed (OSC 9;4 — ConEmu/iTerm2/Windows Terminal).
1036
-
1037
- ```json
1038
- {
1039
- "state": "value", // "none", "value", "error", "indeterminate", "warning"
1040
- "percent": 75 // 0-100, present when state is "value"
1041
- }
1042
- ```
1043
-
1044
- ---
1045
-
1046
- ### Tier 2 — Mode Changes
1047
-
1048
- #### `Terminal.modeChanged`
1049
-
1050
- A terminal mode was set or reset. Rather than individual events per mode, this provides a unified notification with the mode name.
1051
-
1052
- ```json
1053
- {
1054
- "mode": "bracketedPaste", // see mode names below
1055
- "enabled": true
1056
- }
1057
- ```
1058
-
1059
- **Mode names:**
1060
- | Mode name | DEC mode | Description |
1061
- |-----------|----------|-------------|
1062
- | `cursorKeyMode` | 1 (DECCKM) | Application vs normal cursor keys |
1063
- | `alternateScreen` | 1049 | Alternate screen buffer (also fires `Terminal.alternateScreen`) |
1064
- | `bracketedPaste` | 2004 | Wrap pastes in escape sequences |
1065
- | `mouseTracking` | 1000-1003 | Mouse event reporting enabled |
1066
- | `focusReporting` | 1004 | Focus in/out reporting |
1067
- | `cursorVisible` | 25 (DECTCEM) | Cursor show/hide |
1068
- | `autoWrap` | 7 (DECAWM) | Auto-wrap at margin |
1069
- | `reverseVideo` | 5 (DECSCNM) | Reverse video mode |
1070
- | `synchronizedOutput` | 2026 | Buffered rendering |
1071
-
1072
- ---
1073
-
1074
- ### Tier 3 — Extended Events (optional, emulator-specific)
1075
-
1076
- #### `Terminal.focusChanged`
1077
-
1078
- Terminal window/pane gained or lost focus (requires mode 1004 to be enabled by the app).
1079
-
1080
- ```json
1081
- {
1082
- "focused": true
1083
- }
1084
- ```
1085
-
1086
- #### `Terminal.hyperlinkHovered`
1087
-
1088
- An OSC 8 hyperlink region is under the cursor (native emulator mode only).
1089
-
1090
- ```json
1091
- {
1092
- "url": "https://example.com",
1093
- "id": "link-1", // hyperlink ID if specified
1094
- "row": 5,
1095
- "colStart": 10,
1096
- "colEnd": 35
1097
- }
1098
- ```
1099
-
1100
- #### `Terminal.imageDisplayed`
1101
-
1102
- An inline image was displayed via Sixel, kitty graphics protocol, or iTerm2 inline image.
1103
-
1104
- ```json
1105
- {
1106
- "protocol": "kitty", // "sixel", "kitty", "iterm2"
1107
- "row": 5,
1108
- "col": 0,
1109
- "widthCells": 40,
1110
- "heightCells": 20,
1111
- "widthPixels": 640,
1112
- "heightPixels": 480,
1113
- "imageId": null // kitty image ID if applicable
1114
- }
1115
- ```
1116
-
1117
- #### `Terminal.colorPaletteChanged`
1118
-
1119
- Application changed terminal colors via OSC 4, OSC 10-19, or pushed/popped the color stack.
1120
-
1121
- ```json
1122
- {
1123
- "changes": {
1124
- "foreground": { "r": 200, "g": 200, "b": 200 },
1125
- "4": { "r": 0, "g": 0, "b": 255 }
1126
- },
1127
- "source": "osc4" // "osc4", "osc10", "push", "pop"
1128
- }
1129
- ```
1130
-
1131
- #### `Terminal.remoteHostChanged`
1132
-
1133
- Remote host info changed (OSC 1337;RemoteHost). Useful for detecting SSH sessions.
1134
-
1135
- ```json
1136
- {
1137
- "user": "deploy",
1138
- "host": "prod-server-01"
1139
- }
1140
- ```
1141
-
1142
- #### `Terminal.userVariableSet`
1143
-
1144
- iTerm2 user variable set (OSC 1337;SetUserVar).
1145
-
1146
- ```json
1147
- {
1148
- "key": "gitBranch",
1149
- "value": "main"
1150
- }
1151
- ```
1152
-
1153
- #### `Terminal.fileTransfer`
1154
-
1155
- Kitty file transfer event (OSC 5113).
1156
-
1157
- ```json
1158
- {
1159
- "action": "receive", // "send", "receive", "progress", "complete", "error"
1160
- "filename": "data.csv",
1161
- "progress": 0.75, // 0.0-1.0 for progress events
1162
- "error": null
1163
- }
1164
- ```
1165
-
1166
- ---
1167
-
1168
- ## 4. Error Codes
1169
-
1170
- Standard JSON-RPC 2.0 errors plus protocol-specific codes.
1171
-
1172
- | Code | Name | Description |
1173
- |------|------|-------------|
1174
- | -32700 | Parse error | Invalid JSON |
1175
- | -32600 | Invalid request | Not a valid JSON-RPC request |
1176
- | -32601 | Method not found | Unknown method |
1177
- | -32602 | Invalid params | Missing or invalid parameters |
1178
- | -32603 | Internal error | Server error |
1179
- | 1001 | SessionNotFound | No session with the given ID |
1180
- | 1002 | SessionDestroyed | Session was already destroyed |
1181
- | 1003 | WaitTimeout | `waitForText`/`waitForCursor` timed out (also returns normally with `found: false`) |
1182
- | 1004 | InvalidPattern | Regex pattern failed to compile |
1183
- | 1005 | SpawnFailed | Failed to spawn PTY/shell process |
1184
- | 1006 | NotSupported | Method or event not supported by this implementation |
1185
- | 1007 | MaxSessionsReached | Cannot create more sessions |
1186
- | 1008 | SubscriptionNotFound | Invalid subscription ID |
1187
-
1188
- **Error response example:**
1189
- ```json
1190
- {
1191
- "jsonrpc": "2.0",
1192
- "id": 5,
1193
- "error": {
1194
- "code": 1001,
1195
- "message": "Session not found",
1196
- "data": { "sessionId": "nonexistent-id" }
1197
- }
1198
- }
1199
- ```
1200
-
1201
- ---
1202
-
1203
- ## 5. Capability Negotiation
1204
-
1205
- Not all implementations support every method or event. Native emulator integrations may only support a subset.
1206
-
1207
- ### 5.1 Capability Flags
1208
-
1209
- Returned in `Wrightty.getInfo`:
1210
-
1211
- ```json
1212
- {
1213
- "capabilities": {
1214
- "screenshot": ["text", "ansi", "json"],
1215
- "maxSessions": 1,
1216
- "supportsResize": true,
1217
- "supportsScrollback": true,
1218
- "supportsMouse": false,
1219
- "supportsColorPalette": false,
1220
- "supportsSessionCreate": true,
1221
- "supportsRawOutput": true,
1222
- "supportsShellIntegration": true,
1223
- "events": [
1224
- "Screen.updated", "Session.exited", "Terminal.bell",
1225
- "Terminal.titleChanged", "Terminal.cwdChanged"
1226
- ]
1227
- }
1228
- }
1229
- ```
1230
-
1231
- The `events` array is the authoritative list of subscribable event types. If an event type is not listed, subscribing to it will silently exclude it from the subscription (reflected in the `subscribedEvents` response).
1232
-
1233
- ### 5.2 Graceful Degradation
1234
-
1235
- If a client calls an unsupported method, the server returns error code `1006 NotSupported`. Clients should check capabilities first and fall back accordingly.
1236
-
1237
- ---
1238
-
1239
- ## 6. Examples
1240
-
1241
- ### 6.1 Run a command and read output
1242
-
1243
- ```json
1244
- // 1. Create session
1245
- → {"jsonrpc":"2.0","id":1,"method":"Session.create","params":{"cols":80,"rows":24}}
1246
- ← {"jsonrpc":"2.0","id":1,"result":{"sessionId":"abc123"}}
1247
-
1248
- // 2. Wait for shell prompt
1249
- → {"jsonrpc":"2.0","id":2,"method":"Screen.waitForText","params":{"sessionId":"abc123","pattern":"\\$","isRegex":true,"timeout":5000}}
1250
- ← {"jsonrpc":"2.0","id":2,"result":{"found":true,"matches":[{"text":"$","row":0,"col":14,"length":1}],"elapsed":120}}
1251
-
1252
- // 3. Type a command
1253
- → {"jsonrpc":"2.0","id":3,"method":"Input.sendKeys","params":{"sessionId":"abc123","keys":["e","c","h","o"," ","h","e","l","l","o","Enter"]}}
1254
- ← {"jsonrpc":"2.0","id":3,"result":{}}
1255
-
1256
- // 4. Wait for output
1257
- → {"jsonrpc":"2.0","id":4,"method":"Screen.waitForText","params":{"sessionId":"abc123","pattern":"hello","timeout":5000}}
1258
- ← {"jsonrpc":"2.0","id":4,"result":{"found":true,"matches":[{"text":"hello","row":1,"col":0,"length":5}],"elapsed":50}}
1259
-
1260
- // 5. Read the screen
1261
- → {"jsonrpc":"2.0","id":5,"method":"Screen.getText","params":{"sessionId":"abc123"}}
1262
- ← {"jsonrpc":"2.0","id":5,"result":{"text":"user@host:~$ echo hello\nhello\nuser@host:~$"}}
1263
-
1264
- // 6. Take a screenshot
1265
- → {"jsonrpc":"2.0","id":6,"method":"Screen.screenshot","params":{"sessionId":"abc123","format":"png"}}
1266
- ← {"jsonrpc":"2.0","id":6,"result":{"format":"png","data":"iVBORw0KGgo...","width":960,"height":480}}
1267
- ```
1268
-
1269
- ### 6.2 Subscribe to events
1270
-
1271
- ```json
1272
- // Subscribe to multiple event types at once
1273
- → {"jsonrpc":"2.0","id":10,"method":"Events.subscribe","params":{"sessionId":"abc123","events":["Screen.updated","Shell.commandFinished","Terminal.bell"]}}
1274
- ← {"jsonrpc":"2.0","id":10,"result":{"subscriptionId":"sub_001","subscribedEvents":["Screen.updated","Shell.commandFinished","Terminal.bell"]}}
1275
-
1276
- // Screen update event arrives
1277
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_001","event":"Screen.updated","sessionId":"abc123","timestamp":1679000000000,"data":{"dirtyRegion":{"top":0,"left":0,"bottom":2,"right":79}}}}
1278
-
1279
- // Command finished event (from OSC 133;D)
1280
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_001","event":"Shell.commandFinished","sessionId":"abc123","timestamp":1679000001000,"data":{"exitCode":0}}}
1281
-
1282
- // Unsubscribe
1283
- → {"jsonrpc":"2.0","id":11,"method":"Events.unsubscribe","params":{"subscriptionId":"sub_001"}}
1284
- ← {"jsonrpc":"2.0","id":11,"result":{}}
1285
- ```
1286
-
1287
- ### 6.3 Interact with a TUI app (vim)
1288
-
1289
- ```json
1290
- // Launch vim
1291
- → {"jsonrpc":"2.0","id":1,"method":"Session.create","params":{"shell":"/usr/bin/vim","args":["test.txt"],"cols":120,"rows":40}}
1292
- ← {"jsonrpc":"2.0","id":1,"result":{"sessionId":"vim123"}}
1293
-
1294
- // Subscribe to know when alternate screen is entered
1295
- → {"jsonrpc":"2.0","id":2,"method":"Events.subscribe","params":{"sessionId":"vim123","events":["Terminal.alternateScreen"]}}
1296
- ← {"jsonrpc":"2.0","id":2,"result":{"subscriptionId":"sub_002","subscribedEvents":["Terminal.alternateScreen"]}}
1297
-
1298
- // Alternate screen event confirms vim loaded
1299
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_002","event":"Terminal.alternateScreen","sessionId":"vim123","timestamp":1679000000100,"data":{"active":true}}}
1300
-
1301
- // Wait for vim status line
1302
- → {"jsonrpc":"2.0","id":3,"method":"Screen.waitForText","params":{"sessionId":"vim123","pattern":"test.txt","timeout":5000}}
1303
- ← {"jsonrpc":"2.0","id":3,"result":{"found":true,"matches":[{"text":"test.txt","row":39,"col":1,"length":8}],"elapsed":200}}
1304
-
1305
- // Enter insert mode and type
1306
- → {"jsonrpc":"2.0","id":4,"method":"Input.sendKeys","params":{"sessionId":"vim123","keys":["i","H","e","l","l","o"," ","w","o","r","l","d","Escape"]}}
1307
- ← {"jsonrpc":"2.0","id":4,"result":{}}
1308
-
1309
- // Save and quit
1310
- → {"jsonrpc":"2.0","id":5,"method":"Input.sendKeys","params":{"sessionId":"vim123","keys":[":","w","q","Enter"]}}
1311
- ← {"jsonrpc":"2.0","id":5,"result":{}}
1312
-
1313
- // Alternate screen exit event confirms vim closed
1314
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_002","event":"Terminal.alternateScreen","sessionId":"vim123","timestamp":1679000005000,"data":{"active":false}}}
1315
- ```
1316
-
1317
- ### 6.4 AI agent with shell integration
1318
-
1319
- ```json
1320
- // Subscribe to shell integration events
1321
- → {"jsonrpc":"2.0","id":1,"method":"Events.subscribe","params":{"sessionId":"abc123","events":["Shell.commandFinished","Terminal.cwdChanged","Terminal.notification"]}}
1322
- ← {"jsonrpc":"2.0","id":1,"result":{"subscriptionId":"sub_003","subscribedEvents":["Shell.commandFinished","Terminal.cwdChanged"]}}
1323
-
1324
- // Send a command
1325
- → {"jsonrpc":"2.0","id":2,"method":"Input.sendKeys","params":{"sessionId":"abc123","keys":["c","d"," ","/","t","m","p","Enter"]}}
1326
- ← {"jsonrpc":"2.0","id":2,"result":{}}
1327
-
1328
- // CWD change detected via OSC 7
1329
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_003","event":"Terminal.cwdChanged","sessionId":"abc123","timestamp":1679000000500,"data":{"cwd":"/tmp","uri":"file://hostname/tmp"}}}
1330
-
1331
- // Command finished with exit code
1332
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_003","event":"Shell.commandFinished","sessionId":"abc123","timestamp":1679000000600,"data":{"exitCode":0}}}
1333
-
1334
- // Run a failing command
1335
- → {"jsonrpc":"2.0","id":3,"method":"Input.sendKeys","params":{"sessionId":"abc123","keys":["l","s"," ","/","n","o","p","e","Enter"]}}
1336
- ← {"jsonrpc":"2.0","id":3,"result":{}}
1337
-
1338
- // Agent knows the command failed without parsing output
1339
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_003","event":"Shell.commandFinished","sessionId":"abc123","timestamp":1679000001200,"data":{"exitCode":2}}}
1340
- ```
1341
-
1342
- ### 6.5 Clipboard interception
1343
-
1344
- ```json
1345
- // Subscribe to clipboard events
1346
- → {"jsonrpc":"2.0","id":1,"method":"Events.subscribe","params":{"sessionId":"abc123","events":["Terminal.clipboardSet"]}}
1347
- ← {"jsonrpc":"2.0","id":1,"result":{"subscriptionId":"sub_004","subscribedEvents":["Terminal.clipboardSet"]}}
1348
-
1349
- // User yanks text in vim (triggers OSC 52)
1350
- ← {"jsonrpc":"2.0","method":"Events.event","params":{"subscriptionId":"sub_004","event":"Terminal.clipboardSet","sessionId":"abc123","timestamp":1679000002000,"data":{"selection":"clipboard","text":"yanked text here","base64":"eWFua2VkIHRleHQgaGVyZQ=="}}}
1351
- ```