tmux-ide 2.9.0-beta.21 → 2.9.0-beta.22
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 +52253 -49070
- package/package.json +1 -1
- 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/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 +345 -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 +16 -10
- 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-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-machine-catalog.js +12 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-navigation.js +190 -31
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-sidebar.jsx +91 -37
- 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-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/fleet-lifecycle-client.js +42 -1
- package/packages/daemon/dist/tui/mirror/runtime/open-tui-generation-host.js +1 -1
- package/packages/daemon/dist/tui/mirror/runtime/select-terminal-pane.js +2 -1
- 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 +468 -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 +16 -8
- 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-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-machine-catalog.ts +19 -7
- package/packages/daemon/src/tui/mirror/runtime/application-machine-navigation.ts +263 -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-root-configuration.ts +12 -3
- package/packages/daemon/src/tui/mirror/runtime/application-root-v2.tsx +24 -24
- package/packages/daemon/src/tui/mirror/runtime/application-route-connection.ts +93 -1
- package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +4 -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/fleet-lifecycle-client.ts +52 -0
- package/packages/daemon/src/tui/mirror/runtime/open-tui-generation-host.ts +1 -1
- package/packages/daemon/src/tui/mirror/runtime/select-terminal-pane.ts +3 -0
- 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, TmuxServerScope } from "@tmux-ide/contracts";
|
|
1
2
|
import { fleetHostColor, summarizeFleetActivity } from "./fleet-presentation.ts";
|
|
2
3
|
import { TuiButton } from "../ui/button.tsx";
|
|
3
4
|
/* @jsxImportSource @opentui/solid */
|
|
@@ -24,6 +25,7 @@ import { Surface } from "../ui/surface.tsx";
|
|
|
24
25
|
import { useKeyboardRoute } from "../ui/keyboard-router.tsx";
|
|
25
26
|
|
|
26
27
|
export interface ApplicationMachineAgent {
|
|
28
|
+
readonly server?: TmuxServerScope;
|
|
27
29
|
readonly id: string;
|
|
28
30
|
readonly name: string;
|
|
29
31
|
readonly sessionName: string;
|
|
@@ -41,8 +43,11 @@ export interface ApplicationMachineGroup {
|
|
|
41
43
|
readonly id: string;
|
|
42
44
|
readonly label: string;
|
|
43
45
|
readonly state: "ready" | "connecting" | "disconnected";
|
|
46
|
+
readonly servers?: readonly TmuxServerDescriptor[];
|
|
44
47
|
readonly sessions: readonly {
|
|
45
48
|
readonly id: string;
|
|
49
|
+
readonly server?: TmuxServerScope;
|
|
50
|
+
readonly serverLabel?: string;
|
|
46
51
|
readonly name: string;
|
|
47
52
|
readonly paneCount: number;
|
|
48
53
|
readonly disabled?: boolean;
|
|
@@ -56,8 +61,15 @@ export interface ApplicationMachineSidebarModel {
|
|
|
56
61
|
readonly onCollapse?: (key: string, enabled: boolean) => void;
|
|
57
62
|
readonly activeMachineId: Accessor<string | null>;
|
|
58
63
|
readonly activeSessionName: Accessor<string | null>;
|
|
64
|
+
readonly activeSessionKey?: Accessor<string | null>;
|
|
59
65
|
readonly activePaneId?: Accessor<string | null>;
|
|
60
|
-
readonly onOpen: (
|
|
66
|
+
readonly onOpen: (
|
|
67
|
+
machineId: string,
|
|
68
|
+
sessionName: string,
|
|
69
|
+
source: "keyboard" | "mouse",
|
|
70
|
+
sessionKey?: string,
|
|
71
|
+
) => void;
|
|
72
|
+
readonly onSelectServer?: (machineId: string, server: TmuxServerScope) => void;
|
|
61
73
|
readonly onSelectMachine: (machineId: string, source: "keyboard" | "mouse") => void;
|
|
62
74
|
readonly onOpenAgent?: (
|
|
63
75
|
machineId: string,
|
|
@@ -92,6 +104,8 @@ type Row = {
|
|
|
92
104
|
session?: ApplicationMachineGroup["sessions"][number];
|
|
93
105
|
agent?: ApplicationMachineAgent;
|
|
94
106
|
agentHeading?: boolean;
|
|
107
|
+
serverHeading?: string;
|
|
108
|
+
server?: TmuxServerDescriptor;
|
|
95
109
|
};
|
|
96
110
|
/** Pure machine navigation. All connection and session authority stays with the caller. */
|
|
97
111
|
export function ApplicationMachineSidebar(props: {
|
|
@@ -145,9 +159,18 @@ export function ApplicationMachineSidebar(props: {
|
|
|
145
159
|
? row.group.state === "ready" &&
|
|
146
160
|
!row.agent.disabled &&
|
|
147
161
|
row.agent.sessionName === props.model.activeSessionName() &&
|
|
162
|
+
(!props.model.activeSessionKey ||
|
|
163
|
+
row.group.sessions.some(
|
|
164
|
+
(session) =>
|
|
165
|
+
session.id === props.model.activeSessionKey?.() &&
|
|
166
|
+
session.server?.serverId === row.agent?.server?.serverId &&
|
|
167
|
+
session.server?.generation === row.agent?.server?.generation,
|
|
168
|
+
)) &&
|
|
148
169
|
row.agent.paneId !== null &&
|
|
149
170
|
row.agent.paneId === props.model.activePaneId?.()
|
|
150
|
-
:
|
|
171
|
+
: props.model.activeSessionKey
|
|
172
|
+
? row.session?.id === props.model.activeSessionKey()
|
|
173
|
+
: row.session?.name === props.model.activeSessionName());
|
|
151
174
|
const preferenceKey = (group: ApplicationMachineGroup) => group.environmentId ?? group.id;
|
|
152
175
|
const rows = createMemo<readonly Row[]>(() =>
|
|
153
176
|
props.model.groups().flatMap((group) => [
|
|
@@ -158,13 +181,34 @@ export function ApplicationMachineSidebar(props: {
|
|
|
158
181
|
!collapsed().has(preferenceKey(group)) ||
|
|
159
182
|
props.model.favorites?.().includes(session.id) ||
|
|
160
183
|
(group.id === props.model.activeMachineId() &&
|
|
161
|
-
|
|
184
|
+
(props.model.activeSessionKey
|
|
185
|
+
? session.id === props.model.activeSessionKey()
|
|
186
|
+
: session.name === props.model.activeSessionName())),
|
|
162
187
|
)
|
|
163
|
-
.map((session) => ({
|
|
188
|
+
.map((session, index, sessions) => ({
|
|
189
|
+
serverHeading:
|
|
190
|
+
(group.servers?.length ??
|
|
191
|
+
new Set(group.sessions.map((row) => row.server?.serverId)).size) > 1 &&
|
|
192
|
+
session.server &&
|
|
193
|
+
(index === 0 || sessions[index - 1]?.server?.serverId !== session.server.serverId)
|
|
194
|
+
? `${session.serverLabel ?? "Server"} · ${session.server.serverId.slice(-6)}`
|
|
195
|
+
: undefined,
|
|
164
196
|
key: JSON.stringify([group.id, "session", session.id]),
|
|
165
197
|
group,
|
|
166
198
|
session,
|
|
167
199
|
})),
|
|
200
|
+
...(collapsed().has(preferenceKey(group))
|
|
201
|
+
? []
|
|
202
|
+
: (group.servers ?? [])
|
|
203
|
+
.filter(
|
|
204
|
+
(server) =>
|
|
205
|
+
!group.sessions.some((session) => session.server?.serverId === server.serverId),
|
|
206
|
+
)
|
|
207
|
+
.map((server) => ({
|
|
208
|
+
key: JSON.stringify([group.id, "server", server.serverId]),
|
|
209
|
+
group,
|
|
210
|
+
server,
|
|
211
|
+
}))),
|
|
168
212
|
...(!collapsed().has(preferenceKey(group))
|
|
169
213
|
? (group.agents ?? []).map((agent, index) => ({
|
|
170
214
|
key: JSON.stringify([group.id, "agent", agent.id]),
|
|
@@ -193,7 +237,11 @@ export function ApplicationMachineSidebar(props: {
|
|
|
193
237
|
const activity = (row: Row) =>
|
|
194
238
|
summarizeFleetActivity(
|
|
195
239
|
(row.group.agents ?? []).filter(
|
|
196
|
-
(agent) =>
|
|
240
|
+
(agent) =>
|
|
241
|
+
!row.session ||
|
|
242
|
+
(agent.sessionName === row.session.name &&
|
|
243
|
+
agent.server?.serverId === row.session.server?.serverId &&
|
|
244
|
+
agent.server?.generation === row.session.server?.generation),
|
|
197
245
|
),
|
|
198
246
|
row.group.state === "ready" && row.group.agentsAvailable !== false && !row.session?.disabled,
|
|
199
247
|
);
|
|
@@ -229,6 +277,14 @@ export function ApplicationMachineSidebar(props: {
|
|
|
229
277
|
setSelectedKey(row.key);
|
|
230
278
|
setLocalFocused(true);
|
|
231
279
|
props.model.onFocus?.();
|
|
280
|
+
if (row.server) {
|
|
281
|
+
if (row.server.state === "online")
|
|
282
|
+
props.model.onSelectServer?.(row.group.id, {
|
|
283
|
+
serverId: row.server.serverId,
|
|
284
|
+
generation: row.server.generation,
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
232
288
|
if (row.agent) {
|
|
233
289
|
if (
|
|
234
290
|
row.group.state === "ready" &&
|
|
@@ -242,7 +298,7 @@ export function ApplicationMachineSidebar(props: {
|
|
|
242
298
|
}
|
|
243
299
|
} else if (row.session) {
|
|
244
300
|
if (row.group.state === "ready" && !row.session.disabled)
|
|
245
|
-
props.model.onOpen(row.group.id, row.session.name, source);
|
|
301
|
+
props.model.onOpen(row.group.id, row.session.name, source, row.session.id);
|
|
246
302
|
} else if (
|
|
247
303
|
row.group.state !== "ready" ||
|
|
248
304
|
(row.group.sessions.length === 0 && !row.group.agents?.length)
|
|
@@ -252,7 +308,8 @@ export function ApplicationMachineSidebar(props: {
|
|
|
252
308
|
};
|
|
253
309
|
const revealFocusedRow = () => {
|
|
254
310
|
if (!focused() || !scroll) return;
|
|
255
|
-
const rowHeight = (row: Row) =>
|
|
311
|
+
const rowHeight = (row: Row) =>
|
|
312
|
+
row.agent ? (row.agentHeading ? 3 : 2) : row.serverHeading ? 2 : 1;
|
|
256
313
|
const y = rows()
|
|
257
314
|
.slice(0, index())
|
|
258
315
|
.reduce((sum, row) => sum + rowHeight(row), 0);
|
|
@@ -457,6 +514,12 @@ export function ApplicationMachineSidebar(props: {
|
|
|
457
514
|
get agent() {
|
|
458
515
|
return current().agent;
|
|
459
516
|
},
|
|
517
|
+
get server() {
|
|
518
|
+
return current().server;
|
|
519
|
+
},
|
|
520
|
+
get serverHeading() {
|
|
521
|
+
return current().serverHeading;
|
|
522
|
+
},
|
|
460
523
|
get agentHeading() {
|
|
461
524
|
return current().agentHeading;
|
|
462
525
|
},
|
|
@@ -464,10 +527,23 @@ export function ApplicationMachineSidebar(props: {
|
|
|
464
527
|
return (
|
|
465
528
|
<box
|
|
466
529
|
width={Math.max(1, props.width - 1)}
|
|
467
|
-
height={row.agent ? (row.agentHeading ? 3 : 2) : 1}
|
|
530
|
+
height={row.agent ? (row.agentHeading ? 3 : 2) : row.serverHeading ? 2 : 1}
|
|
468
531
|
flexShrink={0}
|
|
469
532
|
flexDirection="column"
|
|
470
533
|
>
|
|
534
|
+
<Show when={row.serverHeading}>
|
|
535
|
+
<NavigationRow
|
|
536
|
+
theme={props.theme}
|
|
537
|
+
width={Math.max(1, props.width - 1)}
|
|
538
|
+
id={`server:${row.group.id}:${row.session?.server?.serverId}`}
|
|
539
|
+
label={row.serverHeading ?? "Server"}
|
|
540
|
+
marker=" ▾"
|
|
541
|
+
onActivate={() => {
|
|
542
|
+
if (row.session?.server)
|
|
543
|
+
props.model.onSelectServer?.(row.group.id, row.session.server);
|
|
544
|
+
}}
|
|
545
|
+
/>
|
|
546
|
+
</Show>
|
|
471
547
|
<Show when={row.agentHeading}>
|
|
472
548
|
<text height={1} fg={props.theme.roles.text.secondary}>
|
|
473
549
|
{" "}
|
|
@@ -480,43 +556,51 @@ export function ApplicationMachineSidebar(props: {
|
|
|
480
556
|
width={Math.max(1, props.width - 1)}
|
|
481
557
|
labelColor={!row.agent && !row.session ? fleetHostColor(row.group) : undefined}
|
|
482
558
|
label={
|
|
483
|
-
row.
|
|
484
|
-
? row.
|
|
485
|
-
: row.
|
|
486
|
-
?
|
|
487
|
-
: row.
|
|
559
|
+
row.server
|
|
560
|
+
? ` ${row.server.label} · ${row.server.serverId.slice(-6)}`
|
|
561
|
+
: row.agent
|
|
562
|
+
? row.agent.name
|
|
563
|
+
: row.session
|
|
564
|
+
? friendlySessionLabel(row.session.name)
|
|
565
|
+
: row.group.label
|
|
488
566
|
}
|
|
489
567
|
marker={
|
|
490
|
-
row.
|
|
491
|
-
?
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
:
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
? "
|
|
503
|
-
:
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
:
|
|
568
|
+
row.server
|
|
569
|
+
? " "
|
|
570
|
+
: row.agent
|
|
571
|
+
? active(row)
|
|
572
|
+
? row.agent.attention
|
|
573
|
+
? "›!"
|
|
574
|
+
: "›"
|
|
575
|
+
: row.agent.attention
|
|
576
|
+
? "!"
|
|
577
|
+
: "•"
|
|
578
|
+
: row.session
|
|
579
|
+
? props.model.favorites?.().includes(row.session.id)
|
|
580
|
+
? " ★"
|
|
581
|
+
: active(row)
|
|
582
|
+
? " ›"
|
|
583
|
+
: " "
|
|
584
|
+
: collapsed().has(preferenceKey(row.group))
|
|
585
|
+
? "▸"
|
|
586
|
+
: "▾"
|
|
507
587
|
}
|
|
508
588
|
detail={
|
|
509
|
-
row.
|
|
510
|
-
? row.
|
|
511
|
-
? "
|
|
512
|
-
:
|
|
513
|
-
: row.
|
|
514
|
-
? row.group.state !== "ready" || row.
|
|
589
|
+
row.server
|
|
590
|
+
? row.server.state === "offline"
|
|
591
|
+
? "offline"
|
|
592
|
+
: "empty"
|
|
593
|
+
: row.agent
|
|
594
|
+
? row.group.state !== "ready" || row.agent.disabled
|
|
515
595
|
? "unavailable"
|
|
516
|
-
:
|
|
517
|
-
: row.
|
|
518
|
-
?
|
|
519
|
-
|
|
596
|
+
: `[${terminalAgentStatusLabel(row.agent.activity)}]`
|
|
597
|
+
: row.session
|
|
598
|
+
? row.group.state !== "ready" || row.session.disabled
|
|
599
|
+
? "unavailable"
|
|
600
|
+
: `${row.session.paneCount}p${row.group.agents?.length ? ` ${activity(row).label}` : ""}`
|
|
601
|
+
: row.group.agents?.length && row.group.state === "ready"
|
|
602
|
+
? activity(row).label
|
|
603
|
+
: `${connectionDetail(row.group)}${row.group.agents?.length ? " ?" : ""}`
|
|
520
604
|
}
|
|
521
605
|
selected={Boolean((row.session || row.agent) && active(row))}
|
|
522
606
|
focused={Boolean(focused() && row.key === selectedKey())}
|
|
@@ -53,6 +53,8 @@ export function ApplicationPalettePreview(props: {
|
|
|
53
53
|
const identity = () =>
|
|
54
54
|
JSON.stringify([
|
|
55
55
|
target()?.machineId,
|
|
56
|
+
target()?.server?.serverId,
|
|
57
|
+
target()?.server?.generation,
|
|
56
58
|
target()?.liveSessionId,
|
|
57
59
|
target()?.daemonInstanceId,
|
|
58
60
|
paneId(),
|
|
@@ -77,6 +79,7 @@ export function ApplicationPalettePreview(props: {
|
|
|
77
79
|
fleet &&
|
|
78
80
|
Boolean(fleet.liveSessionId) &&
|
|
79
81
|
!fleet.disabled &&
|
|
82
|
+
(!fleet.server || fleet.server.generation === fleet.daemonInstanceId) &&
|
|
80
83
|
handle?.endpoint().state === "ready" &&
|
|
81
84
|
handle.read()?.instanceId === fleet.daemonInstanceId;
|
|
82
85
|
owner.select(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TmuxServerIdSchemaZ } from "@tmux-ide/contracts";
|
|
1
2
|
import { parseArgs } from "node:util";
|
|
2
3
|
|
|
3
4
|
import { loadAppConfig, type AppConfig } from "../../../lib/app-config.ts";
|
|
@@ -6,11 +7,13 @@ import { tuiPerfMark } from "./application-performance-log.ts";
|
|
|
6
7
|
|
|
7
8
|
export interface ApplicationArgs {
|
|
8
9
|
readonly target: string | null;
|
|
10
|
+
readonly serverId?: string | null;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export interface ApplicationConfig {
|
|
12
14
|
readonly app: AppConfig;
|
|
13
15
|
readonly target: string | null;
|
|
16
|
+
readonly serverId?: string | null;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
export interface StartApplicationRootOptions {
|
|
@@ -31,11 +34,17 @@ export const parseApplicationArgs = (argv: readonly string[]): ApplicationArgs =
|
|
|
31
34
|
args: [...argv],
|
|
32
35
|
allowPositionals: true,
|
|
33
36
|
strict: false,
|
|
34
|
-
options: { target: { type: "string" } },
|
|
37
|
+
options: { target: { type: "string" }, server: { type: "string" } },
|
|
35
38
|
});
|
|
36
39
|
const positional = parsed.positionals.find((value) => value !== "app") ?? null;
|
|
37
40
|
const target = typeof parsed.values.target === "string" ? parsed.values.target : positional;
|
|
38
|
-
return Object.freeze({
|
|
41
|
+
return Object.freeze({
|
|
42
|
+
target: target && target !== "home" ? target : null,
|
|
43
|
+
serverId:
|
|
44
|
+
typeof parsed.values.server === "string"
|
|
45
|
+
? TmuxServerIdSchemaZ.parse(parsed.values.server)
|
|
46
|
+
: null,
|
|
47
|
+
});
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
export async function loadApplicationConfig(args: ApplicationArgs): Promise<ApplicationConfig> {
|
|
@@ -43,5 +52,5 @@ export async function loadApplicationConfig(args: ApplicationArgs): Promise<Appl
|
|
|
43
52
|
// Home discovery is daemon-authoritative and remains live after mount. The
|
|
44
53
|
// immutable bootstrap config only carries an explicit user target.
|
|
45
54
|
tuiPerfMark("config-load-end", { target: args.target });
|
|
46
|
-
return Object.freeze({ app: loadAppConfig(), target: args.target });
|
|
55
|
+
return Object.freeze({ app: loadAppConfig(), target: args.target, serverId: args.serverId });
|
|
47
56
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { TmuxServerScope } from "@tmux-ide/contracts";
|
|
2
|
+
import { terminalWindowActionCallbacks } from "./application-terminal-workspace-policy.ts";
|
|
1
3
|
import { applicationRouteConnection } from "./application-route-connection.ts";
|
|
2
4
|
import { ApplicationMachineOverlays } from "./application-machine-overlays.tsx";
|
|
3
|
-
import { handleFleetShortcut } from "./application-machine-navigation.ts";
|
|
4
5
|
import { applicationMachineAuthorityManager } from "./application-machine-authority.ts";
|
|
5
6
|
import { createApplicationMachineAgentNavigator } from "./application-machine-agent-navigation.ts";
|
|
6
7
|
import { createApplicationMachineNavigation } from "./application-machine-navigation.ts";
|
|
8
|
+
import { handleFleetShortcut } from "./application-machine-navigation.ts";
|
|
7
9
|
import { disposeApplicationDaemonAuthority } from "./application-daemon-authority.ts";
|
|
8
10
|
import { createTerminalLinkOpener } from "./terminal-link-opener.ts";
|
|
9
11
|
import { createApplicationPaneActivityOwner } from "./application-pane-activity-owner.ts";
|
|
@@ -174,6 +176,7 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
174
176
|
const makeSessionOwner = (
|
|
175
177
|
machineId = applicationMachineAuthorityManager.snapshot().selectedMachineId,
|
|
176
178
|
expectedLiveSessionId?: string,
|
|
179
|
+
server?: TmuxServerScope,
|
|
177
180
|
) => {
|
|
178
181
|
const ownedEpoch = ++sessionOwnerEpoch;
|
|
179
182
|
connectionProgress.replaceOwner();
|
|
@@ -181,6 +184,7 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
181
184
|
applicationMachineAuthorityManager.getMachine(machineId)!,
|
|
182
185
|
expectedLiveSessionId,
|
|
183
186
|
tuiLifecycleStream ? tuiPerfMark : undefined,
|
|
187
|
+
server,
|
|
184
188
|
);
|
|
185
189
|
return createOpenTuiSessionOwner({
|
|
186
190
|
onStartupFailure: (sessionName, failure) => {
|
|
@@ -315,19 +319,18 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
315
319
|
| ReturnType<typeof createApplicationMachineAgentNavigator>
|
|
316
320
|
| undefined;
|
|
317
321
|
const machines = createApplicationMachineNavigation({
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
322
|
+
attachedGeneration: generation,
|
|
323
|
+
resetWorkspace(machineId, expectedLiveSessionId, server) {
|
|
324
|
+
void initialPreparation?.preparedConnection
|
|
325
|
+
.then((connection) => connection?.dispose())
|
|
326
|
+
.catch(() => undefined);
|
|
327
|
+
initialPreparation = null;
|
|
325
328
|
interaction?.adoptGeneration(null);
|
|
326
329
|
setGeneration(null);
|
|
327
330
|
shellBinding.adoptGeneration(null);
|
|
328
331
|
terminalHostFocus.adopt(null);
|
|
329
332
|
void sessionOwner?.dispose().catch(() => undefined);
|
|
330
|
-
sessionOwner = makeSessionOwner(machineId, expectedLiveSessionId);
|
|
333
|
+
sessionOwner = makeSessionOwner(machineId, expectedLiveSessionId, server);
|
|
331
334
|
},
|
|
332
335
|
cancelOpen: () => {
|
|
333
336
|
machineAgentNavigator?.cancel();
|
|
@@ -361,9 +364,11 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
361
364
|
onCleanup(() => machineAgentNavigator?.dispose());
|
|
362
365
|
const homeCatalog = createApplicationHomeCatalogOwner({
|
|
363
366
|
lifecycle,
|
|
364
|
-
automaticOpen: config.target === null && machines.automaticOpen,
|
|
367
|
+
automaticOpen: config.target === null && !config.serverId && machines.automaticOpen,
|
|
365
368
|
automaticOpenAllowed: machines.automaticOpenAllowed,
|
|
366
369
|
catalog: machines.catalog.selectedCatalog,
|
|
370
|
+
openCatalogSession: (session) =>
|
|
371
|
+
machines.openSelectedSession(session.name, "keyboard", session.id),
|
|
367
372
|
startGeneration,
|
|
368
373
|
setNote: appearance.setNote,
|
|
369
374
|
});
|
|
@@ -417,11 +422,7 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
417
422
|
useKeyboard((event) => {
|
|
418
423
|
noteHostInteraction();
|
|
419
424
|
const name = event.name.toLowerCase();
|
|
420
|
-
if (paletteModalOpen()) {
|
|
421
|
-
componentKeyboardRoutes.route(event);
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
if (machines.switching()) {
|
|
425
|
+
if (paletteModalOpen() || machines.switching()) {
|
|
425
426
|
componentKeyboardRoutes.route(event);
|
|
426
427
|
return;
|
|
427
428
|
}
|
|
@@ -525,7 +526,7 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
525
526
|
});
|
|
526
527
|
onMount(() => {
|
|
527
528
|
tuiPerfMark("solid-mounted");
|
|
528
|
-
machines.start(config.target);
|
|
529
|
+
machines.start(config.target, config.serverId);
|
|
529
530
|
});
|
|
530
531
|
const resizeIngress = tuiPerfStream ? interaction.beginResizePointerIngress : undefined;
|
|
531
532
|
const applicationMouseIngress = applicationMousePointerIngressCapability(
|
|
@@ -591,7 +592,7 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
591
592
|
onOpenSession={recoverHostFocus((sessionName, source) => {
|
|
592
593
|
machineAgentNavigator?.cancel();
|
|
593
594
|
homeAgents?.cancel();
|
|
594
|
-
void
|
|
595
|
+
void machines.openSelectedSession(sessionName, source);
|
|
595
596
|
})}
|
|
596
597
|
onOpenAgent={recoverHostFocus((sessionName, paneId, source) => {
|
|
597
598
|
machineAgentNavigator?.cancel();
|
|
@@ -600,9 +601,12 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
600
601
|
})}
|
|
601
602
|
onSetPaletteOpen={recoverHostFocus(paletteCommands.setOpen)}
|
|
602
603
|
onPaletteActivate={recoverHostFocus(paletteCommands.activate)}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
604
|
+
{...terminalWindowActionCallbacks(
|
|
605
|
+
interaction,
|
|
606
|
+
setTransientNote,
|
|
607
|
+
recoverHostFocus,
|
|
608
|
+
() => machineAgentNavigator?.cancel(),
|
|
609
|
+
)}
|
|
606
610
|
onCreateWindow={recoverHostFocus(() =>
|
|
607
611
|
paletteCommands.activate("new-window", "mouse"),
|
|
608
612
|
)}
|
|
@@ -616,10 +620,6 @@ export async function startApplicationRoot(options: StartApplicationRootOptions
|
|
|
616
620
|
onCancelPaneRename={recoverHostFocus(paneRename.cancel)}
|
|
617
621
|
onSubmitPaneRename={recoverHostFocus(paneRename.submit)}
|
|
618
622
|
onDismissNotification={recoverHostFocus(() => setTransientNote(null))}
|
|
619
|
-
onSelectPane={recoverHostFocus((paneId, source) => {
|
|
620
|
-
machineAgentNavigator?.cancel();
|
|
621
|
-
interaction.selectPane(paneId, source);
|
|
622
|
-
})}
|
|
623
623
|
onResizePreview={recoverHostFocus(interaction.previewPaneResize)}
|
|
624
624
|
onResizePane={recoverHostFocus(interaction.resizePane)}
|
|
625
625
|
onCancelResize={interaction.cancelPaneResize}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listTmuxServers,
|
|
3
|
+
createTmuxServerClient,
|
|
4
|
+
} from "@tmux-ide/daemon-client/tmux-server-client";
|
|
5
|
+
import { canonicalDaemonUrl } from "../../../lib/canonical-daemon.ts";
|
|
6
|
+
import type { TmuxServerScope } from "@tmux-ide/contracts";
|
|
1
7
|
import { fetchCanonicalLiveWorkspaceRouting } from "../canonical-workspace-routing.ts";
|
|
2
8
|
import type { ApplicationMachineAuthorityHandle } from "./application-machine-authority.ts";
|
|
3
9
|
import { prepareOpenTuiApplicationShellConnection } from "../application-shell-daemon-connection.ts";
|
|
@@ -8,14 +14,100 @@ export function applicationRouteConnection(
|
|
|
8
14
|
handle: ApplicationMachineAuthorityHandle,
|
|
9
15
|
expectedLiveSessionId?: string,
|
|
10
16
|
onDiagnostic?: (phase: string, details: Readonly<Record<string, unknown>>) => void,
|
|
17
|
+
server?: TmuxServerScope,
|
|
11
18
|
) {
|
|
19
|
+
let rootInstanceId = handle.read()?.instanceId;
|
|
20
|
+
let selectedServer = server;
|
|
21
|
+
let refresh: { root: string; promise: Promise<TmuxServerScope> } | null = null;
|
|
22
|
+
const refreshAfterDaemonReplacement = async (nextRoot: string): Promise<TmuxServerScope> => {
|
|
23
|
+
if (!selectedServer) throw new Error("Select the server session again");
|
|
24
|
+
if (rootInstanceId === nextRoot) return selectedServer;
|
|
25
|
+
if (!expectedLiveSessionId) throw new Error("Select the server session again");
|
|
26
|
+
if (refresh?.root === nextRoot) return refresh.promise;
|
|
27
|
+
const stableServerId = selectedServer.serverId;
|
|
28
|
+
const promise = (async () => {
|
|
29
|
+
const daemon = handle.read();
|
|
30
|
+
const epoch = handle.endpoint()?.epoch;
|
|
31
|
+
if (!daemon?.authToken || daemon.instanceId !== nextRoot)
|
|
32
|
+
throw new Error("Daemon changed during reconnect");
|
|
33
|
+
const options = {
|
|
34
|
+
baseUrl: canonicalDaemonUrl("http", daemon.bindHostname, daemon.port),
|
|
35
|
+
ownerToken: daemon.authToken,
|
|
36
|
+
hostClientId: `opentui-reconnect:${process.pid}`,
|
|
37
|
+
origin: "tmux-ide://opentui",
|
|
38
|
+
};
|
|
39
|
+
const catalog = await listTmuxServers(options);
|
|
40
|
+
const descriptor = catalog.servers.find((candidate) => candidate.serverId === stableServerId);
|
|
41
|
+
if (!descriptor || descriptor.state !== "online")
|
|
42
|
+
throw new Error("Selected tmux server is unavailable");
|
|
43
|
+
const scope = { serverId: descriptor.serverId, generation: descriptor.generation };
|
|
44
|
+
const client = createTmuxServerClient(options, scope);
|
|
45
|
+
try {
|
|
46
|
+
const sessions = await client.sessions();
|
|
47
|
+
if (!sessions.sessions.some((session) => session.liveSessionId === expectedLiveSessionId))
|
|
48
|
+
throw new Error("Selected tmux session was replaced");
|
|
49
|
+
} finally {
|
|
50
|
+
client.dispose();
|
|
51
|
+
}
|
|
52
|
+
if (handle.read()?.instanceId !== nextRoot || handle.endpoint()?.epoch !== epoch)
|
|
53
|
+
throw new Error("Daemon changed during reconnect");
|
|
54
|
+
rootInstanceId = nextRoot;
|
|
55
|
+
selectedServer = scope;
|
|
56
|
+
return scope;
|
|
57
|
+
})();
|
|
58
|
+
refresh = { root: nextRoot, promise };
|
|
59
|
+
try {
|
|
60
|
+
return await promise;
|
|
61
|
+
} finally {
|
|
62
|
+
if (refresh?.promise === promise) refresh = null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
12
65
|
return {
|
|
13
66
|
readDaemon: handle.read,
|
|
14
|
-
observeCanonicalGeneration:
|
|
67
|
+
observeCanonicalGeneration: server
|
|
68
|
+
? async (listener: (generation: string | null) => void) => {
|
|
69
|
+
let stopped = false;
|
|
70
|
+
let revision = 0;
|
|
71
|
+
const stop = await handle.observe((generation) => {
|
|
72
|
+
const token = ++revision;
|
|
73
|
+
if (!generation) {
|
|
74
|
+
listener(null);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (generation === rootInstanceId) {
|
|
78
|
+
listener(selectedServer!.generation);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Retire old input before reading the replacement daemon's registration.
|
|
82
|
+
listener(null);
|
|
83
|
+
void refreshAfterDaemonReplacement(generation).then(
|
|
84
|
+
(scope) => {
|
|
85
|
+
if (!stopped && token === revision && handle.read()?.instanceId === generation)
|
|
86
|
+
listener(scope.generation);
|
|
87
|
+
},
|
|
88
|
+
() => {
|
|
89
|
+
if (!stopped && token === revision) listener(null);
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
return () => {
|
|
94
|
+
stopped = true;
|
|
95
|
+
revision++;
|
|
96
|
+
stop();
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
: handle.observe,
|
|
15
100
|
resolveConnection: async (sessionName: string) => {
|
|
101
|
+
if (selectedServer) {
|
|
102
|
+
const currentRoot = handle.read()?.instanceId;
|
|
103
|
+
if (!currentRoot) return null;
|
|
104
|
+
await refreshAfterDaemonReplacement(currentRoot);
|
|
105
|
+
}
|
|
16
106
|
const connection = await prepareOpenTuiApplicationShellConnection(sessionName, {
|
|
17
107
|
...(onDiagnostic ? { onDiagnostic } : {}),
|
|
108
|
+
...(selectedServer ? { server: selectedServer, expectedLiveSessionId } : {}),
|
|
18
109
|
readCanonicalDaemonInfo: handle.read,
|
|
110
|
+
readDaemonEndpoint: handle.endpoint,
|
|
19
111
|
isCanonicalDaemonAlive: handle.isAlive,
|
|
20
112
|
ensureSessionWorkspace: (name) =>
|
|
21
113
|
ensureOpenTuiSessionWorkspaceResult(name, {
|
|
@@ -123,6 +123,8 @@ export interface ApplicationShellViewProps {
|
|
|
123
123
|
readonly onDismissNotification?: () => void;
|
|
124
124
|
readonly paletteCloseArmed?: Accessor<boolean>;
|
|
125
125
|
readonly onSelectPane: TerminalWorkspaceProps["onSelectPane"];
|
|
126
|
+
readonly onSelectWindowLink?: TerminalWorkspaceProps["onSelectWindowLink"];
|
|
127
|
+
readonly onUnlinkWindowLink?: TerminalWorkspaceProps["onUnlinkWindowLink"];
|
|
126
128
|
readonly onResizePreview: TerminalWorkspaceProps["onResizePreview"];
|
|
127
129
|
readonly onResizePane: TerminalWorkspaceProps["onResizePane"];
|
|
128
130
|
readonly onCancelResize?: TerminalWorkspaceProps["onCancelResize"];
|
|
@@ -509,6 +511,8 @@ export function ApplicationShellView(props: ApplicationShellViewProps): JSX.Elem
|
|
|
509
511
|
agentIndicators={agentIndicators}
|
|
510
512
|
paneInteractions={props.paneInteractions}
|
|
511
513
|
onSelectPane={props.onSelectPane}
|
|
514
|
+
onSelectWindowLink={props.onSelectWindowLink}
|
|
515
|
+
onUnlinkWindowLink={props.onUnlinkWindowLink}
|
|
512
516
|
onCreateWindow={props.onCreateWindow}
|
|
513
517
|
onPaneContextAction={(paneId, action, currentName) => {
|
|
514
518
|
if (action === "rename-pane")
|