tmux-ide 2.9.0-beta.21 → 2.9.0-beta.26
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/bin/cli.js +46791 -43589
- package/package.json +2 -2
- package/packages/contracts/src/__tests__/daemon-wire.test.ts +2 -2
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v3.json +35 -0
- package/packages/contracts/src/__tests__/issue-error.test.ts +1 -1
- package/packages/contracts/src/__tests__/multiplexer-verbs.test.ts +3 -1
- package/packages/contracts/src/__tests__/pane-stream.test.ts +17 -5
- package/packages/contracts/src/__tests__/tmux-server-scope.test.ts +166 -0
- package/packages/contracts/src/__tests__/window-links.test.ts +243 -0
- package/packages/contracts/src/actions-contract.ts +12 -0
- package/packages/contracts/src/daemon-resource-request.test.ts +1 -1
- package/packages/contracts/src/daemon-wire.ts +10 -5
- package/packages/contracts/src/fleet-client-state.ts +3 -0
- package/packages/contracts/src/fleet-lifecycle.ts +5 -0
- package/packages/contracts/src/index.ts +2 -0
- package/packages/contracts/src/interaction-receipts.ts +39 -0
- package/packages/contracts/src/issue-error.ts +1 -1
- package/packages/contracts/src/multiplexer-verbs.ts +25 -1
- package/packages/contracts/src/pane-stream.ts +51 -8
- package/packages/contracts/src/tmux-server-scope.ts +172 -0
- package/packages/contracts/src/window-links.ts +76 -0
- package/packages/contracts/src/workspace-multiplexer.ts +54 -0
- package/packages/core/src/interaction-receipts.ts +4 -0
- package/packages/daemon/dist/command-center/actions/command-definitions.js +6 -0
- package/packages/daemon/dist/command-center/actions/handlers/workspace-multiplexer.js +2 -0
- package/packages/daemon/dist/command-center/actions/registry.js +13 -1
- package/packages/daemon/dist/command-center/discovery.js +2 -9
- package/packages/daemon/dist/command-center/server.js +21 -1
- package/packages/daemon/dist/command-center/tmux-server-native-backing.js +37 -0
- package/packages/daemon/dist/command-center/tmux-servers.js +351 -0
- package/packages/daemon/dist/lib/canonical-daemon-bootstrap.js +64 -8
- package/packages/daemon/dist/lib/canonical-daemon.js +5 -2
- package/packages/daemon/dist/lib/daemon-embed.js +198 -30
- package/packages/daemon/dist/lib/embedded-tmux-server-owners.js +147 -0
- package/packages/daemon/dist/lib/fleet-lifecycle-authority.js +31 -11
- package/packages/daemon/dist/lib/headless-daemon.js +10 -1
- package/packages/daemon/dist/lib/runtime-namespace.js +17 -3
- package/packages/daemon/dist/lib/tmux-client-execution.js +59 -0
- package/packages/daemon/dist/lib/tmux-named-socket-fence.js +4 -0
- package/packages/daemon/dist/lib/tmux-server-generation-runner.js +62 -0
- package/packages/daemon/dist/lib/tmux-server-owner.js +285 -0
- package/packages/daemon/dist/lib/tmux-server-owners.js +192 -0
- package/packages/daemon/dist/lib/tmux-server-proof.js +82 -0
- package/packages/daemon/dist/lib/tmux-server-registration.js +85 -0
- package/packages/daemon/dist/lib/tmux-server-session-create.js +43 -0
- package/packages/daemon/dist/lib/tmux-server-session-open.js +101 -0
- package/packages/daemon/dist/lib/tmux-servers-cli.js +134 -0
- package/packages/daemon/dist/lib/tmux-session-mutation-fence.js +55 -0
- package/packages/daemon/dist/lib/tmux-window-link-guard.js +88 -0
- package/packages/daemon/dist/lib/workspace-config-loader.js +3 -0
- package/packages/daemon/dist/lib/workspace-multiplexer-verbs.js +82 -1
- package/packages/daemon/dist/lib/workspace-pane-creation.js +13 -57
- package/packages/daemon/dist/lib/workspace-promotion.js +91 -12
- package/packages/daemon/dist/lib/workspace-registry.js +4 -0
- package/packages/daemon/dist/server/pane-stream-upgrade.js +20 -6
- package/packages/daemon/dist/terminal/attachments/native-runtime.js +61 -17
- package/packages/daemon/dist/terminal/mirror/__tests__/scripted-channel.js +9 -1
- package/packages/daemon/dist/terminal/mirror/__tests__/simulated-channel.js +11 -2
- package/packages/daemon/dist/terminal/mirror/control-channel.js +65 -6
- package/packages/daemon/dist/terminal/mirror/mirror-service.js +44 -0
- package/packages/daemon/dist/terminal/mirror/session-channel.js +210 -50
- package/packages/daemon/dist/terminal/mirror/window-link-authority.js +160 -0
- package/packages/daemon/dist/terminal/pane-stream/lease-manager.js +3 -3
- package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +40 -6
- package/packages/daemon/dist/terminal/protocol/live-session-identity.js +9 -0
- package/packages/daemon/dist/terminal/protocol/native-backing-client.js +2 -1
- package/packages/daemon/dist/terminal/session-runtime/interaction-receipt-facts.js +9 -0
- package/packages/daemon/dist/terminal/session-runtime/registry.js +6 -0
- package/packages/daemon/dist/terminal/session-runtime/semantic-mutation-executor.js +1 -1
- package/packages/daemon/dist/terminal/session-runtime/semantic-mutation-resource-changes.js +1 -0
- package/packages/daemon/dist/tui/mirror/application-shell-daemon-connection.js +7 -2
- package/packages/daemon/dist/tui/mirror/application-shell-server-connection.js +114 -0
- package/packages/daemon/dist/tui/mirror/menu-model.js +1 -1
- package/packages/daemon/dist/tui/mirror/open-tui-verified-routing.js +34 -4
- package/packages/daemon/dist/tui/mirror/open-tui-workspace-runtime-port.js +29 -8
- package/packages/daemon/dist/tui/mirror/runtime/application-guided-tour-integration.jsx +119 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-guided-tour-owner.js +132 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-home-agent-roster.jsx +21 -9
- package/packages/daemon/dist/tui/mirror/runtime/application-home-agent-transport.js +63 -1
- package/packages/daemon/dist/tui/mirror/runtime/application-home-agents-owner.js +8 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-home-agents.js +3 -1
- package/packages/daemon/dist/tui/mirror/runtime/application-home-catalog-owner.js +11 -5
- package/packages/daemon/dist/tui/mirror/runtime/application-home-catalog.js +140 -75
- package/packages/daemon/dist/tui/mirror/runtime/application-home-experience.js +40 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-home-fleet.js +132 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-agents.js +9 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-catalog.js +12 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-navigation.js +211 -31
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-sidebar.jsx +91 -37
- package/packages/daemon/dist/tui/mirror/runtime/application-performance-log.js +20 -7
- package/packages/daemon/dist/tui/mirror/runtime/application-root-configuration.js +9 -3
- package/packages/daemon/dist/tui/mirror/runtime/application-route-connection.js +95 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-shell-home.jsx +6 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +158 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-workspace-policy.js +43 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-workspace.jsx +78 -25
- package/packages/daemon/dist/tui/mirror/runtime/application-theme-repaint.js +9 -0
- package/packages/daemon/dist/tui/mirror/runtime/fleet-lifecycle-client.js +44 -1
- package/packages/daemon/dist/tui/mirror/runtime/guided-tour-coach.jsx +54 -0
- package/packages/daemon/dist/tui/mirror/runtime/guided-tour-storage.js +67 -0
- package/packages/daemon/dist/tui/mirror/runtime/guided-tour.js +113 -0
- package/packages/daemon/dist/tui/mirror/runtime/open-tui-generation-host.js +1 -1
- package/packages/daemon/dist/tui/mirror/runtime/resize-terminal-pane.js +4 -0
- package/packages/daemon/dist/tui/mirror/runtime/select-terminal-pane.js +2 -1
- package/packages/daemon/dist/tui/mirror/runtime/semantic-shell-viewport-resize.js +12 -4
- package/packages/daemon/dist/tui/mirror/runtime/terminal-pane-input-router.js +6 -3
- package/packages/daemon/dist/tui/mirror/workspace/application-command-description.js +11 -2
- package/packages/daemon/dist/tui/mirror/workspace/terminal-window-strip.jsx +2 -1
- package/packages/daemon/src/command-center/actions/command-definitions.ts +6 -0
- package/packages/daemon/src/command-center/actions/errors.ts +4 -0
- package/packages/daemon/src/command-center/actions/handlers/workspace-multiplexer.ts +2 -0
- package/packages/daemon/src/command-center/actions/registry.ts +14 -0
- package/packages/daemon/src/command-center/discovery.ts +2 -10
- package/packages/daemon/src/command-center/server.ts +29 -1
- package/packages/daemon/src/command-center/tmux-server-native-backing.ts +49 -0
- package/packages/daemon/src/command-center/tmux-servers.ts +479 -0
- package/packages/daemon/src/lib/canonical-daemon-bootstrap.ts +111 -4
- package/packages/daemon/src/lib/canonical-daemon.ts +15 -3
- package/packages/daemon/src/lib/daemon-embed.ts +241 -28
- package/packages/daemon/src/lib/embedded-tmux-server-owners.ts +190 -0
- package/packages/daemon/src/lib/fleet-lifecycle-authority.ts +33 -9
- package/packages/daemon/src/lib/headless-daemon.ts +18 -1
- package/packages/daemon/src/lib/runtime-namespace.ts +24 -3
- package/packages/daemon/src/lib/tmux-client-execution.ts +56 -0
- package/packages/daemon/src/lib/tmux-named-socket-fence.ts +5 -0
- package/packages/daemon/src/lib/tmux-server-generation-runner.ts +81 -0
- package/packages/daemon/src/lib/tmux-server-owner.ts +336 -0
- package/packages/daemon/src/lib/tmux-server-owners.ts +228 -0
- package/packages/daemon/src/lib/tmux-server-proof.ts +95 -0
- package/packages/daemon/src/lib/tmux-server-registration.ts +105 -0
- package/packages/daemon/src/lib/tmux-server-session-create.ts +52 -0
- package/packages/daemon/src/lib/tmux-server-session-open.ts +106 -0
- package/packages/daemon/src/lib/tmux-servers-cli.ts +186 -0
- package/packages/daemon/src/lib/tmux-session-mutation-fence.ts +62 -0
- package/packages/daemon/src/lib/tmux-window-link-guard.ts +112 -0
- package/packages/daemon/src/lib/workspace-config-loader.ts +3 -0
- package/packages/daemon/src/lib/workspace-multiplexer-verbs.ts +121 -1
- package/packages/daemon/src/lib/workspace-pane-creation.ts +16 -55
- package/packages/daemon/src/lib/workspace-promotion.ts +98 -12
- package/packages/daemon/src/lib/workspace-registry.ts +5 -0
- package/packages/daemon/src/server/pane-stream-upgrade.ts +25 -5
- package/packages/daemon/src/terminal/attachments/native-runtime.ts +70 -16
- package/packages/daemon/src/terminal/mirror/control-channel.ts +64 -7
- package/packages/daemon/src/terminal/mirror/events.ts +2 -0
- package/packages/daemon/src/terminal/mirror/mirror-service.ts +56 -0
- package/packages/daemon/src/terminal/mirror/session-channel.ts +245 -50
- package/packages/daemon/src/terminal/mirror/window-link-authority.ts +203 -0
- package/packages/daemon/src/terminal/pane-stream/lease-manager.ts +3 -3
- package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +50 -6
- package/packages/daemon/src/terminal/protocol/live-session-identity.ts +14 -0
- package/packages/daemon/src/terminal/protocol/native-backing-client.ts +4 -1
- package/packages/daemon/src/terminal/session-runtime/interaction-receipt-facts.ts +9 -0
- package/packages/daemon/src/terminal/session-runtime/registry.ts +9 -0
- package/packages/daemon/src/terminal/session-runtime/semantic-mutation-executor.ts +2 -2
- package/packages/daemon/src/terminal/session-runtime/semantic-mutation-resource-changes.ts +1 -0
- package/packages/daemon/src/tui/mirror/application-shell-daemon-connection.ts +28 -2
- package/packages/daemon/src/tui/mirror/application-shell-server-connection.ts +154 -0
- package/packages/daemon/src/tui/mirror/menu-model.ts +1 -1
- package/packages/daemon/src/tui/mirror/open-tui-verified-routing.ts +41 -3
- package/packages/daemon/src/tui/mirror/open-tui-workspace-runtime-port.ts +47 -6
- package/packages/daemon/src/tui/mirror/runtime/application-entry.ts +2 -1
- package/packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions.tsx +10 -4
- package/packages/daemon/src/tui/mirror/runtime/application-fleet-tabs.ts +2 -0
- package/packages/daemon/src/tui/mirror/runtime/application-guided-tour-integration.tsx +199 -0
- package/packages/daemon/src/tui/mirror/runtime/application-guided-tour-owner.ts +162 -0
- package/packages/daemon/src/tui/mirror/runtime/application-home-agent-roster.tsx +36 -10
- package/packages/daemon/src/tui/mirror/runtime/application-home-agent-transport.ts +69 -0
- package/packages/daemon/src/tui/mirror/runtime/application-home-agents-owner.ts +12 -2
- package/packages/daemon/src/tui/mirror/runtime/application-home-agents.ts +13 -2
- package/packages/daemon/src/tui/mirror/runtime/application-home-catalog-owner.ts +13 -3
- package/packages/daemon/src/tui/mirror/runtime/application-home-catalog.ts +172 -100
- package/packages/daemon/src/tui/mirror/runtime/application-home-experience.ts +59 -0
- package/packages/daemon/src/tui/mirror/runtime/application-home-fleet.ts +175 -0
- package/packages/daemon/src/tui/mirror/runtime/application-machine-agents.ts +9 -1
- package/packages/daemon/src/tui/mirror/runtime/application-machine-catalog.ts +19 -7
- package/packages/daemon/src/tui/mirror/runtime/application-machine-navigation.ts +285 -36
- package/packages/daemon/src/tui/mirror/runtime/application-machine-overlays.tsx +1 -1
- package/packages/daemon/src/tui/mirror/runtime/application-machine-sidebar.tsx +124 -40
- package/packages/daemon/src/tui/mirror/runtime/application-palette-preview.tsx +3 -0
- package/packages/daemon/src/tui/mirror/runtime/application-performance-log.ts +18 -6
- package/packages/daemon/src/tui/mirror/runtime/application-root-configuration.ts +12 -3
- package/packages/daemon/src/tui/mirror/runtime/application-root-v2.tsx +40 -40
- package/packages/daemon/src/tui/mirror/runtime/application-route-connection.ts +93 -1
- package/packages/daemon/src/tui/mirror/runtime/application-shell-catalog.tsx +4 -0
- package/packages/daemon/src/tui/mirror/runtime/application-shell-home.tsx +20 -1
- package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +10 -0
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +177 -2
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-policy.ts +62 -0
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-workspace.tsx +87 -30
- package/packages/daemon/src/tui/mirror/runtime/application-theme-repaint.ts +19 -0
- package/packages/daemon/src/tui/mirror/runtime/fleet-lifecycle-client.ts +55 -0
- package/packages/daemon/src/tui/mirror/runtime/guided-tour-coach.tsx +118 -0
- package/packages/daemon/src/tui/mirror/runtime/guided-tour-storage.ts +72 -0
- package/packages/daemon/src/tui/mirror/runtime/guided-tour.ts +147 -0
- package/packages/daemon/src/tui/mirror/runtime/open-tui-generation-host.ts +1 -1
- package/packages/daemon/src/tui/mirror/runtime/resize-terminal-pane.ts +3 -0
- package/packages/daemon/src/tui/mirror/runtime/select-terminal-pane.ts +3 -0
- package/packages/daemon/src/tui/mirror/runtime/semantic-shell-viewport-resize.ts +11 -4
- package/packages/daemon/src/tui/mirror/runtime/terminal-pane-input-router.ts +15 -4
- package/packages/daemon/src/tui/mirror/workspace/application-command-description.ts +13 -2
- package/packages/daemon/src/tui/mirror/workspace/terminal-window-strip.tsx +5 -1
- package/packages/daemon-client/package.json +3 -1
- package/packages/daemon-client/src/index.ts +2 -0
- package/packages/daemon-client/src/pane-stream-client.test.ts +108 -38
- package/packages/daemon-client/src/pane-stream-client.ts +26 -0
- package/packages/daemon-client/src/scoped-tmux-server-transport.test.ts +114 -0
- package/packages/daemon-client/src/scoped-tmux-server-transport.ts +385 -0
- package/packages/daemon-client/src/tmux-server-client.test.ts +279 -0
- package/packages/daemon-client/src/tmux-server-client.ts +287 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TmuxServerDescriptor } from "@tmux-ide/contracts";
|
|
1
2
|
import type { FleetCachedRoute } from "@tmux-ide/contracts/fleet-client-state";
|
|
2
3
|
import { groupFleetEnvironments } from "@tmux-ide/daemon-client/fleet-environments";
|
|
3
4
|
import {
|
|
@@ -27,6 +28,7 @@ export interface ApplicationMachineCatalogGroup {
|
|
|
27
28
|
readonly label: string;
|
|
28
29
|
readonly state: "ready" | "connecting" | "disconnected";
|
|
29
30
|
readonly sessions: readonly ApplicationMachineCatalogSession[];
|
|
31
|
+
readonly servers?: readonly TmuxServerDescriptor[];
|
|
30
32
|
readonly note: string | null;
|
|
31
33
|
readonly diagnostic?: FleetConnectionStatus;
|
|
32
34
|
readonly environmentId?: string | null;
|
|
@@ -114,6 +116,7 @@ export function createApplicationMachineCatalog(
|
|
|
114
116
|
diagnostic && diagnostic.phase !== "ready"
|
|
115
117
|
? fleetConnectionMessage(diagnostic)
|
|
116
118
|
: (entry?.snapshot.note ?? null),
|
|
119
|
+
servers: entry?.snapshot.servers,
|
|
117
120
|
sessions: (entry?.lastSessions ?? []).map((session) => ({
|
|
118
121
|
...session,
|
|
119
122
|
sourceId: session.id,
|
|
@@ -152,7 +155,13 @@ export function createApplicationMachineCatalog(
|
|
|
152
155
|
...session,
|
|
153
156
|
id:
|
|
154
157
|
session.liveSessionId && joined.environmentId && !joined.conflict
|
|
155
|
-
? JSON.stringify([
|
|
158
|
+
? JSON.stringify([
|
|
159
|
+
joined.environmentId,
|
|
160
|
+
"session",
|
|
161
|
+
session.server?.serverId,
|
|
162
|
+
session.server?.generation,
|
|
163
|
+
session.liveSessionId,
|
|
164
|
+
])
|
|
156
165
|
: session.id,
|
|
157
166
|
})),
|
|
158
167
|
};
|
|
@@ -214,12 +223,15 @@ export function createApplicationMachineCatalog(
|
|
|
214
223
|
environmentId: entry.environmentId,
|
|
215
224
|
generation: entry.generation,
|
|
216
225
|
seenAt: entry.seenAt,
|
|
217
|
-
sessions: value.sessions
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
sessions: value.sessions
|
|
227
|
+
.slice(0, 64)
|
|
228
|
+
.map(({ id, liveSessionId, name, paneCount, server, serverLabel }) => ({
|
|
229
|
+
id,
|
|
230
|
+
...(liveSessionId ? { liveSessionId } : {}),
|
|
231
|
+
name,
|
|
232
|
+
paneCount,
|
|
233
|
+
...(server ? { server, serverLabel } : {}),
|
|
234
|
+
})),
|
|
223
235
|
});
|
|
224
236
|
} catch {
|
|
225
237
|
/* Cache failure must never prevent live catalog publication. */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { OpenTuiGenerationHostSnapshot } from "./open-tui-generation-host.ts";
|
|
2
|
+
import type { TmuxServerScope } from "@tmux-ide/contracts";
|
|
1
3
|
import { fleetHostColor } from "./fleet-presentation.ts";
|
|
2
4
|
import type { ApplicationPaletteCommand } from "./application-palette-input.ts";
|
|
3
5
|
import { createFleetTabs, type FleetTabTarget } from "./application-fleet-tabs.ts";
|
|
@@ -13,13 +15,30 @@ import { createApplicationMachineCatalog } from "./application-machine-catalog.t
|
|
|
13
15
|
import { ephemeralMachineProfile } from "./application-machine-startup.ts";
|
|
14
16
|
import type { ApplicationMachineSidebarModel } from "./application-machine-sidebar.tsx";
|
|
15
17
|
|
|
18
|
+
/** Exact attached authority; an unscoped default connection still proves its incarnation. */
|
|
19
|
+
function attachedMachineNavigationTarget(active: OpenTuiGenerationHostSnapshot | null) {
|
|
20
|
+
if (active?.status !== "live" || !active.connection?.liveSessionId || !active.daemonGeneration)
|
|
21
|
+
return null;
|
|
22
|
+
return {
|
|
23
|
+
liveSessionId: active.connection.liveSessionId,
|
|
24
|
+
daemonGeneration: active.daemonGeneration,
|
|
25
|
+
...(active.connection.server ? { server: active.connection.server } : {}),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
export function createApplicationMachineNavigation(options: {
|
|
17
|
-
resetWorkspace(machineId: string, expectedLiveSessionId?: string): void;
|
|
30
|
+
resetWorkspace(machineId: string, expectedLiveSessionId?: string, server?: TmuxServerScope): void;
|
|
18
31
|
openAgent?(agent: ApplicationMachineAgent, source: "keyboard" | "mouse"): Promise<unknown> | void;
|
|
19
32
|
cancelOpen(): void;
|
|
20
33
|
openSession(name: string, source: "keyboard" | "mouse"): Promise<unknown>;
|
|
21
34
|
sessionName(): string | null;
|
|
22
35
|
activePaneId?(): string | null;
|
|
36
|
+
attachedGeneration?(): OpenTuiGenerationHostSnapshot | null;
|
|
37
|
+
attachedTarget?(): {
|
|
38
|
+
liveSessionId: string;
|
|
39
|
+
daemonGeneration: string;
|
|
40
|
+
server?: TmuxServerScope;
|
|
41
|
+
} | null;
|
|
23
42
|
setSurface(value: "home" | "terminals"): void;
|
|
24
43
|
setNote(value: string | null | ((current: string | null) => string | null)): void;
|
|
25
44
|
}) {
|
|
@@ -45,10 +64,15 @@ export function createApplicationMachineNavigation(options: {
|
|
|
45
64
|
const [snapshot, setSnapshot] = createSignal(catalog.getSnapshot());
|
|
46
65
|
const [focused, setFocused] = createSignal(false);
|
|
47
66
|
const [switching, setSwitching] = createSignal(false);
|
|
67
|
+
const [serverFocus, setServerFocus] = createSignal<{
|
|
68
|
+
machineId: string;
|
|
69
|
+
server: TmuxServerScope;
|
|
70
|
+
} | null>(null);
|
|
48
71
|
const [attentionOnly, setAttentionOnly] = createSignal(false);
|
|
49
72
|
const showSwitcher = (attention: boolean) => {
|
|
50
73
|
navigation++;
|
|
51
74
|
options.cancelOpen();
|
|
75
|
+
setServerFocus(null);
|
|
52
76
|
setAttentionOnly(attention);
|
|
53
77
|
setFocused(false);
|
|
54
78
|
setSwitching(true);
|
|
@@ -56,21 +80,41 @@ export function createApplicationMachineNavigation(options: {
|
|
|
56
80
|
const [adding, setAdding] = createSignal(false);
|
|
57
81
|
const [alias, setAlias] = createSignal("");
|
|
58
82
|
const [error, setError] = createSignal<string | null>(null);
|
|
59
|
-
|
|
83
|
+
let attemptStartup: (() => void) | null = null;
|
|
84
|
+
const stop = catalog.subscribe((value) => {
|
|
85
|
+
setSnapshot(value);
|
|
86
|
+
attemptStartup?.();
|
|
87
|
+
});
|
|
60
88
|
let navigation = 0;
|
|
89
|
+
const [activeSessionKey, setActiveSessionKey] = createSignal<string | null>(null);
|
|
61
90
|
const [tabRevision, setTabRevision] = createSignal(0);
|
|
62
91
|
const history: string[] = [...saved().recent].reverse();
|
|
63
92
|
let historyIndex = history.length - 1;
|
|
64
|
-
const select = (id: string, expectedLiveSessionId?: string) => {
|
|
93
|
+
const select = (id: string, expectedLiveSessionId?: string, server?: TmuxServerScope) => {
|
|
65
94
|
if (!manager.getMachine(id)) return false;
|
|
66
95
|
if (manager.snapshot().selectedMachineId !== id) {
|
|
67
96
|
navigation++;
|
|
68
97
|
options.cancelOpen();
|
|
69
98
|
// Synchronously remove the old input/shell owner before changing the route.
|
|
70
|
-
options.resetWorkspace(id, expectedLiveSessionId);
|
|
99
|
+
if (server) options.resetWorkspace(id, expectedLiveSessionId, server);
|
|
100
|
+
else options.resetWorkspace(id, expectedLiveSessionId);
|
|
71
101
|
manager.select(id);
|
|
72
102
|
} else if (expectedLiveSessionId) {
|
|
73
|
-
|
|
103
|
+
const attached =
|
|
104
|
+
options.attachedTarget?.() ??
|
|
105
|
+
attachedMachineNavigationTarget(options.attachedGeneration?.() ?? null);
|
|
106
|
+
const sameAuthority =
|
|
107
|
+
attached?.liveSessionId === expectedLiveSessionId &&
|
|
108
|
+
(server
|
|
109
|
+
? attached.server
|
|
110
|
+
? attached.server.serverId === server.serverId &&
|
|
111
|
+
attached.server.generation === server.generation
|
|
112
|
+
: attached.daemonGeneration === server.generation &&
|
|
113
|
+
manager.getMachine(id)?.read()?.instanceId === server.generation
|
|
114
|
+
: !attached.server);
|
|
115
|
+
if (sameAuthority) return true;
|
|
116
|
+
if (server) options.resetWorkspace(id, expectedLiveSessionId, server);
|
|
117
|
+
else options.resetWorkspace(id, expectedLiveSessionId);
|
|
74
118
|
}
|
|
75
119
|
return true;
|
|
76
120
|
};
|
|
@@ -80,18 +124,44 @@ export function createApplicationMachineNavigation(options: {
|
|
|
80
124
|
source: "keyboard" | "mouse",
|
|
81
125
|
remember = true,
|
|
82
126
|
expectedLiveSessionId?: string,
|
|
127
|
+
server?: TmuxServerScope,
|
|
128
|
+
sessionKey?: string,
|
|
83
129
|
) => {
|
|
84
130
|
// A same-machine session click supersedes any pending exact-agent focus too.
|
|
85
131
|
if (manager.snapshot().selectedMachineId === id) options.cancelOpen();
|
|
86
132
|
// A sidebar selection can leave a tab whose route is pinned to a different
|
|
87
133
|
// live incarnation on this same machine. Select a new exact owner before
|
|
88
134
|
// preparation; never apply that old tab's identity fence to the new name.
|
|
89
|
-
if (
|
|
90
|
-
|
|
135
|
+
if (manager.getMachine(id)?.endpoint().state !== "ready") {
|
|
136
|
+
select(id);
|
|
137
|
+
options.setNote("This machine is disconnected. Select the session after reconnecting.");
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
const candidates =
|
|
141
|
+
snapshot()
|
|
91
142
|
.groups.find((group) => group.id === id || group.routeIds?.includes(id))
|
|
92
|
-
?.sessions.
|
|
143
|
+
?.sessions.filter(
|
|
144
|
+
(row) =>
|
|
145
|
+
row.name === name &&
|
|
146
|
+
!row.disabled &&
|
|
147
|
+
(!sessionKey || row.id === sessionKey) &&
|
|
148
|
+
(!expectedLiveSessionId || row.liveSessionId === expectedLiveSessionId) &&
|
|
149
|
+
(!server ||
|
|
150
|
+
(row.server?.serverId === server.serverId &&
|
|
151
|
+
row.server.generation === server.generation)),
|
|
152
|
+
) ?? [];
|
|
153
|
+
if (candidates.length !== 1) {
|
|
154
|
+
options.setNote(
|
|
155
|
+
"Select the session under its tmux server; this target is ambiguous or has changed.",
|
|
156
|
+
);
|
|
157
|
+
return false;
|
|
93
158
|
}
|
|
94
|
-
|
|
159
|
+
const selected = candidates[0]!;
|
|
160
|
+
const sameSelection = activeSessionKey() === selected.id && options.sessionName() === name;
|
|
161
|
+
setActiveSessionKey(selected.id);
|
|
162
|
+
expectedLiveSessionId = selected.liveSessionId;
|
|
163
|
+
server = selected.server;
|
|
164
|
+
if (!select(id, sameSelection ? undefined : expectedLiveSessionId, server)) return;
|
|
95
165
|
const token = ++navigation;
|
|
96
166
|
setFocused(false);
|
|
97
167
|
options.setSurface("terminals");
|
|
@@ -111,15 +181,21 @@ export function createApplicationMachineNavigation(options: {
|
|
|
111
181
|
if (token === navigation) {
|
|
112
182
|
const session = snapshot()
|
|
113
183
|
.groups.find((group) => group.id === id || group.routeIds?.includes(id))
|
|
114
|
-
?.sessions.find((row) => row.
|
|
184
|
+
?.sessions.find((row) => row.id === selected.id && !row.disabled);
|
|
115
185
|
if (session) {
|
|
116
186
|
if (session.liveSessionId)
|
|
117
187
|
tabs.remember({
|
|
118
|
-
key: JSON.stringify([
|
|
188
|
+
key: JSON.stringify([
|
|
189
|
+
id,
|
|
190
|
+
session.server?.serverId,
|
|
191
|
+
session.server?.generation,
|
|
192
|
+
session.liveSessionId,
|
|
193
|
+
]),
|
|
194
|
+
server: session.server,
|
|
119
195
|
machineId: id,
|
|
120
196
|
liveSessionId: session.liveSessionId,
|
|
121
197
|
label: session.name,
|
|
122
|
-
hostLabel: manager.getMachine(id)?.label ?? id
|
|
198
|
+
hostLabel: `${manager.getMachine(id)?.label ?? id}${session.serverLabel ? ` / ${session.serverLabel}` : ""}`,
|
|
123
199
|
});
|
|
124
200
|
preferences.change({ type: "visit", key: session.id });
|
|
125
201
|
if (remember && history[historyIndex] !== session.id) {
|
|
@@ -138,30 +214,57 @@ export function createApplicationMachineNavigation(options: {
|
|
|
138
214
|
(g) => g.id === target.machineId || g.routeIds?.includes(target.machineId),
|
|
139
215
|
);
|
|
140
216
|
const row = group?.sessions.find(
|
|
141
|
-
(s) =>
|
|
217
|
+
(s) =>
|
|
218
|
+
s.liveSessionId === target.liveSessionId &&
|
|
219
|
+
!s.disabled &&
|
|
220
|
+
s.server?.serverId === target.server?.serverId &&
|
|
221
|
+
s.server?.generation === target.server?.generation,
|
|
142
222
|
);
|
|
143
223
|
return row ? { ...target, label: row.name } : null;
|
|
144
224
|
};
|
|
145
225
|
const tabs = createFleetTabs({
|
|
146
226
|
resolve: resolveTab,
|
|
147
227
|
retireActive: () => {
|
|
228
|
+
setActiveSessionKey(null);
|
|
148
229
|
navigation++;
|
|
149
230
|
options.cancelOpen();
|
|
150
231
|
options.resetWorkspace(manager.snapshot().selectedMachineId);
|
|
151
232
|
options.setSurface("home");
|
|
152
233
|
},
|
|
153
234
|
open: async (target) =>
|
|
154
|
-
!!(await open(
|
|
235
|
+
!!(await open(
|
|
236
|
+
target.machineId,
|
|
237
|
+
target.label,
|
|
238
|
+
"keyboard",
|
|
239
|
+
true,
|
|
240
|
+
target.liveSessionId,
|
|
241
|
+
target.server,
|
|
242
|
+
)),
|
|
155
243
|
publish: () => setTabRevision((value) => value + 1),
|
|
156
244
|
unavailable: () => options.setNote("That tab's session is unavailable or has been replaced."),
|
|
157
245
|
});
|
|
246
|
+
const isDefaultSession = (machineId: string, session: { server?: TmuxServerScope }) =>
|
|
247
|
+
!session.server ||
|
|
248
|
+
session.server.generation === manager.getMachine(machineId)?.read()?.instanceId;
|
|
158
249
|
const sidebar: ApplicationMachineSidebarModel = {
|
|
159
250
|
groups: () =>
|
|
160
251
|
snapshot().groups.map((group) => ({
|
|
161
252
|
...group,
|
|
162
253
|
agentsAvailable:
|
|
163
|
-
|
|
164
|
-
|
|
254
|
+
group.sessions.some((session) => isDefaultSession(group.id, session)) &&
|
|
255
|
+
(agentGroups().find((value) => value.machineId === group.id)?.available ?? false),
|
|
256
|
+
agents: !group.sessions.some((session) => isDefaultSession(group.id, session))
|
|
257
|
+
? []
|
|
258
|
+
: (agentGroups().find((value) => value.machineId === group.id)?.agents ?? []).map(
|
|
259
|
+
(agent) => ({
|
|
260
|
+
...agent,
|
|
261
|
+
server: group.sessions.find(
|
|
262
|
+
(session) =>
|
|
263
|
+
session.liveSessionId === agent.liveSessionId &&
|
|
264
|
+
isDefaultSession(group.id, session),
|
|
265
|
+
)?.server,
|
|
266
|
+
}),
|
|
267
|
+
),
|
|
165
268
|
})),
|
|
166
269
|
tabs: () => {
|
|
167
270
|
tabRevision();
|
|
@@ -182,6 +285,7 @@ export function createApplicationMachineNavigation(options: {
|
|
|
182
285
|
onCollapse: (key, enabled) => preferences.change({ type: "collapse", key, enabled }),
|
|
183
286
|
activeMachineId: () => snapshot().selectedMachineId,
|
|
184
287
|
activeSessionName: options.sessionName,
|
|
288
|
+
activeSessionKey,
|
|
185
289
|
activePaneId: options.activePaneId,
|
|
186
290
|
focused,
|
|
187
291
|
onFocus: () => {
|
|
@@ -190,8 +294,17 @@ export function createApplicationMachineNavigation(options: {
|
|
|
190
294
|
setFocused(true);
|
|
191
295
|
},
|
|
192
296
|
onBlur: () => setFocused(false),
|
|
193
|
-
onOpen: (id, name, source) =>
|
|
297
|
+
onOpen: (id, name, source, sessionKey) =>
|
|
298
|
+
void open(id, name, source, true, undefined, undefined, sessionKey),
|
|
194
299
|
onOpenAgent: (id, sessionName, paneId, source) => {
|
|
300
|
+
const sessions = snapshot().groups.find((group) => group.id === id)?.sessions ?? [];
|
|
301
|
+
const selectedSession = sessions.find(
|
|
302
|
+
(session) => session.name === sessionName && isDefaultSession(id, session),
|
|
303
|
+
);
|
|
304
|
+
if (sessions.length && !selectedSession) {
|
|
305
|
+
options.setNote("Open this agent through its server session first.");
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
195
308
|
const row = agentGroups()
|
|
196
309
|
.find((group) => group.machineId === id)
|
|
197
310
|
?.agents.find((agent) => agent.sessionName === sessionName && agent.paneId === paneId);
|
|
@@ -202,11 +315,16 @@ export function createApplicationMachineNavigation(options: {
|
|
|
202
315
|
return;
|
|
203
316
|
}
|
|
204
317
|
options.cancelOpen();
|
|
205
|
-
if (!select(id)) return;
|
|
318
|
+
if (!select(id, selectedSession?.liveSessionId, selectedSession?.server)) return;
|
|
319
|
+
if (selectedSession) setActiveSessionKey(selectedSession.id);
|
|
206
320
|
navigation++;
|
|
207
321
|
setFocused(false);
|
|
208
322
|
void options.openAgent?.(row, source);
|
|
209
323
|
},
|
|
324
|
+
onSelectServer: (machineId, server) => {
|
|
325
|
+
showSwitcher(false);
|
|
326
|
+
setServerFocus({ machineId, server });
|
|
327
|
+
},
|
|
210
328
|
onSelectMachine: (id) => {
|
|
211
329
|
tabs.suspend();
|
|
212
330
|
navigation++;
|
|
@@ -242,6 +360,30 @@ export function createApplicationMachineNavigation(options: {
|
|
|
242
360
|
catalog,
|
|
243
361
|
agents,
|
|
244
362
|
selectedMachineId: () => manager.snapshot().selectedMachineId,
|
|
363
|
+
openHomeAgent: (row: ApplicationMachineAgent, source: "keyboard" | "mouse") => {
|
|
364
|
+
if (!agents.isCurrentTarget(row.machineId, row) || row.disabled) return;
|
|
365
|
+
const session = snapshot()
|
|
366
|
+
.groups.find((group) => group.id === row.machineId)
|
|
367
|
+
?.sessions.find(
|
|
368
|
+
(session) =>
|
|
369
|
+
session.liveSessionId === row.liveSessionId &&
|
|
370
|
+
!session.disabled &&
|
|
371
|
+
session.server?.serverId === row.server?.serverId &&
|
|
372
|
+
session.server?.generation === row.server?.generation,
|
|
373
|
+
);
|
|
374
|
+
if (!session) {
|
|
375
|
+
options.setNote("That agent session has changed. Select it again.");
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
options.cancelOpen();
|
|
379
|
+
if (!select(row.machineId, row.liveSessionId, row.server)) return;
|
|
380
|
+
setActiveSessionKey(session.id);
|
|
381
|
+
navigation++;
|
|
382
|
+
setFocused(false);
|
|
383
|
+
return options.openAgent?.(row, source);
|
|
384
|
+
},
|
|
385
|
+
openSelectedSession: (name: string, source: "keyboard" | "mouse", key?: string) =>
|
|
386
|
+
open(manager.snapshot().selectedMachineId, name, source, true, undefined, undefined, key),
|
|
245
387
|
automaticOpen: manager.snapshot().machines.length === 1,
|
|
246
388
|
automaticOpenAllowed: () =>
|
|
247
389
|
navigation === 0 && manager.snapshot().selectedMachineId === "local",
|
|
@@ -262,7 +404,18 @@ export function createApplicationMachineNavigation(options: {
|
|
|
262
404
|
options.setNote("That session is unavailable or has been replaced.");
|
|
263
405
|
return;
|
|
264
406
|
}
|
|
265
|
-
if (
|
|
407
|
+
if (
|
|
408
|
+
await open(
|
|
409
|
+
group.id,
|
|
410
|
+
session.name,
|
|
411
|
+
"keyboard",
|
|
412
|
+
false,
|
|
413
|
+
session.liveSessionId,
|
|
414
|
+
session.server,
|
|
415
|
+
session.id,
|
|
416
|
+
)
|
|
417
|
+
)
|
|
418
|
+
historyIndex = next;
|
|
266
419
|
},
|
|
267
420
|
cycleTab(direction: -1 | 1, close = false) {
|
|
268
421
|
const value = tabs.snapshot();
|
|
@@ -276,10 +429,22 @@ export function createApplicationMachineNavigation(options: {
|
|
|
276
429
|
if (target) void tabs.activate(target.key);
|
|
277
430
|
},
|
|
278
431
|
closeSwitcher: () => setSwitching(false),
|
|
432
|
+
switcherFilter: (command: ApplicationPaletteCommand) => {
|
|
433
|
+
const focus = serverFocus();
|
|
434
|
+
return (
|
|
435
|
+
!focus ||
|
|
436
|
+
(typeof command === "object" &&
|
|
437
|
+
command.fleet?.machineId === focus.machineId &&
|
|
438
|
+
command.fleet?.server?.serverId === focus.server.serverId &&
|
|
439
|
+
command.fleet?.server?.generation === focus.server.generation)
|
|
440
|
+
);
|
|
441
|
+
},
|
|
279
442
|
paletteCommands(): readonly ApplicationPaletteCommand[] {
|
|
280
443
|
const groupsById = new Map(agentGroups().map((group) => [group.machineId, group]));
|
|
281
444
|
return snapshot().groups.flatMap((group) => {
|
|
282
|
-
const agentGroup =
|
|
445
|
+
const agentGroup = !group.sessions.some((session) => isDefaultSession(group.id, session))
|
|
446
|
+
? undefined
|
|
447
|
+
: groupsById.get(group.id);
|
|
283
448
|
const agentsBySession = new Map<string, ApplicationMachineAgent[]>();
|
|
284
449
|
for (const agent of agentGroup?.agents ?? []) {
|
|
285
450
|
if (!agent.liveSessionId || !agent.paneId) continue;
|
|
@@ -297,20 +462,25 @@ export function createApplicationMachineNavigation(options: {
|
|
|
297
462
|
? saved().recent.indexOf(session.id)
|
|
298
463
|
: 1000,
|
|
299
464
|
liveSessionId: session.liveSessionId,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
465
|
+
server: session.server,
|
|
466
|
+
hostLabel: `${group.label}${session.serverLabel ? ` / ${session.serverLabel}` : ""}`,
|
|
467
|
+
agentActivities:
|
|
468
|
+
isDefaultSession(group.id, session) && agentGroup?.available
|
|
469
|
+
? (agentsBySession.get(session.liveSessionId) ?? []).map((a) => ({
|
|
470
|
+
paneId: a.paneId!,
|
|
471
|
+
attention: a.attention,
|
|
472
|
+
activity: a.activity,
|
|
473
|
+
}))
|
|
474
|
+
: undefined,
|
|
308
475
|
daemonInstanceId: daemon?.instanceId ?? "",
|
|
309
476
|
disabled: session.disabled || group.state !== "ready",
|
|
310
477
|
};
|
|
311
478
|
return [
|
|
312
479
|
{ kind: "open-session", sessionName: session.name, label: session.name, fleet },
|
|
313
|
-
...(
|
|
480
|
+
...(isDefaultSession(group.id, session)
|
|
481
|
+
? (agentsBySession.get(session.liveSessionId) ?? [])
|
|
482
|
+
: []
|
|
483
|
+
).map((a) => ({
|
|
314
484
|
kind: "jump-agent" as const,
|
|
315
485
|
sessionName: session.name,
|
|
316
486
|
paneId: a.paneId!,
|
|
@@ -332,6 +502,21 @@ export function createApplicationMachineNavigation(options: {
|
|
|
332
502
|
disabled: group.state !== "ready",
|
|
333
503
|
},
|
|
334
504
|
},
|
|
505
|
+
...(group.servers ?? []).map((server) => ({
|
|
506
|
+
kind: "open-machine" as const,
|
|
507
|
+
sessionName: "" as const,
|
|
508
|
+
label: `${server.label} · ${server.serverId.slice(-6)} · New session ^N`,
|
|
509
|
+
fleet: {
|
|
510
|
+
machineId: group.id,
|
|
511
|
+
hostLabel: `${group.label} / ${server.label}`,
|
|
512
|
+
liveSessionId: "",
|
|
513
|
+
daemonInstanceId: daemon?.instanceId ?? "",
|
|
514
|
+
disabled: group.state !== "ready" || server.state !== "online",
|
|
515
|
+
...(server.state === "online"
|
|
516
|
+
? { server: { serverId: server.serverId, generation: server.generation } }
|
|
517
|
+
: {}),
|
|
518
|
+
},
|
|
519
|
+
})),
|
|
335
520
|
...sessions,
|
|
336
521
|
];
|
|
337
522
|
});
|
|
@@ -341,7 +526,12 @@ export function createApplicationMachineNavigation(options: {
|
|
|
341
526
|
const target = command.fleet;
|
|
342
527
|
const session = snapshot()
|
|
343
528
|
.groups.find((g) => g.id === target.machineId)
|
|
344
|
-
?.sessions.find(
|
|
529
|
+
?.sessions.find(
|
|
530
|
+
(s) =>
|
|
531
|
+
s.liveSessionId === target.liveSessionId &&
|
|
532
|
+
s.server?.serverId === target.server?.serverId &&
|
|
533
|
+
s.server?.generation === target.server?.generation,
|
|
534
|
+
);
|
|
345
535
|
if (session)
|
|
346
536
|
preferences.change({
|
|
347
537
|
type: "favorite",
|
|
@@ -357,6 +547,22 @@ export function createApplicationMachineNavigation(options: {
|
|
|
357
547
|
if (!target) return;
|
|
358
548
|
const handle = manager.getMachine(target.machineId);
|
|
359
549
|
if (command.kind === "open-machine") {
|
|
550
|
+
if (target.server) {
|
|
551
|
+
const descriptor = snapshot()
|
|
552
|
+
.groups.find((group) => group.id === target.machineId)
|
|
553
|
+
?.servers?.find(
|
|
554
|
+
(server) =>
|
|
555
|
+
server.serverId === target.server?.serverId &&
|
|
556
|
+
server.generation === target.server.generation &&
|
|
557
|
+
server.state === "online",
|
|
558
|
+
);
|
|
559
|
+
if (!descriptor || handle?.read()?.instanceId !== target.daemonInstanceId) {
|
|
560
|
+
options.setNote("That server has changed. Select it again.");
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
sidebar.onSelectServer?.(target.machineId, target.server);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
360
566
|
if (
|
|
361
567
|
handle?.endpoint().state === "ready" &&
|
|
362
568
|
handle.read()?.instanceId === target.daemonInstanceId
|
|
@@ -369,7 +575,11 @@ export function createApplicationMachineNavigation(options: {
|
|
|
369
575
|
(g) => g.id === target.machineId || g.routeIds?.includes(target.machineId),
|
|
370
576
|
);
|
|
371
577
|
const session = group?.sessions.find(
|
|
372
|
-
(s) =>
|
|
578
|
+
(s) =>
|
|
579
|
+
s.liveSessionId === target.liveSessionId &&
|
|
580
|
+
!s.disabled &&
|
|
581
|
+
s.server?.serverId === target.server?.serverId &&
|
|
582
|
+
s.server?.generation === target.server?.generation,
|
|
373
583
|
);
|
|
374
584
|
if (
|
|
375
585
|
!session ||
|
|
@@ -381,7 +591,15 @@ export function createApplicationMachineNavigation(options: {
|
|
|
381
591
|
}
|
|
382
592
|
if (command.kind === "jump-agent")
|
|
383
593
|
sidebar.onOpenAgent?.(target.machineId, session.name, command.paneId, source);
|
|
384
|
-
else
|
|
594
|
+
else
|
|
595
|
+
await open(
|
|
596
|
+
target.machineId,
|
|
597
|
+
session.name,
|
|
598
|
+
source,
|
|
599
|
+
true,
|
|
600
|
+
target.liveSessionId,
|
|
601
|
+
target.server,
|
|
602
|
+
);
|
|
385
603
|
},
|
|
386
604
|
adding,
|
|
387
605
|
alias,
|
|
@@ -433,16 +651,47 @@ export function createApplicationMachineNavigation(options: {
|
|
|
433
651
|
setError(cause instanceof Error ? cause.message : "Could not add this machine.");
|
|
434
652
|
}
|
|
435
653
|
},
|
|
436
|
-
start(target: string | null) {
|
|
654
|
+
start(target: string | null, serverId?: string | null) {
|
|
437
655
|
agents.start();
|
|
438
656
|
catalog.start();
|
|
439
|
-
if (!target) return;
|
|
657
|
+
if (!target && !serverId) return;
|
|
440
658
|
const id = manager.snapshot().selectedMachineId;
|
|
441
659
|
const token = navigation;
|
|
660
|
+
|
|
661
|
+
let machineReady = false;
|
|
662
|
+
const attempt = () => {
|
|
663
|
+
if (!machineReady) return;
|
|
664
|
+
if (token !== navigation) {
|
|
665
|
+
attemptStartup = null;
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const group = snapshot().groups.find((group) => group.id === id);
|
|
669
|
+
if (group?.state !== "ready") return;
|
|
670
|
+
const matches = group.sessions.filter(
|
|
671
|
+
(row) =>
|
|
672
|
+
!row.disabled &&
|
|
673
|
+
(!serverId || row.server?.serverId === serverId) &&
|
|
674
|
+
(!target || row.name === target),
|
|
675
|
+
);
|
|
676
|
+
if (matches.length !== 1) {
|
|
677
|
+
options.setNote(
|
|
678
|
+
matches.length
|
|
679
|
+
? "Select a session under the requested tmux server."
|
|
680
|
+
: "Requested server or session is unavailable. Select it again.",
|
|
681
|
+
);
|
|
682
|
+
attemptStartup = null;
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const row = matches[0]!;
|
|
686
|
+
attemptStartup = null;
|
|
687
|
+
void open(id, row.name, "keyboard", true, row.liveSessionId, row.server, row.id);
|
|
688
|
+
};
|
|
689
|
+
attemptStartup = attempt;
|
|
442
690
|
void manager.getMachine(id)?.ready.then((ready) => {
|
|
443
|
-
|
|
444
|
-
|
|
691
|
+
machineReady = ready;
|
|
692
|
+
attemptStartup?.();
|
|
445
693
|
});
|
|
694
|
+
attempt();
|
|
446
695
|
},
|
|
447
696
|
};
|
|
448
697
|
}
|
|
@@ -17,7 +17,7 @@ export function ApplicationMachineOverlays(props: {
|
|
|
17
17
|
open={true}
|
|
18
18
|
attentionOnly={props.machines.attentionOnly()}
|
|
19
19
|
rows={[]}
|
|
20
|
-
commands={props.machines.paletteCommands()}
|
|
20
|
+
commands={props.machines.paletteCommands().filter(props.machines.switcherFilter)}
|
|
21
21
|
onActivate={(c) => {
|
|
22
22
|
if (typeof c === "object") void props.machines.openPalette(c, "keyboard");
|
|
23
23
|
}}
|