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,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
captureTmuxServerProof,
|
|
3
|
+
captureUnboundTmuxSelectorProof,
|
|
4
|
+
type TmuxServerProof,
|
|
5
|
+
} from "./tmux-server-proof.ts";
|
|
6
|
+
import {
|
|
7
|
+
createPinnedWorkspaceTmuxRunner,
|
|
8
|
+
resolveWorkspacePaneTmuxAuthority,
|
|
9
|
+
} from "./workspace-pane-creation.ts";
|
|
10
|
+
import { resolveRuntimeNamespace, resolveTmuxServerIntent } from "./runtime-namespace.ts";
|
|
2
11
|
import { compareProductVersions } from "./semver.ts";
|
|
3
12
|
import { spawn, type ChildProcess } from "node:child_process";
|
|
4
13
|
import { resolve } from "node:path";
|
|
@@ -25,12 +34,15 @@ import {
|
|
|
25
34
|
} from "./canonical-daemon.ts";
|
|
26
35
|
|
|
27
36
|
export type CanonicalDaemonBootstrapFailure =
|
|
37
|
+
| "tmux-server-mismatch"
|
|
38
|
+
| "tmux-server-unproven"
|
|
28
39
|
| "canonical-record-invalid"
|
|
29
40
|
| "identity-mismatch"
|
|
30
41
|
| "protocol-mismatch"
|
|
31
42
|
| "product-version-mismatch";
|
|
32
43
|
|
|
33
44
|
export interface CanonicalDaemonBootstrapOptions {
|
|
45
|
+
readonly tmuxServerIntent?: ReturnType<typeof resolveTmuxServerIntent>;
|
|
34
46
|
readonly supervisionId?: string;
|
|
35
47
|
/** The shipped CLI entry which owns `runHeadlessDaemon`. */
|
|
36
48
|
readonly entryPath: string;
|
|
@@ -43,6 +55,9 @@ export interface CanonicalDaemonBootstrapOptions {
|
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
export interface CanonicalDaemonBootstrapDependencies {
|
|
58
|
+
readonly serverProof: (
|
|
59
|
+
intent: NonNullable<ReturnType<typeof resolveTmuxServerIntent>>,
|
|
60
|
+
) => TmuxServerProof | null;
|
|
46
61
|
readonly inspect: () => CanonicalDaemonInfoState;
|
|
47
62
|
readonly ownerProvenDead: (
|
|
48
63
|
state: Exclude<CanonicalDaemonInfoState, { status: "missing" }>,
|
|
@@ -135,6 +150,17 @@ function sameCanonicalInstance(left: CanonicalDaemonInfo, right: CanonicalDaemon
|
|
|
135
150
|
const defaultDependencies: CanonicalDaemonBootstrapDependencies = {
|
|
136
151
|
// This adapter owns startup, so legacy permission preparation is explicit
|
|
137
152
|
// here. Injected inspectors remain isolated from real filesystem mutation.
|
|
153
|
+
serverProof: (intent) => {
|
|
154
|
+
try {
|
|
155
|
+
const authority = { ...resolveWorkspacePaneTmuxAuthority(), socketSelector: intent.selector };
|
|
156
|
+
return (
|
|
157
|
+
captureTmuxServerProof(createPinnedWorkspaceTmuxRunner(authority, { timeoutMs: 1000 })) ??
|
|
158
|
+
captureUnboundTmuxSelectorProof(authority)
|
|
159
|
+
);
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
},
|
|
138
164
|
inspect: prepareCanonicalDaemonInfoForBootstrap,
|
|
139
165
|
ownerProvenDead: isCanonicalDaemonRecordOwnerProvenDead,
|
|
140
166
|
alive: isCanonicalDaemonAlive,
|
|
@@ -164,6 +190,7 @@ async function replaceOlderCanonicalDaemon(
|
|
|
164
190
|
info: CanonicalDaemonInfo,
|
|
165
191
|
timeoutMs: number,
|
|
166
192
|
expectedProductVersion?: string,
|
|
193
|
+
intent: ReturnType<typeof resolveTmuxServerIntent> = null,
|
|
167
194
|
): Promise<void> {
|
|
168
195
|
if (!needsReplacement(info, expectedProductVersion)) {
|
|
169
196
|
throw new DaemonBootstrapError(
|
|
@@ -172,7 +199,10 @@ async function replaceOlderCanonicalDaemon(
|
|
|
172
199
|
{ reason: "protocol-mismatch" },
|
|
173
200
|
);
|
|
174
201
|
}
|
|
175
|
-
const [identity, health] = await Promise.all([
|
|
202
|
+
const [identity, health] = await Promise.all([
|
|
203
|
+
deps.identity(info, undefined, Boolean(intent)),
|
|
204
|
+
deps.health(info),
|
|
205
|
+
]);
|
|
176
206
|
if (
|
|
177
207
|
!info.authToken ||
|
|
178
208
|
!identity ||
|
|
@@ -191,6 +221,7 @@ async function replaceOlderCanonicalDaemon(
|
|
|
191
221
|
{ reason: "identity-mismatch" },
|
|
192
222
|
);
|
|
193
223
|
}
|
|
224
|
+
assertServerIntent(deps, info, identity, intent);
|
|
194
225
|
const latest = deps.inspect();
|
|
195
226
|
if (
|
|
196
227
|
latest.status !== "valid" ||
|
|
@@ -221,9 +252,35 @@ async function replaceOlderCanonicalDaemon(
|
|
|
221
252
|
);
|
|
222
253
|
}
|
|
223
254
|
|
|
255
|
+
function assertServerIntent(
|
|
256
|
+
deps: CanonicalDaemonBootstrapDependencies,
|
|
257
|
+
info: CanonicalDaemonInfo,
|
|
258
|
+
identity: NonNullable<Awaited<ReturnType<typeof probeCanonicalDaemonIdentity>>>,
|
|
259
|
+
intent: ReturnType<typeof resolveTmuxServerIntent>,
|
|
260
|
+
): void {
|
|
261
|
+
if (!intent) return;
|
|
262
|
+
const proof = deps.serverProof(intent);
|
|
263
|
+
if (info.tmuxServerProofVersion !== 1 || !identity.tmuxServerProof || !proof)
|
|
264
|
+
throw new DaemonBootstrapError(
|
|
265
|
+
"incompatible",
|
|
266
|
+
"Cannot prove the requested tmux server for this daemon. Its server identity is unavailable or unsupported; the existing daemon was left running.",
|
|
267
|
+
{ reason: "tmux-server-unproven" },
|
|
268
|
+
);
|
|
269
|
+
if (
|
|
270
|
+
identity.tmuxServerProof.kind !== proof.kind ||
|
|
271
|
+
identity.tmuxServerProof.digest !== proof.digest
|
|
272
|
+
)
|
|
273
|
+
throw new DaemonBootstrapError(
|
|
274
|
+
"incompatible",
|
|
275
|
+
"The existing daemon manages a different tmux server. It was left running; select its server or use a separate daemon namespace.",
|
|
276
|
+
{ reason: "tmux-server-mismatch" },
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
224
280
|
async function probeCanonical(
|
|
225
281
|
deps: CanonicalDaemonBootstrapDependencies,
|
|
226
282
|
expectedProductVersion?: string,
|
|
283
|
+
intent: ReturnType<typeof resolveTmuxServerIntent> = null,
|
|
227
284
|
): Promise<DaemonBootstrapProbe<CanonicalDaemonInfo, CanonicalDaemonBootstrapFailure>> {
|
|
228
285
|
const state = deps.inspect();
|
|
229
286
|
if (state.status === "missing") return { status: "absent-or-stale" };
|
|
@@ -244,7 +301,7 @@ async function probeCanonical(
|
|
|
244
301
|
return { status: state.info.supervisionId ? "owner-pending" : "absent-or-stale" };
|
|
245
302
|
|
|
246
303
|
const [identity, health] = await Promise.all([
|
|
247
|
-
deps.identity(state.info),
|
|
304
|
+
deps.identity(state.info, undefined, Boolean(intent)),
|
|
248
305
|
deps.health(state.info),
|
|
249
306
|
]);
|
|
250
307
|
// A living elected generation may publish before its accept loop. Preserve
|
|
@@ -258,6 +315,7 @@ async function probeCanonical(
|
|
|
258
315
|
) {
|
|
259
316
|
return { status: "incompatible", reason: "identity-mismatch" };
|
|
260
317
|
}
|
|
318
|
+
assertServerIntent(deps, state.info, identity, intent);
|
|
261
319
|
if (
|
|
262
320
|
state.info.protocolVersion !== DAEMON_WIRE_PROTOCOL_VERSION ||
|
|
263
321
|
identity.protocolVersion !== state.info.protocolVersion ||
|
|
@@ -325,12 +383,24 @@ export function createCanonicalDaemonBootstrapCoordinator(
|
|
|
325
383
|
options: CanonicalDaemonBootstrapOptions,
|
|
326
384
|
dependencies: Partial<CanonicalDaemonBootstrapDependencies> = {},
|
|
327
385
|
): DaemonBootstrapCoordinator<CanonicalDaemonInfo, never, CanonicalDaemonBootstrapFailure> {
|
|
386
|
+
options = {
|
|
387
|
+
...options,
|
|
388
|
+
tmuxServerIntent:
|
|
389
|
+
options.tmuxServerIntent === undefined ? resolveTmuxServerIntent() : options.tmuxServerIntent,
|
|
390
|
+
};
|
|
328
391
|
const deps = supervisedAdmission(
|
|
329
392
|
{ ...defaultDependencies, ...dependencies },
|
|
330
393
|
options.supervisionId,
|
|
331
394
|
);
|
|
332
395
|
return new DaemonBootstrapCoordinator({
|
|
333
|
-
probe: () =>
|
|
396
|
+
probe: () =>
|
|
397
|
+
probeCanonical(
|
|
398
|
+
deps,
|
|
399
|
+
options.expectedProductVersion,
|
|
400
|
+
options.tmuxServerIntent === undefined
|
|
401
|
+
? resolveTmuxServerIntent()
|
|
402
|
+
: options.tmuxServerIntent,
|
|
403
|
+
),
|
|
334
404
|
spawn: () => deps.spawnOwner(resolve(options.entryPath), resolve(options.cwd ?? process.cwd())),
|
|
335
405
|
timeoutMs: options.timeoutMs,
|
|
336
406
|
onPhaseChanged: options.onPhaseChanged,
|
|
@@ -343,6 +413,11 @@ export function ensureCanonicalDaemon(
|
|
|
343
413
|
options: CanonicalDaemonBootstrapOptions,
|
|
344
414
|
dependencies: Partial<CanonicalDaemonBootstrapDependencies> = {},
|
|
345
415
|
): Promise<DaemonBootstrapResult<CanonicalDaemonInfo, never>> {
|
|
416
|
+
options = {
|
|
417
|
+
...options,
|
|
418
|
+
tmuxServerIntent:
|
|
419
|
+
options.tmuxServerIntent === undefined ? resolveTmuxServerIntent() : options.tmuxServerIntent,
|
|
420
|
+
};
|
|
346
421
|
const deps = supervisedAdmission(
|
|
347
422
|
{ ...defaultDependencies, ...dependencies },
|
|
348
423
|
options.supervisionId,
|
|
@@ -378,6 +453,9 @@ export function ensureCanonicalDaemon(
|
|
|
378
453
|
replacing,
|
|
379
454
|
options.timeoutMs ?? 15_000,
|
|
380
455
|
options.expectedProductVersion,
|
|
456
|
+
options.tmuxServerIntent === undefined
|
|
457
|
+
? resolveTmuxServerIntent()
|
|
458
|
+
: options.tmuxServerIntent,
|
|
381
459
|
);
|
|
382
460
|
} catch (replacementError) {
|
|
383
461
|
// A duplicate upgrader can retire the exact owner while this caller is
|
|
@@ -402,6 +480,11 @@ export async function retireOutdatedCanonicalDaemon(
|
|
|
402
480
|
options: CanonicalDaemonBootstrapOptions,
|
|
403
481
|
dependencies: Partial<CanonicalDaemonBootstrapDependencies> = {},
|
|
404
482
|
): Promise<boolean> {
|
|
483
|
+
options = {
|
|
484
|
+
...options,
|
|
485
|
+
tmuxServerIntent:
|
|
486
|
+
options.tmuxServerIntent === undefined ? resolveTmuxServerIntent() : options.tmuxServerIntent,
|
|
487
|
+
};
|
|
405
488
|
const deps = supervisedAdmission(
|
|
406
489
|
{ ...defaultDependencies, ...dependencies },
|
|
407
490
|
options.supervisionId,
|
|
@@ -436,6 +519,7 @@ export async function retireOutdatedCanonicalDaemon(
|
|
|
436
519
|
state.info,
|
|
437
520
|
options.timeoutMs ?? 15_000,
|
|
438
521
|
options.expectedProductVersion,
|
|
522
|
+
options.tmuxServerIntent === undefined ? resolveTmuxServerIntent() : options.tmuxServerIntent,
|
|
439
523
|
);
|
|
440
524
|
return true;
|
|
441
525
|
} catch (error) {
|
|
@@ -448,3 +532,26 @@ export async function retireOutdatedCanonicalDaemon(
|
|
|
448
532
|
throw error;
|
|
449
533
|
}
|
|
450
534
|
}
|
|
535
|
+
|
|
536
|
+
/** Admission for foreground election winners and explicit takeover paths. */
|
|
537
|
+
export async function assertCanonicalDaemonServerIntent(
|
|
538
|
+
info: CanonicalDaemonInfo,
|
|
539
|
+
intent: ReturnType<typeof resolveTmuxServerIntent> = resolveTmuxServerIntent(),
|
|
540
|
+
dependencies: Partial<CanonicalDaemonBootstrapDependencies> = {},
|
|
541
|
+
): Promise<void> {
|
|
542
|
+
if (!intent) return;
|
|
543
|
+
const deps = { ...defaultDependencies, ...dependencies };
|
|
544
|
+
const identity = await deps.identity(info, undefined, true);
|
|
545
|
+
if (
|
|
546
|
+
!identity ||
|
|
547
|
+
identity.pid !== info.pid ||
|
|
548
|
+
identity.instanceId !== info.instanceId ||
|
|
549
|
+
identity.startedAt !== info.startedAt
|
|
550
|
+
)
|
|
551
|
+
throw new DaemonBootstrapError(
|
|
552
|
+
"incompatible",
|
|
553
|
+
"Canonical daemon identity could not be verified for the requested tmux server.",
|
|
554
|
+
{ reason: "identity-mismatch" },
|
|
555
|
+
);
|
|
556
|
+
assertServerIntent(deps, info, identity, intent);
|
|
557
|
+
}
|
|
@@ -644,6 +644,9 @@ export function writeCanonicalDaemonInfo(
|
|
|
644
644
|
instanceId: info.instanceId,
|
|
645
645
|
startedAt: info.startedAt,
|
|
646
646
|
...(info.environmentId !== undefined ? { environmentId: info.environmentId } : {}),
|
|
647
|
+
...(info.tmuxServerProofVersion !== undefined
|
|
648
|
+
? { tmuxServerProofVersion: info.tmuxServerProofVersion }
|
|
649
|
+
: {}),
|
|
647
650
|
bindHostname: info.bindHostname,
|
|
648
651
|
authToken: info.authToken,
|
|
649
652
|
...(info.provenance !== undefined ? { provenance: info.provenance } : {}),
|
|
@@ -1051,12 +1054,21 @@ export async function probeCanonicalDaemonHealth(
|
|
|
1051
1054
|
export async function probeCanonicalDaemonIdentity(
|
|
1052
1055
|
info: CanonicalDaemonInfo,
|
|
1053
1056
|
parentSignal?: AbortSignal,
|
|
1057
|
+
includeTmuxServerProof = false,
|
|
1054
1058
|
): Promise<DaemonIdentity | null> {
|
|
1055
1059
|
if (!(await isCanonicalDaemonAlive(info))) return null;
|
|
1056
1060
|
try {
|
|
1057
|
-
const res = await fetch(
|
|
1058
|
-
|
|
1059
|
-
|
|
1061
|
+
const res = await fetch(
|
|
1062
|
+
canonicalDaemonUrl(
|
|
1063
|
+
"http",
|
|
1064
|
+
info.bindHostname,
|
|
1065
|
+
info.port,
|
|
1066
|
+
includeTmuxServerProof ? "/identity?tmuxServerProof=1" : "/identity",
|
|
1067
|
+
),
|
|
1068
|
+
{
|
|
1069
|
+
signal: parentSignal ?? timeoutSignal(750),
|
|
1070
|
+
},
|
|
1071
|
+
);
|
|
1060
1072
|
if (!res.ok) return null;
|
|
1061
1073
|
const parsed = DaemonIdentitySchema.safeParse(await res.json());
|
|
1062
1074
|
return parsed.success ? parsed.data : null;
|