@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,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;
|
|
@@ -12,6 +16,15 @@ interface RepositoryPromptState {
|
|
|
12
16
|
readonly error: string | null;
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
interface ApiKeyPromptState {
|
|
20
|
+
readonly keyName: string;
|
|
21
|
+
readonly displayName: string;
|
|
22
|
+
readonly value: string;
|
|
23
|
+
readonly error: string | null;
|
|
24
|
+
readonly hasExistingValue: boolean;
|
|
25
|
+
readonly lineInputState?: LinePromptInputState;
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
interface HandleAddDirectoryPromptInputOptions {
|
|
16
29
|
input: Buffer;
|
|
17
30
|
prompt: AddDirectoryPromptState | null;
|
|
@@ -36,6 +49,18 @@ interface HandleRepositoryPromptInputOptions {
|
|
|
36
49
|
upsertRepositoryByRemoteUrl: (remoteUrl: string, existingRepositoryId?: string) => Promise<void>;
|
|
37
50
|
}
|
|
38
51
|
|
|
52
|
+
interface HandleApiKeyPromptInputOptions {
|
|
53
|
+
input: Buffer;
|
|
54
|
+
prompt: ApiKeyPromptState | null;
|
|
55
|
+
isQuitShortcut: (input: Buffer) => boolean;
|
|
56
|
+
dismissOnOutsideClick: (input: Buffer, dismiss: () => void) => boolean;
|
|
57
|
+
setPrompt: (next: ApiKeyPromptState | null) => void;
|
|
58
|
+
markDirty: () => void;
|
|
59
|
+
persistApiKey: (keyName: string, value: string) => void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const MOUSE_EVENT_PREFIX = Buffer.from('\u001b[<', 'utf8');
|
|
63
|
+
|
|
39
64
|
export function handleAddDirectoryPromptInput(
|
|
40
65
|
options: HandleAddDirectoryPromptInputOptions,
|
|
41
66
|
): boolean {
|
|
@@ -60,7 +85,9 @@ export function handleAddDirectoryPromptInput(
|
|
|
60
85
|
markDirty();
|
|
61
86
|
return true;
|
|
62
87
|
}
|
|
88
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
63
89
|
if (
|
|
90
|
+
maybeMouseSequence &&
|
|
64
91
|
dismissOnOutsideClick(input, () => {
|
|
65
92
|
setPrompt(null);
|
|
66
93
|
markDirty();
|
|
@@ -123,7 +150,9 @@ export function handleRepositoryPromptInput(options: HandleRepositoryPromptInput
|
|
|
123
150
|
markDirty();
|
|
124
151
|
return true;
|
|
125
152
|
}
|
|
153
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
126
154
|
if (
|
|
155
|
+
maybeMouseSequence &&
|
|
127
156
|
dismissOnOutsideClick(input, () => {
|
|
128
157
|
setPrompt(null);
|
|
129
158
|
markDirty();
|
|
@@ -185,3 +214,80 @@ export function handleRepositoryPromptInput(options: HandleRepositoryPromptInput
|
|
|
185
214
|
markDirty();
|
|
186
215
|
return true;
|
|
187
216
|
}
|
|
217
|
+
|
|
218
|
+
export function handleApiKeyPromptInput(options: HandleApiKeyPromptInputOptions): boolean {
|
|
219
|
+
const {
|
|
220
|
+
input,
|
|
221
|
+
prompt,
|
|
222
|
+
isQuitShortcut,
|
|
223
|
+
dismissOnOutsideClick,
|
|
224
|
+
setPrompt,
|
|
225
|
+
markDirty,
|
|
226
|
+
persistApiKey,
|
|
227
|
+
} = options;
|
|
228
|
+
if (prompt === null) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
if (input.length === 1 && input[0] === 0x03) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
if (isQuitShortcut(input)) {
|
|
235
|
+
setPrompt(null);
|
|
236
|
+
markDirty();
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
240
|
+
if (
|
|
241
|
+
maybeMouseSequence &&
|
|
242
|
+
dismissOnOutsideClick(input, () => {
|
|
243
|
+
setPrompt(null);
|
|
244
|
+
markDirty();
|
|
245
|
+
})
|
|
246
|
+
) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const reduced = reduceLinePromptInput(
|
|
251
|
+
prompt.value,
|
|
252
|
+
input,
|
|
253
|
+
prompt.lineInputState ?? createLinePromptInputState(),
|
|
254
|
+
);
|
|
255
|
+
const value = reduced.value;
|
|
256
|
+
const lineInputState = reduced.lineInputState;
|
|
257
|
+
if (!reduced.submit) {
|
|
258
|
+
setPrompt({
|
|
259
|
+
...prompt,
|
|
260
|
+
value,
|
|
261
|
+
error: null,
|
|
262
|
+
lineInputState,
|
|
263
|
+
});
|
|
264
|
+
markDirty();
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const trimmed = value.trim();
|
|
269
|
+
if (trimmed.length === 0) {
|
|
270
|
+
setPrompt({
|
|
271
|
+
...prompt,
|
|
272
|
+
value,
|
|
273
|
+
error: `${prompt.displayName.toLowerCase()} required`,
|
|
274
|
+
lineInputState,
|
|
275
|
+
});
|
|
276
|
+
markDirty();
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
persistApiKey(prompt.keyName, trimmed);
|
|
281
|
+
setPrompt(null);
|
|
282
|
+
} catch (error: unknown) {
|
|
283
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
284
|
+
setPrompt({
|
|
285
|
+
...prompt,
|
|
286
|
+
value,
|
|
287
|
+
error: message,
|
|
288
|
+
lineInputState,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
markDirty();
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { ReleaseNotesPrompt } from './release-notes.ts';
|
|
2
|
+
import { RELEASE_NOTES_UPDATE_ACTION_ROW_OFFSET } from './modal-overlays.ts';
|
|
3
|
+
|
|
4
|
+
interface HandleReleaseNotesModalInputOptions {
|
|
5
|
+
readonly input: Buffer;
|
|
6
|
+
readonly prompt: ReleaseNotesPrompt | null;
|
|
7
|
+
readonly isQuitShortcut: (input: Buffer) => boolean;
|
|
8
|
+
readonly dismissOnOutsideClick: (
|
|
9
|
+
input: Buffer,
|
|
10
|
+
dismiss: () => void,
|
|
11
|
+
onInsidePointerPress?: (col: number, row: number) => boolean,
|
|
12
|
+
) => boolean;
|
|
13
|
+
readonly buildReleaseNotesModalOverlay: () => { top: number } | null;
|
|
14
|
+
readonly setPrompt: (next: ReleaseNotesPrompt | null) => void;
|
|
15
|
+
readonly markDirty: () => void;
|
|
16
|
+
readonly onDismiss: (latestTag: string) => void;
|
|
17
|
+
readonly onNeverShowAgain: (latestTag: string) => void;
|
|
18
|
+
readonly onOpenLatest: (prompt: ReleaseNotesPrompt) => void;
|
|
19
|
+
readonly onUpdate: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function byteMatches(inputByte: number, lower: string): boolean {
|
|
23
|
+
const ascii = lower.charCodeAt(0);
|
|
24
|
+
return inputByte === ascii || inputByte === ascii - 32;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function handleReleaseNotesModalInput(
|
|
28
|
+
options: HandleReleaseNotesModalInputOptions,
|
|
29
|
+
): boolean {
|
|
30
|
+
const {
|
|
31
|
+
input,
|
|
32
|
+
prompt,
|
|
33
|
+
isQuitShortcut,
|
|
34
|
+
dismissOnOutsideClick,
|
|
35
|
+
buildReleaseNotesModalOverlay,
|
|
36
|
+
setPrompt,
|
|
37
|
+
markDirty,
|
|
38
|
+
onDismiss,
|
|
39
|
+
onNeverShowAgain,
|
|
40
|
+
onOpenLatest,
|
|
41
|
+
onUpdate,
|
|
42
|
+
} = options;
|
|
43
|
+
if (prompt === null) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (input.length === 1 && input[0] === 0x03) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (isQuitShortcut(input)) {
|
|
50
|
+
setPrompt(null);
|
|
51
|
+
onDismiss(prompt.latestTag);
|
|
52
|
+
markDirty();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (
|
|
56
|
+
input.includes(0x3c) &&
|
|
57
|
+
dismissOnOutsideClick(
|
|
58
|
+
input,
|
|
59
|
+
() => {
|
|
60
|
+
setPrompt(null);
|
|
61
|
+
onDismiss(prompt.latestTag);
|
|
62
|
+
markDirty();
|
|
63
|
+
},
|
|
64
|
+
(_col, row) => {
|
|
65
|
+
const overlay = buildReleaseNotesModalOverlay();
|
|
66
|
+
if (overlay === null) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (row - 1 !== overlay.top + RELEASE_NOTES_UPDATE_ACTION_ROW_OFFSET) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
setPrompt(null);
|
|
73
|
+
onDismiss(prompt.latestTag);
|
|
74
|
+
onUpdate();
|
|
75
|
+
markDirty();
|
|
76
|
+
return true;
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const byte of input) {
|
|
84
|
+
if (byte === 0x0d || byte === 0x0a) {
|
|
85
|
+
setPrompt(null);
|
|
86
|
+
onDismiss(prompt.latestTag);
|
|
87
|
+
markDirty();
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
if (byteMatches(byte, 'n')) {
|
|
91
|
+
setPrompt(null);
|
|
92
|
+
onNeverShowAgain(prompt.latestTag);
|
|
93
|
+
markDirty();
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (byteMatches(byte, 'u')) {
|
|
97
|
+
setPrompt(null);
|
|
98
|
+
onDismiss(prompt.latestTag);
|
|
99
|
+
onUpdate();
|
|
100
|
+
markDirty();
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
if (byteMatches(byte, 'o')) {
|
|
104
|
+
onOpenLatest(prompt);
|
|
105
|
+
markDirty();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
@@ -12,9 +12,10 @@ interface TaskEditorPromptState extends TaskEditorPromptInputState {
|
|
|
12
12
|
interface TaskEditorSubmitPayload {
|
|
13
13
|
mode: 'create' | 'edit';
|
|
14
14
|
taskId: string | null;
|
|
15
|
-
repositoryId: string;
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
repositoryId: string | null;
|
|
16
|
+
projectId?: string | null;
|
|
17
|
+
title: string | null;
|
|
18
|
+
body: string;
|
|
18
19
|
commandLabel: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -32,6 +33,8 @@ interface HandleTaskEditorPromptInputOptions {
|
|
|
32
33
|
dismissOnOutsideClick: (input: Buffer, dismiss: () => void) => boolean;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
const MOUSE_EVENT_PREFIX = Buffer.from('\u001b[<', 'utf8');
|
|
37
|
+
|
|
35
38
|
export function handleTaskEditorPromptInput(
|
|
36
39
|
options: HandleTaskEditorPromptInputOptions,
|
|
37
40
|
): HandleTaskEditorPromptInputResult {
|
|
@@ -57,7 +60,9 @@ export function handleTaskEditorPromptInput(
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
let dismissed = false;
|
|
63
|
+
const maybeMouseSequence = input.includes(MOUSE_EVENT_PREFIX);
|
|
60
64
|
if (
|
|
65
|
+
maybeMouseSequence &&
|
|
61
66
|
dismissOnOutsideClick(input, () => {
|
|
62
67
|
dismissed = true;
|
|
63
68
|
})
|
|
@@ -77,13 +82,13 @@ export function handleTaskEditorPromptInput(
|
|
|
77
82
|
|
|
78
83
|
const reduced = reduceTaskEditorPromptInput(prompt, input);
|
|
79
84
|
const nextTitle = reduced.title;
|
|
80
|
-
const
|
|
85
|
+
const nextBody = reduced.body;
|
|
81
86
|
const nextFieldIndex = reduced.fieldIndex;
|
|
82
87
|
const nextRepositoryIndex = reduced.repositoryIndex;
|
|
83
88
|
const submit = reduced.submit;
|
|
84
89
|
const changed =
|
|
85
90
|
nextTitle !== prompt.title ||
|
|
86
|
-
|
|
91
|
+
nextBody !== prompt.body ||
|
|
87
92
|
nextFieldIndex !== prompt.fieldIndex ||
|
|
88
93
|
nextRepositoryIndex !== prompt.repositoryIndex;
|
|
89
94
|
|
|
@@ -91,7 +96,7 @@ export function handleTaskEditorPromptInput(
|
|
|
91
96
|
? {
|
|
92
97
|
...prompt,
|
|
93
98
|
title: nextTitle,
|
|
94
|
-
|
|
99
|
+
body: nextBody,
|
|
95
100
|
fieldIndex: nextFieldIndex,
|
|
96
101
|
repositoryIndex: nextRepositoryIndex,
|
|
97
102
|
error: null,
|
|
@@ -113,13 +118,12 @@ export function handleTaskEditorPromptInput(
|
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
const repositoryId = prompt.repositoryIds[nextRepositoryIndex] ?? null;
|
|
116
|
-
|
|
117
|
-
if (title.length === 0) {
|
|
121
|
+
if (nextBody.trim().length === 0) {
|
|
118
122
|
return {
|
|
119
123
|
handled: true,
|
|
120
124
|
nextPrompt: {
|
|
121
125
|
...changedPrompt,
|
|
122
|
-
error: '
|
|
126
|
+
error: 'task body required',
|
|
123
127
|
},
|
|
124
128
|
markDirty: true,
|
|
125
129
|
};
|
|
@@ -148,8 +152,9 @@ export function handleTaskEditorPromptInput(
|
|
|
148
152
|
mode: prompt.mode,
|
|
149
153
|
taskId: prompt.taskId,
|
|
150
154
|
repositoryId,
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
projectId: null,
|
|
156
|
+
title: nextTitle.trim().length === 0 ? null : nextTitle.trim(),
|
|
157
|
+
body: nextBody,
|
|
153
158
|
commandLabel: prompt.mode === 'create' ? 'tasks-create' : 'tasks-edit',
|
|
154
159
|
},
|
|
155
160
|
};
|
|
@@ -45,9 +45,10 @@ export function handleSeparatorPointerPress(options: HandleSeparatorPointerPress
|
|
|
45
45
|
interface HandleMainPaneWheelInputOptions {
|
|
46
46
|
target: string;
|
|
47
47
|
wheelDelta: number | null;
|
|
48
|
-
mainPaneMode: 'conversation' | 'project' | 'home';
|
|
48
|
+
mainPaneMode: 'conversation' | 'project' | 'home' | 'nim';
|
|
49
49
|
onProjectWheel: (delta: number) => void;
|
|
50
50
|
onHomeWheel: (delta: number) => void;
|
|
51
|
+
onNimWheel: (delta: number) => void;
|
|
51
52
|
onConversationWheel: (delta: number) => void;
|
|
52
53
|
markDirty: () => void;
|
|
53
54
|
}
|
|
@@ -60,6 +61,8 @@ export function handleMainPaneWheelInput(options: HandleMainPaneWheelInputOption
|
|
|
60
61
|
options.onProjectWheel(options.wheelDelta);
|
|
61
62
|
} else if (options.mainPaneMode === 'home') {
|
|
62
63
|
options.onHomeWheel(options.wheelDelta);
|
|
64
|
+
} else if (options.mainPaneMode === 'nim') {
|
|
65
|
+
options.onNimWheel(options.wheelDelta);
|
|
63
66
|
} else {
|
|
64
67
|
options.onConversationWheel(options.wheelDelta);
|
|
65
68
|
}
|
|
@@ -77,7 +80,7 @@ interface HomePaneDragState {
|
|
|
77
80
|
|
|
78
81
|
interface HandleHomePaneDragMoveOptions {
|
|
79
82
|
homePaneDragState: HomePaneDragState | null;
|
|
80
|
-
mainPaneMode: 'conversation' | 'project' | 'home';
|
|
83
|
+
mainPaneMode: 'conversation' | 'project' | 'home' | 'nim';
|
|
81
84
|
target: string;
|
|
82
85
|
isSelectionDrag: boolean;
|
|
83
86
|
hasAltModifier: boolean;
|
|
@@ -14,6 +14,7 @@ interface HandleProjectPaneActionClickOptions<TSnapshot extends { directoryId: s
|
|
|
14
14
|
) => string | null;
|
|
15
15
|
openNewThreadPrompt: (directoryId: string) => void;
|
|
16
16
|
queueCloseDirectory: (directoryId: string) => void;
|
|
17
|
+
handleProjectPaneAction?: (action: string, directoryId: string) => boolean;
|
|
17
18
|
markDirty: () => void;
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -40,5 +41,12 @@ export function handleProjectPaneActionClick<TSnapshot extends { directoryId: st
|
|
|
40
41
|
options.markDirty();
|
|
41
42
|
return true;
|
|
42
43
|
}
|
|
44
|
+
if (
|
|
45
|
+
action !== null &&
|
|
46
|
+
options.handleProjectPaneAction?.(action, options.snapshot.directoryId) === true
|
|
47
|
+
) {
|
|
48
|
+
options.markDirty();
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
43
51
|
return false;
|
|
44
52
|
}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
import type { ConversationRailSessionSummary } from '../conversation-rail.ts';
|
|
3
|
-
import { firstShortcutText } from '../input-shortcuts.ts';
|
|
4
|
-
import type { resolveMuxShortcutBindings } from '../input-shortcuts.ts';
|
|
5
3
|
import { buildWorkspaceRailViewRows } from '../workspace-rail-model.ts';
|
|
6
4
|
import { renderWorkspaceRailAnsiRows } from '../workspace-rail.ts';
|
|
5
|
+
import type { ProjectPaneGitHubReviewSummary } from '../project-pane-github-review.ts';
|
|
7
6
|
import type {
|
|
8
7
|
StreamSessionController,
|
|
9
8
|
StreamSessionStatusModel,
|
|
10
9
|
} from '../../control-plane/stream-protocol.ts';
|
|
11
10
|
|
|
12
|
-
type ResolvedMuxShortcutBindings = ReturnType<typeof resolveMuxShortcutBindings>;
|
|
13
11
|
type WorkspaceRailModel = Parameters<typeof renderWorkspaceRailAnsiRows>[0];
|
|
14
12
|
|
|
15
13
|
interface GitSummary {
|
|
@@ -71,12 +69,20 @@ interface BuildRailModelArgs {
|
|
|
71
69
|
readonly projectSelectionEnabled: boolean;
|
|
72
70
|
readonly repositorySelectionEnabled: boolean;
|
|
73
71
|
readonly homeSelectionEnabled: boolean;
|
|
72
|
+
readonly nimSelectionEnabled?: boolean;
|
|
73
|
+
readonly tasksSelectionEnabled?: boolean;
|
|
74
|
+
readonly showNimEntry?: boolean;
|
|
75
|
+
readonly showTasksEntry?: boolean;
|
|
76
|
+
readonly showGitHubIntegration?: boolean;
|
|
77
|
+
readonly visibleGitHubDirectoryIds?: ReadonlySet<string>;
|
|
78
|
+
readonly expandedGitHubDirectoryIds?: ReadonlySet<string>;
|
|
79
|
+
readonly githubReviewByDirectoryId?: ReadonlyMap<string, ProjectPaneGitHubReviewSummary>;
|
|
80
|
+
readonly githubSelectionEnabled?: boolean;
|
|
81
|
+
readonly activeGitHubProjectId?: string | null;
|
|
74
82
|
readonly repositoriesCollapsed: boolean;
|
|
75
83
|
readonly collapsedRepositoryGroupIds: ReadonlySet<string>;
|
|
76
|
-
readonly shortcutsCollapsed: boolean;
|
|
77
84
|
readonly gitSummaryByDirectoryId: ReadonlyMap<string, GitSummary>;
|
|
78
85
|
readonly processUsageBySessionId: ReadonlyMap<string, MuxRailProcessUsageSample>;
|
|
79
|
-
readonly shortcutBindings: ResolvedMuxShortcutBindings;
|
|
80
86
|
readonly loadingGitSummary: GitSummary;
|
|
81
87
|
}
|
|
82
88
|
|
|
@@ -87,29 +93,6 @@ interface BuildRailRowsArgs extends BuildRailModelArgs {
|
|
|
87
93
|
};
|
|
88
94
|
}
|
|
89
95
|
|
|
90
|
-
function shortcutHintText(bindings: ResolvedMuxShortcutBindings): string {
|
|
91
|
-
const newConversation = firstShortcutText(bindings, 'mux.conversation.new') || 'ctrl+t';
|
|
92
|
-
const critiqueConversation =
|
|
93
|
-
firstShortcutText(bindings, 'mux.conversation.critique.open-or-create') || 'ctrl+g';
|
|
94
|
-
const deleteConversation = firstShortcutText(bindings, 'mux.conversation.delete') || 'ctrl+x';
|
|
95
|
-
const takeoverConversation = firstShortcutText(bindings, 'mux.conversation.takeover') || 'ctrl+l';
|
|
96
|
-
const addProject = firstShortcutText(bindings, 'mux.directory.add') || 'ctrl+o';
|
|
97
|
-
const closeProject = firstShortcutText(bindings, 'mux.directory.close') || 'ctrl+w';
|
|
98
|
-
const next = firstShortcutText(bindings, 'mux.conversation.next') || 'ctrl+j';
|
|
99
|
-
const previous = firstShortcutText(bindings, 'mux.conversation.previous') || 'ctrl+k';
|
|
100
|
-
const interruptConversation = firstShortcutText(bindings, 'mux.conversation.interrupt');
|
|
101
|
-
const quit = firstShortcutText(bindings, 'mux.app.interrupt-all') || 'ctrl+c';
|
|
102
|
-
const commandMenu = firstShortcutText(bindings, 'mux.command-menu.toggle') || 'ctrl+p';
|
|
103
|
-
const profile = firstShortcutText(bindings, 'mux.gateway.profile.toggle') || 'ctrl+shift+p';
|
|
104
|
-
const statusTimeline =
|
|
105
|
-
firstShortcutText(bindings, 'mux.gateway.status-timeline.toggle') || 'alt+r';
|
|
106
|
-
const renderTrace = firstShortcutText(bindings, 'mux.gateway.render-trace.toggle') || 'ctrl+]';
|
|
107
|
-
const switchHint = next === previous ? next : `${next}/${previous}`;
|
|
108
|
-
const interruptHint =
|
|
109
|
-
interruptConversation.length === 0 ? '' : ` ${interruptConversation} interrupt`;
|
|
110
|
-
return `${commandMenu} menu ${newConversation} new ${critiqueConversation} critique ${deleteConversation} archive ${takeoverConversation} takeover ${addProject}/${closeProject} projects ${switchHint} switch nav ${profile} profile ${statusTimeline} status ${renderTrace} render${interruptHint} ←/→ collapse/expand ${quit} quit`;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
96
|
function conversationSummary(
|
|
114
97
|
conversation: MuxRailConversationRecord,
|
|
115
98
|
): ConversationRailSessionSummary {
|
|
@@ -219,14 +202,34 @@ export function buildRailModel(args: BuildRailModelArgs): WorkspaceRailModel {
|
|
|
219
202
|
activeRepositoryId: args.activeRepositoryId,
|
|
220
203
|
activeConversationId: args.activeConversationId,
|
|
221
204
|
showTaskPlanningUi: true,
|
|
205
|
+
showNimEntry: args.showNimEntry ?? true,
|
|
206
|
+
showTasksEntry: args.showTasksEntry ?? true,
|
|
207
|
+
showGitHubIntegration: args.showGitHubIntegration ?? false,
|
|
208
|
+
...(args.visibleGitHubDirectoryIds === undefined
|
|
209
|
+
? {}
|
|
210
|
+
: {
|
|
211
|
+
visibleGitHubDirectoryKeys: [...args.visibleGitHubDirectoryIds],
|
|
212
|
+
}),
|
|
213
|
+
...(args.expandedGitHubDirectoryIds === undefined
|
|
214
|
+
? {}
|
|
215
|
+
: {
|
|
216
|
+
expandedGitHubDirectoryKeys: [...args.expandedGitHubDirectoryIds],
|
|
217
|
+
}),
|
|
218
|
+
...(args.githubReviewByDirectoryId === undefined
|
|
219
|
+
? {}
|
|
220
|
+
: {
|
|
221
|
+
githubReviewByDirectoryKey: args.githubReviewByDirectoryId,
|
|
222
|
+
}),
|
|
222
223
|
projectSelectionEnabled: args.projectSelectionEnabled,
|
|
224
|
+
githubSelectionEnabled: args.githubSelectionEnabled ?? false,
|
|
225
|
+
activeGitHubProjectId: args.activeGitHubProjectId ?? null,
|
|
223
226
|
repositorySelectionEnabled: args.repositorySelectionEnabled,
|
|
224
227
|
homeSelectionEnabled: args.homeSelectionEnabled,
|
|
228
|
+
nimSelectionEnabled: args.nimSelectionEnabled ?? false,
|
|
229
|
+
tasksSelectionEnabled: args.tasksSelectionEnabled ?? false,
|
|
225
230
|
repositoriesCollapsed: args.repositoriesCollapsed,
|
|
226
231
|
collapsedRepositoryGroupIds: [...args.collapsedRepositoryGroupIds],
|
|
227
232
|
processes: [],
|
|
228
|
-
shortcutHint: shortcutHintText(args.shortcutBindings),
|
|
229
|
-
shortcutsCollapsed: args.shortcutsCollapsed,
|
|
230
233
|
nowMs: Date.now(),
|
|
231
234
|
};
|
|
232
235
|
}
|