tmux-ide 2.9.6 → 2.9.8
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 +2881 -1336
- package/package.json +2 -2
- package/packages/contracts/src/index.ts +5 -0
- package/packages/contracts/src/pane-stream.ts +54 -0
- package/packages/contracts/src/terminal-graphics.ts +118 -0
- package/packages/contracts/src/terminal-history-anchor.ts +61 -0
- package/packages/contracts/src/tmux-server-diagnostics.ts +16 -0
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/kitty-placeholders.ts +208 -0
- package/packages/daemon/dist/command-center/tmux-server-diagnostics.js +24 -0
- package/packages/daemon/dist/command-center/tmux-server-history-anchor.js +48 -0
- package/packages/daemon/dist/command-center/tmux-servers.js +11 -0
- package/packages/daemon/dist/lib/canonical-daemon-bootstrap.js +23 -1
- package/packages/daemon/dist/lib/daemon-embed.js +21 -0
- package/packages/daemon/dist/lib/tmux-server-owner.js +10 -1
- package/packages/daemon/dist/lib/tmux-session-mutation-fence.js +2 -1
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Info.plist +2 -2
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/MacOS/tmux-ide-notifier +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/Assets.car +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources +2 -2
- package/packages/daemon/dist/native/tmux/darwin-arm64/lib/libevent_core-2.1.7.dylib +0 -0
- package/packages/daemon/dist/native/tmux/darwin-arm64/lib/libutf8proc.3.3.0.dylib +0 -0
- package/packages/daemon/dist/native/tmux/darwin-arm64/manifest.json +12 -4
- package/packages/daemon/dist/native/tmux/darwin-arm64/tmux +0 -0
- package/packages/daemon/dist/native/tmux/linux-arm64/manifest.json +9 -1
- package/packages/daemon/dist/native/tmux/linux-arm64/tmux +0 -0
- package/packages/daemon/dist/native/tmux/linux-x64/manifest.json +9 -1
- package/packages/daemon/dist/native/tmux/linux-x64/tmux +0 -0
- package/packages/daemon/dist/terminal/attachments/native-runtime.js +25 -12
- package/packages/daemon/dist/terminal/graphics/kitty-graphics.js +699 -0
- package/packages/daemon/dist/terminal/mirror/control-channel.js +17 -1
- package/packages/daemon/dist/terminal/mirror/mirror-service.js +7 -0
- package/packages/daemon/dist/terminal/mirror/native-grid-capture.js +8 -0
- package/packages/daemon/dist/terminal/mirror/native-grid-reader.js +6 -1
- package/packages/daemon/dist/terminal/mirror/session-channel.js +56 -4
- package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +180 -1
- package/packages/daemon/dist/terminal/protocol/session-descriptor-discovery.js +3 -2
- package/packages/daemon/dist/terminal/session-runtime/history-anchor-owner.js +171 -0
- package/packages/daemon/dist/terminal/session-runtime/registry.js +29 -0
- package/packages/daemon/dist/terminal/session-runtime/terminal-delivery-hub.js +20 -1
- package/packages/daemon/dist/terminal/session-runtime/terminal-replica-interpreter.js +85 -1
- package/packages/daemon/dist/terminal/session-runtime/terminal-replica-owner.js +30 -0
- package/packages/daemon/dist/terminal/session-runtime/transport-binding.js +53 -21
- package/packages/daemon/dist/terminal/session-runtime/xterm-terminal-interpreter-backend.js +11 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-home-agents-owner.js +7 -1
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-input-ingress.js +35 -5
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-paste.js +2 -2
- package/packages/daemon/dist/tui/mirror/runtime/terminal-input-adapter.js +2 -2
- package/packages/daemon/src/command-center/tmux-server-diagnostics.ts +38 -0
- package/packages/daemon/src/command-center/tmux-server-history-anchor.ts +69 -0
- package/packages/daemon/src/command-center/tmux-servers.ts +11 -0
- package/packages/daemon/src/lib/canonical-daemon-bootstrap.ts +20 -2
- package/packages/daemon/src/lib/daemon-embed.ts +26 -0
- package/packages/daemon/src/lib/tmux-server-owner.ts +10 -0
- package/packages/daemon/src/lib/tmux-session-mutation-fence.ts +2 -1
- package/packages/daemon/src/terminal/attachments/native-runtime.ts +28 -13
- package/packages/daemon/src/terminal/graphics/__fixtures__/full-frame-client-recorded.ctl +87 -0
- package/packages/daemon/src/terminal/graphics/__fixtures__/full-frame-client.ctl +10 -0
- package/packages/daemon/src/terminal/graphics/kitty-graphics.ts +756 -0
- package/packages/daemon/src/terminal/mirror/control-channel.ts +18 -1
- package/packages/daemon/src/terminal/mirror/mirror-service.ts +14 -0
- package/packages/daemon/src/terminal/mirror/native-grid-capture.ts +11 -0
- package/packages/daemon/src/terminal/mirror/native-grid-reader.ts +10 -1
- package/packages/daemon/src/terminal/mirror/session-channel.ts +75 -3
- package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +199 -0
- package/packages/daemon/src/terminal/protocol/session-descriptor-discovery.ts +3 -2
- package/packages/daemon/src/terminal/session-runtime/history-anchor-owner.ts +190 -0
- package/packages/daemon/src/terminal/session-runtime/registry.ts +38 -0
- package/packages/daemon/src/terminal/session-runtime/terminal-delivery-hub.ts +38 -0
- package/packages/daemon/src/terminal/session-runtime/terminal-interpreter-backend.ts +4 -0
- package/packages/daemon/src/terminal/session-runtime/terminal-replica-interpreter.ts +99 -1
- package/packages/daemon/src/terminal/session-runtime/terminal-replica-owner.ts +39 -0
- package/packages/daemon/src/terminal/session-runtime/transport-binding.ts +58 -24
- package/packages/daemon/src/terminal/session-runtime/xterm-terminal-interpreter-backend.ts +13 -0
- package/packages/daemon/src/tui/mirror/runtime/application-home-agents-owner.ts +6 -1
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-input-ingress.ts +44 -9
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-paste.ts +2 -1
- package/packages/daemon/src/tui/mirror/runtime/terminal-input-adapter.ts +5 -2
- package/packages/daemon-client/src/fleet-connection-status.ts +1 -1
- package/packages/daemon-client/src/pane-creation-refusal.ts +48 -0
- package/packages/daemon-client/src/pane-stream-client.ts +37 -0
- package/packages/daemon-client/src/tmux-server-client.ts +133 -6
- package/packages/daemon/dist/native/tmux/darwin-arm64/lib/libutf8proc.3.2.3.dylib +0 -0
- /package/packages/daemon/dist/native/tmux/darwin-arm64/licenses/{libutf8proc.3.2.3.dylib.txt → libutf8proc.3.3.0.dylib.txt} +0 -0
|
@@ -32,6 +32,13 @@ function spawnOwner(entryPath, cwd) {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
+
class ShutdownTransportError extends Error {
|
|
36
|
+
original;
|
|
37
|
+
constructor(original) {
|
|
38
|
+
super("Canonical daemon shutdown transport failed.", { cause: original });
|
|
39
|
+
this.original = original;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
35
42
|
async function shutdownOlderOwner(info) {
|
|
36
43
|
const headers = { "content-type": "application/json" };
|
|
37
44
|
if (info.authToken)
|
|
@@ -45,6 +52,8 @@ async function shutdownOlderOwner(info) {
|
|
|
45
52
|
expectedInstanceId: info.instanceId,
|
|
46
53
|
}),
|
|
47
54
|
signal: AbortSignal.timeout(2_000),
|
|
55
|
+
}).catch((error) => {
|
|
56
|
+
throw new ShutdownTransportError(error);
|
|
48
57
|
});
|
|
49
58
|
const envelope = (await response.json().catch(() => null));
|
|
50
59
|
// The authenticated handler verifies expectedInstanceId before reporting this
|
|
@@ -141,7 +150,18 @@ async function replaceOlderCanonicalDaemon(deps, info, timeoutMs, expectedProduc
|
|
|
141
150
|
"tmux-ide --headless --supervised <id> before restarting it. " +
|
|
142
151
|
"The existing daemon has been left running.", { reason: "canonical-record-invalid" });
|
|
143
152
|
}
|
|
144
|
-
|
|
153
|
+
let transportFailure;
|
|
154
|
+
try {
|
|
155
|
+
await deps.shutdownOlderOwner(info);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (!(error instanceof ShutdownTransportError))
|
|
159
|
+
throw error;
|
|
160
|
+
transportFailure = error;
|
|
161
|
+
}
|
|
162
|
+
// A competing upgrader may close the authenticated owner's listener before
|
|
163
|
+
// removing its record. Observe retirement, without repeating the mutation.
|
|
164
|
+
// A transport failure alone never authorizes starting a replacement.
|
|
145
165
|
const deadline = deps.now() + timeoutMs;
|
|
146
166
|
while (deps.now() < deadline) {
|
|
147
167
|
const state = deps.inspect();
|
|
@@ -153,6 +173,8 @@ async function replaceOlderCanonicalDaemon(deps, info, timeoutMs, expectedProduc
|
|
|
153
173
|
return;
|
|
154
174
|
await deps.sleep(25);
|
|
155
175
|
}
|
|
176
|
+
if (transportFailure)
|
|
177
|
+
throw transportFailure.original;
|
|
156
178
|
throw new DaemonBootstrapError("control-timeout", "The older canonical daemon did not retire after accepting the version upgrade.", { reason: "protocol-mismatch" });
|
|
157
179
|
}
|
|
158
180
|
async function assertServerIntent(deps, info, identity, intent) {
|
|
@@ -6,6 +6,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
+
import { TmuxServerVersionSchemaZ } from "@tmux-ide/contracts";
|
|
9
10
|
import { createNativeSplitCapabilityProbe, createNativeSplitReadiness, } from "./native-split-capability.js";
|
|
10
11
|
import { executeCanonicalSplitMutation } from "./canonical-split-mutation.js";
|
|
11
12
|
import { createGuardedNativeSplitResize } from "./guarded-native-split-resize.js";
|
|
@@ -956,6 +957,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
956
957
|
let paneStreamRuntime = null;
|
|
957
958
|
let serverOwners = null;
|
|
958
959
|
let defaultEditorContextRetired = false;
|
|
960
|
+
const defaultDiagnosticsLifetime = new AbortController();
|
|
959
961
|
const defaultSessionCreator = createNativeTmuxSessionCreator({
|
|
960
962
|
generation: instanceId,
|
|
961
963
|
registry: workspaceRegistry,
|
|
@@ -1287,6 +1289,24 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1287
1289
|
stateDirectory: resolveRuntimeNamespace().runtimeDir,
|
|
1288
1290
|
webSocketBaseUrl: canonicalDaemonUrl("ws", bindHostname, port),
|
|
1289
1291
|
defaultOwner: {
|
|
1292
|
+
readServerVersion: async (signal) => {
|
|
1293
|
+
const assertCurrent = () => {
|
|
1294
|
+
if (defaultEditorContextRetired ||
|
|
1295
|
+
serverOwners?.defaultRetired ||
|
|
1296
|
+
!initialNativeServerIdentity)
|
|
1297
|
+
throw new Error("Default tmux diagnostics owner is unavailable");
|
|
1298
|
+
};
|
|
1299
|
+
assertCurrent();
|
|
1300
|
+
const combined = AbortSignal.any([
|
|
1301
|
+
defaultDiagnosticsLifetime.signal,
|
|
1302
|
+
...(signal ? [signal] : []),
|
|
1303
|
+
]);
|
|
1304
|
+
combined.throwIfAborted();
|
|
1305
|
+
const output = await fleetFactsTmuxRunner(["display-message", "-p", "#{version}"], combined);
|
|
1306
|
+
combined.throwIfAborted();
|
|
1307
|
+
assertCurrent();
|
|
1308
|
+
return TmuxServerVersionSchemaZ.parse(output.trim());
|
|
1309
|
+
},
|
|
1290
1310
|
get interactionObservation() {
|
|
1291
1311
|
return interactionObservation;
|
|
1292
1312
|
},
|
|
@@ -1375,6 +1395,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
1375
1395
|
paneStreamRuntime,
|
|
1376
1396
|
dispose: async () => {
|
|
1377
1397
|
defaultEditorContextRetired = true;
|
|
1398
|
+
defaultDiagnosticsLifetime.abort();
|
|
1378
1399
|
sessionMonitor?.stop();
|
|
1379
1400
|
paneSourceCredentials.dispose();
|
|
1380
1401
|
const transportResults = await Promise.allSettled([
|
|
@@ -17,7 +17,7 @@ import { createNativeTmuxSessionOpener } from "./tmux-server-session-open.js";
|
|
|
17
17
|
import { observedAgentSchema } from "./tmux-server-agent-admission.js";
|
|
18
18
|
import { createPaneEditorContextResolver } from "./tmux-pane-editor-context.js";
|
|
19
19
|
import { createHash, randomUUID } from "node:crypto";
|
|
20
|
-
import { WorkspaceIdSchemaZ, WindowLinkTargetSchemaZ, } from "@tmux-ide/contracts";
|
|
20
|
+
import { TmuxServerVersionSchemaZ, WorkspaceIdSchemaZ, WindowLinkTargetSchemaZ, } from "@tmux-ide/contracts";
|
|
21
21
|
import { WindowSplitLayoutUnavailable } from "../terminal/mirror/window-split-authority.js";
|
|
22
22
|
import { mkdirSync } from "node:fs";
|
|
23
23
|
import { z } from "zod";
|
|
@@ -483,6 +483,15 @@ export async function createNativeTmuxServerOwner(options) {
|
|
|
483
483
|
throw error;
|
|
484
484
|
}
|
|
485
485
|
return {
|
|
486
|
+
readServerVersion: async (signal) => {
|
|
487
|
+
assertOpen();
|
|
488
|
+
const combined = AbortSignal.any([credentialLifetime.signal, ...(signal ? [signal] : [])]);
|
|
489
|
+
combined.throwIfAborted();
|
|
490
|
+
const output = await generationRunAsync(["display-message", "-p", "#{version}"], combined);
|
|
491
|
+
combined.throwIfAborted();
|
|
492
|
+
assertOpen();
|
|
493
|
+
return TmuxServerVersionSchemaZ.parse(output.trim());
|
|
494
|
+
},
|
|
486
495
|
serverId: options.serverId,
|
|
487
496
|
generation,
|
|
488
497
|
resolvePaneEditorContext,
|
|
@@ -23,7 +23,8 @@ export function createTmuxSessionMutationFence() {
|
|
|
23
23
|
const output = run([
|
|
24
24
|
"if-shell",
|
|
25
25
|
"-t",
|
|
26
|
-
|
|
26
|
+
// if-shell resolves a pane target: the colon selects this exact session.
|
|
27
|
+
`=${selected.name}:`,
|
|
27
28
|
"-F",
|
|
28
29
|
`#{&&:#{==:#{session_id},${selected.id}},#{==:#{session_created},${selected.created}}}`,
|
|
29
30
|
args.map((arg) => (arg === ";" ? ";" : shellEscape(arg))).join(" "),
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
<key>CFBundlePackageType</key>
|
|
22
22
|
<string>APPL</string>
|
|
23
23
|
<key>CFBundleShortVersionString</key>
|
|
24
|
-
<string>2.9.
|
|
24
|
+
<string>2.9.8</string>
|
|
25
25
|
<key>CFBundleVersion</key>
|
|
26
|
-
<string>2.9.
|
|
26
|
+
<string>2.9.8</string>
|
|
27
27
|
<key>LSMinimumSystemVersion</key>
|
|
28
28
|
<string>11.0</string>
|
|
29
29
|
<key>LSUIElement</key>
|
|
Binary file
|
|
Binary file
|
package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</data>
|
|
11
11
|
<key>Resources/Assets.car</key>
|
|
12
12
|
<data>
|
|
13
|
-
|
|
13
|
+
l0+pnfS5aykXdUJ9hqLbM8D+kxA=
|
|
14
14
|
</data>
|
|
15
15
|
</dict>
|
|
16
16
|
<key>files2</key>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<dict>
|
|
27
27
|
<key>hash2</key>
|
|
28
28
|
<data>
|
|
29
|
-
|
|
29
|
+
w7jEtdTuow3Sd//xEnaf1qdzU3Mu7zdDF3IKDCN08Yw=
|
|
30
30
|
</data>
|
|
31
31
|
</dict>
|
|
32
32
|
</dict>
|
|
Binary file
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
{
|
|
23
23
|
"patch": "split-resize.patch",
|
|
24
24
|
"patchSha256": "4d010271fb4eb52cf36fd29b66e7b3c52c44f6ba90296b944014d74bf3d4222a"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"patch": "kitty-graphics.patch",
|
|
28
|
+
"patchSha256": "1ff7b3022aa2a3d7014b7339c0f2ae868292d5d6df3c668cefa403509ecbc1f6"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"patch": "precise-cell-pixels.patch",
|
|
32
|
+
"patchSha256": "11b2f09f347d0369a744be5aef14e7be3407f4bfa6cae2047b9477234a01ba24"
|
|
25
33
|
}
|
|
26
34
|
],
|
|
27
35
|
"experimentalExtensions": [
|
|
@@ -40,12 +48,12 @@
|
|
|
40
48
|
"platform": "darwin",
|
|
41
49
|
"arch": "arm64",
|
|
42
50
|
"files": {
|
|
43
|
-
"tmux": "
|
|
44
|
-
"lib/libutf8proc.3.
|
|
51
|
+
"tmux": "78b5efc7cb7308e892487a0ea046c531a271680c812c8b8851796dbdf57b0fe8",
|
|
52
|
+
"lib/libutf8proc.3.3.0.dylib": "da17133f84767a9873ff61402ac1a9d6a19ddfc1efb90cffc7c894df68532ce2",
|
|
45
53
|
"lib/libncursesw.6.dylib": "c9b3c77b5874b0c694590774f7b7b1568b2bb13e82707bdf29cb7296446fe596",
|
|
46
|
-
"lib/libevent_core-2.1.7.dylib": "
|
|
54
|
+
"lib/libevent_core-2.1.7.dylib": "65a205eee103b07356c1d6b1102b6b6ca08b0abaad44d960a0dad809722d0a9d",
|
|
47
55
|
"licenses/interaction-journal.txt": "9f02e74957c4c5efb1b65cf35d14b291a7e83807d89e8afedf6e9cb5dbfed39c",
|
|
48
|
-
"licenses/libutf8proc.3.
|
|
56
|
+
"licenses/libutf8proc.3.3.0.dylib.txt": "3b510150d34f248a221bb88e1d811238d6c6c18b51231822c42974c39bb07256",
|
|
49
57
|
"licenses/libncursesw.6.dylib.txt": "708999f95527e1ffa670c6fce288c6c600cb477dd04afcc1171422b3dd4ee226",
|
|
50
58
|
"licenses/libevent_core-2.1.7.dylib.txt": "ff02effc9b331edcdac387d198691bfa3e575e7d244ad10cb826aa51ef085670",
|
|
51
59
|
"share/terminfo/31/1178": "e7172b912d33529169b2f877bf18009c2947d7045a845ec2178ada7bba2b8b48",
|
|
Binary file
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
{
|
|
23
23
|
"patch": "split-resize.patch",
|
|
24
24
|
"patchSha256": "4d010271fb4eb52cf36fd29b66e7b3c52c44f6ba90296b944014d74bf3d4222a"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"patch": "kitty-graphics.patch",
|
|
28
|
+
"patchSha256": "1ff7b3022aa2a3d7014b7339c0f2ae868292d5d6df3c668cefa403509ecbc1f6"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"patch": "precise-cell-pixels.patch",
|
|
32
|
+
"patchSha256": "11b2f09f347d0369a744be5aef14e7be3407f4bfa6cae2047b9477234a01ba24"
|
|
25
33
|
}
|
|
26
34
|
],
|
|
27
35
|
"experimentalExtensions": [
|
|
@@ -68,7 +76,7 @@
|
|
|
68
76
|
"platform": "linux",
|
|
69
77
|
"arch": "arm64",
|
|
70
78
|
"files": {
|
|
71
|
-
"tmux": "
|
|
79
|
+
"tmux": "23ce24278d4c778f6ce974c492e46fcc09e20de577125a841f1d5f91b21a79ce",
|
|
72
80
|
"lib/libutf8proc.so.3": "83cd7bce65037a46494b154b0f7bfd2479bc1659f56321b9ec896f4b64fb490c",
|
|
73
81
|
"lib/libtinfo.so.6": "22952a4f434fd0f356fad23b92de42084e6666d8a594eadd11511b059cc5bb66",
|
|
74
82
|
"lib/libevent_core-2.1.so.7": "80ad9f14cdea14f65c7a778fef4d831d51d23edc55efd263d7f265587eab73d4",
|
|
Binary file
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
{
|
|
23
23
|
"patch": "split-resize.patch",
|
|
24
24
|
"patchSha256": "4d010271fb4eb52cf36fd29b66e7b3c52c44f6ba90296b944014d74bf3d4222a"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"patch": "kitty-graphics.patch",
|
|
28
|
+
"patchSha256": "1ff7b3022aa2a3d7014b7339c0f2ae868292d5d6df3c668cefa403509ecbc1f6"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"patch": "precise-cell-pixels.patch",
|
|
32
|
+
"patchSha256": "11b2f09f347d0369a744be5aef14e7be3407f4bfa6cae2047b9477234a01ba24"
|
|
25
33
|
}
|
|
26
34
|
],
|
|
27
35
|
"experimentalExtensions": [
|
|
@@ -68,7 +76,7 @@
|
|
|
68
76
|
"platform": "linux",
|
|
69
77
|
"arch": "x64",
|
|
70
78
|
"files": {
|
|
71
|
-
"tmux": "
|
|
79
|
+
"tmux": "ef3549656f724cb37e5e94f718d9997570fb3cf55bdafa2585fa1f827e66ba3c",
|
|
72
80
|
"lib/libutf8proc.so.3": "a5aa10c99ac2e9a30c4e01fa4baa85a03dadf71eb73119c76fb3f9f54798962d",
|
|
73
81
|
"lib/libtinfo.so.6": "170db4dd0c324ee73d8d5440a38708726066e1288aba942d57191c6f002240d9",
|
|
74
82
|
"lib/libevent_core-2.1.so.7": "adf343350b739d3dba2b8a6cccbe0729cd9e9ee32b38ba69c08bd14f24a8431e",
|
|
Binary file
|
|
@@ -583,6 +583,9 @@ function parsePaneSnapshot(stdout, expected) {
|
|
|
583
583
|
* application-shell inventory. Names are resolved exactly to `$session_id`
|
|
584
584
|
* before any pane query, and a second identity/topology snapshot closes races.
|
|
585
585
|
*/
|
|
586
|
+
const INVENTORY_FENCE_ATTEMPTS = 4;
|
|
587
|
+
/** 25, 50, 100 ms: enough for a mutation's identity stamps, bounded for every reader. */
|
|
588
|
+
const settleDelay = (attempt) => new Promise((resolve) => setTimeout(resolve, 25 * 2 ** (attempt - 1)));
|
|
586
589
|
export async function discoverWorkspaceRegistryTerminalInventory(registry, runner, signal) {
|
|
587
590
|
const workspaces = registry.list();
|
|
588
591
|
if (workspaces.length > MAX_DISCOVERED_WORKSPACES) {
|
|
@@ -604,13 +607,6 @@ export async function discoverWorkspaceRegistryTerminalInventory(registry, runne
|
|
|
604
607
|
const before = await requiredTmuxResult(runner, argv, signal);
|
|
605
608
|
if (before === null)
|
|
606
609
|
continue;
|
|
607
|
-
const first = parsePaneSnapshot(before, identity);
|
|
608
|
-
const panes = first.panes;
|
|
609
|
-
const after = await requiredTmuxResult(runner, argv, signal);
|
|
610
|
-
if (after === null)
|
|
611
|
-
throw new NativeTerminalAttachmentRuntimeError("discovery-failed");
|
|
612
|
-
const second = parsePaneSnapshot(after, identity);
|
|
613
|
-
const latest = second.panes;
|
|
614
610
|
// Foreground commands, titles, focus and paths can change while the same
|
|
615
611
|
// pane remains valid. Fence binding/topology only, then publish one complete
|
|
616
612
|
// latest snapshot rather than mixing presentation values across reads.
|
|
@@ -625,12 +621,29 @@ export async function discoverWorkspaceRegistryTerminalInventory(registry, runne
|
|
|
625
621
|
"windowStamp",
|
|
626
622
|
"index",
|
|
627
623
|
];
|
|
628
|
-
|
|
629
|
-
panes.length
|
|
630
|
-
panes.
|
|
631
|
-
|
|
624
|
+
const matches = (first, second) => first.linksProof === second.linksProof &&
|
|
625
|
+
first.panes.length === second.panes.length &&
|
|
626
|
+
first.panes.every((pane, index) => proofKeys.every((key) => pane[key] === second.panes[index][key]));
|
|
627
|
+
// A just-created window or split is still being stamped, so topology can
|
|
628
|
+
// move between two reads. Let it settle for a bounded number of re-reads;
|
|
629
|
+
// only two consecutive matching reads are ever published.
|
|
630
|
+
let previous = parsePaneSnapshot(before, identity);
|
|
631
|
+
let stable = null;
|
|
632
|
+
for (let attempt = 0; attempt < INVENTORY_FENCE_ATTEMPTS && !stable; attempt += 1) {
|
|
633
|
+
if (attempt > 0)
|
|
634
|
+
await settleDelay(attempt);
|
|
635
|
+
const after = await requiredTmuxResult(runner, argv, signal);
|
|
636
|
+
if (after === null)
|
|
637
|
+
throw new NativeTerminalAttachmentRuntimeError("discovery-failed");
|
|
638
|
+
const next = parsePaneSnapshot(after, identity);
|
|
639
|
+
if (matches(previous, next))
|
|
640
|
+
stable = next;
|
|
641
|
+
else
|
|
642
|
+
previous = next;
|
|
632
643
|
}
|
|
633
|
-
|
|
644
|
+
if (!stable)
|
|
645
|
+
throw new NativeTerminalAttachmentRuntimeError("discovery-failed");
|
|
646
|
+
bySessionName.set(sessionName, stable.panes);
|
|
634
647
|
}
|
|
635
648
|
const panes = [];
|
|
636
649
|
for (const workspace of workspaces) {
|