@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
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
COMMAND_MENU_MAX_RESULTS,
|
|
3
2
|
clampCommandMenuState,
|
|
3
|
+
moveSelectionByDelta,
|
|
4
4
|
reduceCommandMenuInput,
|
|
5
5
|
resolveCommandMenuMatches,
|
|
6
|
+
resolveCommandMenuPage,
|
|
6
7
|
type CommandMenuActionDescriptor,
|
|
7
8
|
type CommandMenuState,
|
|
8
9
|
} from './command-menu.ts';
|
|
10
|
+
import { parseMuxInputChunk, wheelDeltaRowsFromCode } from '../dual-pane-core.ts';
|
|
9
11
|
|
|
10
12
|
interface HandleCommandMenuInputOptions {
|
|
11
13
|
readonly input: Buffer;
|
|
@@ -28,29 +30,45 @@ const COMMAND_MENU_BODY_ROW_OFFSET = 2;
|
|
|
28
30
|
const COMMAND_MENU_ACTION_ROW_START = 2;
|
|
29
31
|
const THEME_PICKER_SCOPE = 'theme-select';
|
|
30
32
|
|
|
33
|
+
function selectionDeltaFromWheelInput(input: Buffer): number {
|
|
34
|
+
if (!input.includes(0x1b) || !input.includes(0x3c)) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
const parsed = parseMuxInputChunk('', input);
|
|
38
|
+
let selectionDelta = 0;
|
|
39
|
+
for (const token of parsed.tokens) {
|
|
40
|
+
if (token.kind !== 'mouse') {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const wheelDelta = wheelDeltaRowsFromCode(token.event.code);
|
|
44
|
+
if (wheelDelta !== null) {
|
|
45
|
+
selectionDelta += wheelDelta;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return selectionDelta;
|
|
49
|
+
}
|
|
50
|
+
|
|
31
51
|
function resolveCommandMenuActionIdByRow(
|
|
32
52
|
menu: CommandMenuState,
|
|
33
53
|
actions: readonly CommandMenuActionDescriptor[],
|
|
34
54
|
overlayTopRowZeroBased: number,
|
|
35
55
|
rowOneBased: number,
|
|
36
56
|
): string | null {
|
|
37
|
-
const
|
|
38
|
-
if (matches.length === 0) {
|
|
57
|
+
const page = resolveCommandMenuPage(actions, menu);
|
|
58
|
+
if (page.matches.length === 0) {
|
|
39
59
|
return null;
|
|
40
60
|
}
|
|
41
|
-
const selectedIndex = clampCommandMenuState(menu, matches.length).selectedIndex;
|
|
42
|
-
const pageStart = Math.floor(selectedIndex / COMMAND_MENU_MAX_RESULTS) * COMMAND_MENU_MAX_RESULTS;
|
|
43
|
-
const visibleMatches = matches.slice(pageStart, pageStart + COMMAND_MENU_MAX_RESULTS);
|
|
44
61
|
const actionStartBodyLine = COMMAND_MENU_ACTION_ROW_START;
|
|
45
62
|
const clickedBodyLine = rowOneBased - 1 - (overlayTopRowZeroBased + COMMAND_MENU_BODY_ROW_OFFSET);
|
|
46
63
|
if (clickedBodyLine < actionStartBodyLine) {
|
|
47
64
|
return null;
|
|
48
65
|
}
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
66
|
+
const displayEntryIndex = clickedBodyLine - actionStartBodyLine;
|
|
67
|
+
if (displayEntryIndex < 0 || displayEntryIndex >= page.displayEntries.length) {
|
|
51
68
|
return null;
|
|
52
69
|
}
|
|
53
|
-
|
|
70
|
+
const entry = page.displayEntries[displayEntryIndex]!;
|
|
71
|
+
return entry.action.id;
|
|
54
72
|
}
|
|
55
73
|
|
|
56
74
|
export function handleCommandMenuInput(options: HandleCommandMenuInputOptions): boolean {
|
|
@@ -82,6 +100,25 @@ export function handleCommandMenuInput(options: HandleCommandMenuInputOptions):
|
|
|
82
100
|
markDirty();
|
|
83
101
|
return true;
|
|
84
102
|
}
|
|
103
|
+
const wheelSelectionDelta = selectionDeltaFromWheelInput(input);
|
|
104
|
+
if (wheelSelectionDelta !== 0) {
|
|
105
|
+
const currentMatches = resolveCommandMenuMatches(resolveActions(), menu.query, null);
|
|
106
|
+
const clampedMenu = clampCommandMenuState(menu, currentMatches.length);
|
|
107
|
+
const nextSelectedIndex = moveSelectionByDelta(
|
|
108
|
+
clampedMenu.selectedIndex,
|
|
109
|
+
currentMatches.length,
|
|
110
|
+
wheelSelectionDelta,
|
|
111
|
+
);
|
|
112
|
+
if (nextSelectedIndex !== menu.selectedIndex) {
|
|
113
|
+
setMenu({
|
|
114
|
+
scope: menu.scope,
|
|
115
|
+
query: menu.query,
|
|
116
|
+
selectedIndex: nextSelectedIndex,
|
|
117
|
+
});
|
|
118
|
+
markDirty();
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
85
122
|
const maybeMouseSequence = input.includes(0x3c);
|
|
86
123
|
if (
|
|
87
124
|
maybeMouseSequence &&
|
|
@@ -56,6 +56,8 @@ interface HandleNewThreadPromptInputOptions {
|
|
|
56
56
|
setPrompt: (prompt: NewThreadPromptState | null) => void;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
const MOUSE_EVENT_PREFIX = Buffer.from('\u001b[<', 'utf8');
|
|
60
|
+
|
|
59
61
|
export function handleConversationTitleEditInput(
|
|
60
62
|
options: HandleConversationTitleEditInputOptions,
|
|
61
63
|
): boolean {
|
|
@@ -92,7 +94,9 @@ export function handleConversationTitleEditInput(
|
|
|
92
94
|
markDirty();
|
|
93
95
|
return true;
|
|
94
96
|
}
|
|
97
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
95
98
|
if (
|
|
99
|
+
maybeMouseSequence &&
|
|
96
100
|
dismissOnOutsideClick(
|
|
97
101
|
input,
|
|
98
102
|
() => {
|
|
@@ -165,7 +169,7 @@ export function handleNewThreadPromptInput(options: HandleNewThreadPromptInputOp
|
|
|
165
169
|
markDirty();
|
|
166
170
|
return true;
|
|
167
171
|
}
|
|
168
|
-
const maybeMouseSequence = input.includes(
|
|
172
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
169
173
|
if (
|
|
170
174
|
maybeMouseSequence &&
|
|
171
175
|
dismissOnOutsideClick(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export interface TaskEditorPromptInputState {
|
|
2
2
|
title: string;
|
|
3
|
-
|
|
3
|
+
body: string;
|
|
4
4
|
repositoryIds: readonly string[];
|
|
5
5
|
repositoryIndex: number;
|
|
6
6
|
fieldIndex: 0 | 1 | 2;
|
|
@@ -8,7 +8,7 @@ export interface TaskEditorPromptInputState {
|
|
|
8
8
|
|
|
9
9
|
interface TaskEditorPromptReduction {
|
|
10
10
|
title: string;
|
|
11
|
-
|
|
11
|
+
body: string;
|
|
12
12
|
repositoryIndex: number;
|
|
13
13
|
fieldIndex: 0 | 1 | 2;
|
|
14
14
|
submit: boolean;
|
|
@@ -19,10 +19,98 @@ interface LinePromptReduction {
|
|
|
19
19
|
submit: boolean;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export
|
|
22
|
+
export interface LinePromptInputState {
|
|
23
|
+
readonly inBracketedPaste: boolean;
|
|
24
|
+
readonly pendingSequence: Buffer;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface StatefulLinePromptReduction extends LinePromptReduction {
|
|
28
|
+
readonly lineInputState: LinePromptInputState;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const BRACKETED_PASTE_START = Buffer.from('\u001b[200~', 'utf8');
|
|
32
|
+
const BRACKETED_PASTE_END = Buffer.from('\u001b[201~', 'utf8');
|
|
33
|
+
const EMPTY_BUFFER = Buffer.alloc(0);
|
|
34
|
+
|
|
35
|
+
export function createLinePromptInputState(): LinePromptInputState {
|
|
36
|
+
return {
|
|
37
|
+
inBracketedPaste: false,
|
|
38
|
+
pendingSequence: EMPTY_BUFFER,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function matchesSequence(input: Buffer, startIndex: number, sequence: Buffer): boolean {
|
|
43
|
+
if (startIndex < 0 || startIndex + sequence.length > input.length) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
for (let index = 0; index < sequence.length; index += 1) {
|
|
47
|
+
if (input[startIndex + index] !== sequence[index]) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isTruncatedSequencePrefix(input: Buffer, startIndex: number, sequence: Buffer): boolean {
|
|
55
|
+
const remaining = input.length - startIndex;
|
|
56
|
+
if (remaining >= sequence.length) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
for (let index = 0; index < remaining; index += 1) {
|
|
60
|
+
if (input[startIndex + index] !== sequence[index]) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function reduceLinePromptInput(value: string, input: Buffer): LinePromptReduction;
|
|
68
|
+
export function reduceLinePromptInput(
|
|
69
|
+
value: string,
|
|
70
|
+
input: Buffer,
|
|
71
|
+
lineInputState: LinePromptInputState,
|
|
72
|
+
): StatefulLinePromptReduction;
|
|
73
|
+
export function reduceLinePromptInput(
|
|
74
|
+
value: string,
|
|
75
|
+
input: Buffer,
|
|
76
|
+
lineInputState?: LinePromptInputState,
|
|
77
|
+
): LinePromptReduction | StatefulLinePromptReduction {
|
|
78
|
+
const activeState = lineInputState ?? createLinePromptInputState();
|
|
79
|
+
const mergedInput =
|
|
80
|
+
activeState.pendingSequence.length === 0
|
|
81
|
+
? input
|
|
82
|
+
: Buffer.concat([activeState.pendingSequence, input]);
|
|
83
|
+
|
|
23
84
|
let nextValue = value;
|
|
24
85
|
let submit = false;
|
|
25
|
-
|
|
86
|
+
let inBracketedPaste = activeState.inBracketedPaste;
|
|
87
|
+
let pendingSequence = EMPTY_BUFFER;
|
|
88
|
+
for (let index = 0; index < mergedInput.length; index += 1) {
|
|
89
|
+
if (!inBracketedPaste && matchesSequence(mergedInput, index, BRACKETED_PASTE_START)) {
|
|
90
|
+
inBracketedPaste = true;
|
|
91
|
+
index += BRACKETED_PASTE_START.length - 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (matchesSequence(mergedInput, index, BRACKETED_PASTE_END)) {
|
|
95
|
+
inBracketedPaste = false;
|
|
96
|
+
index += BRACKETED_PASTE_END.length - 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (
|
|
100
|
+
isTruncatedSequencePrefix(mergedInput, index, BRACKETED_PASTE_START) ||
|
|
101
|
+
isTruncatedSequencePrefix(mergedInput, index, BRACKETED_PASTE_END)
|
|
102
|
+
) {
|
|
103
|
+
pendingSequence = Buffer.from(mergedInput.subarray(index));
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const byte = mergedInput[index]!;
|
|
108
|
+
if (inBracketedPaste) {
|
|
109
|
+
if (byte >= 32 && byte <= 126) {
|
|
110
|
+
nextValue += String.fromCharCode(byte);
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
26
114
|
if (byte === 0x0d || byte === 0x0a) {
|
|
27
115
|
submit = true;
|
|
28
116
|
break;
|
|
@@ -35,9 +123,19 @@ export function reduceLinePromptInput(value: string, input: Buffer): LinePromptR
|
|
|
35
123
|
nextValue += String.fromCharCode(byte);
|
|
36
124
|
}
|
|
37
125
|
}
|
|
126
|
+
if (lineInputState === undefined) {
|
|
127
|
+
return {
|
|
128
|
+
value: nextValue,
|
|
129
|
+
submit,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
38
132
|
return {
|
|
39
133
|
value: nextValue,
|
|
40
134
|
submit,
|
|
135
|
+
lineInputState: {
|
|
136
|
+
inBracketedPaste,
|
|
137
|
+
pendingSequence,
|
|
138
|
+
},
|
|
41
139
|
};
|
|
42
140
|
}
|
|
43
141
|
|
|
@@ -46,7 +144,7 @@ export function reduceTaskEditorPromptInput(
|
|
|
46
144
|
input: Buffer,
|
|
47
145
|
): TaskEditorPromptReduction {
|
|
48
146
|
let nextTitle = prompt.title;
|
|
49
|
-
let
|
|
147
|
+
let nextBody = prompt.body;
|
|
50
148
|
let nextFieldIndex = prompt.fieldIndex;
|
|
51
149
|
let nextRepositoryIndex = prompt.repositoryIndex;
|
|
52
150
|
let submit = false;
|
|
@@ -71,7 +169,7 @@ export function reduceTaskEditorPromptInput(
|
|
|
71
169
|
if (nextFieldIndex === 0) {
|
|
72
170
|
nextTitle = nextTitle.slice(0, -1);
|
|
73
171
|
} else if (nextFieldIndex === 2) {
|
|
74
|
-
|
|
172
|
+
nextBody = nextBody.slice(0, -1);
|
|
75
173
|
}
|
|
76
174
|
continue;
|
|
77
175
|
}
|
|
@@ -79,14 +177,14 @@ export function reduceTaskEditorPromptInput(
|
|
|
79
177
|
if (nextFieldIndex === 0) {
|
|
80
178
|
nextTitle += String.fromCharCode(byte);
|
|
81
179
|
} else if (nextFieldIndex === 2) {
|
|
82
|
-
|
|
180
|
+
nextBody += String.fromCharCode(byte);
|
|
83
181
|
}
|
|
84
182
|
}
|
|
85
183
|
}
|
|
86
184
|
}
|
|
87
185
|
return {
|
|
88
186
|
title: nextTitle,
|
|
89
|
-
|
|
187
|
+
body: nextBody,
|
|
90
188
|
repositoryIndex: nextRepositoryIndex,
|
|
91
189
|
fieldIndex: nextFieldIndex,
|
|
92
190
|
submit,
|
|
@@ -8,22 +8,27 @@ import {
|
|
|
8
8
|
resolveGoldenModalSize,
|
|
9
9
|
} from '../harness-core-ui.ts';
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
resolveCommandMenuMatches,
|
|
11
|
+
resolveCommandMenuPage,
|
|
13
12
|
type CommandMenuActionDescriptor,
|
|
14
13
|
type CommandMenuState,
|
|
15
14
|
} from './command-menu.ts';
|
|
16
15
|
import type { createNewThreadPromptState } from '../new-thread-prompt.ts';
|
|
17
16
|
import { newThreadPromptBodyLines } from '../new-thread-prompt.ts';
|
|
18
|
-
import {
|
|
17
|
+
import { UiKit, type UiModalOverlayOptions } from '../../../packages/harness-ui/src/kit.ts';
|
|
19
18
|
|
|
20
19
|
type NewThreadPromptState = ReturnType<typeof createNewThreadPromptState>;
|
|
20
|
+
const uiKit = new UiKit();
|
|
21
|
+
|
|
22
|
+
function buildUiModalOverlay(options: UiModalOverlayOptions) {
|
|
23
|
+
return uiKit.buildModalOverlay(options);
|
|
24
|
+
}
|
|
25
|
+
|
|
21
26
|
type UiModalThemeInput = NonNullable<Parameters<typeof buildUiModalOverlay>[0]['theme']>;
|
|
22
27
|
|
|
23
28
|
interface TaskEditorPromptOverlayState {
|
|
24
29
|
mode: 'create' | 'edit';
|
|
25
30
|
title: string;
|
|
26
|
-
|
|
31
|
+
body: string;
|
|
27
32
|
repositoryIds: readonly string[];
|
|
28
33
|
repositoryIndex: number;
|
|
29
34
|
fieldIndex: 0 | 1 | 2;
|
|
@@ -36,6 +41,14 @@ interface RepositoryPromptOverlayState {
|
|
|
36
41
|
readonly error: string | null;
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
interface ApiKeyPromptOverlayState {
|
|
45
|
+
readonly keyName: string;
|
|
46
|
+
readonly displayName: string;
|
|
47
|
+
readonly value: string;
|
|
48
|
+
readonly error: string | null;
|
|
49
|
+
readonly hasExistingValue: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
interface ConversationTitleOverlayState {
|
|
40
53
|
value: string;
|
|
41
54
|
lastSavedValue: string;
|
|
@@ -43,6 +56,69 @@ interface ConversationTitleOverlayState {
|
|
|
43
56
|
persistInFlight: boolean;
|
|
44
57
|
}
|
|
45
58
|
|
|
59
|
+
interface ReleaseNotesOverlayState {
|
|
60
|
+
readonly currentVersion: string;
|
|
61
|
+
readonly latestTag: string;
|
|
62
|
+
readonly releasesPageUrl: string;
|
|
63
|
+
readonly releases: readonly {
|
|
64
|
+
tag: string;
|
|
65
|
+
name: string;
|
|
66
|
+
url: string;
|
|
67
|
+
previewLines: readonly string[];
|
|
68
|
+
previewTruncated: boolean;
|
|
69
|
+
}[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const RELEASE_NOTES_UPDATE_ACTION_BODY_LINE_INDEX = 2;
|
|
73
|
+
const RELEASE_NOTES_BODY_START_ROW_OFFSET = 2;
|
|
74
|
+
export const RELEASE_NOTES_UPDATE_ACTION_ROW_OFFSET =
|
|
75
|
+
RELEASE_NOTES_BODY_START_ROW_OFFSET + RELEASE_NOTES_UPDATE_ACTION_BODY_LINE_INDEX;
|
|
76
|
+
export const RELEASE_NOTES_UPDATE_ACTION_LABEL = '[ click to update now ]';
|
|
77
|
+
const COMMAND_PALETTE_MODAL_SIZE = {
|
|
78
|
+
preferredHeight: 18,
|
|
79
|
+
minWidth: 48,
|
|
80
|
+
maxWidth: 96,
|
|
81
|
+
} as const;
|
|
82
|
+
|
|
83
|
+
function truncateColumn(value: string, width: number): string {
|
|
84
|
+
const safeWidth = Math.max(1, width);
|
|
85
|
+
const normalized = value.trim();
|
|
86
|
+
if (normalized.length <= safeWidth) {
|
|
87
|
+
return normalized.padEnd(safeWidth, ' ');
|
|
88
|
+
}
|
|
89
|
+
return safeWidth <= 1 ? normalized.slice(0, safeWidth) : `${normalized.slice(0, safeWidth - 1)}…`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function renderShortcutsTableRows(
|
|
93
|
+
page: ReturnType<typeof resolveCommandMenuPage>,
|
|
94
|
+
totalWidth: number,
|
|
95
|
+
): readonly string[] {
|
|
96
|
+
const tableWidth = Math.max(30, totalWidth - 2);
|
|
97
|
+
const separatorWidth = 6;
|
|
98
|
+
const baseColumnWidth = Math.max(6, Math.floor((tableWidth - separatorWidth) / 3));
|
|
99
|
+
const leftWidth = baseColumnWidth;
|
|
100
|
+
const middleWidth = baseColumnWidth;
|
|
101
|
+
const rightWidth = Math.max(8, tableWidth - leftWidth - middleWidth - separatorWidth);
|
|
102
|
+
const rows: string[] = [];
|
|
103
|
+
rows.push(
|
|
104
|
+
`${truncateColumn('screen', leftWidth)} | ${truncateColumn('action', middleWidth)} | ${truncateColumn('bindings', rightWidth)}`,
|
|
105
|
+
);
|
|
106
|
+
for (const entry of page.displayEntries) {
|
|
107
|
+
const prefix = entry.absoluteIndex === page.selectedIndex ? '>' : ' ';
|
|
108
|
+
const screen = entry.action.screenLabel ?? 'Global';
|
|
109
|
+
const action = `${prefix} ${entry.action.title}`;
|
|
110
|
+
const bindingText =
|
|
111
|
+
entry.action.bindingHint?.trim() ??
|
|
112
|
+
entry.action.detail?.trim() ??
|
|
113
|
+
entry.action.sectionLabel?.trim() ??
|
|
114
|
+
'';
|
|
115
|
+
rows.push(
|
|
116
|
+
`${truncateColumn(screen, leftWidth)} | ${truncateColumn(action, middleWidth)} | ${truncateColumn(bindingText, rightWidth)}`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return rows;
|
|
120
|
+
}
|
|
121
|
+
|
|
46
122
|
export function buildNewThreadModalOverlay(
|
|
47
123
|
layoutCols: number,
|
|
48
124
|
viewportRows: number,
|
|
@@ -88,37 +164,43 @@ export function buildCommandMenuModalOverlay(
|
|
|
88
164
|
return null;
|
|
89
165
|
}
|
|
90
166
|
const isThemePicker = menu.scope === 'theme-select';
|
|
167
|
+
const isShortcutsScope = menu.scope === 'shortcuts';
|
|
91
168
|
const modalSize = resolveGoldenModalSize(layoutCols, viewportRows, {
|
|
92
|
-
preferredHeight:
|
|
93
|
-
minWidth:
|
|
94
|
-
maxWidth:
|
|
169
|
+
preferredHeight: isShortcutsScope ? 24 : COMMAND_PALETTE_MODAL_SIZE.preferredHeight,
|
|
170
|
+
minWidth: isShortcutsScope ? 84 : COMMAND_PALETTE_MODAL_SIZE.minWidth,
|
|
171
|
+
maxWidth: isShortcutsScope ? 132 : COMMAND_PALETTE_MODAL_SIZE.maxWidth,
|
|
95
172
|
});
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
: Math.floor(selectedIndex / COMMAND_MENU_MAX_RESULTS) * COMMAND_MENU_MAX_RESULTS;
|
|
103
|
-
const visibleMatches = matches.slice(pageStart, pageStart + COMMAND_MENU_MAX_RESULTS);
|
|
104
|
-
const bodyLines: string[] = [`${isThemePicker ? 'theme' : 'search'}: ${menu.query}_`, ''];
|
|
105
|
-
if (matches.length === 0) {
|
|
173
|
+
const page = resolveCommandMenuPage(actions, menu);
|
|
174
|
+
const bodyLines: string[] = [
|
|
175
|
+
`${isThemePicker ? 'theme' : isShortcutsScope ? 'shortcuts' : 'search'}: ${menu.query}_`,
|
|
176
|
+
'',
|
|
177
|
+
];
|
|
178
|
+
if (page.matches.length === 0) {
|
|
106
179
|
bodyLines.push('no actions match');
|
|
107
180
|
} else {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
181
|
+
if (isShortcutsScope) {
|
|
182
|
+
bodyLines.push(...renderShortcutsTableRows(page, modalSize.width));
|
|
183
|
+
} else {
|
|
184
|
+
for (const entry of page.displayEntries) {
|
|
185
|
+
const prefix = entry.absoluteIndex === page.selectedIndex ? '>' : ' ';
|
|
186
|
+
const detail = entry.action.detail?.trim() ?? '';
|
|
187
|
+
bodyLines.push(
|
|
188
|
+
detail.length > 0
|
|
189
|
+
? `${prefix} ${entry.action.title} - ${detail}`
|
|
190
|
+
: `${prefix} ${entry.action.title}`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
118
193
|
}
|
|
119
194
|
}
|
|
120
|
-
bodyLines.push(
|
|
121
|
-
|
|
195
|
+
bodyLines.push(
|
|
196
|
+
'',
|
|
197
|
+
isThemePicker
|
|
198
|
+
? 'type to filter themes'
|
|
199
|
+
: isShortcutsScope
|
|
200
|
+
? 'type to filter keybindings'
|
|
201
|
+
: 'type to filter',
|
|
202
|
+
);
|
|
203
|
+
const title = isThemePicker ? 'Choose Theme' : isShortcutsScope ? 'Shortcuts' : 'Command Menu';
|
|
122
204
|
return buildUiModalOverlay({
|
|
123
205
|
viewportCols: layoutCols,
|
|
124
206
|
viewportRows,
|
|
@@ -128,7 +210,11 @@ export function buildCommandMenuModalOverlay(
|
|
|
128
210
|
marginRows: 1,
|
|
129
211
|
title,
|
|
130
212
|
bodyLines,
|
|
131
|
-
footer: isThemePicker
|
|
213
|
+
footer: isThemePicker
|
|
214
|
+
? 'enter apply esc cancel'
|
|
215
|
+
: isShortcutsScope
|
|
216
|
+
? 'enter close esc'
|
|
217
|
+
: 'enter run esc',
|
|
132
218
|
theme,
|
|
133
219
|
});
|
|
134
220
|
}
|
|
@@ -191,7 +277,7 @@ export function buildTaskEditorModalOverlay(
|
|
|
191
277
|
const taskBody = [
|
|
192
278
|
`${prompt.fieldIndex === 0 ? '>' : ' '} title: ${prompt.title}${prompt.fieldIndex === 0 ? '_' : ''}`,
|
|
193
279
|
`${prompt.fieldIndex === 1 ? '>' : ' '} repository: ${selectedRepositoryName}`,
|
|
194
|
-
`${prompt.fieldIndex === 2 ? '>' : ' '}
|
|
280
|
+
`${prompt.fieldIndex === 2 ? '>' : ' '} body: ${prompt.body}${
|
|
195
281
|
prompt.fieldIndex === 2 ? '_' : ''
|
|
196
282
|
}`,
|
|
197
283
|
'',
|
|
@@ -252,6 +338,43 @@ export function buildRepositoryModalOverlay(
|
|
|
252
338
|
});
|
|
253
339
|
}
|
|
254
340
|
|
|
341
|
+
export function buildApiKeyModalOverlay(
|
|
342
|
+
layoutCols: number,
|
|
343
|
+
viewportRows: number,
|
|
344
|
+
prompt: ApiKeyPromptOverlayState | null,
|
|
345
|
+
theme: UiModalThemeInput,
|
|
346
|
+
): ReturnType<typeof buildUiModalOverlay> | null {
|
|
347
|
+
if (prompt === null) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const modalSize = resolveGoldenModalSize(layoutCols, viewportRows, {
|
|
351
|
+
preferredHeight: COMMAND_PALETTE_MODAL_SIZE.preferredHeight,
|
|
352
|
+
minWidth: COMMAND_PALETTE_MODAL_SIZE.minWidth,
|
|
353
|
+
maxWidth: COMMAND_PALETTE_MODAL_SIZE.maxWidth,
|
|
354
|
+
});
|
|
355
|
+
const promptValue = prompt.value.length > 0 ? prompt.value : '(enter value)';
|
|
356
|
+
const bodyLines = [`${prompt.keyName}: ${promptValue}_`];
|
|
357
|
+
if (prompt.error !== null && prompt.error.length > 0) {
|
|
358
|
+
bodyLines.push(`error: ${prompt.error}`);
|
|
359
|
+
} else if (prompt.hasExistingValue) {
|
|
360
|
+
bodyLines.push('warning: existing value detected (submit will overwrite)');
|
|
361
|
+
} else {
|
|
362
|
+
bodyLines.push('value is saved to user-global secrets.env');
|
|
363
|
+
}
|
|
364
|
+
return buildUiModalOverlay({
|
|
365
|
+
viewportCols: layoutCols,
|
|
366
|
+
viewportRows,
|
|
367
|
+
width: modalSize.width,
|
|
368
|
+
height: modalSize.height,
|
|
369
|
+
anchor: 'center',
|
|
370
|
+
marginRows: 1,
|
|
371
|
+
title: `Set ${prompt.displayName}`,
|
|
372
|
+
bodyLines,
|
|
373
|
+
footer: 'enter save esc',
|
|
374
|
+
theme,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
255
378
|
export function buildConversationTitleModalOverlay(
|
|
256
379
|
layoutCols: number,
|
|
257
380
|
viewportRows: number,
|
|
@@ -293,3 +416,59 @@ export function buildConversationTitleModalOverlay(
|
|
|
293
416
|
theme,
|
|
294
417
|
});
|
|
295
418
|
}
|
|
419
|
+
|
|
420
|
+
export function buildReleaseNotesModalOverlay(
|
|
421
|
+
layoutCols: number,
|
|
422
|
+
viewportRows: number,
|
|
423
|
+
prompt: ReleaseNotesOverlayState | null,
|
|
424
|
+
theme: UiModalThemeInput,
|
|
425
|
+
): ReturnType<typeof buildUiModalOverlay> | null {
|
|
426
|
+
if (prompt === null) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
const modalSize = resolveGoldenModalSize(layoutCols, viewportRows, {
|
|
430
|
+
preferredHeight: 24,
|
|
431
|
+
minWidth: 48,
|
|
432
|
+
maxWidth: 110,
|
|
433
|
+
});
|
|
434
|
+
const bodyLines: string[] = [
|
|
435
|
+
`installed: v${prompt.currentVersion}`,
|
|
436
|
+
`latest: ${prompt.latestTag}`,
|
|
437
|
+
RELEASE_NOTES_UPDATE_ACTION_LABEL,
|
|
438
|
+
'',
|
|
439
|
+
];
|
|
440
|
+
const hasPreviewContent = prompt.releases.some(
|
|
441
|
+
(release) => release.previewLines.length > 0 || release.previewTruncated,
|
|
442
|
+
);
|
|
443
|
+
if (!hasPreviewContent) {
|
|
444
|
+
bodyLines.push(`version available: ${prompt.latestTag}`);
|
|
445
|
+
bodyLines.push('release notes not published yet');
|
|
446
|
+
bodyLines.push(`cmd+click: ${prompt.releases[0]?.url ?? prompt.releasesPageUrl}`, '');
|
|
447
|
+
} else {
|
|
448
|
+
for (const release of prompt.releases) {
|
|
449
|
+
const heading =
|
|
450
|
+
release.name.trim().length > 0 ? `${release.tag} - ${release.name}` : release.tag;
|
|
451
|
+
bodyLines.push(heading);
|
|
452
|
+
for (const line of release.previewLines) {
|
|
453
|
+
bodyLines.push(` ${line}`);
|
|
454
|
+
}
|
|
455
|
+
if (release.previewTruncated) {
|
|
456
|
+
bodyLines.push(' ...');
|
|
457
|
+
}
|
|
458
|
+
bodyLines.push(` cmd+click: ${release.url}`, '');
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
bodyLines.push(`all releases: ${prompt.releasesPageUrl}`);
|
|
462
|
+
return buildUiModalOverlay({
|
|
463
|
+
viewportCols: layoutCols,
|
|
464
|
+
viewportRows,
|
|
465
|
+
width: modalSize.width,
|
|
466
|
+
height: modalSize.height,
|
|
467
|
+
anchor: 'center',
|
|
468
|
+
marginRows: 1,
|
|
469
|
+
title: "What's New",
|
|
470
|
+
bodyLines,
|
|
471
|
+
footer: 'click update enter dismiss u update n never o open latest',
|
|
472
|
+
theme,
|
|
473
|
+
});
|
|
474
|
+
}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { parseMuxInputChunk } from '../dual-pane-core.ts';
|
|
2
|
-
import {
|
|
2
|
+
import type { UiModalOverlay } from '../../../packages/harness-ui/src/kit.ts';
|
|
3
3
|
import { isMotionMouseCode, isWheelMouseCode } from './selection.ts';
|
|
4
4
|
|
|
5
5
|
interface DismissModalOnOutsideClickOptions {
|
|
6
6
|
input: Buffer;
|
|
7
7
|
inputRemainder: string;
|
|
8
8
|
dismiss: () => void;
|
|
9
|
-
buildCurrentModalOverlay: () =>
|
|
9
|
+
buildCurrentModalOverlay: () => UiModalOverlay | null;
|
|
10
10
|
onInsidePointerPress?: (col: number, row: number) => boolean;
|
|
11
|
-
isOverlayHit: (
|
|
12
|
-
overlay: ReturnType<typeof buildUiModalOverlay>,
|
|
13
|
-
col: number,
|
|
14
|
-
row: number,
|
|
15
|
-
) => boolean;
|
|
11
|
+
isOverlayHit: (overlay: UiModalOverlay, col: number, row: number) => boolean;
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
interface DismissModalOnOutsideClickResult {
|