@otto-code/protocol 0.5.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 (102) hide show
  1. package/README.md +12 -0
  2. package/dist/agent-attention-notification.d.ts +41 -0
  3. package/dist/agent-attention-notification.js +140 -0
  4. package/dist/agent-labels.d.ts +7 -0
  5. package/dist/agent-labels.js +11 -0
  6. package/dist/agent-lifecycle.d.ts +3 -0
  7. package/dist/agent-lifecycle.js +8 -0
  8. package/dist/agent-personalities.d.ts +32 -0
  9. package/dist/agent-personalities.js +69 -0
  10. package/dist/agent-state-bucket.d.ts +14 -0
  11. package/dist/agent-state-bucket.js +41 -0
  12. package/dist/agent-title-limits.d.ts +2 -0
  13. package/dist/agent-title-limits.js +2 -0
  14. package/dist/agent-types.d.ts +479 -0
  15. package/dist/agent-types.js +22 -0
  16. package/dist/artifacts/rpc-schemas.d.ts +396 -0
  17. package/dist/artifacts/rpc-schemas.js +175 -0
  18. package/dist/artifacts/types.d.ts +166 -0
  19. package/dist/artifacts/types.js +73 -0
  20. package/dist/binary-frames/demux.d.ts +11 -0
  21. package/dist/binary-frames/demux.js +23 -0
  22. package/dist/binary-frames/file-transfer.d.ts +50 -0
  23. package/dist/binary-frames/file-transfer.js +107 -0
  24. package/dist/binary-frames/index.d.ts +4 -0
  25. package/dist/binary-frames/index.js +4 -0
  26. package/dist/binary-frames/terminal.d.ts +31 -0
  27. package/dist/binary-frames/terminal.js +99 -0
  28. package/dist/branch-slug.d.ts +14 -0
  29. package/dist/branch-slug.js +49 -0
  30. package/dist/browser-automation/capabilities.d.ts +7 -0
  31. package/dist/browser-automation/capabilities.js +31 -0
  32. package/dist/browser-automation/rpc-schemas.d.ts +1329 -0
  33. package/dist/browser-automation/rpc-schemas.js +555 -0
  34. package/dist/chat/rpc-schemas.d.ts +158 -0
  35. package/dist/chat/rpc-schemas.js +103 -0
  36. package/dist/chat/types.d.ts +30 -0
  37. package/dist/chat/types.js +22 -0
  38. package/dist/client-capabilities.d.ts +8 -0
  39. package/dist/client-capabilities.js +16 -0
  40. package/dist/connection-offer.d.ts +36 -0
  41. package/dist/connection-offer.js +53 -0
  42. package/dist/daemon-endpoints.d.ts +47 -0
  43. package/dist/daemon-endpoints.js +201 -0
  44. package/dist/default-personalities.d.ts +3 -0
  45. package/dist/default-personalities.js +127 -0
  46. package/dist/effort.d.ts +32 -0
  47. package/dist/effort.js +99 -0
  48. package/dist/error-utils.d.ts +11 -0
  49. package/dist/error-utils.js +27 -0
  50. package/dist/generated/validation/ws-outbound.aot.d.ts +2 -0
  51. package/dist/generated/validation/ws-outbound.aot.js +48755 -0
  52. package/dist/git-hosting.d.ts +21 -0
  53. package/dist/git-hosting.js +36 -0
  54. package/dist/git-remote.d.ts +18 -0
  55. package/dist/git-remote.js +84 -0
  56. package/dist/host-connection-schema.d.ts +11 -0
  57. package/dist/host-connection-schema.js +9 -0
  58. package/dist/literal-union.d.ts +2 -0
  59. package/dist/literal-union.js +2 -0
  60. package/dist/loop/rpc-schemas.d.ts +636 -0
  61. package/dist/loop/rpc-schemas.js +163 -0
  62. package/dist/messages.d.ts +38505 -0
  63. package/dist/messages.js +4719 -0
  64. package/dist/otto-config-schema.d.ts +136 -0
  65. package/dist/otto-config-schema.js +96 -0
  66. package/dist/path-utils.d.ts +2 -0
  67. package/dist/path-utils.js +16 -0
  68. package/dist/provider-config.d.ts +266 -0
  69. package/dist/provider-config.js +238 -0
  70. package/dist/provider-icon-names.d.ts +5 -0
  71. package/dist/provider-icon-names.js +52 -0
  72. package/dist/provider-manifest.d.ts +34 -0
  73. package/dist/provider-manifest.js +227 -0
  74. package/dist/schedule/cron-expression.d.ts +13 -0
  75. package/dist/schedule/cron-expression.js +97 -0
  76. package/dist/schedule/rpc-schemas.d.ts +667 -0
  77. package/dist/schedule/rpc-schemas.js +155 -0
  78. package/dist/schedule/types.d.ts +236 -0
  79. package/dist/schedule/types.js +84 -0
  80. package/dist/terminal-activity.d.ts +21 -0
  81. package/dist/terminal-activity.js +25 -0
  82. package/dist/terminal-input-mode.d.ts +26 -0
  83. package/dist/terminal-input-mode.js +151 -0
  84. package/dist/terminal-key-input.d.ts +13 -0
  85. package/dist/terminal-key-input.js +201 -0
  86. package/dist/terminal-profiles.d.ts +6 -0
  87. package/dist/terminal-profiles.js +28 -0
  88. package/dist/terminal-snapshot.d.ts +3 -0
  89. package/dist/terminal-snapshot.js +178 -0
  90. package/dist/terminal-stream-protocol.d.ts +2 -0
  91. package/dist/terminal-stream-protocol.js +2 -0
  92. package/dist/terminal-subscription-key.d.ts +2 -0
  93. package/dist/terminal-subscription-key.js +9 -0
  94. package/dist/tool-call-display.d.ts +11 -0
  95. package/dist/tool-call-display.js +135 -0
  96. package/dist/tool-name-normalization.d.ts +9 -0
  97. package/dist/tool-name-normalization.js +82 -0
  98. package/dist/validation/ws-outbound-schema-metadata.d.ts +7256 -0
  99. package/dist/validation/ws-outbound-schema-metadata.js +3 -0
  100. package/dist/validation/ws-outbound.d.ts +12 -0
  101. package/dist/validation/ws-outbound.js +8 -0
  102. package/package.json +42 -0
@@ -0,0 +1,151 @@
1
+ export const DEFAULT_TERMINAL_INPUT_MODE_STATE = {
2
+ kittyKeyboardFlags: 0,
3
+ win32InputMode: false,
4
+ };
5
+ const ESC = String.fromCharCode(0x1b);
6
+ const WIN32_INPUT_MODE = 9001;
7
+ const CSI_INPUT_MODE_SEQUENCE = new RegExp(`${ESC}\\[(?:([<>=?]?)([0-9;]*)u|\\?([0-9;]*)([hl]))`, "g");
8
+ const INCOMPLETE_CSI_INPUT_MODE_SEQUENCE = new RegExp(`${ESC}\\[[<>=?]?[0-9;]*$`);
9
+ function parseFirstParam(params) {
10
+ const first = params.split(";")[0];
11
+ if (!first || !/^\d+$/.test(first)) {
12
+ return null;
13
+ }
14
+ return Number(first);
15
+ }
16
+ function parseSecondParam(params) {
17
+ const second = params.split(";")[1];
18
+ if (!second || !/^\d+$/.test(second)) {
19
+ return null;
20
+ }
21
+ return Number(second);
22
+ }
23
+ function parsePrivateModeParams(params) {
24
+ const modes = new Set();
25
+ for (const param of params.split(";")) {
26
+ if (/^\d+$/.test(param)) {
27
+ modes.add(Number(param));
28
+ }
29
+ }
30
+ return modes;
31
+ }
32
+ export function terminalInputModeSupportsModifiedEnter(state) {
33
+ return state.kittyKeyboardFlags > 0 || state.win32InputMode;
34
+ }
35
+ export function terminalInputModeStatesEqual(left, right) {
36
+ return (left.kittyKeyboardFlags === right.kittyKeyboardFlags &&
37
+ left.win32InputMode === right.win32InputMode);
38
+ }
39
+ export class TerminalInputModeTracker {
40
+ constructor() {
41
+ this.kittyKeyboardFlags = 0;
42
+ this.win32InputMode = false;
43
+ this.kittyKeyboardStack = [];
44
+ this.pending = "";
45
+ }
46
+ feed(data) {
47
+ if (data.length === 0) {
48
+ return { changed: false, responses: [] };
49
+ }
50
+ const text = `${this.pending}${data}`;
51
+ this.pending = "";
52
+ let changed = false;
53
+ const responses = [];
54
+ let consumedUntil = 0;
55
+ CSI_INPUT_MODE_SEQUENCE.lastIndex = 0;
56
+ for (;;) {
57
+ const match = CSI_INPUT_MODE_SEQUENCE.exec(text);
58
+ if (!match) {
59
+ break;
60
+ }
61
+ consumedUntil = CSI_INPUT_MODE_SEQUENCE.lastIndex;
62
+ if (match[4]) {
63
+ changed = this.applyPrivateModeSequence(match[3] ?? "", match[4]) || changed;
64
+ continue;
65
+ }
66
+ const result = this.applyKittyKeyboardSequence(match[1] ?? "", match[2] ?? "");
67
+ changed = changed || result.changed;
68
+ responses.push(...result.responses);
69
+ }
70
+ const tail = text.slice(consumedUntil);
71
+ const pendingStart = tail.lastIndexOf(`${ESC}[`);
72
+ if (pendingStart >= 0) {
73
+ const pending = tail.slice(pendingStart);
74
+ if (INCOMPLETE_CSI_INPUT_MODE_SEQUENCE.test(pending)) {
75
+ this.pending = pending;
76
+ }
77
+ }
78
+ return { changed, responses };
79
+ }
80
+ reset() {
81
+ this.kittyKeyboardFlags = 0;
82
+ this.win32InputMode = false;
83
+ this.kittyKeyboardStack.length = 0;
84
+ this.pending = "";
85
+ }
86
+ getState() {
87
+ return {
88
+ kittyKeyboardFlags: this.kittyKeyboardFlags,
89
+ win32InputMode: this.win32InputMode,
90
+ };
91
+ }
92
+ getKittyKeyboardFlags() {
93
+ return this.kittyKeyboardFlags;
94
+ }
95
+ supportsModifiedEnter() {
96
+ return terminalInputModeSupportsModifiedEnter(this.getState());
97
+ }
98
+ getPreamble() {
99
+ const parts = [];
100
+ if (this.kittyKeyboardFlags > 0) {
101
+ parts.push(`\x1b[=${this.kittyKeyboardFlags};1u`);
102
+ }
103
+ if (this.win32InputMode) {
104
+ parts.push("\x1b[?9001h");
105
+ }
106
+ return parts.join("");
107
+ }
108
+ applyKittyKeyboardSequence(prefix, params) {
109
+ const previousFlags = this.kittyKeyboardFlags;
110
+ switch (prefix) {
111
+ case ">": {
112
+ this.kittyKeyboardStack.push(this.kittyKeyboardFlags);
113
+ this.kittyKeyboardFlags = parseFirstParam(params) ?? 1;
114
+ break;
115
+ }
116
+ case "=": {
117
+ const mode = parseSecondParam(params) ?? 1;
118
+ this.kittyKeyboardFlags = mode === 0 ? 0 : (parseFirstParam(params) ?? 0);
119
+ break;
120
+ }
121
+ case "<": {
122
+ const count = Math.max(1, parseFirstParam(params) ?? 1);
123
+ for (let index = 0; index < count; index += 1) {
124
+ this.kittyKeyboardFlags = this.kittyKeyboardStack.pop() ?? 0;
125
+ }
126
+ break;
127
+ }
128
+ case "?":
129
+ return {
130
+ changed: false,
131
+ responses: [`\x1b[?${this.kittyKeyboardFlags}u`],
132
+ };
133
+ default:
134
+ return { changed: false, responses: [] };
135
+ }
136
+ return {
137
+ changed: this.kittyKeyboardFlags !== previousFlags,
138
+ responses: [],
139
+ };
140
+ }
141
+ applyPrivateModeSequence(params, final) {
142
+ const modes = parsePrivateModeParams(params);
143
+ if (!modes.has(WIN32_INPUT_MODE)) {
144
+ return false;
145
+ }
146
+ const previous = this.win32InputMode;
147
+ this.win32InputMode = final === "h";
148
+ return this.win32InputMode !== previous;
149
+ }
150
+ }
151
+ //# sourceMappingURL=terminal-input-mode.js.map
@@ -0,0 +1,13 @@
1
+ import type { TerminalInputModeState } from "./terminal-input-mode.js";
2
+ export interface TerminalKeyInput {
3
+ key: string;
4
+ ctrl?: boolean;
5
+ alt?: boolean;
6
+ shift?: boolean;
7
+ meta?: boolean;
8
+ }
9
+ export interface TerminalKeyInputEncodingOptions {
10
+ inputMode?: TerminalInputModeState;
11
+ }
12
+ export declare function encodeTerminalKeyInput(input: TerminalKeyInput, options?: TerminalKeyInputEncodingOptions): string;
13
+ //# sourceMappingURL=terminal-key-input.d.ts.map
@@ -0,0 +1,201 @@
1
+ const WIN32_LEFT_ALT_PRESSED = 0x0002;
2
+ const WIN32_LEFT_CTRL_PRESSED = 0x0008;
3
+ const WIN32_SHIFT_PRESSED = 0x0010;
4
+ function modifierParam(input) {
5
+ let value = 1;
6
+ if (input.shift)
7
+ value += 1;
8
+ if (input.alt)
9
+ value += 2;
10
+ if (input.ctrl)
11
+ value += 4;
12
+ if (input.meta)
13
+ value += 8;
14
+ return value;
15
+ }
16
+ function win32ControlKeyState(input) {
17
+ let value = 0;
18
+ if (input.shift)
19
+ value += WIN32_SHIFT_PRESSED;
20
+ if (input.ctrl)
21
+ value += WIN32_LEFT_CTRL_PRESSED;
22
+ if (input.alt)
23
+ value += WIN32_LEFT_ALT_PRESSED;
24
+ return value;
25
+ }
26
+ function shouldUseWin32InputMode(input, options) {
27
+ if (!options.inputMode?.win32InputMode) {
28
+ return false;
29
+ }
30
+ return Boolean(input.shift || input.ctrl || input.alt);
31
+ }
32
+ function shouldUseKittyKeyboardMode(input, options) {
33
+ if ((options.inputMode?.kittyKeyboardFlags ?? 0) <= 0) {
34
+ return false;
35
+ }
36
+ return Boolean(input.shift || input.ctrl || input.alt || input.meta);
37
+ }
38
+ function encodeWin32EnterKeyInput(input) {
39
+ const controlKeyState = win32ControlKeyState(input);
40
+ // ConPTY Win32 input mode: CSI Vk;Sc;Uc;Kd;Cs;Rc _
41
+ return `\x1b[13;28;13;1;${controlKeyState};1_`;
42
+ }
43
+ function applyAltLikePrefix(sequence, input) {
44
+ return input.alt ? `\x1b${sequence}` : sequence;
45
+ }
46
+ function ctrlSymbolCode(char) {
47
+ switch (char) {
48
+ case " ":
49
+ case "@":
50
+ case "2":
51
+ return "\x00";
52
+ case "[":
53
+ case "3":
54
+ return "\x1b";
55
+ case "\\":
56
+ case "4":
57
+ return "\x1c";
58
+ case "]":
59
+ case "5":
60
+ return "\x1d";
61
+ case "^":
62
+ case "6":
63
+ return "\x1e";
64
+ case "_":
65
+ case "/":
66
+ case "7":
67
+ return "\x1f";
68
+ case "8":
69
+ case "?":
70
+ return "\x7f";
71
+ default:
72
+ return null;
73
+ }
74
+ }
75
+ function encodeCtrlChar(char, input) {
76
+ const upper = char.toUpperCase();
77
+ if (upper.length === 1 && upper >= "A" && upper <= "Z") {
78
+ return applyAltLikePrefix(String.fromCharCode(upper.charCodeAt(0) - 64), input);
79
+ }
80
+ const symbol = ctrlSymbolCode(char);
81
+ if (symbol !== null) {
82
+ return applyAltLikePrefix(symbol, input);
83
+ }
84
+ if (char.length === 1) {
85
+ const code = char.charCodeAt(0) & 0x1f;
86
+ return applyAltLikePrefix(String.fromCharCode(code), input);
87
+ }
88
+ return applyAltLikePrefix(char, input);
89
+ }
90
+ function encodePrintableKey(input) {
91
+ const raw = input.key;
92
+ const char = input.shift ? raw.toUpperCase() : raw;
93
+ if (input.ctrl) {
94
+ return encodeCtrlChar(char, input);
95
+ }
96
+ return applyAltLikePrefix(char, input);
97
+ }
98
+ function csiWithModifier(finalByte, input) {
99
+ const mod = modifierParam(input);
100
+ return mod === 1 ? `\x1b[${finalByte}` : `\x1b[1;${mod}${finalByte}`;
101
+ }
102
+ function csiTilde(base, input) {
103
+ const mod = modifierParam(input);
104
+ return mod === 1 ? `\x1b[${base}~` : `\x1b[${base};${mod}~`;
105
+ }
106
+ function encodeFunctionKey(key, input) {
107
+ switch (key) {
108
+ case "F1":
109
+ return modifierParam(input) === 1 ? "\x1bOP" : csiWithModifier("P", input);
110
+ case "F2":
111
+ return modifierParam(input) === 1 ? "\x1bOQ" : csiWithModifier("Q", input);
112
+ case "F3":
113
+ return modifierParam(input) === 1 ? "\x1bOR" : csiWithModifier("R", input);
114
+ case "F4":
115
+ return modifierParam(input) === 1 ? "\x1bOS" : csiWithModifier("S", input);
116
+ case "F5":
117
+ return csiTilde(15, input);
118
+ case "F6":
119
+ return csiTilde(17, input);
120
+ case "F7":
121
+ return csiTilde(18, input);
122
+ case "F8":
123
+ return csiTilde(19, input);
124
+ case "F9":
125
+ return csiTilde(20, input);
126
+ case "F10":
127
+ return csiTilde(21, input);
128
+ case "F11":
129
+ return csiTilde(23, input);
130
+ case "F12":
131
+ return csiTilde(24, input);
132
+ default:
133
+ return null;
134
+ }
135
+ }
136
+ function encodeNavigationKey(key, input) {
137
+ switch (key) {
138
+ case "ArrowUp":
139
+ return csiWithModifier("A", input);
140
+ case "ArrowDown":
141
+ return csiWithModifier("B", input);
142
+ case "ArrowRight":
143
+ return csiWithModifier("C", input);
144
+ case "ArrowLeft":
145
+ return csiWithModifier("D", input);
146
+ case "Home":
147
+ return csiWithModifier("H", input);
148
+ case "End":
149
+ return csiWithModifier("F", input);
150
+ case "Insert":
151
+ return csiTilde(2, input);
152
+ case "Delete":
153
+ return csiTilde(3, input);
154
+ case "PageUp":
155
+ return csiTilde(5, input);
156
+ case "PageDown":
157
+ return csiTilde(6, input);
158
+ default:
159
+ return null;
160
+ }
161
+ }
162
+ export function encodeTerminalKeyInput(input, options = {}) {
163
+ const key = input.key;
164
+ if (!key) {
165
+ return "";
166
+ }
167
+ if (key.length === 1) {
168
+ return encodePrintableKey(input);
169
+ }
170
+ switch (key) {
171
+ case "Enter": {
172
+ const mod = modifierParam(input);
173
+ if (mod > 1 && shouldUseWin32InputMode(input, options)) {
174
+ return encodeWin32EnterKeyInput(input);
175
+ }
176
+ if (mod > 1 && shouldUseKittyKeyboardMode(input, options)) {
177
+ return `\x1b[13;${mod}u`;
178
+ }
179
+ return "\r";
180
+ }
181
+ case "Tab":
182
+ if (input.shift && !input.ctrl && !input.alt && !input.meta) {
183
+ return "\x1b[Z";
184
+ }
185
+ return applyAltLikePrefix("\t", input);
186
+ case "Backspace":
187
+ return applyAltLikePrefix("\x7f", input);
188
+ case "Escape":
189
+ return "\x1b";
190
+ default:
191
+ break;
192
+ }
193
+ const nav = encodeNavigationKey(key, input);
194
+ if (nav !== null)
195
+ return nav;
196
+ const fn = encodeFunctionKey(key, input);
197
+ if (fn !== null)
198
+ return fn;
199
+ return "";
200
+ }
201
+ //# sourceMappingURL=terminal-key-input.js.map
@@ -0,0 +1,6 @@
1
+ import type { TerminalProfile } from "./messages.js";
2
+ export declare const DEFAULT_TERMINAL_PROFILES: readonly TerminalProfile[];
3
+ export declare function guessTerminalProfileIcon(command: string): string | undefined;
4
+ export declare function getTerminalProfileIcon(profile: TerminalProfile): string | undefined;
5
+ export declare function resolveTerminalProfiles(terminalProfiles: TerminalProfile[] | undefined): readonly TerminalProfile[];
6
+ //# sourceMappingURL=terminal-profiles.d.ts.map
@@ -0,0 +1,28 @@
1
+ import { KNOWN_PROVIDER_ICON_NAMES } from "./provider-icon-names.js";
2
+ export const DEFAULT_TERMINAL_PROFILES = [
3
+ { id: "claude", name: "Claude Code", command: "claude", icon: "claude" },
4
+ { id: "codex", name: "Codex", command: "codex", icon: "codex" },
5
+ { id: "opencode", name: "OpenCode", command: "opencode", icon: "opencode" },
6
+ ];
7
+ const WELL_KNOWN_COMMAND_ICONS = new Map(KNOWN_PROVIDER_ICON_NAMES.map((name) => [name, name]));
8
+ function getCommandBaseName(command) {
9
+ const lastSlash = command.lastIndexOf("/");
10
+ const lastBackslash = command.lastIndexOf("\\");
11
+ const start = Math.max(lastSlash, lastBackslash) + 1;
12
+ const base = command.slice(start).toLowerCase();
13
+ const dotIndex = base.indexOf(".");
14
+ return dotIndex > 0 ? base.slice(0, dotIndex) : base;
15
+ }
16
+ export function guessTerminalProfileIcon(command) {
17
+ return WELL_KNOWN_COMMAND_ICONS.get(getCommandBaseName(command));
18
+ }
19
+ export function getTerminalProfileIcon(profile) {
20
+ return profile.icon ?? guessTerminalProfileIcon(profile.command);
21
+ }
22
+ export function resolveTerminalProfiles(terminalProfiles) {
23
+ if (terminalProfiles === undefined) {
24
+ return DEFAULT_TERMINAL_PROFILES;
25
+ }
26
+ return terminalProfiles;
27
+ }
28
+ //# sourceMappingURL=terminal-profiles.js.map
@@ -0,0 +1,3 @@
1
+ import type { TerminalState } from "./messages.js";
2
+ export declare function renderTerminalSnapshotToAnsi(state: TerminalState): string;
3
+ //# sourceMappingURL=terminal-snapshot.d.ts.map
@@ -0,0 +1,178 @@
1
+ const DEFAULT_STYLE = {
2
+ fg: undefined,
3
+ bg: undefined,
4
+ fgMode: undefined,
5
+ bgMode: undefined,
6
+ bold: false,
7
+ italic: false,
8
+ underline: false,
9
+ dim: false,
10
+ inverse: false,
11
+ strikethrough: false,
12
+ };
13
+ export function renderTerminalSnapshotToAnsi(state) {
14
+ const rows = [...state.scrollback, ...state.grid];
15
+ const wrapFlags = [...(state.scrollbackWrapped ?? []), ...(state.gridWrapped ?? [])];
16
+ // Soft-wrapped lines can only be re-wrapped on resize when we know which rows
17
+ // were continuations. With that per-row flag we replay each logical line as one
18
+ // unbroken run (autowrap on) so xterm marks the continuations wrapped and reflows
19
+ // them. Without it (old daemon) we keep the verbatim per-row replay: autowrap off
20
+ // plus a hard newline per row.
21
+ const hasWrapInfo = wrapFlags.length === rows.length;
22
+ const lines = hasWrapInfo ? [] : ["\u001b[?7l"];
23
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex += 1) {
24
+ const row = rows[rowIndex] ?? [];
25
+ const continuesToNextRow = hasWrapInfo && wrapFlags[rowIndex] === true;
26
+ // A continuation row must fill the full width so the next row first cell
27
+ // triggers xterm auto-wrap, which is what marks the row wrapped/reflowable.
28
+ lines.push(renderTerminalRow(row, continuesToNextRow ? state.cols : undefined));
29
+ if (rowIndex < rows.length - 1 && !continuesToNextRow) {
30
+ lines.push("\r\n");
31
+ }
32
+ }
33
+ lines.push("\u001b[0m");
34
+ const cursorPresentationAnsi = renderCursorPresentationToAnsi(state.cursor);
35
+ if (cursorPresentationAnsi) {
36
+ lines.push(cursorPresentationAnsi);
37
+ }
38
+ lines.push(`\u001b[${state.cursor.row + 1};${state.cursor.col + 1}H`);
39
+ lines.push(state.cursor.hidden ? "\u001b[?25l" : "\u001b[?25h");
40
+ if (!hasWrapInfo) {
41
+ lines.push("\u001b[?7h");
42
+ }
43
+ return lines.join("");
44
+ }
45
+ function renderCursorPresentationToAnsi(cursor) {
46
+ if (!cursor.style) {
47
+ return null;
48
+ }
49
+ const cursorStyleCode = (() => {
50
+ if (cursor.style === "block") {
51
+ return cursor.blink === false ? 2 : 1;
52
+ }
53
+ if (cursor.style === "underline") {
54
+ return cursor.blink === false ? 4 : 3;
55
+ }
56
+ return cursor.blink === false ? 6 : 5;
57
+ })();
58
+ return `\u001b[${cursorStyleCode} q`;
59
+ }
60
+ function renderTerminalRow(row, padToCols) {
61
+ const output = [];
62
+ const contentLength = getTerminalRowLength(row);
63
+ const length = padToCols !== undefined ? Math.max(contentLength, padToCols) : contentLength;
64
+ let previousStyle = DEFAULT_STYLE;
65
+ for (let index = 0; index < length; index += 1) {
66
+ const cell = row[index] ?? { char: " " };
67
+ const nextStyle = getTerminalStyle(cell);
68
+ if (!terminalStylesEqual(previousStyle, nextStyle)) {
69
+ output.push(styleToAnsi(nextStyle));
70
+ previousStyle = nextStyle;
71
+ }
72
+ output.push(cell.char || " ");
73
+ }
74
+ if (!terminalStylesEqual(previousStyle, DEFAULT_STYLE)) {
75
+ output.push("\u001b[0m");
76
+ }
77
+ return output.join("");
78
+ }
79
+ function getTerminalRowLength(row) {
80
+ for (let index = row.length - 1; index >= 0; index -= 1) {
81
+ const cell = row[index];
82
+ if (!cell) {
83
+ continue;
84
+ }
85
+ if (cell.char !== " ") {
86
+ return index + 1;
87
+ }
88
+ if (cell.fg !== undefined ||
89
+ cell.bg !== undefined ||
90
+ cell.fgMode !== undefined ||
91
+ cell.bgMode !== undefined ||
92
+ cell.bold ||
93
+ cell.italic ||
94
+ cell.underline ||
95
+ cell.dim ||
96
+ cell.inverse ||
97
+ cell.strikethrough) {
98
+ return index + 1;
99
+ }
100
+ }
101
+ return 0;
102
+ }
103
+ function getTerminalStyle(cell) {
104
+ return {
105
+ fg: cell.fg,
106
+ bg: cell.bg,
107
+ fgMode: cell.fgMode,
108
+ bgMode: cell.bgMode,
109
+ bold: Boolean(cell.bold),
110
+ italic: Boolean(cell.italic),
111
+ underline: Boolean(cell.underline),
112
+ dim: Boolean(cell.dim),
113
+ inverse: Boolean(cell.inverse),
114
+ strikethrough: Boolean(cell.strikethrough),
115
+ };
116
+ }
117
+ function terminalStylesEqual(left, right) {
118
+ return (left.fg === right.fg &&
119
+ left.bg === right.bg &&
120
+ left.fgMode === right.fgMode &&
121
+ left.bgMode === right.bgMode &&
122
+ left.bold === right.bold &&
123
+ left.italic === right.italic &&
124
+ left.underline === right.underline &&
125
+ left.dim === right.dim &&
126
+ left.inverse === right.inverse &&
127
+ left.strikethrough === right.strikethrough);
128
+ }
129
+ function styleToAnsi(style) {
130
+ const codes = ["0"];
131
+ if (style.bold) {
132
+ codes.push("1");
133
+ }
134
+ if (style.dim) {
135
+ codes.push("2");
136
+ }
137
+ if (style.italic) {
138
+ codes.push("3");
139
+ }
140
+ if (style.underline) {
141
+ codes.push("4");
142
+ }
143
+ if (style.inverse) {
144
+ codes.push("7");
145
+ }
146
+ if (style.strikethrough) {
147
+ codes.push("9");
148
+ }
149
+ if (style.fg !== undefined && style.fgMode !== undefined) {
150
+ codes.push(...colorToSgr(style.fgMode, style.fg, false));
151
+ }
152
+ if (style.bg !== undefined && style.bgMode !== undefined) {
153
+ codes.push(...colorToSgr(style.bgMode, style.bg, true));
154
+ }
155
+ return `\u001b[${codes.join(";")}m`;
156
+ }
157
+ function colorToSgr(mode, value, background) {
158
+ if (mode === 1) {
159
+ if (value >= 8) {
160
+ return [String((background ? 100 : 90) + (value - 8))];
161
+ }
162
+ return [String((background ? 40 : 30) + value)];
163
+ }
164
+ if (mode === 2) {
165
+ return [background ? "48" : "38", "5", String(value)];
166
+ }
167
+ if (mode === 3) {
168
+ return [
169
+ background ? "48" : "38",
170
+ "2",
171
+ String((value >> 16) & 0xff),
172
+ String((value >> 8) & 0xff),
173
+ String(value & 0xff),
174
+ ];
175
+ }
176
+ return [];
177
+ }
178
+ //# sourceMappingURL=terminal-snapshot.js.map
@@ -0,0 +1,2 @@
1
+ export * from "./binary-frames/terminal.js";
2
+ //# sourceMappingURL=terminal-stream-protocol.d.ts.map
@@ -0,0 +1,2 @@
1
+ export * from "./binary-frames/terminal.js";
2
+ //# sourceMappingURL=terminal-stream-protocol.js.map
@@ -0,0 +1,2 @@
1
+ export declare function terminalSubscriptionKey(cwd: string, workspaceId: string | undefined): string;
2
+ //# sourceMappingURL=terminal-subscription-key.d.ts.map
@@ -0,0 +1,9 @@
1
+ // A terminal directory subscription is scoped to a (cwd, workspaceId) pair, not
2
+ // cwd alone: under Model B two workspaces can share a cwd, and each must track
3
+ // and tear down its own live subscription without disturbing the other. An
4
+ // absent workspaceId (old clients) keys to the cwd on its own. The `::`
5
+ // separator cannot collide with a workspace id, which is always `wks_<hex>`.
6
+ export function terminalSubscriptionKey(cwd, workspaceId) {
7
+ return workspaceId === undefined ? cwd : `${workspaceId}::${cwd}`;
8
+ }
9
+ //# sourceMappingURL=terminal-subscription-key.js.map
@@ -0,0 +1,11 @@
1
+ import type { ToolCallTimelineItem } from "./agent-types.js";
2
+ export type ToolCallDisplayInput = Pick<ToolCallTimelineItem, "name" | "status" | "error" | "metadata" | "detail"> & {
3
+ cwd?: string;
4
+ };
5
+ export interface ToolCallDisplayModel {
6
+ displayName: string;
7
+ summary?: string;
8
+ errorText?: string;
9
+ }
10
+ export declare function buildToolCallDisplayModel(input: ToolCallDisplayInput): ToolCallDisplayModel;
11
+ //# sourceMappingURL=tool-call-display.d.ts.map