@jmoyers/harness 0.1.11 → 0.1.20

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 (232) hide show
  1. package/README.md +31 -39
  2. package/package.json +31 -11
  3. package/packages/harness-ai/src/anthropic-protocol.ts +68 -68
  4. package/packages/harness-ai/src/stream-text.ts +13 -91
  5. package/packages/harness-ui/src/frame-primitives.ts +158 -0
  6. package/packages/harness-ui/src/index.ts +18 -0
  7. package/packages/harness-ui/src/interaction/conversation-input-forwarder.ts +221 -0
  8. package/packages/harness-ui/src/interaction/conversation-selection-input.ts +213 -0
  9. package/packages/harness-ui/src/interaction/global-shortcut-input.ts +172 -0
  10. package/{src/ui → packages/harness-ui/src/interaction}/input-preflight.ts +10 -12
  11. package/{src/ui → packages/harness-ui/src/interaction}/input-token-router.ts +120 -69
  12. package/packages/harness-ui/src/interaction/input.ts +420 -0
  13. package/packages/harness-ui/src/interaction/left-nav-input.ts +166 -0
  14. package/{src/ui → packages/harness-ui/src/interaction}/main-pane-pointer-input.ts +91 -23
  15. package/{src/ui → packages/harness-ui/src/interaction}/pointer-routing-input.ts +112 -48
  16. package/packages/harness-ui/src/interaction/rail-pointer-input.ts +62 -0
  17. package/packages/harness-ui/src/interaction/repository-fold-input.ts +118 -0
  18. package/packages/harness-ui/src/kit.ts +476 -0
  19. package/packages/harness-ui/src/layout.ts +238 -0
  20. package/packages/harness-ui/src/modal-manager.ts +222 -0
  21. package/{src/ui → packages/harness-ui/src}/screen.ts +53 -26
  22. package/packages/harness-ui/src/surface.ts +252 -0
  23. package/packages/harness-ui/src/text-layout.ts +210 -0
  24. package/packages/nim-core/src/contracts.ts +239 -0
  25. package/packages/nim-core/src/event-store.ts +299 -0
  26. package/packages/nim-core/src/events.ts +53 -0
  27. package/packages/nim-core/src/index.ts +9 -0
  28. package/packages/nim-core/src/provider-router.ts +129 -0
  29. package/packages/nim-core/src/providers/anthropic-driver.ts +291 -0
  30. package/packages/nim-core/src/runtime-factory.ts +49 -0
  31. package/packages/nim-core/src/runtime.ts +1797 -0
  32. package/packages/nim-core/src/session-store.ts +516 -0
  33. package/packages/nim-core/src/telemetry.ts +48 -0
  34. package/packages/nim-test-tui/src/index.ts +150 -0
  35. package/packages/nim-ui-core/src/index.ts +1 -0
  36. package/packages/nim-ui-core/src/projection.ts +87 -0
  37. package/scripts/codex-live-mux-runtime.ts +2 -3872
  38. package/scripts/control-plane-daemon.ts +11 -0
  39. package/scripts/harness-bin.js +5 -0
  40. package/scripts/harness-commands.ts +300 -0
  41. package/scripts/harness-runtime.ts +82 -0
  42. package/scripts/harness.ts +33 -3019
  43. package/scripts/nim-tui-smoke.ts +748 -0
  44. package/src/cli/auth/runtime.ts +948 -0
  45. package/src/cli/gateway/runtime.ts +1872 -0
  46. package/src/cli/parsing/flags.ts +23 -0
  47. package/src/cli/parsing/session.ts +42 -0
  48. package/src/cli/runtime/context.ts +193 -0
  49. package/src/cli/runtime-app/application.ts +392 -0
  50. package/src/cli/runtime-infra/gateway-control.ts +729 -0
  51. package/{scripts/harness-inspector.ts → src/cli/workflows/inspector.ts} +14 -11
  52. package/src/cli/workflows/runtime.ts +965 -0
  53. package/src/clients/tui/left-rail-interactions.ts +519 -0
  54. package/src/clients/tui/main-pane-interactions.ts +509 -0
  55. package/src/clients/tui/modal-input-routing.ts +71 -0
  56. package/src/clients/tui/render-snapshot-adapter.ts +88 -0
  57. package/src/clients/web/synced-selectors.ts +132 -0
  58. package/src/codex/live-session.ts +82 -29
  59. package/src/config/config-core.ts +348 -8
  60. package/src/config/harness.config.template.jsonc +33 -0
  61. package/src/control-plane/agent-realtime-api.ts +82 -427
  62. package/src/control-plane/session-summary.ts +10 -81
  63. package/src/control-plane/status/reducer-base.ts +12 -12
  64. package/src/control-plane/status/reducers/claude-status-reducer.ts +3 -3
  65. package/src/control-plane/status/reducers/codex-status-reducer.ts +4 -4
  66. package/src/control-plane/status/reducers/cursor-status-reducer.ts +3 -3
  67. package/src/control-plane/stream-client.ts +12 -2
  68. package/src/control-plane/stream-command-parser.ts +83 -143
  69. package/src/control-plane/stream-protocol.ts +53 -37
  70. package/src/control-plane/stream-server-command.ts +376 -69
  71. package/src/control-plane/stream-server-session-runtime.ts +3 -2
  72. package/src/control-plane/stream-server.ts +864 -70
  73. package/src/control-plane/stream-session-runtime-types.ts +41 -0
  74. package/src/{mux/live-mux/control-plane-records.ts → core/contracts/records.ts} +24 -97
  75. package/src/core/state/observed-stream-cursor.ts +43 -0
  76. package/src/core/state/synced-observed-state.ts +273 -0
  77. package/src/core/store/harness-synced-store.ts +81 -0
  78. package/src/diff/budget.ts +136 -0
  79. package/src/diff/build.ts +289 -0
  80. package/src/diff/chunker.ts +146 -0
  81. package/src/diff/git-invoke.ts +315 -0
  82. package/src/diff/git-parse.ts +472 -0
  83. package/src/diff/hash.ts +70 -0
  84. package/src/diff/index.ts +24 -0
  85. package/src/diff/normalize.ts +134 -0
  86. package/src/diff/types.ts +178 -0
  87. package/src/diff-ui/args.ts +346 -0
  88. package/src/diff-ui/commands.ts +123 -0
  89. package/src/diff-ui/finder.ts +94 -0
  90. package/src/diff-ui/highlight.ts +127 -0
  91. package/src/diff-ui/index.ts +2 -0
  92. package/src/diff-ui/model.ts +141 -0
  93. package/src/diff-ui/pager.ts +412 -0
  94. package/src/diff-ui/render.ts +337 -0
  95. package/src/diff-ui/runtime.ts +379 -0
  96. package/src/diff-ui/state.ts +224 -0
  97. package/src/diff-ui/types.ts +236 -0
  98. package/src/domain/workspace.ts +68 -5
  99. package/src/mux/control-plane-op-queue.ts +93 -7
  100. package/src/mux/conversation-rail.ts +28 -71
  101. package/src/mux/dual-pane-core.ts +13 -13
  102. package/src/mux/harness-core-ui.ts +313 -42
  103. package/src/mux/input-shortcuts.ts +13 -131
  104. package/src/mux/keybinding-catalog.ts +340 -0
  105. package/src/mux/keybinding-registry.ts +103 -0
  106. package/src/mux/live-mux/command-menu-open-in.ts +280 -0
  107. package/src/mux/live-mux/command-menu.ts +167 -4
  108. package/src/mux/live-mux/conversation-state.ts +13 -0
  109. package/src/mux/live-mux/directory-resolution.ts +1 -1
  110. package/src/mux/live-mux/git-snapshot.ts +33 -2
  111. package/src/mux/live-mux/global-shortcut-handlers.ts +6 -0
  112. package/src/mux/live-mux/home-pane-drop.ts +1 -1
  113. package/src/mux/live-mux/home-pane-pointer.ts +10 -0
  114. package/src/mux/live-mux/input-forwarding.ts +59 -2
  115. package/src/mux/live-mux/left-nav-activation.ts +124 -7
  116. package/src/mux/live-mux/left-nav.ts +35 -0
  117. package/src/mux/live-mux/link-click.ts +292 -0
  118. package/src/mux/live-mux/modal-command-menu-handler.ts +46 -9
  119. package/src/mux/live-mux/modal-conversation-handlers.ts +5 -1
  120. package/src/mux/live-mux/modal-input-reducers.ts +77 -12
  121. package/src/mux/live-mux/modal-overlays.ts +168 -34
  122. package/src/mux/live-mux/modal-pointer.ts +3 -7
  123. package/src/mux/live-mux/modal-prompt-handlers.ts +23 -2
  124. package/src/mux/live-mux/modal-release-notes-handler.ts +111 -0
  125. package/src/mux/live-mux/modal-task-editor-handler.ts +16 -11
  126. package/src/mux/live-mux/pointer-routing.ts +5 -2
  127. package/src/mux/live-mux/project-pane-pointer.ts +8 -0
  128. package/src/mux/live-mux/rail-layout.ts +33 -30
  129. package/src/mux/live-mux/release-notes.ts +383 -0
  130. package/src/mux/live-mux/render-trace-analysis.ts +52 -7
  131. package/src/mux/live-mux/repository-folding.ts +3 -0
  132. package/src/mux/live-mux/selection.ts +0 -4
  133. package/src/mux/live-mux/session-diagnostics-paths.ts +21 -0
  134. package/src/mux/project-pane-github-review.ts +271 -0
  135. package/src/mux/render-frame.ts +4 -0
  136. package/src/mux/runtime-app/codex-live-mux-runtime.ts +5191 -0
  137. package/src/mux/task-composer.ts +21 -14
  138. package/src/mux/task-focused-pane.ts +118 -117
  139. package/src/mux/task-screen-keybindings.ts +10 -101
  140. package/src/mux/workspace-rail-model.ts +270 -104
  141. package/src/mux/workspace-rail.ts +45 -22
  142. package/src/pty/session-broker.ts +1 -1
  143. package/{scripts → src/recording}/terminal-recording-gif-lib.ts +2 -2
  144. package/src/services/control-plane.ts +50 -32
  145. package/src/services/conversation-lifecycle.ts +118 -87
  146. package/src/services/conversation-startup-hydration.ts +20 -12
  147. package/src/services/directory-hydration.ts +21 -16
  148. package/src/services/event-persistence.ts +7 -0
  149. package/src/services/left-rail-pointer-handler.ts +329 -0
  150. package/src/services/mux-ui-state-persistence.ts +5 -1
  151. package/src/services/recording.ts +34 -26
  152. package/src/services/runtime-command-menu-agent-tools.ts +1 -1
  153. package/src/services/runtime-control-actions.ts +79 -61
  154. package/src/services/runtime-control-plane-ops.ts +122 -83
  155. package/src/services/runtime-conversation-actions.ts +40 -26
  156. package/src/services/runtime-conversation-activation.ts +73 -46
  157. package/src/services/runtime-conversation-starter.ts +53 -45
  158. package/src/services/runtime-conversation-title-edit.ts +91 -80
  159. package/src/services/runtime-envelope-handler.ts +107 -105
  160. package/src/services/runtime-git-state.ts +42 -29
  161. package/src/services/runtime-layout-resize.ts +3 -1
  162. package/src/services/runtime-left-rail-render.ts +99 -63
  163. package/src/services/runtime-nim-cli-session.ts +438 -0
  164. package/src/services/runtime-nim-session.ts +705 -0
  165. package/src/services/runtime-nim-tool-bridge.ts +141 -0
  166. package/src/services/runtime-observed-event-projection-pipeline.ts +45 -0
  167. package/src/services/runtime-process-wiring.ts +29 -36
  168. package/src/services/runtime-project-pane-github-review-cache.ts +164 -0
  169. package/src/services/runtime-render-flush.ts +63 -70
  170. package/src/services/runtime-render-lifecycle.ts +65 -64
  171. package/src/services/runtime-render-orchestrator.ts +55 -45
  172. package/src/services/runtime-render-pipeline.ts +106 -103
  173. package/src/services/runtime-render-state.ts +62 -49
  174. package/src/services/runtime-repository-actions.ts +97 -72
  175. package/src/services/runtime-right-pane-render.ts +80 -53
  176. package/src/services/runtime-shutdown.ts +38 -35
  177. package/src/services/runtime-stream-subscriptions.ts +35 -27
  178. package/src/services/runtime-task-composer-persistence.ts +71 -59
  179. package/src/services/runtime-task-composer-snapshot.ts +14 -0
  180. package/src/services/runtime-task-editor-actions.ts +46 -29
  181. package/src/services/runtime-task-pane-actions.ts +220 -134
  182. package/src/services/runtime-task-pane-shortcuts.ts +323 -123
  183. package/src/services/runtime-workspace-observed-effect-queue.ts +25 -0
  184. package/src/services/runtime-workspace-observed-events.ts +33 -184
  185. package/src/services/runtime-workspace-observed-transition-policy.ts +228 -0
  186. package/src/services/session-diagnostics-store.ts +217 -0
  187. package/src/services/startup-background-resume.ts +26 -21
  188. package/src/services/startup-orchestrator.ts +16 -13
  189. package/src/services/startup-paint-tracker.ts +29 -21
  190. package/src/services/startup-persisted-conversation-queue.ts +19 -13
  191. package/src/services/startup-settled-gate.ts +25 -15
  192. package/src/services/startup-shutdown.ts +18 -22
  193. package/src/services/startup-state-hydration.ts +44 -34
  194. package/src/services/startup-visibility.ts +12 -4
  195. package/src/services/task-pane-selection-actions.ts +89 -72
  196. package/src/services/task-planning-hydration.ts +24 -18
  197. package/src/services/task-planning-observed-events.ts +50 -52
  198. package/src/services/workspace-observed-events.ts +66 -63
  199. package/src/storage/storage-lifecycle-core.ts +438 -0
  200. package/src/store/control-plane-store-normalize.ts +33 -242
  201. package/src/store/control-plane-store-types.ts +1 -35
  202. package/src/store/control-plane-store.ts +360 -56
  203. package/src/store/event-store.ts +366 -8
  204. package/src/terminal/snapshot-oracle.ts +207 -94
  205. package/src/ui/mux-theme.ts +112 -8
  206. package/src/ui/panes/home-gridfire.ts +40 -31
  207. package/src/ui/panes/home.ts +10 -2
  208. package/src/ui/panes/nim.ts +315 -0
  209. package/src/mux/live-mux/actions-task.ts +0 -115
  210. package/src/mux/live-mux/left-rail-actions.ts +0 -118
  211. package/src/mux/live-mux/left-rail-conversation-click.ts +0 -85
  212. package/src/mux/live-mux/left-rail-pointer.ts +0 -74
  213. package/src/mux/live-mux/task-pane-shortcuts.ts +0 -206
  214. package/src/services/runtime-directory-actions.ts +0 -164
  215. package/src/services/runtime-input-pipeline.ts +0 -50
  216. package/src/services/runtime-input-router.ts +0 -195
  217. package/src/services/runtime-main-pane-input.ts +0 -230
  218. package/src/services/runtime-modal-input.ts +0 -137
  219. package/src/services/runtime-navigation-input.ts +0 -197
  220. package/src/services/runtime-rail-input.ts +0 -279
  221. package/src/services/runtime-task-pane.ts +0 -62
  222. package/src/services/runtime-workspace-actions.ts +0 -158
  223. package/src/ui/conversation-input-forwarder.ts +0 -114
  224. package/src/ui/conversation-selection-input.ts +0 -103
  225. package/src/ui/global-shortcut-input.ts +0 -89
  226. package/src/ui/input.ts +0 -269
  227. package/src/ui/kit.ts +0 -509
  228. package/src/ui/left-nav-input.ts +0 -80
  229. package/src/ui/left-rail-pointer-input.ts +0 -148
  230. package/src/ui/modals/manager.ts +0 -218
  231. package/src/ui/repository-fold-input.ts +0 -91
  232. package/src/ui/surface.ts +0 -224
@@ -0,0 +1,132 @@
1
+ import type {
2
+ ControlPlaneConversationRecord,
3
+ ControlPlaneDirectoryRecord,
4
+ ControlPlaneTaskRecord,
5
+ } from '../../core/contracts/records.ts';
6
+ import type {
7
+ HarnessSyncedStore,
8
+ HarnessSyncedStoreState,
9
+ } from '../../core/store/harness-synced-store.ts';
10
+
11
+ export interface WebConversationListItem {
12
+ readonly conversationId: string;
13
+ readonly directoryId: string;
14
+ readonly title: string;
15
+ readonly agentType: string;
16
+ readonly runtimeStatus: ControlPlaneConversationRecord['runtimeStatus'];
17
+ readonly phase: NonNullable<ControlPlaneConversationRecord['runtimeStatusModel']>['phase'] | null;
18
+ readonly activityHint:
19
+ | NonNullable<ControlPlaneConversationRecord['runtimeStatusModel']>['activityHint']
20
+ | null;
21
+ }
22
+
23
+ export interface WebTaskListItem {
24
+ readonly taskId: string;
25
+ readonly repositoryId: string | null;
26
+ readonly title: string;
27
+ readonly status: ControlPlaneTaskRecord['status'];
28
+ readonly orderIndex: number;
29
+ }
30
+
31
+ interface MemoizedProjection<TResult> {
32
+ readonly read: (state: HarnessSyncedStoreState) => TResult;
33
+ }
34
+
35
+ function createMemoizedProjection<TById extends Readonly<Record<string, unknown>>, TResult>(
36
+ selectById: (state: HarnessSyncedStoreState) => TById,
37
+ project: (byId: TById) => TResult,
38
+ ): MemoizedProjection<TResult> {
39
+ let previousById: TById | null = null;
40
+ let previousResult: TResult | null = null;
41
+ return {
42
+ read: (state) => {
43
+ const currentById = selectById(state);
44
+ if (previousById === currentById && previousResult !== null) {
45
+ return previousResult;
46
+ }
47
+ const nextResult = project(currentById);
48
+ previousById = currentById;
49
+ previousResult = nextResult;
50
+ return nextResult;
51
+ },
52
+ };
53
+ }
54
+
55
+ export function createWebConversationListSelector(): (
56
+ state: HarnessSyncedStoreState,
57
+ ) => readonly WebConversationListItem[] {
58
+ const memoized = createMemoizedProjection(
59
+ (state) => state.synced.conversationsById,
60
+ (conversationsById) =>
61
+ Object.values(conversationsById)
62
+ .sort((left, right) => left.conversationId.localeCompare(right.conversationId))
63
+ .map((conversation) => ({
64
+ conversationId: conversation.conversationId,
65
+ directoryId: conversation.directoryId,
66
+ title: conversation.title,
67
+ agentType: conversation.agentType,
68
+ runtimeStatus: conversation.runtimeStatus,
69
+ phase: conversation.runtimeStatusModel?.phase ?? null,
70
+ activityHint: conversation.runtimeStatusModel?.activityHint ?? null,
71
+ })),
72
+ );
73
+ return (state) => memoized.read(state);
74
+ }
75
+
76
+ export function createWebTaskListSelector(): (
77
+ state: HarnessSyncedStoreState,
78
+ ) => readonly WebTaskListItem[] {
79
+ const memoized = createMemoizedProjection(
80
+ (state) => state.synced.tasksById,
81
+ (tasksById) =>
82
+ Object.values(tasksById)
83
+ .sort((left, right) => left.taskId.localeCompare(right.taskId))
84
+ .sort((left, right) => {
85
+ if (left.orderIndex !== right.orderIndex) {
86
+ return left.orderIndex - right.orderIndex;
87
+ }
88
+ return left.taskId.localeCompare(right.taskId);
89
+ })
90
+ .map((task) => ({
91
+ taskId: task.taskId,
92
+ repositoryId: task.repositoryId,
93
+ title: task.title,
94
+ status: task.status,
95
+ orderIndex: task.orderIndex,
96
+ })),
97
+ );
98
+ return (state) => memoized.read(state);
99
+ }
100
+
101
+ export function selectWebDirectoryList(
102
+ state: HarnessSyncedStoreState,
103
+ ): readonly ControlPlaneDirectoryRecord[] {
104
+ return Object.values(state.synced.directoriesById).sort((left, right) =>
105
+ left.directoryId.localeCompare(right.directoryId),
106
+ );
107
+ }
108
+
109
+ export function selectWebConversationById(
110
+ state: HarnessSyncedStoreState,
111
+ conversationId: string,
112
+ ): ControlPlaneConversationRecord | null {
113
+ return state.synced.conversationsById[conversationId] ?? null;
114
+ }
115
+
116
+ export function subscribeStoreSelector<TSelected>(
117
+ store: HarnessSyncedStore,
118
+ select: (state: HarnessSyncedStoreState) => TSelected,
119
+ onChange: (selected: TSelected, previous: TSelected) => void,
120
+ equals: (left: TSelected, right: TSelected) => boolean = Object.is,
121
+ ): () => void {
122
+ let previousSelected = select(store.getState());
123
+ return store.subscribe((state) => {
124
+ const nextSelected = select(state);
125
+ if (equals(nextSelected, previousSelected)) {
126
+ return;
127
+ }
128
+ const before = previousSelected;
129
+ previousSelected = nextSelected;
130
+ onChange(nextSelected, before);
131
+ });
132
+ }
@@ -172,6 +172,68 @@ const DEFAULT_DA2_REPLY = '\u001b[>1;10;0c';
172
172
  const CELL_PIXEL_HEIGHT = 16;
173
173
  const CELL_PIXEL_WIDTH = 8;
174
174
 
175
+ function isAsciiDigits(value: string, allowEmpty = false): boolean {
176
+ if (!allowEmpty && value.length === 0) {
177
+ return false;
178
+ }
179
+ for (let index = 0; index < value.length; index += 1) {
180
+ const code = value.charCodeAt(index);
181
+ if (code < 0x30 || code > 0x39) {
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ }
187
+
188
+ function isAsciiDigitsOrSemicolons(value: string): boolean {
189
+ for (let index = 0; index < value.length; index += 1) {
190
+ const code = value.charCodeAt(index);
191
+ if (code === 0x3b) {
192
+ continue;
193
+ }
194
+ if (code < 0x30 || code > 0x39) {
195
+ return false;
196
+ }
197
+ }
198
+ return true;
199
+ }
200
+
201
+ function parseAsciiInt(value: string): number | null {
202
+ if (!isAsciiDigits(value, false)) {
203
+ return null;
204
+ }
205
+ let parsed = 0;
206
+ for (let index = 0; index < value.length; index += 1) {
207
+ parsed = parsed * 10 + (value.charCodeAt(index) - 0x30);
208
+ }
209
+ return parsed;
210
+ }
211
+
212
+ function parseKittyKeyboardFlags(payload: string): number | null {
213
+ if (!payload.startsWith('>') || !payload.endsWith('u')) {
214
+ return null;
215
+ }
216
+ return parseAsciiInt(payload.slice(1, -1));
217
+ }
218
+
219
+ function parseModifyOtherKeysLevel(payload: string): number | null {
220
+ if (payload === '>4m') {
221
+ return 0;
222
+ }
223
+ if (!payload.startsWith('>4;') || !payload.endsWith('m')) {
224
+ return null;
225
+ }
226
+ const rawLevel = payload.slice(3, -1);
227
+ if (!isAsciiDigits(rawLevel, false)) {
228
+ return null;
229
+ }
230
+ const parsedLevel = parseAsciiInt(rawLevel);
231
+ if (parsedLevel === null) {
232
+ return null;
233
+ }
234
+ return Math.max(0, Math.min(2, parsedLevel));
235
+ }
236
+
175
237
  function tsRuntimeArgs(scriptPath: string, args: readonly string[] = []): string[] {
176
238
  return [scriptPath, ...args];
177
239
  }
@@ -381,8 +443,7 @@ class TerminalQueryResponder {
381
443
  };
382
444
  let handled = false;
383
445
 
384
- const modifyOtherKeysQueryMatch = payload.match(/^>4;\?m$/u);
385
- if (!handled && modifyOtherKeysQueryMatch !== null) {
446
+ if (!handled && payload === '>4;?m') {
386
447
  this.writeReply(`\u001b[>4;${String(this.modifyOtherKeysLevel)}m`);
387
448
  handled = true;
388
449
  }
@@ -446,29 +507,15 @@ class TerminalQueryResponder {
446
507
  }
447
508
 
448
509
  private observeCsiCommand(payload: string): void {
449
- const kittyKeyboardMatch = payload.match(/^>(\d+)u$/u);
450
- if (kittyKeyboardMatch !== null) {
451
- const nextFlags = Number.parseInt(kittyKeyboardMatch[1]!, 10);
452
- if (Number.isFinite(nextFlags)) {
453
- this.kittyKeyboardFlags = Math.max(0, nextFlags);
454
- }
510
+ const nextFlags = parseKittyKeyboardFlags(payload);
511
+ if (nextFlags !== null) {
512
+ this.kittyKeyboardFlags = Math.max(0, nextFlags);
455
513
  return;
456
514
  }
457
515
 
458
- const modifyOtherKeysMatch = payload.match(/^>4(?:;(\d+))?m$/u);
459
- if (modifyOtherKeysMatch !== null) {
460
- const rawLevel = modifyOtherKeysMatch[1];
461
- if (rawLevel === undefined) {
462
- this.modifyOtherKeysLevel = 0;
463
- return;
464
- }
465
-
466
- const parsedLevel = Number.parseInt(rawLevel, 10);
467
- if (!Number.isFinite(parsedLevel)) {
468
- return;
469
- }
470
-
471
- this.modifyOtherKeysLevel = Math.max(0, Math.min(2, parsedLevel));
516
+ const modifyOtherKeysLevel = parseModifyOtherKeysLevel(payload);
517
+ if (modifyOtherKeysLevel !== null) {
518
+ this.modifyOtherKeysLevel = modifyOtherKeysLevel;
472
519
  }
473
520
  }
474
521
 
@@ -491,22 +538,28 @@ class TerminalQueryResponder {
491
538
  }
492
539
 
493
540
  private isLikelyCsiQueryPayload(payload: string): boolean {
494
- if (/^(?:c|0c|>c|>0c)$/.test(payload)) {
541
+ if (payload === 'c' || payload === '0c' || payload === '>c' || payload === '>0c') {
495
542
  return true;
496
543
  }
497
- if (/^[0-9]*n$/.test(payload)) {
544
+ if (payload.endsWith('n') && isAsciiDigits(payload.slice(0, -1), true)) {
498
545
  return true;
499
546
  }
500
- if (/^(?:14|16|18)t$/.test(payload)) {
547
+ if (payload === '14t' || payload === '16t' || payload === '18t') {
501
548
  return true;
502
549
  }
503
- if (/^>0q$/.test(payload)) {
550
+ if (payload === '>0q') {
504
551
  return true;
505
552
  }
506
- if (/^>4;\?m$/.test(payload)) {
553
+ if (payload === '>4;?m') {
507
554
  return true;
508
555
  }
509
- if (/^\?[0-9;]*\$p$/.test(payload)) {
556
+ if (
557
+ payload.length >= 3 &&
558
+ payload.startsWith('?') &&
559
+ payload.endsWith('p') &&
560
+ payload.charCodeAt(payload.length - 2) === 0x24 &&
561
+ isAsciiDigitsOrSemicolons(payload.slice(1, -2))
562
+ ) {
510
563
  return true;
511
564
  }
512
565
  if (payload === '?u') {
@@ -616,7 +669,7 @@ class CodexLiveSession {
616
669
  this.emit({
617
670
  type: 'terminal-output',
618
671
  cursor: event.cursor,
619
- chunk: Buffer.from(event.chunk),
672
+ chunk: event.chunk,
620
673
  });
621
674
  },
622
675
  onExit: (exit: PtyExit) => {