@jmoyers/harness 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/native/ptyd/Cargo.lock +16 -0
- package/native/ptyd/Cargo.toml +7 -0
- package/native/ptyd/src/main.rs +257 -0
- package/package.json +90 -0
- package/scripts/build-ptyd.sh +73 -0
- package/scripts/control-plane-daemon.ts +277 -0
- package/scripts/cursor-hook-relay.ts +82 -0
- package/scripts/harness-animate.ts +469 -0
- package/scripts/harness-bin.js +77 -0
- package/scripts/harness-core.ts +1 -0
- package/scripts/harness-inspector.ts +439 -0
- package/scripts/harness.ts +2493 -0
- package/src/adapters/agent-session-state.ts +390 -0
- package/src/cli/gateway-record.ts +173 -0
- package/src/codex/live-session.ts +872 -0
- package/src/config/config-core.ts +1359 -0
- package/src/config/secrets-core.ts +170 -0
- package/src/control-plane/agent-realtime-api.ts +2441 -0
- package/src/control-plane/codex-session-stream.ts +392 -0
- package/src/control-plane/codex-telemetry.ts +1325 -0
- package/src/control-plane/lifecycle-hooks.ts +706 -0
- package/src/control-plane/session-summary.ts +380 -0
- package/src/control-plane/status/agent-status-reducer.ts +21 -0
- package/src/control-plane/status/reducer-base.ts +170 -0
- package/src/control-plane/status/reducers/claude-status-reducer.ts +37 -0
- package/src/control-plane/status/reducers/codex-status-reducer.ts +48 -0
- package/src/control-plane/status/reducers/critique-status-reducer.ts +15 -0
- package/src/control-plane/status/reducers/cursor-status-reducer.ts +37 -0
- package/src/control-plane/status/reducers/terminal-status-reducer.ts +15 -0
- package/src/control-plane/status/session-status-engine.ts +76 -0
- package/src/control-plane/stream-client.ts +396 -0
- package/src/control-plane/stream-command-parser.ts +1673 -0
- package/src/control-plane/stream-protocol.ts +1808 -0
- package/src/control-plane/stream-server-background.ts +486 -0
- package/src/control-plane/stream-server-command.ts +2557 -0
- package/src/control-plane/stream-server-connection.ts +234 -0
- package/src/control-plane/stream-server-observed-filter.ts +112 -0
- package/src/control-plane/stream-server-session-runtime.ts +566 -0
- package/src/control-plane/stream-server-state-store.ts +15 -0
- package/src/control-plane/stream-server.ts +3192 -0
- package/src/cursor/managed-hooks.ts +282 -0
- package/src/domain/conversations.ts +414 -0
- package/src/domain/directories.ts +78 -0
- package/src/domain/repositories.ts +123 -0
- package/src/domain/tasks.ts +148 -0
- package/src/domain/workspace.ts +156 -0
- package/src/events/normalized-events.ts +124 -0
- package/src/mux/ansi-integrity.ts +103 -0
- package/src/mux/control-plane-op-queue.ts +212 -0
- package/src/mux/conversation-rail.ts +339 -0
- package/src/mux/double-click.ts +78 -0
- package/src/mux/dual-pane-core.ts +435 -0
- package/src/mux/harness-core-ui.ts +817 -0
- package/src/mux/input-shortcuts.ts +667 -0
- package/src/mux/live-mux/actions-conversation.ts +344 -0
- package/src/mux/live-mux/actions-repository.ts +246 -0
- package/src/mux/live-mux/actions-task.ts +115 -0
- package/src/mux/live-mux/args.ts +142 -0
- package/src/mux/live-mux/command-menu.ts +298 -0
- package/src/mux/live-mux/control-plane-records.ts +546 -0
- package/src/mux/live-mux/conversation-state.ts +188 -0
- package/src/mux/live-mux/directory-resolution.ts +34 -0
- package/src/mux/live-mux/event-mapping.ts +96 -0
- package/src/mux/live-mux/gateway-profiler.ts +152 -0
- package/src/mux/live-mux/gateway-render-trace.ts +177 -0
- package/src/mux/live-mux/gateway-status-timeline.ts +166 -0
- package/src/mux/live-mux/git-parsing.ts +131 -0
- package/src/mux/live-mux/git-snapshot.ts +263 -0
- package/src/mux/live-mux/git-state.ts +136 -0
- package/src/mux/live-mux/global-shortcut-handlers.ts +143 -0
- package/src/mux/live-mux/home-pane-actions.ts +58 -0
- package/src/mux/live-mux/home-pane-drop.ts +44 -0
- package/src/mux/live-mux/home-pane-entity-click.ts +96 -0
- package/src/mux/live-mux/home-pane-pointer.ts +96 -0
- package/src/mux/live-mux/input-forwarding.ts +112 -0
- package/src/mux/live-mux/layout.ts +30 -0
- package/src/mux/live-mux/left-nav-activation.ts +103 -0
- package/src/mux/live-mux/left-nav.ts +85 -0
- package/src/mux/live-mux/left-rail-actions.ts +118 -0
- package/src/mux/live-mux/left-rail-conversation-click.ts +82 -0
- package/src/mux/live-mux/left-rail-pointer.ts +74 -0
- package/src/mux/live-mux/modal-command-menu-handler.ts +101 -0
- package/src/mux/live-mux/modal-conversation-handlers.ts +217 -0
- package/src/mux/live-mux/modal-input-reducers.ts +94 -0
- package/src/mux/live-mux/modal-overlays.ts +287 -0
- package/src/mux/live-mux/modal-pointer.ts +70 -0
- package/src/mux/live-mux/modal-prompt-handlers.ts +187 -0
- package/src/mux/live-mux/modal-task-editor-handler.ts +156 -0
- package/src/mux/live-mux/observed-stream.ts +87 -0
- package/src/mux/live-mux/palette-parsing.ts +128 -0
- package/src/mux/live-mux/pointer-routing.ts +108 -0
- package/src/mux/live-mux/process-usage.ts +53 -0
- package/src/mux/live-mux/project-pane-pointer.ts +44 -0
- package/src/mux/live-mux/rail-layout.ts +244 -0
- package/src/mux/live-mux/render-trace-analysis.ts +213 -0
- package/src/mux/live-mux/render-trace-state.ts +84 -0
- package/src/mux/live-mux/repository-folding.ts +207 -0
- package/src/mux/live-mux/runtime-shutdown.ts +51 -0
- package/src/mux/live-mux/selection.ts +411 -0
- package/src/mux/live-mux/startup-utils.ts +187 -0
- package/src/mux/live-mux/status-timeline-state.ts +82 -0
- package/src/mux/live-mux/task-pane-shortcuts.ts +206 -0
- package/src/mux/live-mux/terminal-palette.ts +79 -0
- package/src/mux/new-thread-prompt.ts +165 -0
- package/src/mux/project-tree.ts +295 -0
- package/src/mux/render-frame.ts +113 -0
- package/src/mux/runtime-wiring.ts +185 -0
- package/src/mux/selector-index.ts +160 -0
- package/src/mux/startup-sequencer.ts +238 -0
- package/src/mux/task-composer.ts +289 -0
- package/src/mux/task-focused-pane.ts +417 -0
- package/src/mux/task-screen-keybindings.ts +539 -0
- package/src/mux/terminal-input-modes.ts +35 -0
- package/src/mux/workspace-path.ts +55 -0
- package/src/mux/workspace-rail-model.ts +701 -0
- package/src/mux/workspace-rail.ts +247 -0
- package/src/perf/perf-core.ts +307 -0
- package/src/pty/pty_host.ts +217 -0
- package/src/pty/session-broker.ts +158 -0
- package/src/recording/terminal-recording.ts +383 -0
- package/src/services/control-plane.ts +567 -0
- package/src/services/conversation-lifecycle.ts +176 -0
- package/src/services/conversation-startup-hydration.ts +47 -0
- package/src/services/directory-hydration.ts +49 -0
- package/src/services/event-persistence.ts +104 -0
- package/src/services/mux-ui-state-persistence.ts +82 -0
- package/src/services/output-load-sampler.ts +231 -0
- package/src/services/process-usage-refresh.ts +88 -0
- package/src/services/recording.ts +75 -0
- package/src/services/render-trace-recorder.ts +177 -0
- package/src/services/runtime-control-actions.ts +123 -0
- package/src/services/runtime-control-plane-ops.ts +131 -0
- package/src/services/runtime-conversation-actions.ts +113 -0
- package/src/services/runtime-conversation-activation.ts +78 -0
- package/src/services/runtime-conversation-starter.ts +171 -0
- package/src/services/runtime-conversation-title-edit.ts +149 -0
- package/src/services/runtime-directory-actions.ts +164 -0
- package/src/services/runtime-envelope-handler.ts +198 -0
- package/src/services/runtime-git-state.ts +92 -0
- package/src/services/runtime-input-pipeline.ts +50 -0
- package/src/services/runtime-input-router.ts +202 -0
- package/src/services/runtime-layout-resize.ts +236 -0
- package/src/services/runtime-left-rail-render.ts +159 -0
- package/src/services/runtime-main-pane-input.ts +230 -0
- package/src/services/runtime-modal-input.ts +119 -0
- package/src/services/runtime-navigation-input.ts +207 -0
- package/src/services/runtime-process-wiring.ts +68 -0
- package/src/services/runtime-rail-input.ts +287 -0
- package/src/services/runtime-render-flush.ts +146 -0
- package/src/services/runtime-render-lifecycle.ts +104 -0
- package/src/services/runtime-render-orchestrator.ts +108 -0
- package/src/services/runtime-render-pipeline.ts +167 -0
- package/src/services/runtime-render-state.ts +72 -0
- package/src/services/runtime-repository-actions.ts +197 -0
- package/src/services/runtime-right-pane-render.ts +132 -0
- package/src/services/runtime-shutdown.ts +79 -0
- package/src/services/runtime-stream-subscriptions.ts +56 -0
- package/src/services/runtime-task-composer-persistence.ts +139 -0
- package/src/services/runtime-task-editor-actions.ts +83 -0
- package/src/services/runtime-task-pane-actions.ts +198 -0
- package/src/services/runtime-task-pane-shortcuts.ts +189 -0
- package/src/services/runtime-task-pane.ts +62 -0
- package/src/services/runtime-workspace-actions.ts +153 -0
- package/src/services/runtime-workspace-observed-events.ts +190 -0
- package/src/services/session-projection-instrumentation.ts +190 -0
- package/src/services/startup-background-probe.ts +91 -0
- package/src/services/startup-background-resume.ts +65 -0
- package/src/services/startup-orchestrator.ts +166 -0
- package/src/services/startup-output-tracker.ts +54 -0
- package/src/services/startup-paint-tracker.ts +115 -0
- package/src/services/startup-persisted-conversation-queue.ts +45 -0
- package/src/services/startup-settled-gate.ts +67 -0
- package/src/services/startup-shutdown.ts +53 -0
- package/src/services/startup-span-tracker.ts +77 -0
- package/src/services/startup-state-hydration.ts +94 -0
- package/src/services/startup-visibility.ts +35 -0
- package/src/services/status-timeline-recorder.ts +144 -0
- package/src/services/task-pane-selection-actions.ts +153 -0
- package/src/services/task-planning-hydration.ts +58 -0
- package/src/services/task-planning-observed-events.ts +89 -0
- package/src/services/workspace-observed-events.ts +113 -0
- package/src/store/control-plane-store-normalize.ts +760 -0
- package/src/store/control-plane-store-types.ts +224 -0
- package/src/store/control-plane-store.ts +2951 -0
- package/src/store/event-store.ts +253 -0
- package/src/store/sqlite.ts +81 -0
- package/src/terminal/compat-matrix.ts +345 -0
- package/src/terminal/differential-checkpoints.ts +132 -0
- package/src/terminal/parity-suite.ts +441 -0
- package/src/terminal/snapshot-oracle.ts +1840 -0
- package/src/ui/conversation-input-forwarder.ts +114 -0
- package/src/ui/conversation-selection-input.ts +103 -0
- package/src/ui/debug-footer-notice.ts +39 -0
- package/src/ui/global-shortcut-input.ts +126 -0
- package/src/ui/input-preflight.ts +68 -0
- package/src/ui/input-token-router.ts +312 -0
- package/src/ui/input.ts +238 -0
- package/src/ui/kit.ts +509 -0
- package/src/ui/left-nav-input.ts +80 -0
- package/src/ui/left-rail-pointer-input.ts +148 -0
- package/src/ui/main-pane-pointer-input.ts +150 -0
- package/src/ui/modals/manager.ts +192 -0
- package/src/ui/mux-theme.ts +529 -0
- package/src/ui/panes/conversation.ts +19 -0
- package/src/ui/panes/home-gridfire.ts +302 -0
- package/src/ui/panes/home.ts +109 -0
- package/src/ui/panes/left-rail.ts +12 -0
- package/src/ui/panes/project.ts +44 -0
- package/src/ui/pointer-routing-input.ts +158 -0
- package/src/ui/repository-fold-input.ts +91 -0
- package/src/ui/screen.ts +210 -0
- package/src/ui/surface.ts +224 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { measureDisplayWidth } from '../../terminal/snapshot-oracle.ts';
|
|
2
|
+
import { createUiSurface, renderUiSurfaceAnsiRows, type UiStyle } from '../surface.ts';
|
|
3
|
+
|
|
4
|
+
interface HomeGridfireOptions {
|
|
5
|
+
readonly cols: number;
|
|
6
|
+
readonly rows: number;
|
|
7
|
+
readonly contentRows: readonly string[];
|
|
8
|
+
readonly timeMs: number;
|
|
9
|
+
readonly overlayTitle: string | null;
|
|
10
|
+
readonly overlaySubtitle: string | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type RgbTriplet = readonly [number, number, number];
|
|
14
|
+
|
|
15
|
+
const GRID_CHARS = {
|
|
16
|
+
intersection: '+',
|
|
17
|
+
hline: '─',
|
|
18
|
+
vline: '│',
|
|
19
|
+
dot: '·',
|
|
20
|
+
brightDot: '•',
|
|
21
|
+
node: '◊',
|
|
22
|
+
brightNode: '◆',
|
|
23
|
+
empty: ' ',
|
|
24
|
+
light: '░',
|
|
25
|
+
heavy: '▓',
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
const FG_PALETTE: readonly RgbTriplet[] = [
|
|
29
|
+
[14, 11, 28],
|
|
30
|
+
[28, 20, 55],
|
|
31
|
+
[50, 30, 100],
|
|
32
|
+
[75, 45, 155],
|
|
33
|
+
[55, 85, 200],
|
|
34
|
+
[90, 140, 240],
|
|
35
|
+
[150, 190, 255],
|
|
36
|
+
[220, 235, 255],
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const BG_PALETTE: readonly RgbTriplet[] = [
|
|
40
|
+
[8, 6, 16],
|
|
41
|
+
[12, 10, 22],
|
|
42
|
+
[16, 13, 30],
|
|
43
|
+
[20, 16, 38],
|
|
44
|
+
[18, 20, 45],
|
|
45
|
+
[16, 24, 50],
|
|
46
|
+
[20, 28, 55],
|
|
47
|
+
[24, 32, 58],
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
function lerp(start: number, end: number, t: number): number {
|
|
51
|
+
return start + (end - start) * t;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function clamp01(value: number): number {
|
|
55
|
+
return Math.max(0, Math.min(1, value));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function colorLerp(start: RgbTriplet, end: RgbTriplet, t: number): RgbTriplet {
|
|
59
|
+
return [
|
|
60
|
+
Math.round(lerp(start[0], end[0], t)),
|
|
61
|
+
Math.round(lerp(start[1], end[1], t)),
|
|
62
|
+
Math.round(lerp(start[2], end[2], t)),
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function paletteColor(palette: readonly RgbTriplet[], t: number): RgbTriplet {
|
|
67
|
+
const normalized = clamp01(t);
|
|
68
|
+
const index = normalized * (palette.length - 1);
|
|
69
|
+
const low = Math.floor(index);
|
|
70
|
+
const high = Math.min(low + 1, palette.length - 1);
|
|
71
|
+
return colorLerp(palette[low]!, palette[high]!, index - low);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function styleFromColors(fg: RgbTriplet, bg: RgbTriplet, bold = false): UiStyle {
|
|
75
|
+
return {
|
|
76
|
+
fg: {
|
|
77
|
+
kind: 'rgb',
|
|
78
|
+
r: fg[0],
|
|
79
|
+
g: fg[1],
|
|
80
|
+
b: fg[2],
|
|
81
|
+
},
|
|
82
|
+
bg: {
|
|
83
|
+
kind: 'rgb',
|
|
84
|
+
r: bg[0],
|
|
85
|
+
g: bg[1],
|
|
86
|
+
b: bg[2],
|
|
87
|
+
},
|
|
88
|
+
bold,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function writeGlyph(
|
|
93
|
+
surface: ReturnType<typeof createUiSurface>,
|
|
94
|
+
row: number,
|
|
95
|
+
col: number,
|
|
96
|
+
glyph: string,
|
|
97
|
+
width: number,
|
|
98
|
+
style: UiStyle,
|
|
99
|
+
): void {
|
|
100
|
+
const start = row * surface.cols + col;
|
|
101
|
+
const first = surface.cells[start]!;
|
|
102
|
+
first.glyph = glyph;
|
|
103
|
+
first.continued = false;
|
|
104
|
+
first.style = style;
|
|
105
|
+
for (let offset = 1; offset < width && col + offset < surface.cols; offset += 1) {
|
|
106
|
+
const trailing = surface.cells[start + offset]!;
|
|
107
|
+
trailing.glyph = '';
|
|
108
|
+
trailing.continued = true;
|
|
109
|
+
trailing.style = style;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function displayWidth(text: string): number {
|
|
114
|
+
let width = 0;
|
|
115
|
+
for (const glyph of text) {
|
|
116
|
+
width += Math.max(0, measureDisplayWidth(glyph));
|
|
117
|
+
}
|
|
118
|
+
return width;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function spacingX(cols: number): number {
|
|
122
|
+
return Math.max(4, Math.round(cols / 15));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function spacingY(rows: number): number {
|
|
126
|
+
return Math.max(2, Math.round(rows / 9));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function gridEnergy(col: number, row: number, cols: number, rows: number, phase: number): number {
|
|
130
|
+
const gridX = spacingX(cols);
|
|
131
|
+
const gridY = spacingY(rows);
|
|
132
|
+
const dxGrid = Math.abs((col % gridX) - gridX / 2) / (gridX / 2);
|
|
133
|
+
const dyGrid = Math.abs((row % gridY) - gridY / 2) / (gridY / 2);
|
|
134
|
+
|
|
135
|
+
const onHLine = 1 - dyGrid;
|
|
136
|
+
const onVLine = 1 - dxGrid;
|
|
137
|
+
const gridLine = Math.max(onHLine * 0.6, onVLine * 0.4);
|
|
138
|
+
const intersectionBoost = Math.pow(onHLine * onVLine, 0.5) * 0.5;
|
|
139
|
+
|
|
140
|
+
const nx = col / Math.max(1, cols);
|
|
141
|
+
const ny = row / Math.max(1, rows);
|
|
142
|
+
const hWave = Math.sin(nx * 12 + phase * 0.8) * 0.5 + 0.5;
|
|
143
|
+
const vWave = Math.sin(ny * 8 - phase * 0.6) * 0.5 + 0.5;
|
|
144
|
+
const crossWave = Math.sin((nx + ny) * 6 + phase * 0.4) * 0.5 + 0.5;
|
|
145
|
+
const lineEnergy = gridLine * (hWave * 0.5 + vWave * 0.3 + crossWave * 0.2);
|
|
146
|
+
|
|
147
|
+
const cx = nx - 0.5;
|
|
148
|
+
const cy = (ny - 0.5) * 0.6;
|
|
149
|
+
const dist = Math.sqrt(cx * cx + cy * cy);
|
|
150
|
+
const radialPulse = Math.sin(dist * 10 - phase * 1.5) * 0.3 * (1 - dist);
|
|
151
|
+
const nodePulse = intersectionBoost * (0.6 + Math.sin(phase * 0.7 + col * 0.3 + row * 0.5) * 0.4);
|
|
152
|
+
const ambient = 0.03 + Math.sin(nx * 4 + phase * 0.2) * Math.sin(ny * 3 - phase * 0.15) * 0.03;
|
|
153
|
+
return clamp01(
|
|
154
|
+
ambient + lineEnergy * 0.6 + nodePulse * 0.5 + Math.max(0, radialPulse) * gridLine,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function pickGridGlyph(
|
|
159
|
+
col: number,
|
|
160
|
+
row: number,
|
|
161
|
+
cols: number,
|
|
162
|
+
rows: number,
|
|
163
|
+
energy: number,
|
|
164
|
+
): string {
|
|
165
|
+
const onHorizontal = row % spacingY(rows) === 0;
|
|
166
|
+
const onVertical = col % spacingX(cols) === 0;
|
|
167
|
+
if (onHorizontal && onVertical) {
|
|
168
|
+
return energy > 0.6
|
|
169
|
+
? GRID_CHARS.brightNode
|
|
170
|
+
: energy > 0.3
|
|
171
|
+
? GRID_CHARS.node
|
|
172
|
+
: GRID_CHARS.intersection;
|
|
173
|
+
}
|
|
174
|
+
if (onHorizontal) {
|
|
175
|
+
return energy > 0.7
|
|
176
|
+
? GRID_CHARS.heavy
|
|
177
|
+
: energy > 0.4
|
|
178
|
+
? GRID_CHARS.hline
|
|
179
|
+
: energy > 0.15
|
|
180
|
+
? GRID_CHARS.dot
|
|
181
|
+
: GRID_CHARS.empty;
|
|
182
|
+
}
|
|
183
|
+
if (onVertical) {
|
|
184
|
+
return energy > 0.7
|
|
185
|
+
? GRID_CHARS.heavy
|
|
186
|
+
: energy > 0.4
|
|
187
|
+
? GRID_CHARS.vline
|
|
188
|
+
: energy > 0.15
|
|
189
|
+
? GRID_CHARS.dot
|
|
190
|
+
: GRID_CHARS.empty;
|
|
191
|
+
}
|
|
192
|
+
return energy > 0.65
|
|
193
|
+
? GRID_CHARS.light
|
|
194
|
+
: energy > 0.45
|
|
195
|
+
? GRID_CHARS.brightDot
|
|
196
|
+
: energy > 0.25
|
|
197
|
+
? GRID_CHARS.dot
|
|
198
|
+
: GRID_CHARS.empty;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function paintBackground(surface: ReturnType<typeof createUiSurface>, phase: number): void {
|
|
202
|
+
for (let row = 0; row < surface.rows; row += 1) {
|
|
203
|
+
for (let col = 0; col < surface.cols; col += 1) {
|
|
204
|
+
const energy = gridEnergy(col, row, surface.cols, surface.rows, phase);
|
|
205
|
+
const fg = paletteColor(FG_PALETTE, energy);
|
|
206
|
+
const bg = paletteColor(BG_PALETTE, energy * 0.3);
|
|
207
|
+
const glyph = pickGridGlyph(col, row, surface.cols, surface.rows, energy);
|
|
208
|
+
writeGlyph(surface, row, col, glyph, 1, styleFromColors(fg, bg));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function paintOverlayTextRow(
|
|
214
|
+
surface: ReturnType<typeof createUiSurface>,
|
|
215
|
+
row: number,
|
|
216
|
+
text: string,
|
|
217
|
+
phase: number,
|
|
218
|
+
): void {
|
|
219
|
+
let col = 0;
|
|
220
|
+
for (const glyph of text) {
|
|
221
|
+
const width = Math.max(0, measureDisplayWidth(glyph));
|
|
222
|
+
if (width === 0) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (col >= surface.cols || col + width > surface.cols) {
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
if (glyph !== ' ') {
|
|
229
|
+
const shimmer = clamp01(0.56 + Math.sin(phase * 0.4 + row * 0.12 + col * 0.05) * 0.06);
|
|
230
|
+
const fg: RgbTriplet = [
|
|
231
|
+
Math.round(lerp(120, 160, shimmer)),
|
|
232
|
+
Math.round(lerp(145, 185, shimmer)),
|
|
233
|
+
Math.round(lerp(180, 220, shimmer)),
|
|
234
|
+
];
|
|
235
|
+
const offset = row * surface.cols + col;
|
|
236
|
+
const background = surface.cells[offset]!.style.bg as Extract<UiStyle['bg'], { kind: 'rgb' }>;
|
|
237
|
+
const bg: RgbTriplet = [background.r, background.g, background.b];
|
|
238
|
+
writeGlyph(surface, row, col, glyph, width, styleFromColors(fg, bg));
|
|
239
|
+
}
|
|
240
|
+
col += width;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function paintCenteredLabel(
|
|
245
|
+
surface: ReturnType<typeof createUiSurface>,
|
|
246
|
+
row: number,
|
|
247
|
+
text: string | null,
|
|
248
|
+
phase: number,
|
|
249
|
+
): void {
|
|
250
|
+
if (text === null || text.length === 0) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const width = displayWidth(text);
|
|
254
|
+
if (width <= 0 || width > surface.cols) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
let col = Math.floor((surface.cols - width) / 2);
|
|
258
|
+
let index = 0;
|
|
259
|
+
for (const glyph of text) {
|
|
260
|
+
const glyphWidth = Math.max(0, measureDisplayWidth(glyph));
|
|
261
|
+
if (glyphWidth === 0) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const shimmer = clamp01(0.58 + Math.sin(phase * 0.35 + index * 0.18) * 0.05);
|
|
265
|
+
const fg: RgbTriplet = [
|
|
266
|
+
Math.round(lerp(125, 165, shimmer)),
|
|
267
|
+
Math.round(lerp(150, 190, shimmer)),
|
|
268
|
+
Math.round(lerp(190, 228, shimmer)),
|
|
269
|
+
];
|
|
270
|
+
const offset = row * surface.cols + col;
|
|
271
|
+
const background = surface.cells[offset]!.style.bg as Extract<UiStyle['bg'], { kind: 'rgb' }>;
|
|
272
|
+
const bg: RgbTriplet = [background.r, background.g, background.b];
|
|
273
|
+
writeGlyph(surface, row, col, glyph, glyphWidth, styleFromColors(fg, bg));
|
|
274
|
+
col += glyphWidth;
|
|
275
|
+
index += 1;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function renderHomeGridfireAnsiRows(options: HomeGridfireOptions): readonly string[] {
|
|
280
|
+
const safeCols = Math.max(1, options.cols);
|
|
281
|
+
const safeRows = Math.max(1, options.rows);
|
|
282
|
+
const surface = createUiSurface(safeCols, safeRows);
|
|
283
|
+
const phase = options.timeMs / 1000;
|
|
284
|
+
|
|
285
|
+
paintBackground(surface, phase);
|
|
286
|
+
|
|
287
|
+
for (let row = 0; row < safeRows; row += 1) {
|
|
288
|
+
const line = options.contentRows[row] ?? '';
|
|
289
|
+
paintOverlayTextRow(surface, row, line, phase);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const centerRow = Math.floor(safeRows / 2);
|
|
293
|
+
paintCenteredLabel(surface, centerRow, options.overlayTitle, phase);
|
|
294
|
+
paintCenteredLabel(
|
|
295
|
+
surface,
|
|
296
|
+
Math.min(safeRows - 1, centerRow + 2),
|
|
297
|
+
options.overlaySubtitle,
|
|
298
|
+
phase,
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return renderUiSurfaceAnsiRows(surface);
|
|
302
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import {
|
|
5
|
+
buildTaskFocusedPaneView,
|
|
6
|
+
type TaskFocusedPaneEditorTarget,
|
|
7
|
+
type TaskFocusedPaneRepositoryRecord,
|
|
8
|
+
type TaskFocusedPaneTaskRecord,
|
|
9
|
+
type TaskFocusedPaneView,
|
|
10
|
+
} from '../../mux/task-focused-pane.ts';
|
|
11
|
+
import type { TaskComposerBuffer } from '../../mux/task-composer.ts';
|
|
12
|
+
import { renderHomeGridfireAnsiRows } from './home-gridfire.ts';
|
|
13
|
+
|
|
14
|
+
const HOME_PACKAGE_JSON_PATH = resolve(
|
|
15
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
16
|
+
'../../../package.json',
|
|
17
|
+
);
|
|
18
|
+
const HOME_PACKAGE_VERSION = String(
|
|
19
|
+
(JSON.parse(readFileSync(HOME_PACKAGE_JSON_PATH, 'utf8')) as { version: unknown }).version,
|
|
20
|
+
);
|
|
21
|
+
const HOME_OVERLAY_SUBTITLE = `- harness v${HOME_PACKAGE_VERSION} -`;
|
|
22
|
+
|
|
23
|
+
interface HomePaneLayout {
|
|
24
|
+
readonly rightCols: number;
|
|
25
|
+
readonly paneRows: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface HomePaneRenderInput {
|
|
29
|
+
readonly layout: HomePaneLayout;
|
|
30
|
+
readonly repositories: ReadonlyMap<string, TaskFocusedPaneRepositoryRecord>;
|
|
31
|
+
readonly tasks: ReadonlyMap<string, TaskFocusedPaneTaskRecord>;
|
|
32
|
+
readonly selectedRepositoryId: string | null;
|
|
33
|
+
readonly repositoryDropdownOpen: boolean;
|
|
34
|
+
readonly editorTarget: TaskFocusedPaneEditorTarget;
|
|
35
|
+
readonly draftBuffer: TaskComposerBuffer;
|
|
36
|
+
readonly taskBufferById: ReadonlyMap<string, TaskComposerBuffer>;
|
|
37
|
+
readonly notice: string | null;
|
|
38
|
+
readonly scrollTop: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface HomePaneOptions {
|
|
42
|
+
readonly showTaskPlanningUi?: boolean;
|
|
43
|
+
readonly animateBackground?: boolean;
|
|
44
|
+
readonly overlaySubtitle?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class HomePane {
|
|
48
|
+
private readonly showTaskPlanningUi: boolean;
|
|
49
|
+
private readonly animateBackground: boolean;
|
|
50
|
+
private readonly staticBackgroundTimeMs: number;
|
|
51
|
+
private readonly overlaySubtitle: string;
|
|
52
|
+
|
|
53
|
+
constructor(
|
|
54
|
+
private readonly renderTaskFocusedPaneView: typeof buildTaskFocusedPaneView = buildTaskFocusedPaneView,
|
|
55
|
+
private readonly renderBackgroundRows: typeof renderHomeGridfireAnsiRows = renderHomeGridfireAnsiRows,
|
|
56
|
+
private readonly nowMs: () => number = Date.now,
|
|
57
|
+
options: HomePaneOptions = {},
|
|
58
|
+
) {
|
|
59
|
+
this.showTaskPlanningUi = options.showTaskPlanningUi ?? false;
|
|
60
|
+
this.animateBackground = options.animateBackground ?? true;
|
|
61
|
+
this.staticBackgroundTimeMs = this.nowMs();
|
|
62
|
+
this.overlaySubtitle = options.overlaySubtitle ?? HOME_OVERLAY_SUBTITLE;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private hiddenTaskPlanningView(layout: HomePaneLayout): TaskFocusedPaneView {
|
|
66
|
+
const safeCols = Math.max(1, layout.rightCols);
|
|
67
|
+
const safeRows = Math.max(1, layout.paneRows);
|
|
68
|
+
const blankRow = ' '.repeat(safeCols);
|
|
69
|
+
const rows = Array.from({ length: safeRows }, () => blankRow);
|
|
70
|
+
return {
|
|
71
|
+
rows,
|
|
72
|
+
taskIds: Array.from({ length: safeRows }, () => null),
|
|
73
|
+
repositoryIds: Array.from({ length: safeRows }, () => null),
|
|
74
|
+
actions: Array.from({ length: safeRows }, () => null),
|
|
75
|
+
actionCells: Array.from({ length: safeRows }, () => null),
|
|
76
|
+
top: 0,
|
|
77
|
+
selectedRepositoryId: null,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
render(input: HomePaneRenderInput): TaskFocusedPaneView {
|
|
82
|
+
const view = this.showTaskPlanningUi
|
|
83
|
+
? this.renderTaskFocusedPaneView({
|
|
84
|
+
repositories: input.repositories,
|
|
85
|
+
tasks: input.tasks,
|
|
86
|
+
selectedRepositoryId: input.selectedRepositoryId,
|
|
87
|
+
repositoryDropdownOpen: input.repositoryDropdownOpen,
|
|
88
|
+
editorTarget: input.editorTarget,
|
|
89
|
+
draftBuffer: input.draftBuffer,
|
|
90
|
+
taskBufferById: input.taskBufferById,
|
|
91
|
+
notice: input.notice,
|
|
92
|
+
cols: input.layout.rightCols,
|
|
93
|
+
rows: input.layout.paneRows,
|
|
94
|
+
scrollTop: input.scrollTop,
|
|
95
|
+
})
|
|
96
|
+
: this.hiddenTaskPlanningView(input.layout);
|
|
97
|
+
return {
|
|
98
|
+
...view,
|
|
99
|
+
rows: this.renderBackgroundRows({
|
|
100
|
+
cols: input.layout.rightCols,
|
|
101
|
+
rows: input.layout.paneRows,
|
|
102
|
+
contentRows: view.rows,
|
|
103
|
+
timeMs: this.animateBackground ? this.nowMs() : this.staticBackgroundTimeMs,
|
|
104
|
+
overlayTitle: 'GSV Sleeper Service',
|
|
105
|
+
overlaySubtitle: this.overlaySubtitle,
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { buildRailRows } from '../../mux/live-mux/rail-layout.ts';
|
|
2
|
+
|
|
3
|
+
type LeftRailRenderInput = Parameters<typeof buildRailRows>[0];
|
|
4
|
+
type LeftRailRenderResult = ReturnType<typeof buildRailRows>;
|
|
5
|
+
|
|
6
|
+
export class LeftRailPane {
|
|
7
|
+
constructor(private readonly renderRailRows: typeof buildRailRows = buildRailRows) {}
|
|
8
|
+
|
|
9
|
+
render(input: LeftRailRenderInput): LeftRailRenderResult {
|
|
10
|
+
return this.renderRailRows(input);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { buildProjectPaneRows, type ProjectPaneSnapshot } from '../../mux/harness-core-ui.ts';
|
|
2
|
+
|
|
3
|
+
interface ProjectPaneLayout {
|
|
4
|
+
readonly rightCols: number;
|
|
5
|
+
readonly paneRows: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ProjectPaneRenderInput {
|
|
9
|
+
readonly layout: ProjectPaneLayout;
|
|
10
|
+
readonly snapshot: ProjectPaneSnapshot | null;
|
|
11
|
+
readonly scrollTop: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ProjectPaneRenderResult {
|
|
15
|
+
readonly rows: readonly string[];
|
|
16
|
+
readonly scrollTop: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ProjectPane {
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly renderProjectRows: typeof buildProjectPaneRows = buildProjectPaneRows,
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
render(input: ProjectPaneRenderInput): ProjectPaneRenderResult {
|
|
25
|
+
if (input.snapshot === null) {
|
|
26
|
+
return {
|
|
27
|
+
rows: Array.from({ length: input.layout.paneRows }, () =>
|
|
28
|
+
' '.repeat(input.layout.rightCols),
|
|
29
|
+
),
|
|
30
|
+
scrollTop: input.scrollTop,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const view = this.renderProjectRows(
|
|
34
|
+
input.snapshot,
|
|
35
|
+
input.layout.rightCols,
|
|
36
|
+
input.layout.paneRows,
|
|
37
|
+
input.scrollTop,
|
|
38
|
+
);
|
|
39
|
+
return {
|
|
40
|
+
rows: view.rows,
|
|
41
|
+
scrollTop: view.top,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { wheelDeltaRowsFromCode } from '../mux/dual-pane-core.ts';
|
|
2
|
+
import { handleHomePaneDragRelease as handleHomePaneDragReleaseFrame } from '../mux/live-mux/home-pane-drop.ts';
|
|
3
|
+
import {
|
|
4
|
+
handleHomePaneDragMove as handleHomePaneDragMoveFrame,
|
|
5
|
+
handleMainPaneWheelInput as handleMainPaneWheelInputFrame,
|
|
6
|
+
handlePaneDividerDragInput as handlePaneDividerDragInputFrame,
|
|
7
|
+
handleSeparatorPointerPress as handleSeparatorPointerPressFrame,
|
|
8
|
+
} from '../mux/live-mux/pointer-routing.ts';
|
|
9
|
+
import {
|
|
10
|
+
hasAltModifier,
|
|
11
|
+
isLeftButtonPress,
|
|
12
|
+
isMouseRelease,
|
|
13
|
+
isSelectionDrag,
|
|
14
|
+
isWheelMouseCode,
|
|
15
|
+
} from '../mux/live-mux/selection.ts';
|
|
16
|
+
|
|
17
|
+
type MainPaneMode = 'conversation' | 'project' | 'home';
|
|
18
|
+
type PointerTarget = 'left' | 'right' | 'separator' | 'status' | 'outside';
|
|
19
|
+
|
|
20
|
+
interface HomePaneDragState {
|
|
21
|
+
readonly kind: 'task' | 'repository';
|
|
22
|
+
readonly itemId: string;
|
|
23
|
+
readonly startedRowIndex: number;
|
|
24
|
+
readonly latestRowIndex: number;
|
|
25
|
+
readonly hasDragged: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface PointerRoutingInputOptions {
|
|
29
|
+
readonly getPaneDividerDragActive: () => boolean;
|
|
30
|
+
readonly setPaneDividerDragActive: (active: boolean) => void;
|
|
31
|
+
readonly applyPaneDividerAtCol: (col: number) => void;
|
|
32
|
+
readonly getHomePaneDragState: () => HomePaneDragState | null;
|
|
33
|
+
readonly setHomePaneDragState: (next: HomePaneDragState | null) => void;
|
|
34
|
+
readonly getMainPaneMode: () => MainPaneMode;
|
|
35
|
+
readonly taskIdAtRow: (index: number) => string | null;
|
|
36
|
+
readonly repositoryIdAtRow: (index: number) => string | null;
|
|
37
|
+
readonly reorderTaskByDrop: (draggedTaskId: string, targetTaskId: string) => void;
|
|
38
|
+
readonly reorderRepositoryByDrop: (
|
|
39
|
+
draggedRepositoryId: string,
|
|
40
|
+
targetRepositoryId: string,
|
|
41
|
+
) => void;
|
|
42
|
+
readonly onProjectWheel: (delta: number) => void;
|
|
43
|
+
readonly onHomeWheel: (delta: number) => void;
|
|
44
|
+
readonly markDirty: () => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface PointerRoutingInputDependencies {
|
|
48
|
+
readonly handlePaneDividerDragInput?: typeof handlePaneDividerDragInputFrame;
|
|
49
|
+
readonly handleHomePaneDragRelease?: typeof handleHomePaneDragReleaseFrame;
|
|
50
|
+
readonly handleSeparatorPointerPress?: typeof handleSeparatorPointerPressFrame;
|
|
51
|
+
readonly handleMainPaneWheelInput?: typeof handleMainPaneWheelInputFrame;
|
|
52
|
+
readonly handleHomePaneDragMove?: typeof handleHomePaneDragMoveFrame;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface PointerEventInput {
|
|
56
|
+
readonly code: number;
|
|
57
|
+
readonly final: 'M' | 'm';
|
|
58
|
+
readonly col: number;
|
|
59
|
+
readonly target: PointerTarget;
|
|
60
|
+
readonly rowIndex: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class PointerRoutingInput {
|
|
64
|
+
private readonly handlePaneDividerDragInput: typeof handlePaneDividerDragInputFrame;
|
|
65
|
+
private readonly handleHomePaneDragReleaseInput: typeof handleHomePaneDragReleaseFrame;
|
|
66
|
+
private readonly handleSeparatorPointerPressInput: typeof handleSeparatorPointerPressFrame;
|
|
67
|
+
private readonly handleMainPaneWheelInput: typeof handleMainPaneWheelInputFrame;
|
|
68
|
+
private readonly handleHomePaneDragMoveInput: typeof handleHomePaneDragMoveFrame;
|
|
69
|
+
|
|
70
|
+
constructor(
|
|
71
|
+
private readonly options: PointerRoutingInputOptions,
|
|
72
|
+
dependencies: PointerRoutingInputDependencies = {},
|
|
73
|
+
) {
|
|
74
|
+
this.handlePaneDividerDragInput =
|
|
75
|
+
dependencies.handlePaneDividerDragInput ?? handlePaneDividerDragInputFrame;
|
|
76
|
+
this.handleHomePaneDragReleaseInput =
|
|
77
|
+
dependencies.handleHomePaneDragRelease ?? handleHomePaneDragReleaseFrame;
|
|
78
|
+
this.handleSeparatorPointerPressInput =
|
|
79
|
+
dependencies.handleSeparatorPointerPress ?? handleSeparatorPointerPressFrame;
|
|
80
|
+
this.handleMainPaneWheelInput =
|
|
81
|
+
dependencies.handleMainPaneWheelInput ?? handleMainPaneWheelInputFrame;
|
|
82
|
+
this.handleHomePaneDragMoveInput =
|
|
83
|
+
dependencies.handleHomePaneDragMove ?? handleHomePaneDragMoveFrame;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
handlePaneDividerDrag(event: Pick<PointerEventInput, 'code' | 'final' | 'col'>): boolean {
|
|
87
|
+
return this.handlePaneDividerDragInput({
|
|
88
|
+
paneDividerDragActive: this.options.getPaneDividerDragActive(),
|
|
89
|
+
isMouseRelease: isMouseRelease(event.final),
|
|
90
|
+
isWheelMouseCode: isWheelMouseCode(event.code),
|
|
91
|
+
mouseCol: event.col,
|
|
92
|
+
setPaneDividerDragActive: this.options.setPaneDividerDragActive,
|
|
93
|
+
applyPaneDividerAtCol: this.options.applyPaneDividerAtCol,
|
|
94
|
+
markDirty: this.options.markDirty,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
handleHomePaneDragRelease(
|
|
99
|
+
event: Pick<PointerEventInput, 'final' | 'target' | 'rowIndex'>,
|
|
100
|
+
): boolean {
|
|
101
|
+
return this.handleHomePaneDragReleaseInput({
|
|
102
|
+
homePaneDragState: this.options.getHomePaneDragState(),
|
|
103
|
+
isMouseRelease: isMouseRelease(event.final),
|
|
104
|
+
mainPaneMode: this.options.getMainPaneMode(),
|
|
105
|
+
target: event.target,
|
|
106
|
+
rowIndex: event.rowIndex,
|
|
107
|
+
taskIdAtRow: this.options.taskIdAtRow,
|
|
108
|
+
repositoryIdAtRow: this.options.repositoryIdAtRow,
|
|
109
|
+
reorderTaskByDrop: this.options.reorderTaskByDrop,
|
|
110
|
+
reorderRepositoryByDrop: this.options.reorderRepositoryByDrop,
|
|
111
|
+
setHomePaneDragState: this.options.setHomePaneDragState,
|
|
112
|
+
markDirty: this.options.markDirty,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
handleSeparatorPointerPress(
|
|
117
|
+
event: Pick<PointerEventInput, 'target' | 'code' | 'final' | 'col'>,
|
|
118
|
+
): boolean {
|
|
119
|
+
return this.handleSeparatorPointerPressInput({
|
|
120
|
+
target: event.target,
|
|
121
|
+
isLeftButtonPress: isLeftButtonPress(event.code, event.final),
|
|
122
|
+
hasAltModifier: hasAltModifier(event.code),
|
|
123
|
+
mouseCol: event.col,
|
|
124
|
+
setPaneDividerDragActive: this.options.setPaneDividerDragActive,
|
|
125
|
+
applyPaneDividerAtCol: this.options.applyPaneDividerAtCol,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
handleMainPaneWheel(
|
|
130
|
+
event: Pick<PointerEventInput, 'target' | 'code'>,
|
|
131
|
+
onConversationWheel: (delta: number) => void,
|
|
132
|
+
): boolean {
|
|
133
|
+
return this.handleMainPaneWheelInput({
|
|
134
|
+
target: event.target,
|
|
135
|
+
wheelDelta: wheelDeltaRowsFromCode(event.code),
|
|
136
|
+
mainPaneMode: this.options.getMainPaneMode(),
|
|
137
|
+
onProjectWheel: this.options.onProjectWheel,
|
|
138
|
+
onHomeWheel: this.options.onHomeWheel,
|
|
139
|
+
onConversationWheel,
|
|
140
|
+
markDirty: this.options.markDirty,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
handleHomePaneDragMove(
|
|
145
|
+
event: Pick<PointerEventInput, 'target' | 'code' | 'final' | 'rowIndex'>,
|
|
146
|
+
): boolean {
|
|
147
|
+
return this.handleHomePaneDragMoveInput({
|
|
148
|
+
homePaneDragState: this.options.getHomePaneDragState(),
|
|
149
|
+
mainPaneMode: this.options.getMainPaneMode(),
|
|
150
|
+
target: event.target,
|
|
151
|
+
isSelectionDrag: isSelectionDrag(event.code, event.final),
|
|
152
|
+
hasAltModifier: hasAltModifier(event.code),
|
|
153
|
+
rowIndex: event.rowIndex,
|
|
154
|
+
setHomePaneDragState: this.options.setHomePaneDragState,
|
|
155
|
+
markDirty: this.options.markDirty,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|