@jmoyers/harness 0.1.11 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -39
- 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/packages/harness-ui/src/modal-manager.ts +222 -0
- 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 -3872
- package/scripts/control-plane-daemon.ts +11 -0
- 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 -3019
- package/scripts/nim-tui-smoke.ts +748 -0
- package/src/cli/auth/runtime.ts +948 -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 +348 -8
- package/src/config/harness.config.template.jsonc +33 -0
- package/src/control-plane/agent-realtime-api.ts +82 -427
- 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-command.ts +376 -69
- package/src/control-plane/stream-server-session-runtime.ts +3 -2
- package/src/control-plane/stream-server.ts +864 -70
- 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/workspace.ts +68 -5
- 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 +13 -131
- 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-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 +77 -12
- package/src/mux/live-mux/modal-overlays.ts +168 -34
- package/src/mux/live-mux/modal-pointer.ts +3 -7
- package/src/mux/live-mux/modal-prompt-handlers.ts +23 -2
- 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 +10 -101
- 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 +73 -46
- package/src/services/runtime-conversation-starter.ts +53 -45
- 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 -72
- 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 +360 -56
- package/src/store/event-store.ts +366 -8
- 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 -85
- 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 -195
- package/src/services/runtime-main-pane-input.ts +0 -230
- package/src/services/runtime-modal-input.ts +0 -137
- package/src/services/runtime-navigation-input.ts +0 -197
- package/src/services/runtime-rail-input.ts +0 -279
- 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 -269
- 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/modals/manager.ts +0 -218
- 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,8 +19,25 @@ interface LinePromptReduction {
|
|
|
19
19
|
submit: boolean;
|
|
20
20
|
}
|
|
21
21
|
|
|
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
|
+
|
|
22
31
|
const BRACKETED_PASTE_START = Buffer.from('\u001b[200~', 'utf8');
|
|
23
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
|
+
}
|
|
24
41
|
|
|
25
42
|
function matchesSequence(input: Buffer, startIndex: number, sequence: Buffer): boolean {
|
|
26
43
|
if (startIndex < 0 || startIndex + sequence.length > input.length) {
|
|
@@ -34,22 +51,60 @@ function matchesSequence(input: Buffer, startIndex: number, sequence: Buffer): b
|
|
|
34
51
|
return true;
|
|
35
52
|
}
|
|
36
53
|
|
|
37
|
-
|
|
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
|
+
|
|
38
84
|
let nextValue = value;
|
|
39
85
|
let submit = false;
|
|
40
|
-
let inBracketedPaste =
|
|
41
|
-
|
|
42
|
-
|
|
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)) {
|
|
43
90
|
inBracketedPaste = true;
|
|
44
91
|
index += BRACKETED_PASTE_START.length - 1;
|
|
45
92
|
continue;
|
|
46
93
|
}
|
|
47
|
-
if (
|
|
94
|
+
if (matchesSequence(mergedInput, index, BRACKETED_PASTE_END)) {
|
|
48
95
|
inBracketedPaste = false;
|
|
49
96
|
index += BRACKETED_PASTE_END.length - 1;
|
|
50
97
|
continue;
|
|
51
98
|
}
|
|
52
|
-
|
|
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]!;
|
|
53
108
|
if (inBracketedPaste) {
|
|
54
109
|
if (byte >= 32 && byte <= 126) {
|
|
55
110
|
nextValue += String.fromCharCode(byte);
|
|
@@ -68,9 +123,19 @@ export function reduceLinePromptInput(value: string, input: Buffer): LinePromptR
|
|
|
68
123
|
nextValue += String.fromCharCode(byte);
|
|
69
124
|
}
|
|
70
125
|
}
|
|
126
|
+
if (lineInputState === undefined) {
|
|
127
|
+
return {
|
|
128
|
+
value: nextValue,
|
|
129
|
+
submit,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
71
132
|
return {
|
|
72
133
|
value: nextValue,
|
|
73
134
|
submit,
|
|
135
|
+
lineInputState: {
|
|
136
|
+
inBracketedPaste,
|
|
137
|
+
pendingSequence,
|
|
138
|
+
},
|
|
74
139
|
};
|
|
75
140
|
}
|
|
76
141
|
|
|
@@ -79,7 +144,7 @@ export function reduceTaskEditorPromptInput(
|
|
|
79
144
|
input: Buffer,
|
|
80
145
|
): TaskEditorPromptReduction {
|
|
81
146
|
let nextTitle = prompt.title;
|
|
82
|
-
let
|
|
147
|
+
let nextBody = prompt.body;
|
|
83
148
|
let nextFieldIndex = prompt.fieldIndex;
|
|
84
149
|
let nextRepositoryIndex = prompt.repositoryIndex;
|
|
85
150
|
let submit = false;
|
|
@@ -104,7 +169,7 @@ export function reduceTaskEditorPromptInput(
|
|
|
104
169
|
if (nextFieldIndex === 0) {
|
|
105
170
|
nextTitle = nextTitle.slice(0, -1);
|
|
106
171
|
} else if (nextFieldIndex === 2) {
|
|
107
|
-
|
|
172
|
+
nextBody = nextBody.slice(0, -1);
|
|
108
173
|
}
|
|
109
174
|
continue;
|
|
110
175
|
}
|
|
@@ -112,14 +177,14 @@ export function reduceTaskEditorPromptInput(
|
|
|
112
177
|
if (nextFieldIndex === 0) {
|
|
113
178
|
nextTitle += String.fromCharCode(byte);
|
|
114
179
|
} else if (nextFieldIndex === 2) {
|
|
115
|
-
|
|
180
|
+
nextBody += String.fromCharCode(byte);
|
|
116
181
|
}
|
|
117
182
|
}
|
|
118
183
|
}
|
|
119
184
|
}
|
|
120
185
|
return {
|
|
121
186
|
title: nextTitle,
|
|
122
|
-
|
|
187
|
+
body: nextBody,
|
|
123
188
|
repositoryIndex: nextRepositoryIndex,
|
|
124
189
|
fieldIndex: nextFieldIndex,
|
|
125
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;
|
|
@@ -51,6 +56,69 @@ interface ConversationTitleOverlayState {
|
|
|
51
56
|
persistInFlight: boolean;
|
|
52
57
|
}
|
|
53
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
|
+
|
|
54
122
|
export function buildNewThreadModalOverlay(
|
|
55
123
|
layoutCols: number,
|
|
56
124
|
viewportRows: number,
|
|
@@ -96,37 +164,43 @@ export function buildCommandMenuModalOverlay(
|
|
|
96
164
|
return null;
|
|
97
165
|
}
|
|
98
166
|
const isThemePicker = menu.scope === 'theme-select';
|
|
167
|
+
const isShortcutsScope = menu.scope === 'shortcuts';
|
|
99
168
|
const modalSize = resolveGoldenModalSize(layoutCols, viewportRows, {
|
|
100
|
-
preferredHeight:
|
|
101
|
-
minWidth:
|
|
102
|
-
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,
|
|
103
172
|
});
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
: Math.floor(selectedIndex / COMMAND_MENU_MAX_RESULTS) * COMMAND_MENU_MAX_RESULTS;
|
|
111
|
-
const visibleMatches = matches.slice(pageStart, pageStart + COMMAND_MENU_MAX_RESULTS);
|
|
112
|
-
const bodyLines: string[] = [`${isThemePicker ? 'theme' : 'search'}: ${menu.query}_`, ''];
|
|
113
|
-
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) {
|
|
114
179
|
bodyLines.push('no actions match');
|
|
115
180
|
} else {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
+
}
|
|
126
193
|
}
|
|
127
194
|
}
|
|
128
|
-
bodyLines.push(
|
|
129
|
-
|
|
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';
|
|
130
204
|
return buildUiModalOverlay({
|
|
131
205
|
viewportCols: layoutCols,
|
|
132
206
|
viewportRows,
|
|
@@ -136,7 +210,11 @@ export function buildCommandMenuModalOverlay(
|
|
|
136
210
|
marginRows: 1,
|
|
137
211
|
title,
|
|
138
212
|
bodyLines,
|
|
139
|
-
footer: isThemePicker
|
|
213
|
+
footer: isThemePicker
|
|
214
|
+
? 'enter apply esc cancel'
|
|
215
|
+
: isShortcutsScope
|
|
216
|
+
? 'enter close esc'
|
|
217
|
+
: 'enter run esc',
|
|
140
218
|
theme,
|
|
141
219
|
});
|
|
142
220
|
}
|
|
@@ -199,7 +277,7 @@ export function buildTaskEditorModalOverlay(
|
|
|
199
277
|
const taskBody = [
|
|
200
278
|
`${prompt.fieldIndex === 0 ? '>' : ' '} title: ${prompt.title}${prompt.fieldIndex === 0 ? '_' : ''}`,
|
|
201
279
|
`${prompt.fieldIndex === 1 ? '>' : ' '} repository: ${selectedRepositoryName}`,
|
|
202
|
-
`${prompt.fieldIndex === 2 ? '>' : ' '}
|
|
280
|
+
`${prompt.fieldIndex === 2 ? '>' : ' '} body: ${prompt.body}${
|
|
203
281
|
prompt.fieldIndex === 2 ? '_' : ''
|
|
204
282
|
}`,
|
|
205
283
|
'',
|
|
@@ -270,9 +348,9 @@ export function buildApiKeyModalOverlay(
|
|
|
270
348
|
return null;
|
|
271
349
|
}
|
|
272
350
|
const modalSize = resolveGoldenModalSize(layoutCols, viewportRows, {
|
|
273
|
-
preferredHeight:
|
|
274
|
-
minWidth:
|
|
275
|
-
maxWidth:
|
|
351
|
+
preferredHeight: COMMAND_PALETTE_MODAL_SIZE.preferredHeight,
|
|
352
|
+
minWidth: COMMAND_PALETTE_MODAL_SIZE.minWidth,
|
|
353
|
+
maxWidth: COMMAND_PALETTE_MODAL_SIZE.maxWidth,
|
|
276
354
|
});
|
|
277
355
|
const promptValue = prompt.value.length > 0 ? prompt.value : '(enter value)';
|
|
278
356
|
const bodyLines = [`${prompt.keyName}: ${promptValue}_`];
|
|
@@ -338,3 +416,59 @@ export function buildConversationTitleModalOverlay(
|
|
|
338
416
|
theme,
|
|
339
417
|
});
|
|
340
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 {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createLinePromptInputState,
|
|
3
|
+
reduceLinePromptInput,
|
|
4
|
+
type LinePromptInputState,
|
|
5
|
+
} from './modal-input-reducers.ts';
|
|
2
6
|
|
|
3
7
|
interface AddDirectoryPromptState {
|
|
4
8
|
value: string;
|
|
@@ -18,6 +22,7 @@ interface ApiKeyPromptState {
|
|
|
18
22
|
readonly value: string;
|
|
19
23
|
readonly error: string | null;
|
|
20
24
|
readonly hasExistingValue: boolean;
|
|
25
|
+
readonly lineInputState?: LinePromptInputState;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
interface HandleAddDirectoryPromptInputOptions {
|
|
@@ -54,6 +59,8 @@ interface HandleApiKeyPromptInputOptions {
|
|
|
54
59
|
persistApiKey: (keyName: string, value: string) => void;
|
|
55
60
|
}
|
|
56
61
|
|
|
62
|
+
const MOUSE_EVENT_PREFIX = Buffer.from('\u001b[<', 'utf8');
|
|
63
|
+
|
|
57
64
|
export function handleAddDirectoryPromptInput(
|
|
58
65
|
options: HandleAddDirectoryPromptInputOptions,
|
|
59
66
|
): boolean {
|
|
@@ -78,7 +85,9 @@ export function handleAddDirectoryPromptInput(
|
|
|
78
85
|
markDirty();
|
|
79
86
|
return true;
|
|
80
87
|
}
|
|
88
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
81
89
|
if (
|
|
90
|
+
maybeMouseSequence &&
|
|
82
91
|
dismissOnOutsideClick(input, () => {
|
|
83
92
|
setPrompt(null);
|
|
84
93
|
markDirty();
|
|
@@ -141,7 +150,9 @@ export function handleRepositoryPromptInput(options: HandleRepositoryPromptInput
|
|
|
141
150
|
markDirty();
|
|
142
151
|
return true;
|
|
143
152
|
}
|
|
153
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
144
154
|
if (
|
|
155
|
+
maybeMouseSequence &&
|
|
145
156
|
dismissOnOutsideClick(input, () => {
|
|
146
157
|
setPrompt(null);
|
|
147
158
|
markDirty();
|
|
@@ -225,7 +236,9 @@ export function handleApiKeyPromptInput(options: HandleApiKeyPromptInputOptions)
|
|
|
225
236
|
markDirty();
|
|
226
237
|
return true;
|
|
227
238
|
}
|
|
239
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
228
240
|
if (
|
|
241
|
+
maybeMouseSequence &&
|
|
229
242
|
dismissOnOutsideClick(input, () => {
|
|
230
243
|
setPrompt(null);
|
|
231
244
|
markDirty();
|
|
@@ -234,13 +247,19 @@ export function handleApiKeyPromptInput(options: HandleApiKeyPromptInputOptions)
|
|
|
234
247
|
return true;
|
|
235
248
|
}
|
|
236
249
|
|
|
237
|
-
const reduced = reduceLinePromptInput(
|
|
250
|
+
const reduced = reduceLinePromptInput(
|
|
251
|
+
prompt.value,
|
|
252
|
+
input,
|
|
253
|
+
prompt.lineInputState ?? createLinePromptInputState(),
|
|
254
|
+
);
|
|
238
255
|
const value = reduced.value;
|
|
256
|
+
const lineInputState = reduced.lineInputState;
|
|
239
257
|
if (!reduced.submit) {
|
|
240
258
|
setPrompt({
|
|
241
259
|
...prompt,
|
|
242
260
|
value,
|
|
243
261
|
error: null,
|
|
262
|
+
lineInputState,
|
|
244
263
|
});
|
|
245
264
|
markDirty();
|
|
246
265
|
return true;
|
|
@@ -252,6 +271,7 @@ export function handleApiKeyPromptInput(options: HandleApiKeyPromptInputOptions)
|
|
|
252
271
|
...prompt,
|
|
253
272
|
value,
|
|
254
273
|
error: `${prompt.displayName.toLowerCase()} required`,
|
|
274
|
+
lineInputState,
|
|
255
275
|
});
|
|
256
276
|
markDirty();
|
|
257
277
|
return true;
|
|
@@ -265,6 +285,7 @@ export function handleApiKeyPromptInput(options: HandleApiKeyPromptInputOptions)
|
|
|
265
285
|
...prompt,
|
|
266
286
|
value,
|
|
267
287
|
error: message,
|
|
288
|
+
lineInputState,
|
|
268
289
|
});
|
|
269
290
|
}
|
|
270
291
|
markDirty();
|