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
|
@@ -432,6 +432,9 @@ export function writeCanonicalDaemonInfo(info, claim) {
|
|
|
432
432
|
instanceId: info.instanceId,
|
|
433
433
|
startedAt: info.startedAt,
|
|
434
434
|
...(info.environmentId !== undefined ? { environmentId: info.environmentId } : {}),
|
|
435
|
+
...(info.tmuxServerProofVersion !== undefined
|
|
436
|
+
? { tmuxServerProofVersion: info.tmuxServerProofVersion }
|
|
437
|
+
: {}),
|
|
435
438
|
bindHostname: info.bindHostname,
|
|
436
439
|
authToken: info.authToken,
|
|
437
440
|
...(info.provenance !== undefined ? { provenance: info.provenance } : {}),
|
|
@@ -795,11 +798,11 @@ export async function probeCanonicalDaemonHealth(info, parentSignal) {
|
|
|
795
798
|
}
|
|
796
799
|
}
|
|
797
800
|
/** Credential-free endpoint binding probe; callers compare instanceId to daemon.json. */
|
|
798
|
-
export async function probeCanonicalDaemonIdentity(info, parentSignal) {
|
|
801
|
+
export async function probeCanonicalDaemonIdentity(info, parentSignal, includeTmuxServerProof = false) {
|
|
799
802
|
if (!(await isCanonicalDaemonAlive(info)))
|
|
800
803
|
return null;
|
|
801
804
|
try {
|
|
802
|
-
const res = await fetch(canonicalDaemonUrl("http", info.bindHostname, info.port, "/identity"), {
|
|
805
|
+
const res = await fetch(canonicalDaemonUrl("http", info.bindHostname, info.port, includeTmuxServerProof ? "/identity?tmuxServerProof=1" : "/identity"), {
|
|
803
806
|
signal: parentSignal ?? timeoutSignal(750),
|
|
804
807
|
});
|
|
805
808
|
if (!res.ok)
|
|
@@ -6,7 +6,15 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
-
import {
|
|
9
|
+
import { createNativeTmuxSessionCreator } from "./tmux-server-session-create.js";
|
|
10
|
+
import { createTmuxSessionMutationFence } from "./tmux-session-mutation-fence.js";
|
|
11
|
+
import { createNativeTmuxSessionOpener } from "./tmux-server-session-open.js";
|
|
12
|
+
import { createServerGenerationFencedTmuxRunner, createServerGenerationFencedTmuxAsyncRunner, } from "./tmux-server-generation-runner.js";
|
|
13
|
+
import { createNativeTmuxServerCatalog } from "./tmux-server-owner.js";
|
|
14
|
+
import { createEmbeddedTmuxServerOwners } from "./embedded-tmux-server-owners.js";
|
|
15
|
+
import { captureTmuxServerProofAsync, captureTmuxServerProof, captureUnboundTmuxSelectorProof, } from "./tmux-server-proof.js";
|
|
16
|
+
import { assertCanonicalDaemonServerIntent } from "./canonical-daemon-bootstrap.js";
|
|
17
|
+
import { runtimeTmuxArgs, resolveTmuxServerIntent, resolveRuntimeNamespace, } from "./runtime-namespace.js";
|
|
10
18
|
import { createFleetPreviewCapture } from "../command-center/resources/fleet-preview-route.js";
|
|
11
19
|
import { mountTerminalNativeBackingRoute } from "../command-center/resources/terminal-native-backing-route.js";
|
|
12
20
|
import { startOwnedEmbeddedDaemon } from "./embedded-daemon-lifecycle.js";
|
|
@@ -28,7 +36,7 @@ import { createTmuxAuthorityReplacementProbe } from "./tmux-authority-replacemen
|
|
|
28
36
|
import { createNamedSocketFence } from "./tmux-named-socket-fence.js";
|
|
29
37
|
import { fleetSessionIdForName } from "../command-center/resources/fleet-catalog.js";
|
|
30
38
|
import { DAEMON_WIRE_PROTOCOL_VERSION, DaemonInstanceIdentitySchemaZ, PANE_STREAM_REDEEM_PATH, PaneStreamLoopbackWebSocketUrlSchemaZ, TERMINAL_ATTACHMENT_REDEEM_PATH, TerminalAttachmentLoopbackWebSocketUrlSchemaZ, } from "@tmux-ide/contracts";
|
|
31
|
-
import { classifySessionInspectionError, DaemonSessionMonitor,
|
|
39
|
+
import { classifySessionInspectionError, DaemonSessionMonitor, isConfirmedMissingTmuxTarget, parseDaemonMonitorPanes, readPortProcessFactsAsync, } from "./daemon-session-monitor.js";
|
|
32
40
|
import { DaemonShutdownError, DaemonStartupError } from "./errors.js";
|
|
33
41
|
import { handlePtyWebSocket, shutdownPtyBridges } from "../server/ws-route.js";
|
|
34
42
|
import { broadcastInteractionReceipt, broadcastResourceChanged, handleWsEventsConnection, setFleetFactsObserverDiagnostics, setFleetFactsTmuxRunner, shutdownWsEventObservation, } from "../command-center/ws-events.js";
|
|
@@ -101,14 +109,6 @@ function tmux(...args) {
|
|
|
101
109
|
timeout: 2_000,
|
|
102
110
|
}).trim();
|
|
103
111
|
}
|
|
104
|
-
function tmuxSilent(...args) {
|
|
105
|
-
try {
|
|
106
|
-
return tmux(...args);
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
return "";
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
112
|
function assertTmuxSession(sessionName, runTmux = (args) => tmux(...args)) {
|
|
113
113
|
try {
|
|
114
114
|
runTmux(["has-session", "-t", sessionName]);
|
|
@@ -353,7 +353,7 @@ function sameCanonicalInstance(left, right) {
|
|
|
353
353
|
left.startedAt === right.startedAt &&
|
|
354
354
|
left.bindHostname === right.bindHostname);
|
|
355
355
|
}
|
|
356
|
-
async function requestValidatedDaemonShutdown(info, deadline) {
|
|
356
|
+
async function requestValidatedDaemonShutdown(info, deadline, intent) {
|
|
357
357
|
if (info.supervisionId)
|
|
358
358
|
throw new DaemonStartupError("A supervised daemon cannot be taken over", "canonical_takeover_refused");
|
|
359
359
|
const identity = await probeCanonicalDaemonIdentity(info, deadline.signal);
|
|
@@ -366,6 +366,8 @@ async function requestValidatedDaemonShutdown(info, deadline) {
|
|
|
366
366
|
identity.startedAt !== info.startedAt) {
|
|
367
367
|
throw new DaemonStartupError("Canonical daemon identity changed before takeover", "canonical_takeover_identity_mismatch");
|
|
368
368
|
}
|
|
369
|
+
await assertCanonicalDaemonServerIntent(info, intent);
|
|
370
|
+
assertTakeoverDeadline(deadline, "Tmux server intent proof exceeded the takeover deadline");
|
|
369
371
|
const health = await probeCanonicalDaemonHealth(info, deadline.signal);
|
|
370
372
|
assertTakeoverDeadline(deadline, "Canonical daemon did not answer the takeover request before the takeover deadline");
|
|
371
373
|
if (!health ||
|
|
@@ -471,7 +473,7 @@ function closeWsGoingAway(ws) {
|
|
|
471
473
|
}
|
|
472
474
|
ws.close(1001, reason);
|
|
473
475
|
}
|
|
474
|
-
async function startHttpServer({ sessionName, requestedPort, bindHostname, dir, authToken, localBypassToken, silent, readProjectAuth, daemonIdentity, workspacePaneCreationBackend, workspaceOpenBackend, workspaceOpenHandoffBackend, fleetLifecycleBackend, workspacePromotionBackend, appWindowMutationBackend, workspaceMultiplexerBackend, workspaceRegistry, terminalInventoryRuntime, getTerminalAttachmentRuntime, peekTerminalAttachmentRuntime, paneStreamRuntime, catalogLiveSessions, catalogFleet, fleetPreviewCapture, sessionRuntimeRegistry, }) {
|
|
476
|
+
async function startHttpServer({ sessionName, requestedPort, bindHostname, dir, authToken, localBypassToken, silent, readProjectAuth, tmuxServerProof, daemonIdentity, workspacePaneCreationBackend, workspaceOpenBackend, workspaceOpenHandoffBackend, fleetLifecycleBackend, workspacePromotionBackend, appWindowMutationBackend, workspaceMultiplexerBackend, workspaceRegistry, terminalInventoryRuntime, getTerminalAttachmentRuntime, peekTerminalAttachmentRuntime, paneStreamRuntime, catalogLiveSessions, catalogFleet, fleetPreviewCapture, sessionRuntimeRegistry, serverOwners, }) {
|
|
475
477
|
const { createApp } = await import("../command-center/server.js");
|
|
476
478
|
const { getRequestListener } = await import(__rewriteRelativeImportExtension(requireFromHere.resolve("@hono/node-server"), true));
|
|
477
479
|
const { AuthService } = await import("./auth/auth-service.js");
|
|
@@ -490,6 +492,7 @@ async function startHttpServer({ sessionName, requestedPort, bindHostname, dir,
|
|
|
490
492
|
}
|
|
491
493
|
const authService = new AuthService(authConfig.secret);
|
|
492
494
|
const app = createApp({
|
|
495
|
+
tmuxServerOwners: serverOwners.owners,
|
|
493
496
|
authService,
|
|
494
497
|
authConfig,
|
|
495
498
|
remoteAccess: {
|
|
@@ -499,6 +502,7 @@ async function startHttpServer({ sessionName, requestedPort, bindHostname, dir,
|
|
|
499
502
|
ownerToken: localBypassToken ?? null,
|
|
500
503
|
},
|
|
501
504
|
daemonIdentity,
|
|
505
|
+
tmuxServerProof,
|
|
502
506
|
workspacePaneCreationBackend,
|
|
503
507
|
workspaceOpenBackend,
|
|
504
508
|
workspaceOpenHandoffBackend,
|
|
@@ -558,7 +562,8 @@ async function startHttpServer({ sessionName, requestedPort, bindHostname, dir,
|
|
|
558
562
|
});
|
|
559
563
|
const terminalAttachmentBoundary = attachTerminalAttachmentWebSocket(server, (create) => (create ? getTerminalAttachmentRuntime() : peekTerminalAttachmentRuntime())?.admission ??
|
|
560
564
|
null);
|
|
561
|
-
const paneStreamBoundary = attachPaneStreamWebSocket(server, paneStreamRuntime.coordinator);
|
|
565
|
+
const paneStreamBoundary = attachPaneStreamWebSocket(server, paneStreamRuntime.coordinator, PANE_STREAM_REDEEM_PATH, () => serverOwners.isDefaultCurrent());
|
|
566
|
+
serverOwners.attach(server);
|
|
562
567
|
try {
|
|
563
568
|
await new Promise((resolve, reject) => {
|
|
564
569
|
const onError = (err) => {
|
|
@@ -612,6 +617,7 @@ export async function startEmbeddedDaemon(opts) {
|
|
|
612
617
|
: startOwnedEmbeddedDaemon(opts, startEmbeddedDaemonGeneration);
|
|
613
618
|
}
|
|
614
619
|
async function startEmbeddedDaemonGeneration(opts) {
|
|
620
|
+
const tmuxServerIntent = resolveTmuxServerIntent();
|
|
615
621
|
const sessionName = opts.sessionName ?? EMBEDDED_SESSION_NAME;
|
|
616
622
|
const sessionless = opts.sessionName == null;
|
|
617
623
|
const appSettings = readAppSettings();
|
|
@@ -645,7 +651,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
645
651
|
if (state.status === "valid" && (await isCanonicalDaemonAlive(state.info))) {
|
|
646
652
|
const takeoverDeadline = createTakeoverDeadline(takeoverTimeoutMs());
|
|
647
653
|
try {
|
|
648
|
-
await requestValidatedDaemonShutdown(state.info, takeoverDeadline);
|
|
654
|
+
await requestValidatedDaemonShutdown(state.info, takeoverDeadline, tmuxServerIntent);
|
|
649
655
|
claim = await acquireCanonicalDaemonClaimAfterTakeover(state.info, takeoverDeadline);
|
|
650
656
|
}
|
|
651
657
|
finally {
|
|
@@ -691,7 +697,20 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
691
697
|
// caller's ambient TMUX/PATH happens to select.
|
|
692
698
|
const tmuxAuthority = resolveWorkspacePaneTmuxAuthority();
|
|
693
699
|
const catalogTmuxRunner = createPinnedWorkspaceTmuxRunner(tmuxAuthority);
|
|
694
|
-
const
|
|
700
|
+
const initialTmuxProof = captureTmuxServerProof(catalogTmuxRunner);
|
|
701
|
+
const initialNativeIdentityParts = initialTmuxProof
|
|
702
|
+
? catalogTmuxRunner(["display-message", "-p", "#{pid}\t#{start_time}"]).split("\t")
|
|
703
|
+
: null;
|
|
704
|
+
const initialNativeServerIdentity = initialNativeIdentityParts
|
|
705
|
+
? { pid: initialNativeIdentityParts[0], startTime: initialNativeIdentityParts[1] }
|
|
706
|
+
: undefined;
|
|
707
|
+
const sessionMutationFence = createTmuxSessionMutationFence();
|
|
708
|
+
const nativeGenerationTmuxRunner = sessionMutationFence.wrap(initialNativeServerIdentity
|
|
709
|
+
? createServerGenerationFencedTmuxRunner(tmuxAuthority, initialNativeServerIdentity)
|
|
710
|
+
: catalogTmuxRunner);
|
|
711
|
+
const fleetFactsTmuxRunner = initialNativeServerIdentity
|
|
712
|
+
? createServerGenerationFencedTmuxAsyncRunner(tmuxAuthority, initialNativeServerIdentity)
|
|
713
|
+
: createPinnedWorkspaceTmuxAsyncRunner(tmuxAuthority);
|
|
695
714
|
const tmuxAuthorityReplaced = createTmuxAuthorityReplacementProbe(tmuxAuthority, catalogTmuxRunner);
|
|
696
715
|
const registryTmuxRunner = createPinnedWorkspaceTmuxRunner(tmuxAuthority, {
|
|
697
716
|
timeoutMs: WORKSPACE_REGISTRY_TMUX_TIMEOUT_MS,
|
|
@@ -714,8 +733,8 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
714
733
|
const workspaceRegistry = getDefaultWorkspaceRegistry();
|
|
715
734
|
await workspaceRegistry.load(() => readWorkspaceRegistrySessionInventory(registryTmuxRunner));
|
|
716
735
|
const paneSourceCredentials = new PaneSourceCredentialAuthority({
|
|
717
|
-
run: (args) =>
|
|
718
|
-
runAsync: (args, signal) =>
|
|
736
|
+
run: (args) => nativeGenerationTmuxRunner(args),
|
|
737
|
+
runAsync: (args, signal) => fleetFactsTmuxRunner(args, signal),
|
|
719
738
|
});
|
|
720
739
|
const legacySession = process.env.TMUX_IDE_SESSION;
|
|
721
740
|
if (legacySession && !workspaceRegistry.has(legacySession)) {
|
|
@@ -754,16 +773,19 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
754
773
|
daemonInstanceId: instanceId,
|
|
755
774
|
registry: workspaceRegistry,
|
|
756
775
|
tmuxAuthority,
|
|
776
|
+
io: { runTmux: nativeGenerationTmuxRunner },
|
|
757
777
|
});
|
|
758
778
|
const workspaceOpen = new WorkspaceOpenAuthority({
|
|
759
779
|
daemonInstanceId: instanceId,
|
|
760
780
|
registry: workspaceRegistry,
|
|
761
781
|
tmuxAuthority,
|
|
782
|
+
io: { runTmux: nativeGenerationTmuxRunner },
|
|
762
783
|
});
|
|
763
784
|
const workspacePromotion = new WorkspacePromotionAuthority({
|
|
764
785
|
daemonInstanceId: instanceId,
|
|
765
786
|
registry: workspaceRegistry,
|
|
766
787
|
tmuxAuthority,
|
|
788
|
+
io: { runTmux: fleetFactsTmuxRunner },
|
|
767
789
|
});
|
|
768
790
|
if (opts.restoreTmuxWorkspaces) {
|
|
769
791
|
for (const workspace of workspaceRegistry.list()) {
|
|
@@ -779,7 +801,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
779
801
|
productVersion,
|
|
780
802
|
startedAt,
|
|
781
803
|
registry: workspaceRegistry,
|
|
782
|
-
runTmux:
|
|
804
|
+
runTmux: nativeGenerationTmuxRunner,
|
|
783
805
|
readFleet: () => readAdoptedFleet(workspaceRegistry, catalogTmuxRunner),
|
|
784
806
|
});
|
|
785
807
|
const appWindowMutation = new AppWindowMutationAuthority({
|
|
@@ -790,13 +812,22 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
790
812
|
daemonInstanceId: instanceId,
|
|
791
813
|
registry: workspaceRegistry,
|
|
792
814
|
tmuxAuthority,
|
|
815
|
+
...(initialTmuxProof
|
|
816
|
+
? {
|
|
817
|
+
io: {
|
|
818
|
+
runTmux: nativeGenerationTmuxRunner,
|
|
819
|
+
},
|
|
820
|
+
}
|
|
821
|
+
: {}),
|
|
793
822
|
});
|
|
794
823
|
let sessionRuntimeRegistry = null;
|
|
795
824
|
let workspaceOpenHandoff = null;
|
|
796
825
|
let terminalInventoryRuntime = null;
|
|
826
|
+
let sessionMonitor = null;
|
|
797
827
|
const externalInteractionObserver = new TmuxExternalInteractionObserver({
|
|
798
828
|
daemonInstanceId: instanceId,
|
|
799
829
|
internalReadOwnerToken: localBypassToken,
|
|
830
|
+
io: { runTmux: fleetFactsTmuxRunner },
|
|
800
831
|
registry: workspaceRegistry,
|
|
801
832
|
tmuxAuthority,
|
|
802
833
|
// A gap cannot reconstruct historical interactions. Refresh inventory
|
|
@@ -838,6 +869,25 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
838
869
|
});
|
|
839
870
|
let terminalAttachmentRuntime = null;
|
|
840
871
|
let paneStreamRuntime = null;
|
|
872
|
+
let serverOwners = null;
|
|
873
|
+
const defaultSessionCreator = createNativeTmuxSessionCreator({
|
|
874
|
+
generation: instanceId,
|
|
875
|
+
registry: workspaceRegistry,
|
|
876
|
+
run: nativeGenerationTmuxRunner,
|
|
877
|
+
assertOpen: () => {
|
|
878
|
+
if (serverOwners?.defaultRetired)
|
|
879
|
+
throw new Error("Default tmux owner is retired");
|
|
880
|
+
},
|
|
881
|
+
});
|
|
882
|
+
const defaultSessionOpener = createNativeTmuxSessionOpener({
|
|
883
|
+
generation: instanceId,
|
|
884
|
+
registry: workspaceRegistry,
|
|
885
|
+
run: fleetFactsTmuxRunner,
|
|
886
|
+
assertOpen: () => {
|
|
887
|
+
if (serverOwners?.defaultRetired)
|
|
888
|
+
throw new Error("Default tmux owner is retired");
|
|
889
|
+
},
|
|
890
|
+
});
|
|
841
891
|
let runtimeTraceStream = null;
|
|
842
892
|
const closeRuntimeTraceStream = async () => {
|
|
843
893
|
externalInteractionObserver.setDiagnostics(null);
|
|
@@ -856,6 +906,15 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
856
906
|
workspaceMultiplexer.readPane(operationId, intent);
|
|
857
907
|
return;
|
|
858
908
|
}
|
|
909
|
+
if (intent.verb === "workspace.window.link.select" ||
|
|
910
|
+
intent.verb === "workspace.window.link.unlink" ||
|
|
911
|
+
intent.verb === "workspace.pane.select") {
|
|
912
|
+
return workspaceMultiplexer.mutateWindowLink({ operationId, expectedDaemonInstanceId: instanceId, intent }, (session, action) => {
|
|
913
|
+
if (!sessionRuntimeRegistry)
|
|
914
|
+
throw new Error("Session runtime unavailable");
|
|
915
|
+
return sessionRuntimeRegistry.executeWindowLinkAction(session, action);
|
|
916
|
+
});
|
|
917
|
+
}
|
|
859
918
|
return workspaceMultiplexer.mutate({ operationId, expectedDaemonInstanceId: instanceId, intent }, timing);
|
|
860
919
|
};
|
|
861
920
|
const runtimeTracePath = process.env.TMUX_IDE_SESSION_RUNTIME_TRACE_LOG;
|
|
@@ -918,8 +977,9 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
918
977
|
publishResourceChange: (change) => broadcastResourceChanged(change, instanceId),
|
|
919
978
|
},
|
|
920
979
|
mirror: {
|
|
980
|
+
nativeServerIdentity: initialNativeServerIdentity,
|
|
921
981
|
executable: tmuxAuthority.executablePath,
|
|
922
|
-
resolveSocketPath: () =>
|
|
982
|
+
resolveSocketPath: () => nativeGenerationTmuxRunner(["display-message", "-p", "#{socket_path}"]),
|
|
923
983
|
internalReadHookEmission: (runtimePaneId, marker) => externalInteractionObserver.internalReadHookEmission(runtimePaneId, marker),
|
|
924
984
|
...(selector.kind === "path" ? { socketPath: selector.path } : {}),
|
|
925
985
|
...(selector.kind === "name" && selector.name !== "default"
|
|
@@ -982,6 +1042,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
982
1042
|
sessionRuntimeRegistry,
|
|
983
1043
|
tmuxAuthority: {
|
|
984
1044
|
executablePath: tmuxAuthority.executablePath,
|
|
1045
|
+
nativeServerIdentity: initialNativeServerIdentity,
|
|
985
1046
|
socketSelector: tmuxAuthority.socketSelector,
|
|
986
1047
|
trustedCwd: dir,
|
|
987
1048
|
...(tmuxAuthority.socketSelector.kind === "name"
|
|
@@ -1026,8 +1087,81 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1026
1087
|
resolvePaneSourceCredential: (credential, resolvedSession, claimedSource) => paneSourceCredentials.resolve(credential, resolvedSession, claimedSource),
|
|
1027
1088
|
});
|
|
1028
1089
|
await externalInteractionObserver.start();
|
|
1090
|
+
serverOwners = await createEmbeddedTmuxServerOwners({
|
|
1091
|
+
defaultAuthority: tmuxAuthority,
|
|
1092
|
+
defaultGeneration: instanceId,
|
|
1093
|
+
expectedDefaultProofDigest: initialTmuxProof?.digest ?? null,
|
|
1094
|
+
stateDirectory: resolveRuntimeNamespace().runtimeDir,
|
|
1095
|
+
webSocketBaseUrl: canonicalDaemonUrl("ws", bindHostname, port),
|
|
1096
|
+
defaultOwner: {
|
|
1097
|
+
catalog: createNativeTmuxServerCatalog(workspaceRegistry, fleetFactsTmuxRunner),
|
|
1098
|
+
openSession: async (liveSessionId) => {
|
|
1099
|
+
await createNativeTmuxServerCatalog(workspaceRegistry, fleetFactsTmuxRunner)();
|
|
1100
|
+
const result = await defaultSessionOpener.openSession(liveSessionId);
|
|
1101
|
+
terminalInventoryRuntime.invalidate();
|
|
1102
|
+
return result;
|
|
1103
|
+
},
|
|
1104
|
+
workspaceRegistry,
|
|
1105
|
+
multiplexerBackend: orderedMultiplexerBackend,
|
|
1106
|
+
createSession: defaultSessionCreator.createSession,
|
|
1107
|
+
createSessionPane: async (liveSessionId, request) => {
|
|
1108
|
+
const selectedSession = workspaceRegistry.get(request.intent.workspaceName)?.sessionName;
|
|
1109
|
+
if (!selectedSession)
|
|
1110
|
+
throw new Error("Selected workspace is unavailable");
|
|
1111
|
+
const result = await sessionMutationFence.execute({
|
|
1112
|
+
liveSessionId,
|
|
1113
|
+
sessionName: selectedSession,
|
|
1114
|
+
run: fleetFactsTmuxRunner,
|
|
1115
|
+
mutate: () => workspacePaneCreation.create(request),
|
|
1116
|
+
});
|
|
1117
|
+
terminalInventoryRuntime.invalidate();
|
|
1118
|
+
return result;
|
|
1119
|
+
},
|
|
1120
|
+
mutateSession: async (liveSessionId, request, authenticatedHostClientId) => {
|
|
1121
|
+
const selectedSession = workspaceRegistry.get(request.intent.workspaceName)?.sessionName;
|
|
1122
|
+
if (!selectedSession)
|
|
1123
|
+
throw new Error("Selected workspace is unavailable");
|
|
1124
|
+
return sessionMutationFence.execute({
|
|
1125
|
+
liveSessionId,
|
|
1126
|
+
sessionName: selectedSession,
|
|
1127
|
+
run: fleetFactsTmuxRunner,
|
|
1128
|
+
mutate: () => orderedMultiplexerBackend.mutate(request, authenticatedHostClientId, undefined, true),
|
|
1129
|
+
});
|
|
1130
|
+
},
|
|
1131
|
+
sessionRuntimeRegistry,
|
|
1132
|
+
terminalInventoryRuntime,
|
|
1133
|
+
paneStreamRuntime,
|
|
1134
|
+
dispose: async () => {
|
|
1135
|
+
sessionMonitor?.stop();
|
|
1136
|
+
paneSourceCredentials.dispose();
|
|
1137
|
+
const transportResults = await Promise.allSettled([
|
|
1138
|
+
Promise.resolve().then(() => terminalAttachmentRuntime?.dispose()),
|
|
1139
|
+
Promise.resolve().then(() => paneStreamRuntime.dispose()),
|
|
1140
|
+
]);
|
|
1141
|
+
const authorityResults = await Promise.allSettled([
|
|
1142
|
+
Promise.resolve().then(() => terminalInventoryRuntime.dispose()),
|
|
1143
|
+
Promise.resolve().then(() => workspacePaneCreation.dispose()),
|
|
1144
|
+
Promise.resolve().then(() => workspaceOpen.dispose()),
|
|
1145
|
+
Promise.resolve().then(() => workspaceOpenHandoff?.dispose()),
|
|
1146
|
+
Promise.resolve().then(() => Promise.all([
|
|
1147
|
+
workspacePromotion.dispose(),
|
|
1148
|
+
defaultSessionOpener.dispose(),
|
|
1149
|
+
defaultSessionCreator.dispose(),
|
|
1150
|
+
]).then(() => { })),
|
|
1151
|
+
Promise.resolve().then(() => appWindowMutation.dispose()),
|
|
1152
|
+
Promise.resolve().then(() => workspaceMultiplexer.dispose()),
|
|
1153
|
+
Promise.resolve().then(() => externalInteractionObserver.dispose()),
|
|
1154
|
+
]);
|
|
1155
|
+
await sessionRuntimeRegistry.dispose();
|
|
1156
|
+
const failures = [...transportResults, ...authorityResults].flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
1157
|
+
if (failures.length)
|
|
1158
|
+
throw new AggregateError(failures, "Default tmux owner retirement failed");
|
|
1159
|
+
},
|
|
1160
|
+
},
|
|
1161
|
+
});
|
|
1029
1162
|
setFleetFactsTmuxRunner(fleetFactsTmuxRunner);
|
|
1030
1163
|
startedServer = await startHttpServer({
|
|
1164
|
+
serverOwners,
|
|
1031
1165
|
sessionName,
|
|
1032
1166
|
requestedPort: port,
|
|
1033
1167
|
bindHostname,
|
|
@@ -1037,6 +1171,11 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1037
1171
|
silent: opts.silent,
|
|
1038
1172
|
readProjectAuth: !sessionless,
|
|
1039
1173
|
daemonIdentity: { productVersion, instanceId, startedAt, environmentId },
|
|
1174
|
+
tmuxServerProof: async () => {
|
|
1175
|
+
const deadline = AbortSignal.timeout(500);
|
|
1176
|
+
return ((await captureTmuxServerProofAsync((args) => fleetFactsTmuxRunner(args, deadline))) ??
|
|
1177
|
+
captureUnboundTmuxSelectorProof(tmuxAuthority));
|
|
1178
|
+
},
|
|
1040
1179
|
workspacePaneCreationBackend: workspacePaneCreation,
|
|
1041
1180
|
workspaceOpenBackend: workspaceOpen,
|
|
1042
1181
|
workspaceOpenHandoffBackend: workspaceOpenHandoff,
|
|
@@ -1056,6 +1195,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1056
1195
|
});
|
|
1057
1196
|
}
|
|
1058
1197
|
catch (error) {
|
|
1198
|
+
await serverOwners?.dispose();
|
|
1059
1199
|
setFleetFactsTmuxRunner(null);
|
|
1060
1200
|
await Promise.allSettled([
|
|
1061
1201
|
Promise.resolve().then(() => terminalAttachmentRuntime?.dispose()),
|
|
@@ -1064,7 +1204,11 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1064
1204
|
workspacePaneCreation.dispose(),
|
|
1065
1205
|
workspaceOpen.dispose(),
|
|
1066
1206
|
Promise.resolve().then(() => workspaceOpenHandoff?.dispose()),
|
|
1067
|
-
|
|
1207
|
+
Promise.all([
|
|
1208
|
+
workspacePromotion.dispose(),
|
|
1209
|
+
defaultSessionOpener.dispose(),
|
|
1210
|
+
defaultSessionCreator.dispose(),
|
|
1211
|
+
]).then(() => { }),
|
|
1068
1212
|
appWindowMutation.dispose(),
|
|
1069
1213
|
workspaceMultiplexer.dispose(),
|
|
1070
1214
|
externalInteractionObserver.dispose(),
|
|
@@ -1088,6 +1232,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1088
1232
|
return [...transportResults, ...runtimeResults].flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
1089
1233
|
};
|
|
1090
1234
|
const abortStartedServer = async () => {
|
|
1235
|
+
await serverOwners?.dispose();
|
|
1091
1236
|
setFleetFactsTmuxRunner(null);
|
|
1092
1237
|
const terminalFailures = [
|
|
1093
1238
|
...(await retireTerminalAttachmentTransport(terminalAttachmentRuntime, terminalAttachmentBoundary)),
|
|
@@ -1097,7 +1242,11 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1097
1242
|
const paneDisposal = Promise.resolve().then(() => workspacePaneCreation.dispose());
|
|
1098
1243
|
const workspaceOpenDisposal = Promise.resolve().then(() => workspaceOpen.dispose());
|
|
1099
1244
|
const workspaceOpenHandoffDisposal = Promise.resolve().then(() => workspaceOpenHandoff?.dispose());
|
|
1100
|
-
const workspacePromotionDisposal = Promise.resolve().then(() =>
|
|
1245
|
+
const workspacePromotionDisposal = Promise.resolve().then(() => Promise.all([
|
|
1246
|
+
workspacePromotion.dispose(),
|
|
1247
|
+
defaultSessionOpener.dispose(),
|
|
1248
|
+
defaultSessionCreator.dispose(),
|
|
1249
|
+
]).then(() => { }));
|
|
1101
1250
|
const appWindowMutationDisposal = Promise.resolve().then(() => appWindowMutation.dispose());
|
|
1102
1251
|
const workspaceMultiplexerDisposal = Promise.resolve().then(() => workspaceMultiplexer.dispose());
|
|
1103
1252
|
const externalInteractionDisposal = Promise.resolve().then(() => externalInteractionObserver.dispose());
|
|
@@ -1152,6 +1301,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1152
1301
|
environmentId,
|
|
1153
1302
|
bindHostname,
|
|
1154
1303
|
authToken: localBypassToken,
|
|
1304
|
+
tmuxServerProofVersion: 1,
|
|
1155
1305
|
provenance,
|
|
1156
1306
|
}, claim);
|
|
1157
1307
|
const published = inspectCanonicalDaemonInfo();
|
|
@@ -1199,14 +1349,14 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1199
1349
|
stop.stop();
|
|
1200
1350
|
},
|
|
1201
1351
|
});
|
|
1202
|
-
|
|
1352
|
+
sessionMonitor = sessionless
|
|
1203
1353
|
? null
|
|
1204
1354
|
: new DaemonSessionMonitor({
|
|
1205
1355
|
sessionName,
|
|
1206
1356
|
backend: {
|
|
1207
1357
|
inspectSession: async (candidate, signal) => {
|
|
1208
1358
|
try {
|
|
1209
|
-
await
|
|
1359
|
+
await fleetFactsTmuxRunner(["has-session", "-t", candidate], signal);
|
|
1210
1360
|
return "yes";
|
|
1211
1361
|
}
|
|
1212
1362
|
catch (error) {
|
|
@@ -1229,7 +1379,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1229
1379
|
},
|
|
1230
1380
|
hasClients: async (signal) => {
|
|
1231
1381
|
try {
|
|
1232
|
-
return (await
|
|
1382
|
+
return (await fleetFactsTmuxRunner(["list-clients"], signal)).length > 0;
|
|
1233
1383
|
}
|
|
1234
1384
|
catch {
|
|
1235
1385
|
return null;
|
|
@@ -1237,7 +1387,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1237
1387
|
},
|
|
1238
1388
|
listPanes: async (candidate, signal) => {
|
|
1239
1389
|
try {
|
|
1240
|
-
const raw = await
|
|
1390
|
+
const raw = await fleetFactsTmuxRunner([
|
|
1241
1391
|
"list-panes",
|
|
1242
1392
|
"-t",
|
|
1243
1393
|
candidate,
|
|
@@ -1260,7 +1410,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1260
1410
|
},
|
|
1261
1411
|
setPaneOption: async (paneId, option, value, signal) => {
|
|
1262
1412
|
try {
|
|
1263
|
-
await
|
|
1413
|
+
await fleetFactsTmuxRunner(["set-option", "-pt", paneId, option, value], signal);
|
|
1264
1414
|
}
|
|
1265
1415
|
catch (error) {
|
|
1266
1416
|
if (!isConfirmedMissingTmuxTarget(error))
|
|
@@ -1269,7 +1419,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1269
1419
|
},
|
|
1270
1420
|
setPaneTitle: async (paneId, title, signal) => {
|
|
1271
1421
|
try {
|
|
1272
|
-
await
|
|
1422
|
+
await fleetFactsTmuxRunner(["select-pane", "-t", paneId, "-T", title], signal);
|
|
1273
1423
|
}
|
|
1274
1424
|
catch (error) {
|
|
1275
1425
|
if (!isConfirmedMissingTmuxTarget(error))
|
|
@@ -1278,7 +1428,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1278
1428
|
},
|
|
1279
1429
|
refreshClients: async (signal) => {
|
|
1280
1430
|
try {
|
|
1281
|
-
await
|
|
1431
|
+
await fleetFactsTmuxRunner(["refresh-client", "-S"], signal);
|
|
1282
1432
|
}
|
|
1283
1433
|
catch (error) {
|
|
1284
1434
|
if (!isConfirmedMissingTmuxTarget(error))
|
|
@@ -1292,7 +1442,20 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1292
1442
|
const apiBaseUrl = canonicalDaemonUrl("http", bindHostname, port);
|
|
1293
1443
|
const wsUrl = canonicalDaemonUrl("ws", bindHostname, port, "/ws/events");
|
|
1294
1444
|
const handle = {
|
|
1295
|
-
tmuxAuthorityReplaced
|
|
1445
|
+
tmuxAuthorityReplaced: async () => {
|
|
1446
|
+
if (serverOwners?.defaultRetired)
|
|
1447
|
+
return false;
|
|
1448
|
+
const replaced = await tmuxAuthorityReplaced();
|
|
1449
|
+
// A native server replacement cannot restart unrelated server owners.
|
|
1450
|
+
// Legacy default-only callers retain the established restart adapter.
|
|
1451
|
+
if (replaced &&
|
|
1452
|
+
serverOwners &&
|
|
1453
|
+
(serverOwners.owners.list().length > 1 || serverOwners.defaultRetired)) {
|
|
1454
|
+
await serverOwners.owners.refresh();
|
|
1455
|
+
return false;
|
|
1456
|
+
}
|
|
1457
|
+
return replaced;
|
|
1458
|
+
},
|
|
1296
1459
|
instanceId,
|
|
1297
1460
|
pid: process.pid,
|
|
1298
1461
|
port,
|
|
@@ -1320,6 +1483,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1320
1483
|
await capture(() => setActivationBackend(null));
|
|
1321
1484
|
await capture(() => sessionMonitor?.stop());
|
|
1322
1485
|
paneSourceCredentials.dispose();
|
|
1486
|
+
await capture(() => serverOwners?.dispose());
|
|
1323
1487
|
// Retire direct-ticket admission, live PTYs, and the direct upgrade
|
|
1324
1488
|
// listener before touching the legacy WS or HTTP surfaces.
|
|
1325
1489
|
failures.push(...(await retireTerminalAttachmentTransport(terminalAttachmentRuntime, terminalAttachmentBoundary)));
|
|
@@ -1328,7 +1492,11 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1328
1492
|
await capture(() => workspacePaneCreation.dispose());
|
|
1329
1493
|
await capture(() => workspaceOpen.dispose());
|
|
1330
1494
|
await capture(() => workspaceOpenHandoff?.dispose());
|
|
1331
|
-
await capture(() =>
|
|
1495
|
+
await capture(() => Promise.all([
|
|
1496
|
+
workspacePromotion.dispose(),
|
|
1497
|
+
defaultSessionOpener.dispose(),
|
|
1498
|
+
defaultSessionCreator.dispose(),
|
|
1499
|
+
]).then(() => { }));
|
|
1332
1500
|
await capture(() => appWindowMutation.dispose());
|
|
1333
1501
|
await capture(() => workspaceMultiplexer.dispose());
|
|
1334
1502
|
await capture(() => externalInteractionObserver.dispose());
|