@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
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { detectConversationDoubleClick } from '../mux/double-click.ts';
|
|
2
|
+
import {
|
|
3
|
+
actionAtWorkspaceRailCell,
|
|
4
|
+
conversationIdAtWorkspaceRailRow,
|
|
5
|
+
kindAtWorkspaceRailRow,
|
|
6
|
+
projectIdAtWorkspaceRailRow,
|
|
7
|
+
repositoryIdAtWorkspaceRailRow,
|
|
8
|
+
type buildWorkspaceRailViewRows,
|
|
9
|
+
} from '../mux/workspace-rail-model.ts';
|
|
10
|
+
import type {
|
|
11
|
+
RailPointerHitDispatcher,
|
|
12
|
+
RailPointerHitResolver,
|
|
13
|
+
} from '../../packages/harness-ui/src/interaction/rail-pointer-input.ts';
|
|
14
|
+
|
|
15
|
+
type RailAction = ReturnType<typeof actionAtWorkspaceRailCell>;
|
|
16
|
+
|
|
17
|
+
interface ConversationTitleClickState {
|
|
18
|
+
readonly conversationId: string;
|
|
19
|
+
readonly atMs: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface LeftRailPointerHit {
|
|
23
|
+
readonly selectedConversationId: string | null;
|
|
24
|
+
readonly selectedProjectId: string | null;
|
|
25
|
+
readonly selectedRepositoryId: string | null;
|
|
26
|
+
readonly selectedAction: RailAction;
|
|
27
|
+
readonly supportsConversationTitleEditClick: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface LeftRailPointerState {
|
|
31
|
+
readonly railViewState: {
|
|
32
|
+
readLatestRows(): ReturnType<typeof buildWorkspaceRailViewRows>;
|
|
33
|
+
};
|
|
34
|
+
readonly conversationTitleEditConversationId: () => string | null;
|
|
35
|
+
readonly activeConversationId: () => string | null;
|
|
36
|
+
readonly repositoriesCollapsed: () => boolean;
|
|
37
|
+
readonly resolveDirectoryForAction: () => string | null;
|
|
38
|
+
readonly previousConversationClickState: () => ConversationTitleClickState | null;
|
|
39
|
+
readonly nowMs: () => number;
|
|
40
|
+
readonly isConversationPaneActive: () => boolean;
|
|
41
|
+
readonly directoriesHas: (directoryId: string) => boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface LeftRailPointerActions {
|
|
45
|
+
readonly clearConversationTitleEditClickState: () => void;
|
|
46
|
+
readonly openNewThreadPrompt: (directoryId: string) => void;
|
|
47
|
+
readonly queueArchiveConversation: (conversationId: string) => void;
|
|
48
|
+
readonly openAddDirectoryPrompt: () => void;
|
|
49
|
+
readonly openRepositoryPromptForCreate: () => void;
|
|
50
|
+
readonly repositoryExists: (repositoryId: string) => boolean;
|
|
51
|
+
readonly openRepositoryPromptForEdit: (repositoryId: string) => void;
|
|
52
|
+
readonly queueArchiveRepository: (repositoryId: string) => void;
|
|
53
|
+
readonly toggleRepositoryGroup: (repositoryGroupId: string) => void;
|
|
54
|
+
readonly selectLeftNavRepository: (repositoryGroupId: string) => void;
|
|
55
|
+
readonly expandAllRepositoryGroups: () => void;
|
|
56
|
+
readonly collapseAllRepositoryGroups: () => void;
|
|
57
|
+
readonly enterHomePane: () => void;
|
|
58
|
+
readonly enterNimPane?: () => void;
|
|
59
|
+
readonly enterTasksPane?: () => void;
|
|
60
|
+
readonly queueCloseDirectory: (directoryId: string) => void;
|
|
61
|
+
readonly toggleShortcutsCollapsed: () => void;
|
|
62
|
+
readonly setConversationClickState: (next: ConversationTitleClickState | null) => void;
|
|
63
|
+
readonly ensureConversationPaneActive: (conversationId: string) => void;
|
|
64
|
+
readonly beginConversationTitleEdit: (conversationId: string) => void;
|
|
65
|
+
readonly queueActivateConversation: (conversationId: string) => void;
|
|
66
|
+
readonly queueActivateConversationAndEdit: (conversationId: string) => void;
|
|
67
|
+
readonly enterProjectPane: (directoryId: string) => void;
|
|
68
|
+
readonly enterGitHubPane?: (directoryId: string) => void;
|
|
69
|
+
readonly toggleGitHubProjectExpanded?: (directoryId: string) => void;
|
|
70
|
+
readonly markDirty: () => void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface LeftRailPointerConfig {
|
|
74
|
+
readonly conversationTitleEditDoubleClickWindowMs: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export class LeftRailPointerHandler
|
|
78
|
+
implements
|
|
79
|
+
RailPointerHitResolver<LeftRailPointerHit>,
|
|
80
|
+
RailPointerHitDispatcher<LeftRailPointerHit>
|
|
81
|
+
{
|
|
82
|
+
constructor(
|
|
83
|
+
private readonly state: LeftRailPointerState,
|
|
84
|
+
private readonly actions: LeftRailPointerActions,
|
|
85
|
+
private readonly config: LeftRailPointerConfig,
|
|
86
|
+
) {}
|
|
87
|
+
|
|
88
|
+
resolveHit(rowIndex: number, colIndex: number, railCols: number): LeftRailPointerHit {
|
|
89
|
+
const rows = this.state.railViewState.readLatestRows();
|
|
90
|
+
const selectedConversationId = conversationIdAtWorkspaceRailRow(rows, rowIndex);
|
|
91
|
+
const selectedProjectId = projectIdAtWorkspaceRailRow(rows, rowIndex);
|
|
92
|
+
const selectedRepositoryId = repositoryIdAtWorkspaceRailRow(rows, rowIndex);
|
|
93
|
+
const selectedAction = actionAtWorkspaceRailCell(rows, rowIndex, colIndex, railCols);
|
|
94
|
+
const selectedRowKind = kindAtWorkspaceRailRow(rows, rowIndex);
|
|
95
|
+
return {
|
|
96
|
+
selectedConversationId,
|
|
97
|
+
selectedProjectId,
|
|
98
|
+
selectedRepositoryId,
|
|
99
|
+
selectedAction,
|
|
100
|
+
supportsConversationTitleEditClick:
|
|
101
|
+
selectedRowKind === 'conversation-title' || selectedRowKind === 'conversation-body',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
shouldKeepConversationTitleEditActive(hit: LeftRailPointerHit): boolean {
|
|
106
|
+
const editConversationId = this.state.conversationTitleEditConversationId();
|
|
107
|
+
return (
|
|
108
|
+
editConversationId !== null &&
|
|
109
|
+
hit.selectedConversationId === editConversationId &&
|
|
110
|
+
hit.supportsConversationTitleEditClick
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
dispatchHit(hit: LeftRailPointerHit): boolean {
|
|
115
|
+
if (this.handleAction(hit)) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
this.handleConversation(hit);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private handleAction(hit: LeftRailPointerHit): boolean {
|
|
123
|
+
const targetDirectoryId = hit.selectedProjectId ?? this.state.resolveDirectoryForAction();
|
|
124
|
+
if (hit.selectedAction === 'conversation.new') {
|
|
125
|
+
this.actions.clearConversationTitleEditClickState();
|
|
126
|
+
if (targetDirectoryId !== null) {
|
|
127
|
+
this.actions.openNewThreadPrompt(targetDirectoryId);
|
|
128
|
+
}
|
|
129
|
+
this.actions.markDirty();
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (hit.selectedAction === 'conversation.delete') {
|
|
134
|
+
this.actions.clearConversationTitleEditClickState();
|
|
135
|
+
const activeConversationId = this.state.activeConversationId();
|
|
136
|
+
if (activeConversationId !== null) {
|
|
137
|
+
this.actions.queueArchiveConversation(activeConversationId);
|
|
138
|
+
}
|
|
139
|
+
this.actions.markDirty();
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (hit.selectedAction === 'project.add') {
|
|
144
|
+
this.actions.clearConversationTitleEditClickState();
|
|
145
|
+
this.actions.openAddDirectoryPrompt();
|
|
146
|
+
this.actions.markDirty();
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (hit.selectedAction === 'repository.add') {
|
|
151
|
+
this.actions.clearConversationTitleEditClickState();
|
|
152
|
+
this.actions.openRepositoryPromptForCreate();
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (hit.selectedAction === 'repository.edit') {
|
|
157
|
+
this.actions.clearConversationTitleEditClickState();
|
|
158
|
+
if (
|
|
159
|
+
hit.selectedRepositoryId !== null &&
|
|
160
|
+
this.actions.repositoryExists(hit.selectedRepositoryId)
|
|
161
|
+
) {
|
|
162
|
+
this.actions.openRepositoryPromptForEdit(hit.selectedRepositoryId);
|
|
163
|
+
}
|
|
164
|
+
this.actions.markDirty();
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (hit.selectedAction === 'repository.archive') {
|
|
169
|
+
this.actions.clearConversationTitleEditClickState();
|
|
170
|
+
if (
|
|
171
|
+
hit.selectedRepositoryId !== null &&
|
|
172
|
+
this.actions.repositoryExists(hit.selectedRepositoryId)
|
|
173
|
+
) {
|
|
174
|
+
this.actions.queueArchiveRepository(hit.selectedRepositoryId);
|
|
175
|
+
}
|
|
176
|
+
this.actions.markDirty();
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (hit.selectedAction === 'repository.toggle') {
|
|
181
|
+
this.actions.clearConversationTitleEditClickState();
|
|
182
|
+
if (hit.selectedRepositoryId !== null) {
|
|
183
|
+
this.actions.toggleRepositoryGroup(hit.selectedRepositoryId);
|
|
184
|
+
this.actions.selectLeftNavRepository(hit.selectedRepositoryId);
|
|
185
|
+
}
|
|
186
|
+
this.actions.markDirty();
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (hit.selectedAction === 'repositories.toggle') {
|
|
191
|
+
this.actions.clearConversationTitleEditClickState();
|
|
192
|
+
if (this.state.repositoriesCollapsed()) {
|
|
193
|
+
this.actions.expandAllRepositoryGroups();
|
|
194
|
+
} else {
|
|
195
|
+
this.actions.collapseAllRepositoryGroups();
|
|
196
|
+
}
|
|
197
|
+
this.actions.markDirty();
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (hit.selectedAction === 'home.open') {
|
|
202
|
+
this.actions.clearConversationTitleEditClickState();
|
|
203
|
+
this.actions.enterHomePane();
|
|
204
|
+
this.actions.markDirty();
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (hit.selectedAction === 'nim.open') {
|
|
209
|
+
this.actions.clearConversationTitleEditClickState();
|
|
210
|
+
if (this.actions.enterNimPane !== undefined) {
|
|
211
|
+
this.actions.enterNimPane();
|
|
212
|
+
} else {
|
|
213
|
+
this.actions.enterHomePane();
|
|
214
|
+
}
|
|
215
|
+
this.actions.markDirty();
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (hit.selectedAction === 'tasks.open') {
|
|
220
|
+
this.actions.clearConversationTitleEditClickState();
|
|
221
|
+
if (this.actions.enterTasksPane !== undefined) {
|
|
222
|
+
this.actions.enterTasksPane();
|
|
223
|
+
} else {
|
|
224
|
+
this.actions.enterHomePane();
|
|
225
|
+
}
|
|
226
|
+
this.actions.markDirty();
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (hit.selectedAction === 'project.close') {
|
|
231
|
+
this.actions.clearConversationTitleEditClickState();
|
|
232
|
+
if (targetDirectoryId !== null) {
|
|
233
|
+
this.actions.queueCloseDirectory(targetDirectoryId);
|
|
234
|
+
}
|
|
235
|
+
this.actions.markDirty();
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (hit.selectedAction === 'project.github.open') {
|
|
240
|
+
this.actions.clearConversationTitleEditClickState();
|
|
241
|
+
if (targetDirectoryId !== null && this.state.directoriesHas(targetDirectoryId)) {
|
|
242
|
+
if (this.actions.enterGitHubPane !== undefined) {
|
|
243
|
+
this.actions.enterGitHubPane(targetDirectoryId);
|
|
244
|
+
} else {
|
|
245
|
+
this.actions.enterProjectPane(targetDirectoryId);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.actions.markDirty();
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (hit.selectedAction === 'project.github.toggle') {
|
|
253
|
+
this.actions.clearConversationTitleEditClickState();
|
|
254
|
+
if (
|
|
255
|
+
targetDirectoryId !== null &&
|
|
256
|
+
this.state.directoriesHas(targetDirectoryId) &&
|
|
257
|
+
this.actions.toggleGitHubProjectExpanded !== undefined
|
|
258
|
+
) {
|
|
259
|
+
this.actions.toggleGitHubProjectExpanded(targetDirectoryId);
|
|
260
|
+
}
|
|
261
|
+
this.actions.markDirty();
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (hit.selectedAction === 'shortcuts.toggle') {
|
|
266
|
+
this.actions.clearConversationTitleEditClickState();
|
|
267
|
+
this.actions.toggleShortcutsCollapsed();
|
|
268
|
+
this.actions.markDirty();
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private handleConversation(hit: LeftRailPointerHit): boolean {
|
|
276
|
+
const conversationClick =
|
|
277
|
+
hit.selectedConversationId !== null && hit.supportsConversationTitleEditClick
|
|
278
|
+
? detectConversationDoubleClick(
|
|
279
|
+
this.state.previousConversationClickState(),
|
|
280
|
+
hit.selectedConversationId,
|
|
281
|
+
this.state.nowMs(),
|
|
282
|
+
this.config.conversationTitleEditDoubleClickWindowMs,
|
|
283
|
+
)
|
|
284
|
+
: {
|
|
285
|
+
doubleClick: false,
|
|
286
|
+
nextState: null,
|
|
287
|
+
};
|
|
288
|
+
this.actions.setConversationClickState(conversationClick.nextState);
|
|
289
|
+
|
|
290
|
+
const activeConversationId = this.state.activeConversationId();
|
|
291
|
+
if (
|
|
292
|
+
hit.selectedConversationId !== null &&
|
|
293
|
+
hit.selectedConversationId === activeConversationId
|
|
294
|
+
) {
|
|
295
|
+
if (!this.state.isConversationPaneActive()) {
|
|
296
|
+
if (conversationClick.doubleClick) {
|
|
297
|
+
this.actions.queueActivateConversationAndEdit(hit.selectedConversationId);
|
|
298
|
+
} else {
|
|
299
|
+
this.actions.queueActivateConversation(hit.selectedConversationId);
|
|
300
|
+
}
|
|
301
|
+
} else if (conversationClick.doubleClick) {
|
|
302
|
+
this.actions.beginConversationTitleEdit(hit.selectedConversationId);
|
|
303
|
+
}
|
|
304
|
+
this.actions.markDirty();
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (hit.selectedConversationId !== null) {
|
|
309
|
+
if (conversationClick.doubleClick) {
|
|
310
|
+
this.actions.queueActivateConversationAndEdit(hit.selectedConversationId);
|
|
311
|
+
} else {
|
|
312
|
+
this.actions.queueActivateConversation(hit.selectedConversationId);
|
|
313
|
+
}
|
|
314
|
+
this.actions.markDirty();
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (hit.selectedProjectId !== null && this.state.directoriesHas(hit.selectedProjectId)) {
|
|
319
|
+
this.actions.setConversationClickState(null);
|
|
320
|
+
this.actions.enterProjectPane(hit.selectedProjectId);
|
|
321
|
+
this.actions.markDirty();
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
this.actions.setConversationClickState(null);
|
|
326
|
+
this.actions.markDirty();
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -2,6 +2,8 @@ export interface MuxUiStateSnapshot {
|
|
|
2
2
|
paneWidthPercent: number;
|
|
3
3
|
repositoriesCollapsed: boolean;
|
|
4
4
|
shortcutsCollapsed: boolean;
|
|
5
|
+
startupPane: 'home' | 'nim';
|
|
6
|
+
showDebugBar: boolean;
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
interface MuxUiStatePersistenceOptions {
|
|
@@ -76,7 +78,9 @@ export class MuxUiStatePersistence {
|
|
|
76
78
|
return (
|
|
77
79
|
left.paneWidthPercent === right.paneWidthPercent &&
|
|
78
80
|
left.repositoriesCollapsed === right.repositoriesCollapsed &&
|
|
79
|
-
left.shortcutsCollapsed === right.shortcutsCollapsed
|
|
81
|
+
left.shortcutsCollapsed === right.shortcutsCollapsed &&
|
|
82
|
+
left.startupPane === right.startupPane &&
|
|
83
|
+
left.showDebugBar === right.showDebugBar
|
|
80
84
|
);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
@@ -7,7 +7,7 @@ interface RenderTerminalRecordingToGifInput {
|
|
|
7
7
|
readonly outputPath: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
interface RecordingServiceOptions {
|
|
10
|
+
export interface RecordingServiceOptions {
|
|
11
11
|
readonly recordingWriter: RecordingWriter | null;
|
|
12
12
|
readonly recordingPath: string | null;
|
|
13
13
|
readonly recordingGifOutputPath: string | null;
|
|
@@ -17,37 +17,50 @@ interface RecordingServiceOptions {
|
|
|
17
17
|
readonly writeStderr: (text: string) => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export
|
|
21
|
-
|
|
20
|
+
export interface RecordingService {
|
|
21
|
+
closeWriter(): Promise<unknown | null>;
|
|
22
|
+
finalizeAfterShutdown(recordingCloseError: unknown | null): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createRecordingService(options: RecordingServiceOptions): RecordingService {
|
|
26
|
+
function formatCloseError(recordingCloseError: unknown): string {
|
|
27
|
+
if (recordingCloseError instanceof Error) {
|
|
28
|
+
return recordingCloseError.message;
|
|
29
|
+
}
|
|
30
|
+
if (typeof recordingCloseError === 'string') {
|
|
31
|
+
return recordingCloseError;
|
|
32
|
+
}
|
|
33
|
+
return 'unknown error';
|
|
34
|
+
}
|
|
22
35
|
|
|
23
|
-
async closeWriter(): Promise<unknown | null> {
|
|
24
|
-
if (
|
|
36
|
+
async function closeWriter(): Promise<unknown | null> {
|
|
37
|
+
if (options.recordingWriter === null) {
|
|
25
38
|
return null;
|
|
26
39
|
}
|
|
27
40
|
try {
|
|
28
|
-
await
|
|
41
|
+
await options.recordingWriter.close();
|
|
29
42
|
return null;
|
|
30
43
|
} catch (error: unknown) {
|
|
31
44
|
return error;
|
|
32
45
|
}
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
async finalizeAfterShutdown(recordingCloseError: unknown | null): Promise<void> {
|
|
48
|
+
async function finalizeAfterShutdown(recordingCloseError: unknown | null): Promise<void> {
|
|
36
49
|
if (
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
options.recordingGifOutputPath !== null &&
|
|
51
|
+
options.recordingPath !== null &&
|
|
39
52
|
recordingCloseError === null
|
|
40
53
|
) {
|
|
41
54
|
try {
|
|
42
|
-
await
|
|
43
|
-
recordingPath:
|
|
44
|
-
outputPath:
|
|
55
|
+
await options.renderTerminalRecordingToGif({
|
|
56
|
+
recordingPath: options.recordingPath,
|
|
57
|
+
outputPath: options.recordingGifOutputPath,
|
|
45
58
|
});
|
|
46
|
-
|
|
47
|
-
`[mux-recording] jsonl=${
|
|
59
|
+
options.writeStderr(
|
|
60
|
+
`[mux-recording] jsonl=${options.recordingPath} gif=${options.recordingGifOutputPath}\n`,
|
|
48
61
|
);
|
|
49
62
|
} catch (error: unknown) {
|
|
50
|
-
|
|
63
|
+
options.writeStderr(
|
|
51
64
|
`[mux-recording] gif-export-failed ${
|
|
52
65
|
error instanceof Error ? error.message : String(error)
|
|
53
66
|
}\n`,
|
|
@@ -57,19 +70,14 @@ export class RecordingService {
|
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
if (recordingCloseError !== null) {
|
|
60
|
-
|
|
61
|
-
`[mux-recording] close-failed ${
|
|
73
|
+
options.writeStderr(
|
|
74
|
+
`[mux-recording] close-failed ${formatCloseError(recordingCloseError)}\n`,
|
|
62
75
|
);
|
|
63
76
|
}
|
|
64
77
|
}
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (typeof recordingCloseError === 'string') {
|
|
71
|
-
return recordingCloseError;
|
|
72
|
-
}
|
|
73
|
-
return 'unknown error';
|
|
74
|
-
}
|
|
79
|
+
return {
|
|
80
|
+
closeWriter,
|
|
81
|
+
finalizeAfterShutdown,
|
|
82
|
+
};
|
|
75
83
|
}
|
|
@@ -75,7 +75,7 @@ interface RuntimeCommandMenuAgentToolsOptions {
|
|
|
75
75
|
readonly markDirty: () => void;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
export class
|
|
78
|
+
export class RuntimeCommandMenuAgentToolsCache {
|
|
79
79
|
private readonly statusByAgent = new Map<InstallableAgentType, AgentToolStatusRecord>();
|
|
80
80
|
|
|
81
81
|
constructor(private readonly options: RuntimeCommandMenuAgentToolsOptions) {}
|
|
@@ -28,7 +28,9 @@ interface RuntimeConversationTitleRefreshResult {
|
|
|
28
28
|
|
|
29
29
|
const THREAD_TITLE_AGENT_TYPES = new Set(['codex', 'claude', 'cursor']);
|
|
30
30
|
|
|
31
|
-
interface RuntimeControlActionsOptions<
|
|
31
|
+
export interface RuntimeControlActionsOptions<
|
|
32
|
+
TConversation extends RuntimeConversationControlState,
|
|
33
|
+
> {
|
|
32
34
|
readonly conversationById: (sessionId: string) => TConversation | undefined;
|
|
33
35
|
readonly interruptSession: (sessionId: string) => Promise<RuntimeInterruptResult>;
|
|
34
36
|
readonly nowIso: () => string;
|
|
@@ -57,81 +59,101 @@ interface RuntimeControlActionsOptions<TConversation extends RuntimeConversation
|
|
|
57
59
|
) => Promise<RuntimeConversationTitleRefreshResult>;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
+
export interface RuntimeControlActions {
|
|
63
|
+
interruptConversation(sessionId: string): Promise<void>;
|
|
64
|
+
toggleGatewayProfiler(): Promise<void>;
|
|
65
|
+
toggleGatewayStatusTimeline(): Promise<void>;
|
|
66
|
+
toggleGatewayRenderTrace(conversationId: string | null): Promise<void>;
|
|
67
|
+
refreshAllConversationTitles(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createRuntimeControlActions<TConversation extends RuntimeConversationControlState>(
|
|
71
|
+
options: RuntimeControlActionsOptions<TConversation>,
|
|
72
|
+
): RuntimeControlActions {
|
|
73
|
+
const scopeMessage = (prefix: string, message: string): string => {
|
|
74
|
+
if (options.sessionName === null) {
|
|
75
|
+
return `[${prefix}] ${message}`;
|
|
76
|
+
}
|
|
77
|
+
return `[${prefix}:${options.sessionName}] ${message}`;
|
|
78
|
+
};
|
|
62
79
|
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
const setNotices = (message: string): void => {
|
|
81
|
+
options.setTaskPaneNotice(message);
|
|
82
|
+
options.setDebugFooterNotice(message);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const interruptConversation = async (sessionId: string): Promise<void> => {
|
|
86
|
+
const conversation = options.conversationById(sessionId);
|
|
65
87
|
if (conversation === undefined || !conversation.live) {
|
|
66
88
|
return;
|
|
67
89
|
}
|
|
68
|
-
const result = await
|
|
90
|
+
const result = await options.interruptSession(sessionId);
|
|
69
91
|
if (!result.interrupted) {
|
|
70
92
|
return;
|
|
71
93
|
}
|
|
72
94
|
conversation.status = 'completed';
|
|
73
95
|
conversation.attentionReason = null;
|
|
74
|
-
conversation.lastEventAt =
|
|
75
|
-
|
|
76
|
-
}
|
|
96
|
+
conversation.lastEventAt = options.nowIso();
|
|
97
|
+
options.markDirty();
|
|
98
|
+
};
|
|
77
99
|
|
|
78
|
-
async
|
|
100
|
+
const toggleGatewayProfiler = async (): Promise<void> => {
|
|
79
101
|
try {
|
|
80
|
-
const result = await
|
|
81
|
-
invocationDirectory:
|
|
82
|
-
sessionName:
|
|
102
|
+
const result = await options.toggleGatewayProfiler({
|
|
103
|
+
invocationDirectory: options.invocationDirectory,
|
|
104
|
+
sessionName: options.sessionName,
|
|
83
105
|
});
|
|
84
|
-
|
|
106
|
+
setNotices(scopeMessage('profile', result.message));
|
|
85
107
|
} catch (error: unknown) {
|
|
86
108
|
const message = error instanceof Error ? error.message : String(error);
|
|
87
|
-
|
|
109
|
+
setNotices(scopeMessage('profile', message));
|
|
88
110
|
} finally {
|
|
89
|
-
|
|
111
|
+
options.markDirty();
|
|
90
112
|
}
|
|
91
|
-
}
|
|
113
|
+
};
|
|
92
114
|
|
|
93
|
-
async
|
|
115
|
+
const toggleGatewayStatusTimeline = async (): Promise<void> => {
|
|
94
116
|
try {
|
|
95
|
-
const result = await
|
|
96
|
-
invocationDirectory:
|
|
97
|
-
sessionName:
|
|
117
|
+
const result = await options.toggleGatewayStatusTimeline({
|
|
118
|
+
invocationDirectory: options.invocationDirectory,
|
|
119
|
+
sessionName: options.sessionName,
|
|
98
120
|
});
|
|
99
|
-
|
|
121
|
+
setNotices(scopeMessage('status-trace', result.message));
|
|
100
122
|
} catch (error: unknown) {
|
|
101
123
|
const message = error instanceof Error ? error.message : String(error);
|
|
102
|
-
|
|
124
|
+
setNotices(scopeMessage('status-trace', message));
|
|
103
125
|
} finally {
|
|
104
|
-
|
|
126
|
+
options.markDirty();
|
|
105
127
|
}
|
|
106
|
-
}
|
|
128
|
+
};
|
|
107
129
|
|
|
108
|
-
async
|
|
130
|
+
const toggleGatewayRenderTrace = async (conversationId: string | null): Promise<void> => {
|
|
109
131
|
try {
|
|
110
|
-
const result = await
|
|
111
|
-
invocationDirectory:
|
|
112
|
-
sessionName:
|
|
132
|
+
const result = await options.toggleGatewayRenderTrace({
|
|
133
|
+
invocationDirectory: options.invocationDirectory,
|
|
134
|
+
sessionName: options.sessionName,
|
|
113
135
|
conversationId,
|
|
114
136
|
});
|
|
115
|
-
|
|
137
|
+
setNotices(scopeMessage('render-trace', result.message));
|
|
116
138
|
} catch (error: unknown) {
|
|
117
139
|
const message = error instanceof Error ? error.message : String(error);
|
|
118
|
-
|
|
140
|
+
setNotices(scopeMessage('render-trace', message));
|
|
119
141
|
} finally {
|
|
120
|
-
|
|
142
|
+
options.markDirty();
|
|
121
143
|
}
|
|
122
|
-
}
|
|
144
|
+
};
|
|
123
145
|
|
|
124
|
-
async
|
|
125
|
-
const listConversationIds =
|
|
126
|
-
const resolveAgentType =
|
|
127
|
-
const refreshConversationTitle =
|
|
146
|
+
const refreshAllConversationTitles = async (): Promise<void> => {
|
|
147
|
+
const listConversationIds = options.listConversationIdsForTitleRefresh;
|
|
148
|
+
const resolveAgentType = options.conversationAgentTypeForTitleRefresh;
|
|
149
|
+
const refreshConversationTitle = options.refreshConversationTitle;
|
|
128
150
|
if (
|
|
129
151
|
listConversationIds === undefined ||
|
|
130
152
|
resolveAgentType === undefined ||
|
|
131
153
|
refreshConversationTitle === undefined
|
|
132
154
|
) {
|
|
133
|
-
|
|
134
|
-
|
|
155
|
+
setNotices(scopeMessage('thread-title', 'refresh unavailable'));
|
|
156
|
+
options.markDirty();
|
|
135
157
|
return;
|
|
136
158
|
}
|
|
137
159
|
const allConversationIds = listConversationIds();
|
|
@@ -140,16 +162,16 @@ export class RuntimeControlActions<TConversation extends RuntimeConversationCont
|
|
|
140
162
|
return agentType !== undefined && THREAD_TITLE_AGENT_TYPES.has(agentType);
|
|
141
163
|
});
|
|
142
164
|
if (eligibleConversationIds.length === 0) {
|
|
143
|
-
|
|
144
|
-
|
|
165
|
+
setNotices(scopeMessage('thread-title', 'no agent threads to refresh'));
|
|
166
|
+
options.markDirty();
|
|
145
167
|
return;
|
|
146
168
|
}
|
|
147
169
|
const total = eligibleConversationIds.length;
|
|
148
170
|
let updated = 0;
|
|
149
171
|
let unchanged = 0;
|
|
150
172
|
let skipped = 0;
|
|
151
|
-
|
|
152
|
-
|
|
173
|
+
setNotices(scopeMessage('thread-title', `refreshing names 0/${String(total)}`));
|
|
174
|
+
options.markDirty();
|
|
153
175
|
for (let index = 0; index < eligibleConversationIds.length; index += 1) {
|
|
154
176
|
const sessionId = eligibleConversationIds[index]!;
|
|
155
177
|
try {
|
|
@@ -164,29 +186,25 @@ export class RuntimeControlActions<TConversation extends RuntimeConversationCont
|
|
|
164
186
|
} catch {
|
|
165
187
|
skipped += 1;
|
|
166
188
|
}
|
|
167
|
-
|
|
168
|
-
|
|
189
|
+
setNotices(
|
|
190
|
+
scopeMessage('thread-title', `refreshing names ${String(index + 1)}/${String(total)}`),
|
|
169
191
|
);
|
|
170
|
-
|
|
192
|
+
options.markDirty();
|
|
171
193
|
}
|
|
172
|
-
|
|
173
|
-
|
|
194
|
+
setNotices(
|
|
195
|
+
scopeMessage(
|
|
174
196
|
'thread-title',
|
|
175
197
|
`refreshed ${String(updated)} updated ${String(unchanged)} unchanged ${String(skipped)} skipped`,
|
|
176
198
|
),
|
|
177
199
|
);
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
private scopeMessage(prefix: string, message: string): string {
|
|
182
|
-
if (this.options.sessionName === null) {
|
|
183
|
-
return `[${prefix}] ${message}`;
|
|
184
|
-
}
|
|
185
|
-
return `[${prefix}:${this.options.sessionName}] ${message}`;
|
|
186
|
-
}
|
|
200
|
+
options.markDirty();
|
|
201
|
+
};
|
|
187
202
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
203
|
+
return {
|
|
204
|
+
interruptConversation,
|
|
205
|
+
toggleGatewayProfiler,
|
|
206
|
+
toggleGatewayStatusTimeline,
|
|
207
|
+
toggleGatewayRenderTrace,
|
|
208
|
+
refreshAllConversationTitles,
|
|
209
|
+
};
|
|
192
210
|
}
|