@brimveyn/aimux 1.13.2 → 1.14.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.
- package/package.json +2 -2
- package/src/app-runtime/backend-attach-runtime.ts +1 -3
- package/src/app-runtime/multi-click-clipboard-guard.ts +24 -12
- package/src/app-runtime/pty-write.ts +6 -9
- package/src/app-runtime/side-effects.ts +4 -18
- package/src/app-runtime/snippet-actions.ts +2 -3
- package/src/app-runtime/use-backend-runtime.ts +4 -7
- package/src/app-runtime/use-mouse-handlers.ts +30 -1
- package/src/app-runtime/use-renderer-bindings.ts +4 -12
- package/src/app-runtime/use-terminal-resize.ts +6 -18
- package/src/app.tsx +0 -3
- package/src/daemon/daemon.ts +2 -19
- package/src/daemon/session-manager.ts +3 -15
- package/src/daemon/session-registry.ts +11 -30
- package/src/input/terminal-text-extraction.ts +7 -8
- package/src/ipc/manager-protocol.ts +6 -38
- package/src/ipc/protocol.ts +9 -37
- package/src/pty/pty-manager.ts +20 -31
- package/src/pty/terminal-snapshot.ts +43 -0
- package/src/session-backend/local-session-backend.ts +7 -31
- package/src/session-backend/remote-session-backend.ts +5 -32
- package/src/session-backend/types.ts +2 -15
- package/src/state/reducers/tab-state.ts +2 -20
- package/src/state/session-persistence.ts +2 -22
- package/src/state/types.ts +3 -11
- package/src/state/validation.ts +0 -8
- package/src/terminal-manager/manager-client.ts +5 -29
- package/src/terminal-manager/terminal-manager.ts +2 -17
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { AppAction, AppState, TabSession } from '../types'
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
allLeafIds,
|
|
3
5
|
createGroupId,
|
|
@@ -15,13 +17,6 @@ import {
|
|
|
15
17
|
import { normalizeGroupedTabOrder } from '../session-persistence'
|
|
16
18
|
import { orderTabsByWorktree, withActiveWorktree } from '../session-worktrees'
|
|
17
19
|
import { createDefaultTerminalModes } from '../terminal-modes'
|
|
18
|
-
import {
|
|
19
|
-
type AppAction,
|
|
20
|
-
type AppState,
|
|
21
|
-
DEFAULT_SCROLL_INTENT,
|
|
22
|
-
deriveScrollIntent,
|
|
23
|
-
type TabSession,
|
|
24
|
-
} from '../types'
|
|
25
20
|
|
|
26
21
|
const MAX_BUFFER_LENGTH = 50_000
|
|
27
22
|
|
|
@@ -448,7 +443,6 @@ export function reduceTabState(state: AppState, action: AppAction): AppState | n
|
|
|
448
443
|
buffer: '',
|
|
449
444
|
errorMessage: undefined,
|
|
450
445
|
exitCode: undefined,
|
|
451
|
-
scrollIntent: DEFAULT_SCROLL_INTENT,
|
|
452
446
|
status: 'starting',
|
|
453
447
|
terminalModes: createDefaultTerminalModes(),
|
|
454
448
|
viewport: undefined,
|
|
@@ -470,23 +464,11 @@ export function reduceTabState(state: AppState, action: AppAction): AppState | n
|
|
|
470
464
|
...state,
|
|
471
465
|
tabs: updateTab(state.tabs, action.tabId, (tab) => ({
|
|
472
466
|
...tab,
|
|
473
|
-
scrollIntent:
|
|
474
|
-
action.source === 'resize' || action.source === 'switch'
|
|
475
|
-
? (tab.scrollIntent ?? DEFAULT_SCROLL_INTENT)
|
|
476
|
-
: deriveScrollIntent(action.viewport),
|
|
477
467
|
status: tab.status === 'starting' ? 'running' : tab.status,
|
|
478
468
|
terminalModes: action.terminalModes,
|
|
479
469
|
viewport: action.viewport,
|
|
480
470
|
})),
|
|
481
471
|
}
|
|
482
|
-
case 'set-scroll-intent':
|
|
483
|
-
return {
|
|
484
|
-
...state,
|
|
485
|
-
tabs: updateTab(state.tabs, action.tabId, (tab) => ({
|
|
486
|
-
...tab,
|
|
487
|
-
scrollIntent: action.intent,
|
|
488
|
-
})),
|
|
489
|
-
}
|
|
490
472
|
case 'set-tab-activity':
|
|
491
473
|
return {
|
|
492
474
|
...state,
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
+
import type { AppState, TabSession, TabStatus, WorkspaceSnapshotV1 } from './types'
|
|
2
|
+
|
|
1
3
|
import { allLeafIds, createGroupId, type LayoutNode, pruneLayoutTree } from './layout-tree'
|
|
2
|
-
import {
|
|
3
|
-
type AppState,
|
|
4
|
-
DEFAULT_SCROLL_INTENT,
|
|
5
|
-
type ScrollIntent,
|
|
6
|
-
type TabSession,
|
|
7
|
-
type TabStatus,
|
|
8
|
-
type WorkspaceSnapshotV1,
|
|
9
|
-
} from './types'
|
|
10
4
|
|
|
11
5
|
export function createEmptyWorkspaceSnapshot(): WorkspaceSnapshotV1 {
|
|
12
6
|
return {
|
|
@@ -47,7 +41,6 @@ export function serializeWorkspace(state: AppState): WorkspaceSnapshotV1 {
|
|
|
47
41
|
errorMessage: tab.errorMessage,
|
|
48
42
|
exitCode: tab.exitCode,
|
|
49
43
|
id: tab.id,
|
|
50
|
-
scrollIntent: tab.scrollIntent,
|
|
51
44
|
status: tab.status === 'disconnected' ? 'running' : tab.status,
|
|
52
45
|
terminalModes: tab.terminalModes,
|
|
53
46
|
title: tab.title,
|
|
@@ -76,7 +69,6 @@ export function restoreTabsFromWorkspace(snapshot: WorkspaceSnapshotV1 | undefin
|
|
|
76
69
|
errorMessage: tab.errorMessage,
|
|
77
70
|
exitCode: tab.exitCode,
|
|
78
71
|
id: tab.id,
|
|
79
|
-
scrollIntent: tab.scrollIntent ?? DEFAULT_SCROLL_INTENT,
|
|
80
72
|
status: getDisconnectedStatus(tab.status),
|
|
81
73
|
terminalModes: tab.terminalModes,
|
|
82
74
|
title: tab.title,
|
|
@@ -85,18 +77,6 @@ export function restoreTabsFromWorkspace(snapshot: WorkspaceSnapshotV1 | undefin
|
|
|
85
77
|
}))
|
|
86
78
|
}
|
|
87
79
|
|
|
88
|
-
export function getSnapshotScrollIntents(
|
|
89
|
-
snapshot: WorkspaceSnapshotV1 | undefined
|
|
90
|
-
): Map<string, ScrollIntent> {
|
|
91
|
-
if (!snapshot || snapshot.version !== 1) {
|
|
92
|
-
return new Map()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return new Map(
|
|
96
|
-
snapshot.tabs.map((tab) => [tab.id, tab.scrollIntent ?? DEFAULT_SCROLL_INTENT] as const)
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
80
|
export function restoreLayoutTrees(
|
|
101
81
|
snapshot: WorkspaceSnapshotV1 | undefined,
|
|
102
82
|
tabs: TabSession[]
|
package/src/state/types.ts
CHANGED
|
@@ -70,16 +70,11 @@ export interface TerminalSnapshot {
|
|
|
70
70
|
cursorVisible: boolean
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// The scroll position is owned end-to-end by the backend emulator; this type
|
|
74
|
+
// only describes the re-anchor target the backend computes for itself across a
|
|
75
|
+
// reflow. The frontend no longer derives, stores, or sends a scroll intent.
|
|
73
76
|
export type ScrollIntent = { kind: 'bottom' } | { absoluteLine: number; kind: 'anchor' }
|
|
74
77
|
|
|
75
|
-
export const DEFAULT_SCROLL_INTENT: ScrollIntent = { kind: 'bottom' }
|
|
76
|
-
|
|
77
|
-
export function deriveScrollIntent(viewport: TerminalSnapshot): ScrollIntent {
|
|
78
|
-
return viewport.viewportY >= viewport.baseY
|
|
79
|
-
? { kind: 'bottom' }
|
|
80
|
-
: { absoluteLine: viewport.viewportY, kind: 'anchor' }
|
|
81
|
-
}
|
|
82
|
-
|
|
83
78
|
export interface TerminalModeState {
|
|
84
79
|
mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any'
|
|
85
80
|
sendFocusMode: boolean
|
|
@@ -97,7 +92,6 @@ export interface PersistedTabSnapshot {
|
|
|
97
92
|
buffer: string
|
|
98
93
|
viewport?: TerminalSnapshot
|
|
99
94
|
terminalModes: TerminalModeState
|
|
100
|
-
scrollIntent?: ScrollIntent
|
|
101
95
|
errorMessage?: string
|
|
102
96
|
exitCode?: number
|
|
103
97
|
worktreeId?: string
|
|
@@ -163,7 +157,6 @@ export interface TabSession {
|
|
|
163
157
|
buffer: string
|
|
164
158
|
viewport?: TerminalSnapshot
|
|
165
159
|
terminalModes: TerminalModeState
|
|
166
|
-
scrollIntent?: ScrollIntent
|
|
167
160
|
command: string
|
|
168
161
|
errorMessage?: string
|
|
169
162
|
exitCode?: number
|
|
@@ -583,7 +576,6 @@ export type TabAction =
|
|
|
583
576
|
terminalModes: TerminalModeState
|
|
584
577
|
source?: 'resize' | 'scroll' | 'data' | 'switch'
|
|
585
578
|
}
|
|
586
|
-
| { type: 'set-scroll-intent'; tabId: string; intent: ScrollIntent }
|
|
587
579
|
| { type: 'set-tab-activity'; tabId: string; activity?: TabActivity }
|
|
588
580
|
| { type: 'set-tab-error'; tabId: string; message: string }
|
|
589
581
|
|
package/src/state/validation.ts
CHANGED
|
@@ -56,13 +56,6 @@ function isTerminalSnapshot(value: unknown): value is TerminalSnapshot {
|
|
|
56
56
|
)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function isScrollIntent(value: unknown): boolean {
|
|
60
|
-
if (!isObjectRecord(value)) return false
|
|
61
|
-
if (value.kind === 'bottom') return true
|
|
62
|
-
if (value.kind === 'anchor') return isFiniteNumber(value.absoluteLine)
|
|
63
|
-
return false
|
|
64
|
-
}
|
|
65
|
-
|
|
66
59
|
function isTerminalModeState(value: unknown): value is TerminalModeState {
|
|
67
60
|
return (
|
|
68
61
|
isObjectRecord(value) &&
|
|
@@ -149,7 +142,6 @@ export function isWorkspaceSnapshotV1(value: unknown): value is WorkspaceSnapsho
|
|
|
149
142
|
isString(tab.buffer) &&
|
|
150
143
|
isTerminalModeState(tab.terminalModes) &&
|
|
151
144
|
(tab.viewport === undefined || isTerminalSnapshot(tab.viewport)) &&
|
|
152
|
-
(tab.scrollIntent === undefined || isScrollIntent(tab.scrollIntent)) &&
|
|
153
145
|
(tab.errorMessage === undefined || isString(tab.errorMessage)) &&
|
|
154
146
|
(tab.exitCode === undefined || isFiniteNumber(tab.exitCode)) &&
|
|
155
147
|
(tab.worktreeId === undefined || isString(tab.worktreeId))
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events'
|
|
2
2
|
import { connect, type Socket } from 'node:net'
|
|
3
3
|
|
|
4
|
-
import type {
|
|
5
|
-
ScrollIntent,
|
|
6
|
-
TerminalModeState,
|
|
7
|
-
TerminalSnapshot,
|
|
8
|
-
WorkspaceSnapshotV1,
|
|
9
|
-
} from '../state/types'
|
|
4
|
+
import type { TerminalModeState, TerminalSnapshot, WorkspaceSnapshotV1 } from '../state/types'
|
|
10
5
|
|
|
11
6
|
import { getTerminalManagerSocketPath } from '../daemon/runtime-paths'
|
|
12
7
|
import { logDebug } from '../debug/input-log'
|
|
@@ -306,29 +301,18 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
|
|
|
306
301
|
})
|
|
307
302
|
}
|
|
308
303
|
|
|
309
|
-
async resize(
|
|
310
|
-
sessionId: string,
|
|
311
|
-
cols: number,
|
|
312
|
-
rows: number,
|
|
313
|
-
intents?: Record<string, ScrollIntent>
|
|
314
|
-
): Promise<void> {
|
|
304
|
+
async resize(sessionId: string, cols: number, rows: number): Promise<void> {
|
|
315
305
|
return this.sendExpectOk({
|
|
316
306
|
id: crypto.randomUUID(),
|
|
317
|
-
payload: { cols,
|
|
307
|
+
payload: { cols, rows, sessionId },
|
|
318
308
|
type: 'resizeClient',
|
|
319
309
|
})
|
|
320
310
|
}
|
|
321
311
|
|
|
322
|
-
async resizeTab(
|
|
323
|
-
sessionId: string,
|
|
324
|
-
tabId: string,
|
|
325
|
-
cols: number,
|
|
326
|
-
rows: number,
|
|
327
|
-
intent?: ScrollIntent
|
|
328
|
-
): Promise<void> {
|
|
312
|
+
async resizeTab(sessionId: string, tabId: string, cols: number, rows: number): Promise<void> {
|
|
329
313
|
return this.sendExpectOk({
|
|
330
314
|
id: crypto.randomUUID(),
|
|
331
|
-
payload: { cols,
|
|
315
|
+
payload: { cols, rows, sessionId, tabId },
|
|
332
316
|
type: 'resizeTab',
|
|
333
317
|
})
|
|
334
318
|
}
|
|
@@ -349,14 +333,6 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
|
|
|
349
333
|
})
|
|
350
334
|
}
|
|
351
335
|
|
|
352
|
-
async reapplyScrollIntent(sessionId: string, tabId: string, intent: ScrollIntent): Promise<void> {
|
|
353
|
-
return this.sendExpectOk({
|
|
354
|
-
id: crypto.randomUUID(),
|
|
355
|
-
payload: { intent, sessionId, tabId },
|
|
356
|
-
type: 'reapplyScrollIntent',
|
|
357
|
-
})
|
|
358
|
-
}
|
|
359
|
-
|
|
360
336
|
async setActiveTab(sessionId: string, tabId: string | null): Promise<void> {
|
|
361
337
|
return this.sendExpectOk({
|
|
362
338
|
id: crypto.randomUUID(),
|
|
@@ -211,15 +211,10 @@ export async function runTerminalManager(): Promise<void> {
|
|
|
211
211
|
break
|
|
212
212
|
case 'resizeClient': {
|
|
213
213
|
requireNegotiatedVersion(socket, negotiatedVersions)
|
|
214
|
-
const intentsRecord = message.payload.intents
|
|
215
|
-
const intentsMap = intentsRecord
|
|
216
|
-
? new Map(Object.entries(intentsRecord))
|
|
217
|
-
: undefined
|
|
218
214
|
sessionManager.resize(
|
|
219
215
|
message.payload.sessionId,
|
|
220
216
|
message.payload.cols,
|
|
221
|
-
message.payload.rows
|
|
222
|
-
intentsMap
|
|
217
|
+
message.payload.rows
|
|
223
218
|
)
|
|
224
219
|
sendOk(socket, message.id)
|
|
225
220
|
break
|
|
@@ -230,8 +225,7 @@ export async function runTerminalManager(): Promise<void> {
|
|
|
230
225
|
message.payload.sessionId,
|
|
231
226
|
message.payload.tabId,
|
|
232
227
|
message.payload.cols,
|
|
233
|
-
message.payload.rows
|
|
234
|
-
message.payload.intent
|
|
228
|
+
message.payload.rows
|
|
235
229
|
)
|
|
236
230
|
sendOk(socket, message.id)
|
|
237
231
|
break
|
|
@@ -249,15 +243,6 @@ export async function runTerminalManager(): Promise<void> {
|
|
|
249
243
|
sessionManager.scrollToBottom(message.payload.sessionId, message.payload.tabId)
|
|
250
244
|
sendOk(socket, message.id)
|
|
251
245
|
break
|
|
252
|
-
case 'reapplyScrollIntent':
|
|
253
|
-
requireNegotiatedVersion(socket, negotiatedVersions)
|
|
254
|
-
sessionManager.reapplyScrollIntent(
|
|
255
|
-
message.payload.sessionId,
|
|
256
|
-
message.payload.tabId,
|
|
257
|
-
message.payload.intent
|
|
258
|
-
)
|
|
259
|
-
sendOk(socket, message.id)
|
|
260
|
-
break
|
|
261
246
|
case 'setActiveTab':
|
|
262
247
|
requireNegotiatedVersion(socket, negotiatedVersions)
|
|
263
248
|
sessionManager.setActiveTab(message.payload.sessionId, message.payload.tabId)
|