@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,19 @@
|
|
|
1
1
|
import type { WorkspaceModel } from '../domain/workspace.ts';
|
|
2
2
|
import type { PaneSelection, PaneSelectionDrag } from '../mux/live-mux/selection.ts';
|
|
3
3
|
|
|
4
|
-
interface
|
|
4
|
+
interface RuntimeRenderStateDirectoryLookup {
|
|
5
|
+
hasDirectory(directoryId: string): boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface RuntimeRenderStateConversationLookup<TConversation> {
|
|
9
|
+
readonly activeConversationId: string | null;
|
|
10
|
+
getActiveConversation(): TConversation | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RuntimeRenderStateOptions<TConversation, TFrame> {
|
|
5
14
|
readonly workspace: WorkspaceModel;
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
8
|
-
readonly activeConversation: () => TConversation | null;
|
|
15
|
+
readonly directories: RuntimeRenderStateDirectoryLookup;
|
|
16
|
+
readonly conversations: RuntimeRenderStateConversationLookup<TConversation>;
|
|
9
17
|
readonly snapshotFrame: (conversation: TConversation) => TFrame;
|
|
10
18
|
readonly selectionVisibleRows: (
|
|
11
19
|
frame: TFrame,
|
|
@@ -13,60 +21,65 @@ interface RuntimeRenderStateOptions<TConversation, TFrame> {
|
|
|
13
21
|
) => readonly number[];
|
|
14
22
|
}
|
|
15
23
|
|
|
16
|
-
interface RuntimeRenderStateResult<TConversation, TFrame> {
|
|
24
|
+
export interface RuntimeRenderStateResult<TConversation, TFrame> {
|
|
17
25
|
readonly projectPaneActive: boolean;
|
|
18
26
|
readonly homePaneActive: boolean;
|
|
27
|
+
readonly nimPaneActive: boolean;
|
|
19
28
|
readonly activeConversation: TConversation | null;
|
|
20
29
|
readonly rightFrame: TFrame | null;
|
|
21
30
|
readonly renderSelection: PaneSelection | null;
|
|
22
31
|
readonly selectionRows: readonly number[];
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
export function prepareRuntimeRenderState<TConversation, TFrame>(
|
|
35
|
+
options: RuntimeRenderStateOptions<TConversation, TFrame>,
|
|
36
|
+
selection: PaneSelection | null,
|
|
37
|
+
selectionDrag: PaneSelectionDrag | null,
|
|
38
|
+
): RuntimeRenderStateResult<TConversation, TFrame> | null {
|
|
39
|
+
const workspace = options.workspace;
|
|
40
|
+
const projectPaneActive =
|
|
41
|
+
workspace.mainPaneMode === 'project' &&
|
|
42
|
+
workspace.activeDirectoryId !== null &&
|
|
43
|
+
options.directories.hasDirectory(workspace.activeDirectoryId);
|
|
44
|
+
const homePaneActive = workspace.mainPaneMode === 'home';
|
|
45
|
+
const nimPaneActive = workspace.mainPaneMode === 'nim';
|
|
46
|
+
if (
|
|
47
|
+
!projectPaneActive &&
|
|
48
|
+
!homePaneActive &&
|
|
49
|
+
!nimPaneActive &&
|
|
50
|
+
options.conversations.activeConversationId === null
|
|
51
|
+
) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
41
54
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
const activeConversation = options.conversations.getActiveConversation();
|
|
56
|
+
if (!projectPaneActive && !homePaneActive && !nimPaneActive && activeConversation === null) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
const rightFrame =
|
|
61
|
+
!projectPaneActive && !homePaneActive && !nimPaneActive && activeConversation !== null
|
|
62
|
+
? options.snapshotFrame(activeConversation)
|
|
63
|
+
: null;
|
|
64
|
+
const renderSelection =
|
|
65
|
+
rightFrame !== null && selectionDrag !== null && selectionDrag.hasDragged
|
|
66
|
+
? {
|
|
67
|
+
anchor: selectionDrag.anchor,
|
|
68
|
+
focus: selectionDrag.focus,
|
|
69
|
+
text: '',
|
|
70
|
+
}
|
|
71
|
+
: rightFrame !== null
|
|
72
|
+
? selection
|
|
50
73
|
: null;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
rightFrame === null ? [] : this.options.selectionVisibleRows(rightFrame, renderSelection);
|
|
63
|
-
return {
|
|
64
|
-
projectPaneActive,
|
|
65
|
-
homePaneActive,
|
|
66
|
-
activeConversation,
|
|
67
|
-
rightFrame,
|
|
68
|
-
renderSelection,
|
|
69
|
-
selectionRows,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
74
|
+
const selectionRows =
|
|
75
|
+
rightFrame === null ? [] : options.selectionVisibleRows(rightFrame, renderSelection);
|
|
76
|
+
return {
|
|
77
|
+
projectPaneActive,
|
|
78
|
+
homePaneActive,
|
|
79
|
+
nimPaneActive,
|
|
80
|
+
activeConversation,
|
|
81
|
+
rightFrame,
|
|
82
|
+
renderSelection,
|
|
83
|
+
selectionRows,
|
|
84
|
+
};
|
|
72
85
|
}
|
|
@@ -24,7 +24,7 @@ interface RuntimeRepositoryActionService<TRepository extends RepositoryRecordSha
|
|
|
24
24
|
archiveRepository(repositoryId: string): Promise<unknown>;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
interface RuntimeRepositoryActionsOptions<TRepository extends RepositoryRecordShape> {
|
|
27
|
+
export interface RuntimeRepositoryActionsOptions<TRepository extends RepositoryRecordShape> {
|
|
28
28
|
readonly workspace: WorkspaceModel;
|
|
29
29
|
readonly repositories: Map<string, TRepository>;
|
|
30
30
|
readonly controlPlaneService: RuntimeRepositoryActionService<TRepository>;
|
|
@@ -49,53 +49,85 @@ function repositoryHomePriority(repository: RepositoryRecordShape): number | nul
|
|
|
49
49
|
return raw;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export
|
|
53
|
-
|
|
52
|
+
export interface RuntimeRepositoryActions {
|
|
53
|
+
openRepositoryPromptForCreate(): void;
|
|
54
|
+
openRepositoryPromptForEdit(repositoryId: string): void;
|
|
55
|
+
queueRepositoryPriorityOrder(orderedRepositoryIds: readonly string[], label: string): void;
|
|
56
|
+
reorderRepositoryByDrop(
|
|
57
|
+
draggedRepositoryId: string,
|
|
58
|
+
targetRepositoryId: string,
|
|
59
|
+
orderedRepositoryIds: readonly string[],
|
|
60
|
+
): void;
|
|
61
|
+
upsertRepositoryByRemoteUrl(remoteUrl: string, existingRepositoryId?: string): Promise<void>;
|
|
62
|
+
archiveRepositoryById(repositoryId: string): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createRuntimeRepositoryActions<TRepository extends RepositoryRecordShape>(
|
|
66
|
+
options: RuntimeRepositoryActionsOptions<TRepository>,
|
|
67
|
+
): RuntimeRepositoryActions {
|
|
68
|
+
const reorderIdsByMove = (
|
|
69
|
+
orderedIds: readonly string[],
|
|
70
|
+
movedId: string,
|
|
71
|
+
targetId: string,
|
|
72
|
+
): readonly string[] | null => {
|
|
73
|
+
const fromIndex = orderedIds.indexOf(movedId);
|
|
74
|
+
const targetIndex = orderedIds.indexOf(targetId);
|
|
75
|
+
if (fromIndex < 0 || targetIndex < 0 || fromIndex === targetIndex) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const reordered = [...orderedIds];
|
|
79
|
+
const moved = reordered.splice(fromIndex, 1)[0]!;
|
|
80
|
+
reordered.splice(targetIndex, 0, moved);
|
|
81
|
+
return reordered;
|
|
82
|
+
};
|
|
54
83
|
|
|
55
|
-
openRepositoryPromptForCreate(): void {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
84
|
+
const openRepositoryPromptForCreate = (): void => {
|
|
85
|
+
options.workspace.newThreadPrompt = null;
|
|
86
|
+
options.workspace.addDirectoryPrompt = null;
|
|
87
|
+
options.workspace.apiKeyPrompt = null;
|
|
88
|
+
if (options.workspace.conversationTitleEdit !== null) {
|
|
89
|
+
options.stopConversationTitleEdit();
|
|
61
90
|
}
|
|
62
|
-
|
|
63
|
-
|
|
91
|
+
options.workspace.conversationTitleEditClickState = null;
|
|
92
|
+
options.workspace.repositoryPrompt = {
|
|
64
93
|
mode: 'add',
|
|
65
94
|
repositoryId: null,
|
|
66
95
|
value: '',
|
|
67
96
|
error: null,
|
|
68
97
|
};
|
|
69
|
-
|
|
70
|
-
}
|
|
98
|
+
options.markDirty();
|
|
99
|
+
};
|
|
71
100
|
|
|
72
|
-
openRepositoryPromptForEdit(repositoryId: string): void {
|
|
73
|
-
const repository =
|
|
101
|
+
const openRepositoryPromptForEdit = (repositoryId: string): void => {
|
|
102
|
+
const repository = options.repositories.get(repositoryId);
|
|
74
103
|
if (repository === undefined) {
|
|
75
104
|
return;
|
|
76
105
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
|
|
106
|
+
options.workspace.newThreadPrompt = null;
|
|
107
|
+
options.workspace.addDirectoryPrompt = null;
|
|
108
|
+
options.workspace.apiKeyPrompt = null;
|
|
109
|
+
if (options.workspace.conversationTitleEdit !== null) {
|
|
110
|
+
options.stopConversationTitleEdit();
|
|
82
111
|
}
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
options.workspace.conversationTitleEditClickState = null;
|
|
113
|
+
options.workspace.repositoryPrompt = {
|
|
85
114
|
mode: 'edit',
|
|
86
115
|
repositoryId,
|
|
87
116
|
value: repository.remoteUrl,
|
|
88
117
|
error: null,
|
|
89
118
|
};
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
119
|
+
options.workspace.taskPaneSelectionFocus = 'repository';
|
|
120
|
+
options.markDirty();
|
|
121
|
+
};
|
|
93
122
|
|
|
94
|
-
queueRepositoryPriorityOrder
|
|
123
|
+
const queueRepositoryPriorityOrder = (
|
|
124
|
+
orderedRepositoryIds: readonly string[],
|
|
125
|
+
label: string,
|
|
126
|
+
): void => {
|
|
95
127
|
const updates: Array<{ repositoryId: string; metadata: Record<string, unknown> }> = [];
|
|
96
128
|
for (let index = 0; index < orderedRepositoryIds.length; index += 1) {
|
|
97
129
|
const repositoryId = orderedRepositoryIds[index]!;
|
|
98
|
-
const repository =
|
|
130
|
+
const repository = options.repositories.get(repositoryId);
|
|
99
131
|
if (repository === undefined) {
|
|
100
132
|
continue;
|
|
101
133
|
}
|
|
@@ -113,25 +145,25 @@ export class RuntimeRepositoryActions<TRepository extends RepositoryRecordShape>
|
|
|
113
145
|
if (updates.length === 0) {
|
|
114
146
|
return;
|
|
115
147
|
}
|
|
116
|
-
|
|
148
|
+
options.queueControlPlaneOp(async () => {
|
|
117
149
|
for (const update of updates) {
|
|
118
|
-
const repository = await
|
|
150
|
+
const repository = await options.controlPlaneService.updateRepository({
|
|
119
151
|
repositoryId: update.repositoryId,
|
|
120
152
|
metadata: update.metadata,
|
|
121
153
|
});
|
|
122
|
-
|
|
154
|
+
options.repositories.set(repository.repositoryId, repository);
|
|
123
155
|
}
|
|
124
|
-
|
|
125
|
-
|
|
156
|
+
options.syncTaskPaneRepositorySelection();
|
|
157
|
+
options.markDirty();
|
|
126
158
|
}, label);
|
|
127
|
-
}
|
|
159
|
+
};
|
|
128
160
|
|
|
129
|
-
reorderRepositoryByDrop(
|
|
161
|
+
const reorderRepositoryByDrop = (
|
|
130
162
|
draggedRepositoryId: string,
|
|
131
163
|
targetRepositoryId: string,
|
|
132
164
|
orderedRepositoryIds: readonly string[],
|
|
133
|
-
): void {
|
|
134
|
-
const reordered =
|
|
165
|
+
): void => {
|
|
166
|
+
const reordered = reorderIdsByMove(
|
|
135
167
|
orderedRepositoryIds,
|
|
136
168
|
draggedRepositoryId,
|
|
137
169
|
targetRepositoryId,
|
|
@@ -139,22 +171,22 @@ export class RuntimeRepositoryActions<TRepository extends RepositoryRecordShape>
|
|
|
139
171
|
if (reordered === null) {
|
|
140
172
|
return;
|
|
141
173
|
}
|
|
142
|
-
|
|
143
|
-
}
|
|
174
|
+
queueRepositoryPriorityOrder(reordered, 'repositories-reorder-drag');
|
|
175
|
+
};
|
|
144
176
|
|
|
145
|
-
async
|
|
177
|
+
const upsertRepositoryByRemoteUrl = async (
|
|
146
178
|
remoteUrl: string,
|
|
147
179
|
existingRepositoryId?: string,
|
|
148
|
-
): Promise<void> {
|
|
149
|
-
const normalizedRemoteUrl =
|
|
180
|
+
): Promise<void> => {
|
|
181
|
+
const normalizedRemoteUrl = options.normalizeGitHubRemoteUrl(remoteUrl);
|
|
150
182
|
if (normalizedRemoteUrl === null) {
|
|
151
183
|
throw new Error('github url required');
|
|
152
184
|
}
|
|
153
|
-
const repositoryName =
|
|
185
|
+
const repositoryName = options.repositoryNameFromGitHubRemoteUrl(normalizedRemoteUrl);
|
|
154
186
|
const repository =
|
|
155
187
|
existingRepositoryId === undefined
|
|
156
|
-
? await
|
|
157
|
-
repositoryId:
|
|
188
|
+
? await options.controlPlaneService.upsertRepository({
|
|
189
|
+
repositoryId: options.createRepositoryId(),
|
|
158
190
|
name: repositoryName,
|
|
159
191
|
remoteUrl: normalizedRemoteUrl,
|
|
160
192
|
defaultBranch: 'main',
|
|
@@ -162,38 +194,31 @@ export class RuntimeRepositoryActions<TRepository extends RepositoryRecordShape>
|
|
|
162
194
|
source: 'mux-manual',
|
|
163
195
|
},
|
|
164
196
|
})
|
|
165
|
-
: await
|
|
197
|
+
: await options.controlPlaneService.updateRepository({
|
|
166
198
|
repositoryId: existingRepositoryId,
|
|
167
199
|
name: repositoryName,
|
|
168
200
|
remoteUrl: normalizedRemoteUrl,
|
|
169
201
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
202
|
+
options.repositories.set(repository.repositoryId, repository);
|
|
203
|
+
options.syncRepositoryAssociationsWithDirectorySnapshots();
|
|
204
|
+
options.syncTaskPaneRepositorySelection();
|
|
205
|
+
options.markDirty();
|
|
206
|
+
};
|
|
175
207
|
|
|
176
|
-
async
|
|
177
|
-
await
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
208
|
+
const archiveRepositoryById = async (repositoryId: string): Promise<void> => {
|
|
209
|
+
await options.controlPlaneService.archiveRepository(repositoryId);
|
|
210
|
+
options.repositories.delete(repositoryId);
|
|
211
|
+
options.syncRepositoryAssociationsWithDirectorySnapshots();
|
|
212
|
+
options.syncTaskPaneRepositorySelection();
|
|
213
|
+
options.markDirty();
|
|
214
|
+
};
|
|
183
215
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return null;
|
|
193
|
-
}
|
|
194
|
-
const reordered = [...orderedIds];
|
|
195
|
-
const moved = reordered.splice(fromIndex, 1)[0]!;
|
|
196
|
-
reordered.splice(targetIndex, 0, moved);
|
|
197
|
-
return reordered;
|
|
198
|
-
}
|
|
216
|
+
return {
|
|
217
|
+
openRepositoryPromptForCreate,
|
|
218
|
+
openRepositoryPromptForEdit,
|
|
219
|
+
queueRepositoryPriorityOrder,
|
|
220
|
+
reorderRepositoryByDrop,
|
|
221
|
+
upsertRepositoryByRemoteUrl,
|
|
222
|
+
archiveRepositoryById,
|
|
223
|
+
};
|
|
199
224
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { WorkspaceModel } from '../domain/workspace.ts';
|
|
2
|
-
import type { TaskManager } from '../domain/tasks.ts';
|
|
3
2
|
import type { ProjectPaneSnapshot } from '../mux/harness-core-ui.ts';
|
|
4
3
|
import type { TaskComposerBuffer } from '../mux/task-composer.ts';
|
|
4
|
+
import type { NimPaneViewModel } from '../ui/panes/nim.ts';
|
|
5
5
|
import type {
|
|
6
6
|
TaskFocusedPaneRepositoryRecord,
|
|
7
7
|
TaskFocusedPaneTaskRecord,
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
} from '../mux/task-focused-pane.ts';
|
|
10
10
|
import type { TerminalSnapshotFrameCore } from '../terminal/snapshot-oracle.ts';
|
|
11
11
|
|
|
12
|
-
interface RuntimeRightPaneLayout {
|
|
12
|
+
export interface RuntimeRightPaneLayout {
|
|
13
13
|
readonly rightCols: number;
|
|
14
14
|
readonly paneRows: number;
|
|
15
15
|
}
|
|
@@ -25,6 +25,7 @@ interface HomePaneRenderInput<
|
|
|
25
25
|
readonly layout: RuntimeRightPaneLayout;
|
|
26
26
|
readonly repositories: ReadonlyMap<string, TRepositoryRecord>;
|
|
27
27
|
readonly tasks: ReadonlyMap<string, TTaskRecord>;
|
|
28
|
+
readonly showTaskPlanningUi?: boolean;
|
|
28
29
|
readonly selectedRepositoryId: string | null;
|
|
29
30
|
readonly repositoryDropdownOpen: boolean;
|
|
30
31
|
readonly editorTarget: WorkspaceModel['taskEditorTarget'];
|
|
@@ -52,81 +53,107 @@ interface ProjectPaneLike {
|
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
interface
|
|
56
|
+
interface NimPaneLike {
|
|
57
|
+
render(input: { layout: RuntimeRightPaneLayout; viewModel: NimPaneViewModel }): {
|
|
58
|
+
readonly rows: readonly string[];
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface RuntimeRightPaneRenderInput<
|
|
63
|
+
TRepositoryRecord extends TaskFocusedPaneRepositoryRecord,
|
|
64
|
+
TTaskRecord extends TaskFocusedPaneTaskRecord,
|
|
65
|
+
> {
|
|
56
66
|
readonly layout: RuntimeRightPaneLayout;
|
|
57
67
|
readonly rightFrame: TerminalSnapshotFrameCore | null;
|
|
58
68
|
readonly homePaneActive: boolean;
|
|
69
|
+
readonly nimPaneActive: boolean;
|
|
59
70
|
readonly projectPaneActive: boolean;
|
|
60
71
|
readonly activeDirectoryId: string | null;
|
|
72
|
+
readonly snapshot: RuntimeRightPaneRenderSnapshot<TRepositoryRecord, TTaskRecord>;
|
|
61
73
|
}
|
|
62
74
|
|
|
63
|
-
interface
|
|
75
|
+
export interface RuntimeRightPaneRenderSnapshot<
|
|
64
76
|
TRepositoryRecord extends TaskFocusedPaneRepositoryRecord,
|
|
65
77
|
TTaskRecord extends TaskFocusedPaneTaskRecord,
|
|
66
78
|
> {
|
|
67
|
-
readonly workspace: WorkspaceModel;
|
|
68
79
|
readonly repositories: ReadonlyMap<string, TRepositoryRecord>;
|
|
69
|
-
readonly
|
|
80
|
+
readonly tasks: ReadonlyMap<string, TTaskRecord>;
|
|
81
|
+
readonly taskComposers: ReadonlyMap<string, TaskComposerBuffer>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface RuntimeRightPaneRenderOptions<
|
|
85
|
+
TRepositoryRecord extends TaskFocusedPaneRepositoryRecord,
|
|
86
|
+
TTaskRecord extends TaskFocusedPaneTaskRecord,
|
|
87
|
+
> {
|
|
88
|
+
readonly workspace: WorkspaceModel;
|
|
89
|
+
readonly showTasks?: boolean;
|
|
70
90
|
readonly conversationPane: ConversationPaneLike;
|
|
71
91
|
readonly homePane: HomePaneLike<TRepositoryRecord, TTaskRecord>;
|
|
72
92
|
readonly projectPane: ProjectPaneLike;
|
|
93
|
+
readonly nimPane: NimPaneLike;
|
|
94
|
+
readonly getNimViewModel: () => NimPaneViewModel;
|
|
73
95
|
readonly refreshProjectPaneSnapshot: (directoryId: string) => ProjectPaneSnapshot | null;
|
|
74
96
|
readonly emptyTaskPaneView: () => TaskFocusedPaneView;
|
|
75
97
|
}
|
|
76
98
|
|
|
77
|
-
export
|
|
99
|
+
export function renderRuntimeRightPaneRows<
|
|
78
100
|
TRepositoryRecord extends TaskFocusedPaneRepositoryRecord,
|
|
79
101
|
TTaskRecord extends TaskFocusedPaneTaskRecord,
|
|
80
|
-
>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
102
|
+
>(
|
|
103
|
+
options: RuntimeRightPaneRenderOptions<TRepositoryRecord, TTaskRecord>,
|
|
104
|
+
input: RuntimeRightPaneRenderInput<TRepositoryRecord, TTaskRecord>,
|
|
105
|
+
): readonly string[] {
|
|
106
|
+
const workspace = options.workspace;
|
|
107
|
+
workspace.latestTaskPaneView = options.emptyTaskPaneView();
|
|
84
108
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
109
|
+
if (input.rightFrame !== null) {
|
|
110
|
+
return options.conversationPane.render(input.rightFrame, input.layout);
|
|
111
|
+
}
|
|
88
112
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
if (input.homePaneActive) {
|
|
114
|
+
const view = options.homePane.render({
|
|
115
|
+
layout: input.layout,
|
|
116
|
+
repositories: input.snapshot.repositories,
|
|
117
|
+
tasks: input.snapshot.tasks,
|
|
118
|
+
showTaskPlanningUi:
|
|
119
|
+
(options.showTasks ?? true) && workspace.leftNavSelection.kind === 'tasks',
|
|
120
|
+
selectedRepositoryId: workspace.taskPaneSelectedRepositoryId,
|
|
121
|
+
repositoryDropdownOpen: workspace.taskRepositoryDropdownOpen,
|
|
122
|
+
editorTarget: workspace.taskEditorTarget,
|
|
123
|
+
draftBuffer: workspace.taskDraftComposer,
|
|
124
|
+
taskBufferById: input.snapshot.taskComposers,
|
|
125
|
+
notice: workspace.taskPaneNotice,
|
|
126
|
+
scrollTop: workspace.taskPaneScrollTop,
|
|
127
|
+
});
|
|
128
|
+
workspace.taskPaneSelectedRepositoryId = view.selectedRepositoryId;
|
|
129
|
+
workspace.taskPaneScrollTop = view.top;
|
|
130
|
+
workspace.latestTaskPaneView = view;
|
|
131
|
+
return view.rows;
|
|
132
|
+
}
|
|
92
133
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
editorTarget: workspace.taskEditorTarget,
|
|
101
|
-
draftBuffer: workspace.taskDraftComposer,
|
|
102
|
-
taskBufferById: this.options.taskManager.readonlyTaskComposers(),
|
|
103
|
-
notice: workspace.taskPaneNotice,
|
|
104
|
-
scrollTop: workspace.taskPaneScrollTop,
|
|
105
|
-
});
|
|
106
|
-
workspace.taskPaneSelectedRepositoryId = view.selectedRepositoryId;
|
|
107
|
-
workspace.taskPaneScrollTop = view.top;
|
|
108
|
-
workspace.latestTaskPaneView = view;
|
|
109
|
-
return view.rows;
|
|
110
|
-
}
|
|
134
|
+
if (input.nimPaneActive) {
|
|
135
|
+
const view = options.nimPane.render({
|
|
136
|
+
layout: input.layout,
|
|
137
|
+
viewModel: options.getNimViewModel(),
|
|
138
|
+
});
|
|
139
|
+
return view.rows;
|
|
140
|
+
}
|
|
111
141
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
input.activeDirectoryId,
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
const view = this.options.projectPane.render({
|
|
122
|
-
layout: input.layout,
|
|
123
|
-
snapshot: workspace.projectPaneSnapshot,
|
|
124
|
-
scrollTop: workspace.projectPaneScrollTop,
|
|
125
|
-
});
|
|
126
|
-
workspace.projectPaneScrollTop = view.scrollTop;
|
|
127
|
-
return view.rows;
|
|
142
|
+
if (input.projectPaneActive && input.activeDirectoryId !== null) {
|
|
143
|
+
const needsSnapshotRefresh =
|
|
144
|
+
workspace.projectPaneSnapshot === null ||
|
|
145
|
+
workspace.projectPaneSnapshot.directoryId !== input.activeDirectoryId;
|
|
146
|
+
if (needsSnapshotRefresh) {
|
|
147
|
+
workspace.projectPaneSnapshot = options.refreshProjectPaneSnapshot(input.activeDirectoryId);
|
|
128
148
|
}
|
|
129
|
-
|
|
130
|
-
|
|
149
|
+
const view = options.projectPane.render({
|
|
150
|
+
layout: input.layout,
|
|
151
|
+
snapshot: workspace.projectPaneSnapshot,
|
|
152
|
+
scrollTop: workspace.projectPaneScrollTop,
|
|
153
|
+
});
|
|
154
|
+
workspace.projectPaneScrollTop = view.scrollTop;
|
|
155
|
+
return view.rows;
|
|
131
156
|
}
|
|
157
|
+
|
|
158
|
+
return Array.from({ length: input.layout.paneRows }, () => ' '.repeat(input.layout.rightCols));
|
|
132
159
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface RuntimeShutdownServiceOptions {
|
|
1
|
+
export interface RuntimeShutdownServiceOptions {
|
|
2
2
|
readonly screen: {
|
|
3
3
|
clearDirty: () => void;
|
|
4
4
|
};
|
|
@@ -11,12 +11,15 @@ interface RuntimeShutdownServiceOptions {
|
|
|
11
11
|
readonly clearResizeTimer: () => void;
|
|
12
12
|
readonly clearPtyResizeTimer: () => void;
|
|
13
13
|
readonly clearHomePaneBackgroundTimer: () => void;
|
|
14
|
+
readonly clearStorageLifecycleTimer: () => void;
|
|
15
|
+
readonly clearProjectPaneGitHubReviewRefreshTimer: () => void;
|
|
14
16
|
readonly persistMuxUiStateNow: () => void;
|
|
15
17
|
readonly clearConversationTitleEditTimer: () => void;
|
|
16
18
|
readonly flushTaskComposerPersist: () => void;
|
|
17
19
|
readonly clearRenderScheduled: () => void;
|
|
18
20
|
readonly detachProcessListeners: () => void;
|
|
19
21
|
readonly removeEnvelopeListener: () => void;
|
|
22
|
+
readonly stopWorkspaceObservedEvents: () => void;
|
|
20
23
|
readonly unsubscribeTaskPlanningEvents: () => Promise<void>;
|
|
21
24
|
readonly closeKeyEventSubscription: () => Promise<void>;
|
|
22
25
|
readonly clearRuntimeFatalExitTimer: () => void;
|
|
@@ -41,39 +44,39 @@ interface RuntimeShutdownServiceOptions {
|
|
|
41
44
|
readonly shutdownPerfCore: () => void;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
export
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.options.eventPersistence.flush('shutdown');
|
|
72
|
-
const recordingCloseError = await this.options.recordingService.closeWriter();
|
|
73
|
-
this.options.store.close();
|
|
74
|
-
this.options.restoreTerminalState();
|
|
75
|
-
await this.options.recordingService.finalizeAfterShutdown(recordingCloseError);
|
|
76
|
-
this.options.startupShutdownService.finalize();
|
|
77
|
-
this.options.shutdownPerfCore();
|
|
47
|
+
export async function finalizeRuntimeShutdown(
|
|
48
|
+
options: RuntimeShutdownServiceOptions,
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
options.screen.clearDirty();
|
|
51
|
+
options.outputLoadSampler.stop();
|
|
52
|
+
options.startupBackgroundProbeService.stop();
|
|
53
|
+
options.clearResizeTimer();
|
|
54
|
+
options.clearPtyResizeTimer();
|
|
55
|
+
options.clearHomePaneBackgroundTimer();
|
|
56
|
+
options.clearStorageLifecycleTimer();
|
|
57
|
+
options.clearProjectPaneGitHubReviewRefreshTimer();
|
|
58
|
+
options.persistMuxUiStateNow();
|
|
59
|
+
options.clearConversationTitleEditTimer();
|
|
60
|
+
options.flushTaskComposerPersist();
|
|
61
|
+
options.clearRenderScheduled();
|
|
62
|
+
options.detachProcessListeners();
|
|
63
|
+
options.removeEnvelopeListener();
|
|
64
|
+
options.stopWorkspaceObservedEvents();
|
|
65
|
+
await options.unsubscribeTaskPlanningEvents();
|
|
66
|
+
await options.closeKeyEventSubscription();
|
|
67
|
+
options.clearRuntimeFatalExitTimer();
|
|
68
|
+
try {
|
|
69
|
+
await options.waitForControlPlaneDrain();
|
|
70
|
+
await options.controlPlaneClient.close();
|
|
71
|
+
} catch {
|
|
72
|
+
// Best-effort shutdown only.
|
|
78
73
|
}
|
|
74
|
+
|
|
75
|
+
options.eventPersistence.flush('shutdown');
|
|
76
|
+
const recordingCloseError = await options.recordingService.closeWriter();
|
|
77
|
+
options.store.close();
|
|
78
|
+
options.restoreTerminalState();
|
|
79
|
+
await options.recordingService.finalizeAfterShutdown(recordingCloseError);
|
|
80
|
+
options.startupShutdownService.finalize();
|
|
81
|
+
options.shutdownPerfCore();
|
|
79
82
|
}
|