@jmoyers/harness 0.1.10 → 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.
- package/README.md +31 -35
- package/package.json +31 -11
- package/packages/harness-ai/src/anthropic-protocol.ts +68 -68
- package/packages/harness-ai/src/stream-text.ts +13 -91
- package/packages/harness-ui/src/frame-primitives.ts +158 -0
- package/packages/harness-ui/src/index.ts +18 -0
- package/packages/harness-ui/src/interaction/conversation-input-forwarder.ts +221 -0
- package/packages/harness-ui/src/interaction/conversation-selection-input.ts +213 -0
- package/packages/harness-ui/src/interaction/global-shortcut-input.ts +172 -0
- package/{src/ui → packages/harness-ui/src/interaction}/input-preflight.ts +10 -12
- package/{src/ui → packages/harness-ui/src/interaction}/input-token-router.ts +120 -69
- package/packages/harness-ui/src/interaction/input.ts +420 -0
- package/packages/harness-ui/src/interaction/left-nav-input.ts +166 -0
- package/{src/ui → packages/harness-ui/src/interaction}/main-pane-pointer-input.ts +91 -23
- package/{src/ui → packages/harness-ui/src/interaction}/pointer-routing-input.ts +112 -48
- package/packages/harness-ui/src/interaction/rail-pointer-input.ts +62 -0
- package/packages/harness-ui/src/interaction/repository-fold-input.ts +118 -0
- package/packages/harness-ui/src/kit.ts +476 -0
- package/packages/harness-ui/src/layout.ts +238 -0
- package/{src/ui/modals/manager.ts → packages/harness-ui/src/modal-manager.ts} +94 -64
- package/{src/ui → packages/harness-ui/src}/screen.ts +53 -26
- package/packages/harness-ui/src/surface.ts +252 -0
- package/packages/harness-ui/src/text-layout.ts +210 -0
- package/packages/nim-core/src/contracts.ts +239 -0
- package/packages/nim-core/src/event-store.ts +299 -0
- package/packages/nim-core/src/events.ts +53 -0
- package/packages/nim-core/src/index.ts +9 -0
- package/packages/nim-core/src/provider-router.ts +129 -0
- package/packages/nim-core/src/providers/anthropic-driver.ts +291 -0
- package/packages/nim-core/src/runtime-factory.ts +49 -0
- package/packages/nim-core/src/runtime.ts +1797 -0
- package/packages/nim-core/src/session-store.ts +516 -0
- package/packages/nim-core/src/telemetry.ts +48 -0
- package/packages/nim-test-tui/src/index.ts +150 -0
- package/packages/nim-ui-core/src/index.ts +1 -0
- package/packages/nim-ui-core/src/projection.ts +87 -0
- package/scripts/codex-live-mux-runtime.ts +2 -3721
- package/scripts/control-plane-daemon.ts +24 -2
- package/scripts/harness-bin.js +5 -0
- package/scripts/harness-commands.ts +300 -0
- package/scripts/harness-runtime.ts +82 -0
- package/scripts/harness.ts +33 -3007
- package/scripts/nim-tui-smoke.ts +748 -0
- package/src/cli/auth/runtime.ts +948 -0
- package/src/cli/default-gateway-pointer.ts +193 -0
- package/src/cli/gateway/runtime.ts +1872 -0
- package/src/cli/parsing/flags.ts +23 -0
- package/src/cli/parsing/session.ts +42 -0
- package/src/cli/runtime/context.ts +193 -0
- package/src/cli/runtime-app/application.ts +392 -0
- package/src/cli/runtime-infra/gateway-control.ts +729 -0
- package/{scripts/harness-inspector.ts → src/cli/workflows/inspector.ts} +14 -11
- package/src/cli/workflows/runtime.ts +965 -0
- package/src/clients/tui/left-rail-interactions.ts +519 -0
- package/src/clients/tui/main-pane-interactions.ts +509 -0
- package/src/clients/tui/modal-input-routing.ts +71 -0
- package/src/clients/tui/render-snapshot-adapter.ts +88 -0
- package/src/clients/web/synced-selectors.ts +132 -0
- package/src/codex/live-session.ts +82 -29
- package/src/config/config-core.ts +361 -10
- package/src/config/harness-paths.ts +4 -7
- package/src/config/harness-runtime-migration.ts +142 -19
- package/src/config/harness.config.template.jsonc +33 -0
- package/src/config/secrets-core.ts +92 -4
- package/src/control-plane/agent-realtime-api.ts +82 -427
- package/src/control-plane/prompt/thread-title-namer.ts +49 -23
- package/src/control-plane/session-summary.ts +10 -81
- package/src/control-plane/status/reducer-base.ts +12 -12
- package/src/control-plane/status/reducers/claude-status-reducer.ts +3 -3
- package/src/control-plane/status/reducers/codex-status-reducer.ts +4 -4
- package/src/control-plane/status/reducers/cursor-status-reducer.ts +3 -3
- package/src/control-plane/stream-client.ts +12 -2
- package/src/control-plane/stream-command-parser.ts +83 -143
- package/src/control-plane/stream-protocol.ts +53 -37
- package/src/control-plane/stream-server-background.ts +18 -2
- package/src/control-plane/stream-server-command.ts +376 -69
- package/src/control-plane/stream-server-session-runtime.ts +3 -2
- package/src/control-plane/stream-server.ts +943 -80
- package/src/control-plane/stream-session-runtime-types.ts +41 -0
- package/src/{mux/live-mux/control-plane-records.ts → core/contracts/records.ts} +24 -97
- package/src/core/state/observed-stream-cursor.ts +43 -0
- package/src/core/state/synced-observed-state.ts +273 -0
- package/src/core/store/harness-synced-store.ts +81 -0
- package/src/diff/budget.ts +136 -0
- package/src/diff/build.ts +289 -0
- package/src/diff/chunker.ts +146 -0
- package/src/diff/git-invoke.ts +315 -0
- package/src/diff/git-parse.ts +472 -0
- package/src/diff/hash.ts +70 -0
- package/src/diff/index.ts +24 -0
- package/src/diff/normalize.ts +134 -0
- package/src/diff/types.ts +178 -0
- package/src/diff-ui/args.ts +346 -0
- package/src/diff-ui/commands.ts +123 -0
- package/src/diff-ui/finder.ts +94 -0
- package/src/diff-ui/highlight.ts +127 -0
- package/src/diff-ui/index.ts +2 -0
- package/src/diff-ui/model.ts +141 -0
- package/src/diff-ui/pager.ts +412 -0
- package/src/diff-ui/render.ts +337 -0
- package/src/diff-ui/runtime.ts +379 -0
- package/src/diff-ui/state.ts +224 -0
- package/src/diff-ui/types.ts +236 -0
- package/src/domain/conversations.ts +11 -7
- package/src/domain/workspace.ts +76 -4
- package/src/mux/control-plane-op-queue.ts +93 -7
- package/src/mux/conversation-rail.ts +28 -71
- package/src/mux/dual-pane-core.ts +13 -13
- package/src/mux/harness-core-ui.ts +313 -42
- package/src/mux/input-shortcuts.ts +22 -112
- package/src/mux/keybinding-catalog.ts +340 -0
- package/src/mux/keybinding-registry.ts +103 -0
- package/src/mux/live-mux/command-menu-open-in.ts +280 -0
- package/src/mux/live-mux/command-menu.ts +167 -4
- package/src/mux/live-mux/conversation-state.ts +13 -0
- package/src/mux/live-mux/directory-resolution.ts +1 -1
- package/src/mux/live-mux/git-parsing.ts +16 -0
- package/src/mux/live-mux/git-snapshot.ts +33 -2
- package/src/mux/live-mux/global-shortcut-handlers.ts +6 -0
- package/src/mux/live-mux/home-pane-drop.ts +1 -1
- package/src/mux/live-mux/home-pane-pointer.ts +10 -0
- package/src/mux/live-mux/input-forwarding.ts +59 -2
- package/src/mux/live-mux/left-nav-activation.ts +124 -7
- package/src/mux/live-mux/left-nav.ts +35 -0
- package/src/mux/live-mux/link-click.ts +292 -0
- package/src/mux/live-mux/modal-command-menu-handler.ts +46 -9
- package/src/mux/live-mux/modal-conversation-handlers.ts +5 -1
- package/src/mux/live-mux/modal-input-reducers.ts +106 -8
- package/src/mux/live-mux/modal-overlays.ts +210 -31
- package/src/mux/live-mux/modal-pointer.ts +3 -7
- package/src/mux/live-mux/modal-prompt-handlers.ts +107 -1
- package/src/mux/live-mux/modal-release-notes-handler.ts +111 -0
- package/src/mux/live-mux/modal-task-editor-handler.ts +16 -11
- package/src/mux/live-mux/pointer-routing.ts +5 -2
- package/src/mux/live-mux/project-pane-pointer.ts +8 -0
- package/src/mux/live-mux/rail-layout.ts +33 -30
- package/src/mux/live-mux/release-notes.ts +383 -0
- package/src/mux/live-mux/render-trace-analysis.ts +52 -7
- package/src/mux/live-mux/repository-folding.ts +3 -0
- package/src/mux/live-mux/selection.ts +0 -4
- package/src/mux/live-mux/session-diagnostics-paths.ts +21 -0
- package/src/mux/project-pane-github-review.ts +271 -0
- package/src/mux/render-frame.ts +4 -0
- package/src/mux/runtime-app/codex-live-mux-runtime.ts +5191 -0
- package/src/mux/task-composer.ts +21 -14
- package/src/mux/task-focused-pane.ts +118 -117
- package/src/mux/task-screen-keybindings.ts +19 -82
- package/src/mux/workspace-rail-model.ts +270 -104
- package/src/mux/workspace-rail.ts +45 -22
- package/src/pty/session-broker.ts +1 -1
- package/{scripts → src/recording}/terminal-recording-gif-lib.ts +2 -2
- package/src/services/control-plane.ts +50 -32
- package/src/services/conversation-lifecycle.ts +118 -87
- package/src/services/conversation-startup-hydration.ts +20 -12
- package/src/services/directory-hydration.ts +21 -16
- package/src/services/event-persistence.ts +7 -0
- package/src/services/left-rail-pointer-handler.ts +329 -0
- package/src/services/mux-ui-state-persistence.ts +5 -1
- package/src/services/recording.ts +34 -26
- package/src/services/runtime-command-menu-agent-tools.ts +1 -1
- package/src/services/runtime-control-actions.ts +79 -61
- package/src/services/runtime-control-plane-ops.ts +122 -83
- package/src/services/runtime-conversation-actions.ts +40 -26
- package/src/services/runtime-conversation-activation.ts +82 -30
- package/src/services/runtime-conversation-starter.ts +80 -48
- package/src/services/runtime-conversation-title-edit.ts +91 -80
- package/src/services/runtime-envelope-handler.ts +107 -105
- package/src/services/runtime-git-state.ts +42 -29
- package/src/services/runtime-layout-resize.ts +3 -1
- package/src/services/runtime-left-rail-render.ts +99 -63
- package/src/services/runtime-nim-cli-session.ts +438 -0
- package/src/services/runtime-nim-session.ts +705 -0
- package/src/services/runtime-nim-tool-bridge.ts +141 -0
- package/src/services/runtime-observed-event-projection-pipeline.ts +45 -0
- package/src/services/runtime-process-wiring.ts +29 -36
- package/src/services/runtime-project-pane-github-review-cache.ts +164 -0
- package/src/services/runtime-render-flush.ts +63 -70
- package/src/services/runtime-render-lifecycle.ts +65 -64
- package/src/services/runtime-render-orchestrator.ts +55 -45
- package/src/services/runtime-render-pipeline.ts +106 -103
- package/src/services/runtime-render-state.ts +62 -49
- package/src/services/runtime-repository-actions.ts +97 -70
- package/src/services/runtime-right-pane-render.ts +80 -53
- package/src/services/runtime-shutdown.ts +38 -35
- package/src/services/runtime-stream-subscriptions.ts +35 -27
- package/src/services/runtime-task-composer-persistence.ts +71 -59
- package/src/services/runtime-task-composer-snapshot.ts +14 -0
- package/src/services/runtime-task-editor-actions.ts +46 -29
- package/src/services/runtime-task-pane-actions.ts +220 -134
- package/src/services/runtime-task-pane-shortcuts.ts +323 -123
- package/src/services/runtime-workspace-observed-effect-queue.ts +25 -0
- package/src/services/runtime-workspace-observed-events.ts +33 -184
- package/src/services/runtime-workspace-observed-transition-policy.ts +228 -0
- package/src/services/session-diagnostics-store.ts +217 -0
- package/src/services/startup-background-resume.ts +26 -21
- package/src/services/startup-orchestrator.ts +16 -13
- package/src/services/startup-paint-tracker.ts +29 -21
- package/src/services/startup-persisted-conversation-queue.ts +19 -13
- package/src/services/startup-settled-gate.ts +25 -15
- package/src/services/startup-shutdown.ts +18 -22
- package/src/services/startup-state-hydration.ts +44 -34
- package/src/services/startup-visibility.ts +12 -4
- package/src/services/task-pane-selection-actions.ts +89 -72
- package/src/services/task-planning-hydration.ts +24 -18
- package/src/services/task-planning-observed-events.ts +50 -52
- package/src/services/workspace-observed-events.ts +66 -63
- package/src/storage/storage-lifecycle-core.ts +438 -0
- package/src/store/control-plane-store-normalize.ts +33 -242
- package/src/store/control-plane-store-types.ts +1 -35
- package/src/store/control-plane-store.ts +396 -56
- package/src/store/event-store.ts +397 -3
- package/src/terminal/snapshot-oracle.ts +207 -94
- package/src/ui/mux-theme.ts +112 -8
- package/src/ui/panes/home-gridfire.ts +40 -31
- package/src/ui/panes/home.ts +10 -2
- package/src/ui/panes/nim.ts +315 -0
- package/src/mux/live-mux/actions-task.ts +0 -115
- package/src/mux/live-mux/left-rail-actions.ts +0 -118
- package/src/mux/live-mux/left-rail-conversation-click.ts +0 -82
- package/src/mux/live-mux/left-rail-pointer.ts +0 -74
- package/src/mux/live-mux/task-pane-shortcuts.ts +0 -206
- package/src/services/runtime-directory-actions.ts +0 -164
- package/src/services/runtime-input-pipeline.ts +0 -50
- package/src/services/runtime-input-router.ts +0 -189
- package/src/services/runtime-main-pane-input.ts +0 -230
- package/src/services/runtime-modal-input.ts +0 -119
- package/src/services/runtime-navigation-input.ts +0 -197
- package/src/services/runtime-rail-input.ts +0 -278
- package/src/services/runtime-task-pane.ts +0 -62
- package/src/services/runtime-workspace-actions.ts +0 -158
- package/src/ui/conversation-input-forwarder.ts +0 -114
- package/src/ui/conversation-selection-input.ts +0 -103
- package/src/ui/global-shortcut-input.ts +0 -89
- package/src/ui/input.ts +0 -238
- package/src/ui/kit.ts +0 -509
- package/src/ui/left-nav-input.ts +0 -80
- package/src/ui/left-rail-pointer-input.ts +0 -148
- package/src/ui/repository-fold-input.ts +0 -91
- package/src/ui/surface.ts +0 -224
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
const MIN_LEFT_PANE_COLS = 28;
|
|
2
|
+
const MIN_RIGHT_PANE_COLS = 20;
|
|
3
|
+
const DEFAULT_LEFT_PANE_WIDTH_PERCENT = 30;
|
|
4
|
+
const MIN_PANE_WIDTH_PERCENT = 1;
|
|
5
|
+
const MAX_PANE_WIDTH_PERCENT = 99;
|
|
6
|
+
const DEFAULT_BASE_LAYER_Z_INDEX = 0;
|
|
7
|
+
const DEFAULT_OVERLAY_LAYER_Z_INDEX = 100;
|
|
8
|
+
|
|
9
|
+
export interface UiLayoutRect {
|
|
10
|
+
readonly col: number;
|
|
11
|
+
readonly row: number;
|
|
12
|
+
readonly cols: number;
|
|
13
|
+
readonly rows: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type UiLayoutAnchor = 'viewport' | 'left-pane' | 'right-pane' | 'status';
|
|
17
|
+
|
|
18
|
+
export interface UiLayoutOverlay {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly col: number;
|
|
21
|
+
readonly row: number;
|
|
22
|
+
readonly cols: number;
|
|
23
|
+
readonly rows: number;
|
|
24
|
+
readonly anchor?: UiLayoutAnchor;
|
|
25
|
+
readonly zIndex?: number;
|
|
26
|
+
readonly clipToViewport?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ComputeUiLayoutOptions {
|
|
30
|
+
readonly leftCols?: number;
|
|
31
|
+
readonly paneWidthPercent?: number;
|
|
32
|
+
readonly statusRows?: number;
|
|
33
|
+
readonly overlays?: readonly UiLayoutOverlay[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UiLayoutLayer {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly kind: 'left-pane' | 'separator' | 'right-pane' | 'status' | 'overlay';
|
|
39
|
+
readonly zIndex: number;
|
|
40
|
+
readonly rect: UiLayoutRect;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface UiDualPaneLayout {
|
|
44
|
+
readonly cols: number;
|
|
45
|
+
readonly rows: number;
|
|
46
|
+
readonly paneRows: number;
|
|
47
|
+
readonly statusRow: number;
|
|
48
|
+
readonly leftCols: number;
|
|
49
|
+
readonly rightCols: number;
|
|
50
|
+
readonly separatorCol: number;
|
|
51
|
+
readonly rightStartCol: number;
|
|
52
|
+
readonly viewport: UiLayoutRect;
|
|
53
|
+
readonly leftPane: UiLayoutRect;
|
|
54
|
+
readonly separator: UiLayoutRect;
|
|
55
|
+
readonly rightPane: UiLayoutRect;
|
|
56
|
+
readonly status: UiLayoutRect;
|
|
57
|
+
readonly layers: readonly UiLayoutLayer[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function clamp(value: number, min: number, max: number): number {
|
|
61
|
+
if (value < min) {
|
|
62
|
+
return min;
|
|
63
|
+
}
|
|
64
|
+
if (value > max) {
|
|
65
|
+
return max;
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeInt(value: number, minimum: number): number {
|
|
71
|
+
if (!Number.isFinite(value)) {
|
|
72
|
+
return minimum;
|
|
73
|
+
}
|
|
74
|
+
return Math.max(minimum, Math.floor(value));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function normalizePaneWidthPercent(value: number): number {
|
|
78
|
+
if (!Number.isFinite(value)) {
|
|
79
|
+
return DEFAULT_LEFT_PANE_WIDTH_PERCENT;
|
|
80
|
+
}
|
|
81
|
+
return clamp(value, MIN_PANE_WIDTH_PERCENT, MAX_PANE_WIDTH_PERCENT);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveLeftPaneCols(
|
|
85
|
+
normalizedCols: number,
|
|
86
|
+
requestedLeftCols: number | undefined,
|
|
87
|
+
paneWidthPercent: number | undefined,
|
|
88
|
+
): number {
|
|
89
|
+
const availablePaneCols = normalizedCols - 1;
|
|
90
|
+
const percent = normalizePaneWidthPercent(paneWidthPercent ?? DEFAULT_LEFT_PANE_WIDTH_PERCENT);
|
|
91
|
+
const defaultLeftCols = Math.round((availablePaneCols * percent) / 100);
|
|
92
|
+
const requested =
|
|
93
|
+
requestedLeftCols === undefined ? defaultLeftCols : Math.floor(requestedLeftCols);
|
|
94
|
+
|
|
95
|
+
let leftCols = clamp(requested, 1, availablePaneCols - 1);
|
|
96
|
+
if (normalizedCols >= MIN_LEFT_PANE_COLS + MIN_RIGHT_PANE_COLS + 1) {
|
|
97
|
+
leftCols = Math.max(MIN_LEFT_PANE_COLS, leftCols);
|
|
98
|
+
const maxLeft = availablePaneCols - MIN_RIGHT_PANE_COLS;
|
|
99
|
+
leftCols = Math.min(leftCols, maxLeft);
|
|
100
|
+
}
|
|
101
|
+
return leftCols;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function rect(col: number, row: number, cols: number, rows: number): UiLayoutRect {
|
|
105
|
+
return {
|
|
106
|
+
col,
|
|
107
|
+
row,
|
|
108
|
+
cols: Math.max(1, cols),
|
|
109
|
+
rows: Math.max(1, rows),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function anchorRect(
|
|
114
|
+
layout: Omit<UiDualPaneLayout, 'layers'>,
|
|
115
|
+
anchor: UiLayoutAnchor,
|
|
116
|
+
): UiLayoutRect {
|
|
117
|
+
if (anchor === 'left-pane') {
|
|
118
|
+
return layout.leftPane;
|
|
119
|
+
}
|
|
120
|
+
if (anchor === 'right-pane') {
|
|
121
|
+
return layout.rightPane;
|
|
122
|
+
}
|
|
123
|
+
if (anchor === 'status') {
|
|
124
|
+
return layout.status;
|
|
125
|
+
}
|
|
126
|
+
return layout.viewport;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function intersectRect(left: UiLayoutRect, right: UiLayoutRect): UiLayoutRect | null {
|
|
130
|
+
const startCol = Math.max(left.col, right.col);
|
|
131
|
+
const startRow = Math.max(left.row, right.row);
|
|
132
|
+
const endCol = Math.min(left.col + left.cols - 1, right.col + right.cols - 1);
|
|
133
|
+
const endRow = Math.min(left.row + left.rows - 1, right.row + right.rows - 1);
|
|
134
|
+
if (endCol < startCol || endRow < startRow) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
return rect(startCol, startRow, endCol - startCol + 1, endRow - startRow + 1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function computeDualPaneLayoutWithLayers(
|
|
141
|
+
cols: number,
|
|
142
|
+
rows: number,
|
|
143
|
+
options: ComputeUiLayoutOptions = {},
|
|
144
|
+
): UiDualPaneLayout {
|
|
145
|
+
const normalizedCols = normalizeInt(cols, 3);
|
|
146
|
+
const normalizedRows = normalizeInt(rows, 2);
|
|
147
|
+
const requestedStatusRows = normalizeInt(options.statusRows ?? 1, 1);
|
|
148
|
+
const statusRows = Math.min(requestedStatusRows, normalizedRows - 1);
|
|
149
|
+
const paneRows = normalizedRows - statusRows;
|
|
150
|
+
const statusRow = paneRows + 1;
|
|
151
|
+
|
|
152
|
+
const availablePaneCols = normalizedCols - 1;
|
|
153
|
+
const leftCols = resolveLeftPaneCols(normalizedCols, options.leftCols, options.paneWidthPercent);
|
|
154
|
+
const rightCols = availablePaneCols - leftCols;
|
|
155
|
+
const separatorCol = leftCols + 1;
|
|
156
|
+
const rightStartCol = leftCols + 2;
|
|
157
|
+
|
|
158
|
+
const layoutBase = {
|
|
159
|
+
cols: normalizedCols,
|
|
160
|
+
rows: normalizedRows,
|
|
161
|
+
paneRows,
|
|
162
|
+
statusRow,
|
|
163
|
+
leftCols,
|
|
164
|
+
rightCols,
|
|
165
|
+
separatorCol,
|
|
166
|
+
rightStartCol,
|
|
167
|
+
viewport: rect(1, 1, normalizedCols, normalizedRows),
|
|
168
|
+
leftPane: rect(1, 1, leftCols, paneRows),
|
|
169
|
+
separator: rect(separatorCol, 1, 1, paneRows),
|
|
170
|
+
rightPane: rect(rightStartCol, 1, rightCols, paneRows),
|
|
171
|
+
status: rect(1, statusRow, normalizedCols, statusRows),
|
|
172
|
+
} satisfies Omit<UiDualPaneLayout, 'layers'>;
|
|
173
|
+
|
|
174
|
+
const layers: UiLayoutLayer[] = [
|
|
175
|
+
{
|
|
176
|
+
id: 'left-pane',
|
|
177
|
+
kind: 'left-pane',
|
|
178
|
+
zIndex: DEFAULT_BASE_LAYER_Z_INDEX,
|
|
179
|
+
rect: layoutBase.leftPane,
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: 'separator',
|
|
183
|
+
kind: 'separator',
|
|
184
|
+
zIndex: DEFAULT_BASE_LAYER_Z_INDEX,
|
|
185
|
+
rect: layoutBase.separator,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: 'right-pane',
|
|
189
|
+
kind: 'right-pane',
|
|
190
|
+
zIndex: DEFAULT_BASE_LAYER_Z_INDEX,
|
|
191
|
+
rect: layoutBase.rightPane,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: 'status',
|
|
195
|
+
kind: 'status',
|
|
196
|
+
zIndex: DEFAULT_BASE_LAYER_Z_INDEX,
|
|
197
|
+
rect: layoutBase.status,
|
|
198
|
+
},
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
for (const overlay of options.overlays ?? []) {
|
|
202
|
+
if (overlay.id.trim().length === 0) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const overlayAnchor = anchorRect(layoutBase, overlay.anchor ?? 'viewport');
|
|
206
|
+
const absoluteRect = rect(
|
|
207
|
+
overlayAnchor.col + overlay.col - 1,
|
|
208
|
+
overlayAnchor.row + overlay.row - 1,
|
|
209
|
+
overlay.cols,
|
|
210
|
+
overlay.rows,
|
|
211
|
+
);
|
|
212
|
+
const resolvedRect =
|
|
213
|
+
overlay.clipToViewport === false
|
|
214
|
+
? absoluteRect
|
|
215
|
+
: intersectRect(absoluteRect, layoutBase.viewport);
|
|
216
|
+
if (resolvedRect === null) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
layers.push({
|
|
220
|
+
id: overlay.id,
|
|
221
|
+
kind: 'overlay',
|
|
222
|
+
zIndex: overlay.zIndex ?? DEFAULT_OVERLAY_LAYER_Z_INDEX,
|
|
223
|
+
rect: resolvedRect,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const sortedLayers = layers.toSorted((left, right) => {
|
|
228
|
+
if (left.zIndex !== right.zIndex) {
|
|
229
|
+
return left.zIndex - right.zIndex;
|
|
230
|
+
}
|
|
231
|
+
return left.id.localeCompare(right.id);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
...layoutBase,
|
|
236
|
+
layers: sortedLayers,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
@@ -1,29 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildCommandMenuModalOverlay as buildCommandMenuModalOverlayFrame,
|
|
3
|
-
buildAddDirectoryModalOverlay as buildAddDirectoryModalOverlayFrame,
|
|
4
|
-
buildConversationTitleModalOverlay as buildConversationTitleModalOverlayFrame,
|
|
5
|
-
buildNewThreadModalOverlay as buildNewThreadModalOverlayFrame,
|
|
6
|
-
buildRepositoryModalOverlay as buildRepositoryModalOverlayFrame,
|
|
7
|
-
buildTaskEditorModalOverlay as buildTaskEditorModalOverlayFrame,
|
|
8
|
-
} from '../../mux/live-mux/modal-overlays.ts';
|
|
9
|
-
import { dismissModalOnOutsideClick as dismissModalOnOutsideClickFrame } from '../../mux/live-mux/modal-pointer.ts';
|
|
1
|
+
import type { UiModalOverlay, UiModalTheme } from './kit.ts';
|
|
10
2
|
import type {
|
|
3
|
+
ApiKeyPromptState,
|
|
11
4
|
CommandMenuActionDescriptor,
|
|
12
5
|
CommandMenuState,
|
|
13
|
-
} from '../../mux/live-mux/command-menu.ts';
|
|
14
|
-
import type { createNewThreadPromptState } from '../../mux/new-thread-prompt.ts';
|
|
15
|
-
import type {
|
|
16
6
|
ConversationTitleEditState,
|
|
7
|
+
NewThreadPromptState,
|
|
17
8
|
RepositoryPromptState,
|
|
18
9
|
TaskEditorPromptState,
|
|
19
|
-
} from '
|
|
20
|
-
import { isUiModalOverlayHit } from '../kit.ts';
|
|
10
|
+
} from './interaction/input.ts';
|
|
21
11
|
|
|
22
|
-
type NewThreadPromptState = ReturnType<typeof createNewThreadPromptState>;
|
|
23
12
|
type AddDirectoryPromptState = { value: string; error: string | null };
|
|
24
|
-
type ModalOverlay =
|
|
25
|
-
type ModalTheme =
|
|
26
|
-
type DismissModalOnOutsideClickInput = Parameters<typeof dismissModalOnOutsideClickFrame>[0];
|
|
13
|
+
type ModalOverlay = UiModalOverlay;
|
|
14
|
+
type ModalTheme = Partial<UiModalTheme>;
|
|
27
15
|
|
|
28
16
|
interface ModalManagerOptions {
|
|
29
17
|
readonly theme: ModalTheme;
|
|
@@ -32,20 +20,75 @@ interface ModalManagerOptions {
|
|
|
32
20
|
readonly resolveCommandMenuActions: () => readonly CommandMenuActionDescriptor[];
|
|
33
21
|
readonly getNewThreadPrompt: () => NewThreadPromptState | null;
|
|
34
22
|
readonly getAddDirectoryPrompt: () => AddDirectoryPromptState | null;
|
|
23
|
+
readonly getApiKeyPrompt?: () => ApiKeyPromptState | null;
|
|
35
24
|
readonly getTaskEditorPrompt: () => TaskEditorPromptState | null;
|
|
36
25
|
readonly getRepositoryPrompt: () => RepositoryPromptState | null;
|
|
37
26
|
readonly getConversationTitleEdit: () => ConversationTitleEditState | null;
|
|
38
27
|
}
|
|
39
28
|
|
|
40
|
-
interface
|
|
41
|
-
readonly
|
|
42
|
-
readonly
|
|
43
|
-
readonly
|
|
44
|
-
readonly
|
|
45
|
-
readonly
|
|
46
|
-
readonly
|
|
47
|
-
|
|
48
|
-
|
|
29
|
+
export interface ModalDismissOnOutsideClickInput {
|
|
30
|
+
readonly input: Buffer;
|
|
31
|
+
readonly inputRemainder: string;
|
|
32
|
+
readonly dismiss: () => void;
|
|
33
|
+
readonly buildCurrentModalOverlay: () => ModalOverlay | null;
|
|
34
|
+
readonly onInsidePointerPress?: (col: number, row: number) => boolean;
|
|
35
|
+
readonly isOverlayHit: (overlay: ModalOverlay, col: number, row: number) => boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ModalDismissOnOutsideClickResult {
|
|
39
|
+
readonly handled: boolean;
|
|
40
|
+
readonly inputRemainder: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ModalManagerStrategies {
|
|
44
|
+
buildCommandMenuModalOverlay(
|
|
45
|
+
layoutCols: number,
|
|
46
|
+
viewportRows: number,
|
|
47
|
+
menu: CommandMenuState | null,
|
|
48
|
+
actions: readonly CommandMenuActionDescriptor[],
|
|
49
|
+
theme: ModalTheme,
|
|
50
|
+
): ModalOverlay | null;
|
|
51
|
+
buildNewThreadModalOverlay(
|
|
52
|
+
layoutCols: number,
|
|
53
|
+
viewportRows: number,
|
|
54
|
+
prompt: NewThreadPromptState | null,
|
|
55
|
+
theme: ModalTheme,
|
|
56
|
+
): ModalOverlay | null;
|
|
57
|
+
buildAddDirectoryModalOverlay(
|
|
58
|
+
layoutCols: number,
|
|
59
|
+
viewportRows: number,
|
|
60
|
+
prompt: AddDirectoryPromptState | null,
|
|
61
|
+
theme: ModalTheme,
|
|
62
|
+
): ModalOverlay | null;
|
|
63
|
+
buildTaskEditorModalOverlay(
|
|
64
|
+
layoutCols: number,
|
|
65
|
+
viewportRows: number,
|
|
66
|
+
prompt: TaskEditorPromptState | null,
|
|
67
|
+
resolveRepositoryName: (repositoryId: string) => string | null,
|
|
68
|
+
theme: ModalTheme,
|
|
69
|
+
): ModalOverlay | null;
|
|
70
|
+
buildApiKeyModalOverlay(
|
|
71
|
+
layoutCols: number,
|
|
72
|
+
viewportRows: number,
|
|
73
|
+
prompt: ApiKeyPromptState | null,
|
|
74
|
+
theme: ModalTheme,
|
|
75
|
+
): ModalOverlay | null;
|
|
76
|
+
buildRepositoryModalOverlay(
|
|
77
|
+
layoutCols: number,
|
|
78
|
+
viewportRows: number,
|
|
79
|
+
prompt: RepositoryPromptState | null,
|
|
80
|
+
theme: ModalTheme,
|
|
81
|
+
): ModalOverlay | null;
|
|
82
|
+
buildConversationTitleModalOverlay(
|
|
83
|
+
layoutCols: number,
|
|
84
|
+
viewportRows: number,
|
|
85
|
+
edit: ConversationTitleEditState | null,
|
|
86
|
+
theme: ModalTheme,
|
|
87
|
+
): ModalOverlay | null;
|
|
88
|
+
dismissModalOnOutsideClick(
|
|
89
|
+
input: ModalDismissOnOutsideClickInput,
|
|
90
|
+
): ModalDismissOnOutsideClickResult;
|
|
91
|
+
isOverlayHit(overlay: ModalOverlay, col: number, row: number): boolean;
|
|
49
92
|
}
|
|
50
93
|
|
|
51
94
|
interface ModalDismissInput {
|
|
@@ -63,38 +106,13 @@ interface ModalDismissResult {
|
|
|
63
106
|
}
|
|
64
107
|
|
|
65
108
|
export class ModalManager {
|
|
66
|
-
private readonly buildCommandMenuModalOverlay: typeof buildCommandMenuModalOverlayFrame;
|
|
67
|
-
private readonly buildNewThreadModalOverlay: typeof buildNewThreadModalOverlayFrame;
|
|
68
|
-
private readonly buildAddDirectoryModalOverlay: typeof buildAddDirectoryModalOverlayFrame;
|
|
69
|
-
private readonly buildTaskEditorModalOverlay: typeof buildTaskEditorModalOverlayFrame;
|
|
70
|
-
private readonly buildRepositoryModalOverlay: typeof buildRepositoryModalOverlayFrame;
|
|
71
|
-
private readonly buildConversationTitleModalOverlay: typeof buildConversationTitleModalOverlayFrame;
|
|
72
|
-
private readonly dismissModalOnOutsideClick: typeof dismissModalOnOutsideClickFrame;
|
|
73
|
-
private readonly isOverlayHit: typeof isUiModalOverlayHit;
|
|
74
|
-
|
|
75
109
|
constructor(
|
|
76
110
|
private readonly options: ModalManagerOptions,
|
|
77
|
-
|
|
78
|
-
) {
|
|
79
|
-
this.buildCommandMenuModalOverlay =
|
|
80
|
-
dependencies.buildCommandMenuModalOverlay ?? buildCommandMenuModalOverlayFrame;
|
|
81
|
-
this.buildNewThreadModalOverlay =
|
|
82
|
-
dependencies.buildNewThreadModalOverlay ?? buildNewThreadModalOverlayFrame;
|
|
83
|
-
this.buildAddDirectoryModalOverlay =
|
|
84
|
-
dependencies.buildAddDirectoryModalOverlay ?? buildAddDirectoryModalOverlayFrame;
|
|
85
|
-
this.buildTaskEditorModalOverlay =
|
|
86
|
-
dependencies.buildTaskEditorModalOverlay ?? buildTaskEditorModalOverlayFrame;
|
|
87
|
-
this.buildRepositoryModalOverlay =
|
|
88
|
-
dependencies.buildRepositoryModalOverlay ?? buildRepositoryModalOverlayFrame;
|
|
89
|
-
this.buildConversationTitleModalOverlay =
|
|
90
|
-
dependencies.buildConversationTitleModalOverlay ?? buildConversationTitleModalOverlayFrame;
|
|
91
|
-
this.dismissModalOnOutsideClick =
|
|
92
|
-
dependencies.dismissModalOnOutsideClick ?? dismissModalOnOutsideClickFrame;
|
|
93
|
-
this.isOverlayHit = dependencies.isOverlayHit ?? isUiModalOverlayHit;
|
|
94
|
-
}
|
|
111
|
+
private readonly strategies: ModalManagerStrategies,
|
|
112
|
+
) {}
|
|
95
113
|
|
|
96
114
|
buildCommandMenuOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
97
|
-
return this.buildCommandMenuModalOverlay(
|
|
115
|
+
return this.strategies.buildCommandMenuModalOverlay(
|
|
98
116
|
layoutCols,
|
|
99
117
|
viewportRows,
|
|
100
118
|
this.options.getCommandMenu(),
|
|
@@ -104,7 +122,7 @@ export class ModalManager {
|
|
|
104
122
|
}
|
|
105
123
|
|
|
106
124
|
buildNewThreadOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
107
|
-
return this.buildNewThreadModalOverlay(
|
|
125
|
+
return this.strategies.buildNewThreadModalOverlay(
|
|
108
126
|
layoutCols,
|
|
109
127
|
viewportRows,
|
|
110
128
|
this.options.getNewThreadPrompt(),
|
|
@@ -113,7 +131,7 @@ export class ModalManager {
|
|
|
113
131
|
}
|
|
114
132
|
|
|
115
133
|
buildAddDirectoryOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
116
|
-
return this.buildAddDirectoryModalOverlay(
|
|
134
|
+
return this.strategies.buildAddDirectoryModalOverlay(
|
|
117
135
|
layoutCols,
|
|
118
136
|
viewportRows,
|
|
119
137
|
this.options.getAddDirectoryPrompt(),
|
|
@@ -122,7 +140,7 @@ export class ModalManager {
|
|
|
122
140
|
}
|
|
123
141
|
|
|
124
142
|
buildTaskEditorOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
125
|
-
return this.buildTaskEditorModalOverlay(
|
|
143
|
+
return this.strategies.buildTaskEditorModalOverlay(
|
|
126
144
|
layoutCols,
|
|
127
145
|
viewportRows,
|
|
128
146
|
this.options.getTaskEditorPrompt(),
|
|
@@ -131,8 +149,17 @@ export class ModalManager {
|
|
|
131
149
|
);
|
|
132
150
|
}
|
|
133
151
|
|
|
152
|
+
buildApiKeyOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
153
|
+
return this.strategies.buildApiKeyModalOverlay(
|
|
154
|
+
layoutCols,
|
|
155
|
+
viewportRows,
|
|
156
|
+
this.options.getApiKeyPrompt?.() ?? null,
|
|
157
|
+
this.options.theme,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
134
161
|
buildRepositoryOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
135
|
-
return this.buildRepositoryModalOverlay(
|
|
162
|
+
return this.strategies.buildRepositoryModalOverlay(
|
|
136
163
|
layoutCols,
|
|
137
164
|
viewportRows,
|
|
138
165
|
this.options.getRepositoryPrompt(),
|
|
@@ -141,7 +168,7 @@ export class ModalManager {
|
|
|
141
168
|
}
|
|
142
169
|
|
|
143
170
|
buildConversationTitleOverlay(layoutCols: number, viewportRows: number): ModalOverlay | null {
|
|
144
|
-
return this.buildConversationTitleModalOverlay(
|
|
171
|
+
return this.strategies.buildConversationTitleModalOverlay(
|
|
145
172
|
layoutCols,
|
|
146
173
|
viewportRows,
|
|
147
174
|
this.options.getConversationTitleEdit(),
|
|
@@ -166,6 +193,10 @@ export class ModalManager {
|
|
|
166
193
|
if (taskEditorOverlay !== null) {
|
|
167
194
|
return taskEditorOverlay;
|
|
168
195
|
}
|
|
196
|
+
const apiKeyOverlay = this.buildApiKeyOverlay(layoutCols, viewportRows);
|
|
197
|
+
if (apiKeyOverlay !== null) {
|
|
198
|
+
return apiKeyOverlay;
|
|
199
|
+
}
|
|
169
200
|
const repositoryOverlay = this.buildRepositoryOverlay(layoutCols, viewportRows);
|
|
170
201
|
if (repositoryOverlay !== null) {
|
|
171
202
|
return repositoryOverlay;
|
|
@@ -174,19 +205,18 @@ export class ModalManager {
|
|
|
174
205
|
}
|
|
175
206
|
|
|
176
207
|
dismissOnOutsideClick(input: ModalDismissInput): ModalDismissResult {
|
|
177
|
-
|
|
208
|
+
return this.strategies.dismissModalOnOutsideClick({
|
|
178
209
|
input: input.input,
|
|
179
210
|
inputRemainder: input.inputRemainder,
|
|
180
211
|
dismiss: input.dismiss,
|
|
181
212
|
buildCurrentModalOverlay: () =>
|
|
182
213
|
this.buildCurrentOverlay(input.layoutCols, input.viewportRows),
|
|
183
|
-
isOverlayHit: this.isOverlayHit,
|
|
214
|
+
isOverlayHit: this.strategies.isOverlayHit,
|
|
184
215
|
...(input.onInsidePointerPress === undefined
|
|
185
216
|
? {}
|
|
186
217
|
: {
|
|
187
218
|
onInsidePointerPress: input.onInsidePointerPress,
|
|
188
219
|
}),
|
|
189
|
-
};
|
|
190
|
-
return this.dismissModalOnOutsideClick(dismissInput);
|
|
220
|
+
});
|
|
191
221
|
}
|
|
192
222
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
cursorStyleEqual,
|
|
3
|
+
cursorStyleToDecscusr,
|
|
4
|
+
diffRenderedRows,
|
|
5
|
+
findAnsiIntegrityIssues,
|
|
6
|
+
type RenderCursorStyle,
|
|
7
|
+
} from './frame-primitives.ts';
|
|
4
8
|
|
|
5
|
-
export
|
|
6
|
-
readonly shape: 'block' | 'underline' | 'bar';
|
|
7
|
-
readonly blinking: boolean;
|
|
8
|
-
}
|
|
9
|
+
export type ScreenCursorStyle = RenderCursorStyle;
|
|
9
10
|
|
|
10
11
|
interface ScreenLayout {
|
|
11
12
|
readonly paneRows: number;
|
|
@@ -43,10 +44,33 @@ interface ScreenFlushResult {
|
|
|
43
44
|
readonly shouldShowCursor: boolean;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
interface
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
export interface ScreenWriter {
|
|
48
|
+
writeOutput(output: string): void;
|
|
49
|
+
writeError(output: string): void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class ProcessScreenWriter implements ScreenWriter {
|
|
53
|
+
constructor() {}
|
|
54
|
+
|
|
55
|
+
writeOutput(output: string): void {
|
|
56
|
+
process.stdout.write(output);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
writeError(output: string): void {
|
|
60
|
+
process.stderr.write(output);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ScreenAnsiValidator {
|
|
65
|
+
findIssues(rows: readonly string[]): readonly string[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class DefaultScreenAnsiValidator implements ScreenAnsiValidator {
|
|
69
|
+
constructor() {}
|
|
70
|
+
|
|
71
|
+
findIssues(rows: readonly string[]): readonly string[] {
|
|
72
|
+
return findAnsiIntegrityIssues(rows);
|
|
73
|
+
}
|
|
50
74
|
}
|
|
51
75
|
|
|
52
76
|
const TERMINAL_SYNC_UPDATE_BEGIN = '\u001b[?2026h';
|
|
@@ -66,7 +90,17 @@ function mergeUniqueRows(left: readonly number[], right: readonly number[]): rea
|
|
|
66
90
|
for (const row of right) {
|
|
67
91
|
merged.add(row);
|
|
68
92
|
}
|
|
69
|
-
|
|
93
|
+
const output = [...merged];
|
|
94
|
+
for (let index = 1; index < output.length; index += 1) {
|
|
95
|
+
const value = output[index]!;
|
|
96
|
+
let insertIndex = index - 1;
|
|
97
|
+
while (insertIndex >= 0 && output[insertIndex]! > value) {
|
|
98
|
+
output[insertIndex + 1] = output[insertIndex]!;
|
|
99
|
+
insertIndex -= 1;
|
|
100
|
+
}
|
|
101
|
+
output[insertIndex + 1] = value;
|
|
102
|
+
}
|
|
103
|
+
return output;
|
|
70
104
|
}
|
|
71
105
|
|
|
72
106
|
export class Screen {
|
|
@@ -79,15 +113,10 @@ export class Screen {
|
|
|
79
113
|
private renderedBracketedPaste: boolean | null = null;
|
|
80
114
|
private ansiValidationReported = false;
|
|
81
115
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
writeOutput: deps?.writeOutput ?? ((output) => process.stdout.write(output)),
|
|
87
|
-
writeError: deps?.writeError ?? ((output) => process.stderr.write(output)),
|
|
88
|
-
findAnsiIssues: deps?.findAnsiIssues ?? findAnsiIntegrityIssues,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
116
|
+
constructor(
|
|
117
|
+
private readonly writer: ScreenWriter = new ProcessScreenWriter(),
|
|
118
|
+
private readonly ansiValidator: ScreenAnsiValidator = new DefaultScreenAnsiValidator(),
|
|
119
|
+
) {}
|
|
91
120
|
|
|
92
121
|
isDirty(): boolean {
|
|
93
122
|
return this.dirty;
|
|
@@ -116,10 +145,10 @@ export class Screen {
|
|
|
116
145
|
}
|
|
117
146
|
|
|
118
147
|
if (input.validateAnsi) {
|
|
119
|
-
const issues = this.
|
|
148
|
+
const issues = this.ansiValidator.findIssues(input.rows);
|
|
120
149
|
if (issues.length > 0 && !this.ansiValidationReported) {
|
|
121
150
|
this.ansiValidationReported = true;
|
|
122
|
-
this.
|
|
151
|
+
this.writer.writeError(`[mux] ansi-integrity-failed ${issues.join(' | ')}\n`);
|
|
123
152
|
}
|
|
124
153
|
}
|
|
125
154
|
|
|
@@ -163,7 +192,6 @@ export class Screen {
|
|
|
163
192
|
}
|
|
164
193
|
|
|
165
194
|
output += input.selectionOverlay;
|
|
166
|
-
|
|
167
195
|
shouldShowCursor =
|
|
168
196
|
input.rightFrame.viewport.followOutput &&
|
|
169
197
|
input.rightFrame.cursor.visible &&
|
|
@@ -194,13 +222,12 @@ export class Screen {
|
|
|
194
222
|
}
|
|
195
223
|
|
|
196
224
|
if (output.length > 0) {
|
|
197
|
-
this.
|
|
225
|
+
this.writer.writeOutput(`${TERMINAL_SYNC_UPDATE_BEGIN}${output}${TERMINAL_SYNC_UPDATE_END}`);
|
|
198
226
|
}
|
|
199
227
|
|
|
200
228
|
this.previousRows = diff.nextRows;
|
|
201
229
|
this.previousSelectionRows = input.selectionRows;
|
|
202
230
|
this.dirty = false;
|
|
203
|
-
|
|
204
231
|
return {
|
|
205
232
|
wroteOutput: output.length > 0,
|
|
206
233
|
changedRowCount: diff.changedRows.length,
|