tmux-ide 2.9.10 → 2.9.11

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.
Files changed (42) hide show
  1. package/bin/cli.js +173 -61
  2. package/package.json +1 -1
  3. package/packages/contracts/src/pane-stream.ts +12 -0
  4. package/packages/core/src/terminal-replica-hash-cache.ts +8 -1
  5. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Info.plist +2 -2
  6. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/MacOS/tmux-ide-notifier +0 -0
  7. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/Assets.car +0 -0
  8. package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources +2 -2
  9. package/packages/daemon/dist/terminal/mirror/mirror-service.js +12 -2
  10. package/packages/daemon/dist/terminal/mirror/session-channel.js +46 -23
  11. package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +15 -4
  12. package/packages/daemon/dist/terminal/session-runtime/registry.js +17 -6
  13. package/packages/daemon/dist/terminal/session-runtime/terminal-replica-interpreter.js +95 -36
  14. package/packages/daemon/dist/terminal/session-runtime/terminal-replica-owner.js +6 -0
  15. package/packages/daemon/dist/terminal/session-runtime/transport-binding.js +2 -2
  16. package/packages/daemon/dist/tui/mirror/runtime/application-generation-starter.js +16 -1
  17. package/packages/daemon/dist/tui/mirror/runtime/application-machine-agent-navigation.js +13 -0
  18. package/packages/daemon/dist/tui/mirror/runtime/application-machine-navigation.js +12 -4
  19. package/packages/daemon/dist/tui/mirror/runtime/application-retained-agent.js +18 -0
  20. package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +62 -2
  21. package/packages/daemon/dist/tui/mirror/runtime/open-tui-generation-host.js +2 -2
  22. package/packages/daemon/dist/tui/mirror/runtime/runtime-layout-presentation.js +6 -3
  23. package/packages/daemon/dist/tui/mirror/runtime/select-terminal-pane.js +7 -2
  24. package/packages/daemon/dist/tui/mirror/runtime/terminal-selection-waiter.js +36 -0
  25. package/packages/daemon/src/terminal/mirror/mirror-service.ts +19 -2
  26. package/packages/daemon/src/terminal/mirror/session-channel.ts +57 -9
  27. package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +29 -1
  28. package/packages/daemon/src/terminal/session-runtime/registry.ts +23 -3
  29. package/packages/daemon/src/terminal/session-runtime/terminal-replica-interpreter.ts +102 -44
  30. package/packages/daemon/src/terminal/session-runtime/terminal-replica-owner.ts +7 -0
  31. package/packages/daemon/src/terminal/session-runtime/transport-binding.ts +3 -0
  32. package/packages/daemon/src/tui/mirror/open-tui-workspace-runtime-port.ts +2 -0
  33. package/packages/daemon/src/tui/mirror/runtime/application-generation-starter.ts +17 -1
  34. package/packages/daemon/src/tui/mirror/runtime/application-machine-agent-navigation.ts +15 -0
  35. package/packages/daemon/src/tui/mirror/runtime/application-machine-navigation.ts +18 -4
  36. package/packages/daemon/src/tui/mirror/runtime/application-retained-agent.ts +29 -0
  37. package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +63 -2
  38. package/packages/daemon/src/tui/mirror/runtime/open-tui-generation-host.ts +2 -2
  39. package/packages/daemon/src/tui/mirror/runtime/runtime-layout-presentation.ts +7 -4
  40. package/packages/daemon/src/tui/mirror/runtime/select-terminal-pane.ts +9 -1
  41. package/packages/daemon/src/tui/mirror/runtime/terminal-selection-waiter.ts +36 -0
  42. package/packages/daemon-client/src/pane-stream-client.ts +17 -0
package/bin/cli.js CHANGED
@@ -7418,7 +7418,7 @@ var init_terminal_delivery = __esm({
7418
7418
 
7419
7419
  // packages/contracts/src/pane-stream.ts
7420
7420
  import { z as z47 } from "zod";
7421
- var PANE_STREAM_CLOCK_BOUNDS_CAPABILITY_V1, PaneStreamDiagnosticCapabilitySchemaZ, PANE_STREAM_PROTOCOL_VERSION, PANE_STREAM_ISSUE_PATH, PANE_STREAM_REDEEM_PATH, PANE_STREAM_WEBSOCKET_SUBPROTOCOL, PANE_STREAM_MAX_PANES, PANE_STREAM_MAX_OUTPUT_BYTES, PANE_STREAM_MAX_OUTPUT_BASE64_CHARS, PANE_STREAM_MAX_SEED_BYTES, PANE_STREAM_MAX_SEED_BASE64_CHARS, PANE_STREAM_MAX_HELD_DELTAS, PANE_STREAM_MAX_LAYOUT_PANES, PANE_STREAM_MAX_GRID_CELLS, PANE_STREAM_MAX_INPUT_SEQUENCE, PaneStreamSemanticPaneIdSchemaZ, PaneStreamViewerModeSchemaZ, PaneSetSchemaZ, PaneStreamLeaseRequestSchemaZ, PaneStreamRedemptionTicketSchemaZ, PaneStreamLoopbackWebSocketUrlSchemaZ, PaneStreamIssueDescriptorSchemaZ, PaneStreamIssueErrorSchemaZ, PaneStreamIssueResultSchemaZ, PaneStreamIssueMutationRequestSchemaZ, BoundedIdentitySchemaZ, PaneStreamRedeemFrameSchemaZ, PaneStreamInputFrameMetadataShape, PaneStreamInputFrameSchemaZ, PaneStreamConsumedFrameSchemaZ, PaneStreamTerminalDeliveryAckFrameSchemaZ, PaneStreamTerminalDeliveryNackFrameSchemaZ, PaneStreamTerminalDeliveryVisibilityFrameSchemaZ, PaneStreamSemanticIntentFrameSchemaZ, PaneStreamViewportFrameSchemaZ, PaneStreamAuthorityRequestIdSchemaZ, PaneStreamAuthorityGenerationSchemaZ, PaneStreamPresenceFrameSchemaZ, PaneStreamActivityFrameSchemaZ, PaneStreamAuthorityRequestFrameSchemaZ, PaneStreamAuthorityReleaseFrameSchemaZ, SharedMonotonicMicrosSchemaZ, PaneStreamClockProbeFrameSchemaZ, PaneStreamTerminalGraphicsRequestFrameSchemaZ, PaneStreamTerminalCellPixelsFrameSchemaZ, PaneStreamClientFrameSchemaZ, Base64SchemaZ, ServerSeqSchemaZ, GridCellSchemaZ, CellCoordinateSchemaZ, PaneStreamReadyFrameSchemaZ, PaneStreamSeedBatchFrameSchemaZ, PaneStreamOutputFrameSchemaZ, PaneStreamCursorFrameSchemaZ, BoundedDisplayNameSchemaZ, PaneDisplayNameSourceSchemaZ, PaneStreamLayoutFrameSchemaZ, PaneStreamLayoutSnapshotV1FrameSchemaZ, PaneStreamLayoutSnapshotV2FrameSchemaZ, PaneStreamLayoutSnapshotFrameSchemaZ, PaneStreamFlowFrameSchemaZ, PaneStreamClosedFrameSchemaZ, PaneStreamInputAckFrameSchemaZ, PaneStreamClockProbeAckFrameSchemaZ, PaneStreamCausalCellProofFrameSchemaZ, PaneStreamCausalCellFailureFrameSchemaZ, PaneStreamTerminalDeliveryReadyFrameSchemaZ, PaneStreamTerminalDeliveryEnvelopeFrameSchemaZ, PaneStreamTerminalDeliveryChunkFrameSchemaZ, PaneStreamTerminalDeliveryFaultFrameSchemaZ, PaneStreamTerminalGraphicsFrameSchemaZ, PaneStreamTerminalGraphicsBlobFrameSchemaZ, PaneStreamSemanticIntentAckFrameSchemaZ, PaneStreamViewportAckFrameSchemaZ, PaneStreamAuthoritySnapshotFrameSchemaZ, PaneStreamAuthorityReceiptFrameSchemaZ, PaneStreamErrorFrameCodeSchemaZ, PaneStreamErrorFrameSchemaZ, PaneStreamServerFrameSchemaZ;
7421
+ var PANE_STREAM_CLOCK_BOUNDS_CAPABILITY_V1, PaneStreamDiagnosticCapabilitySchemaZ, PANE_STREAM_PROTOCOL_VERSION, PANE_STREAM_ISSUE_PATH, PANE_STREAM_REDEEM_PATH, PANE_STREAM_WEBSOCKET_SUBPROTOCOL, PANE_STREAM_MAX_PANES, PANE_STREAM_MAX_OUTPUT_BYTES, PANE_STREAM_MAX_OUTPUT_BASE64_CHARS, PANE_STREAM_MAX_SEED_BYTES, PANE_STREAM_MAX_SEED_BASE64_CHARS, PANE_STREAM_MAX_HELD_DELTAS, PANE_STREAM_MAX_LAYOUT_PANES, PANE_STREAM_MAX_GRID_CELLS, PANE_STREAM_MAX_INPUT_SEQUENCE, PaneStreamSemanticPaneIdSchemaZ, PaneStreamViewerModeSchemaZ, PaneSetSchemaZ, PaneStreamLeaseRequestSchemaZ, PaneStreamRedemptionTicketSchemaZ, PaneStreamLoopbackWebSocketUrlSchemaZ, PaneStreamIssueDescriptorSchemaZ, PaneStreamIssueErrorSchemaZ, PaneStreamIssueResultSchemaZ, PaneStreamIssueMutationRequestSchemaZ, BoundedIdentitySchemaZ, PaneStreamRedeemFrameSchemaZ, PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION, PaneStreamInputLifetimeSchemaZ, PaneStreamInputFrameMetadataShape, PaneStreamInputFrameSchemaZ, PaneStreamConsumedFrameSchemaZ, PaneStreamTerminalDeliveryAckFrameSchemaZ, PaneStreamTerminalDeliveryNackFrameSchemaZ, PaneStreamTerminalDeliveryVisibilityFrameSchemaZ, PaneStreamSemanticIntentFrameSchemaZ, PaneStreamViewportFrameSchemaZ, PaneStreamAuthorityRequestIdSchemaZ, PaneStreamAuthorityGenerationSchemaZ, PaneStreamPresenceFrameSchemaZ, PaneStreamActivityFrameSchemaZ, PaneStreamAuthorityRequestFrameSchemaZ, PaneStreamAuthorityReleaseFrameSchemaZ, SharedMonotonicMicrosSchemaZ, PaneStreamClockProbeFrameSchemaZ, PaneStreamTerminalGraphicsRequestFrameSchemaZ, PaneStreamTerminalCellPixelsFrameSchemaZ, PaneStreamClientFrameSchemaZ, Base64SchemaZ, ServerSeqSchemaZ, GridCellSchemaZ, CellCoordinateSchemaZ, PaneStreamReadyFrameSchemaZ, PaneStreamSeedBatchFrameSchemaZ, PaneStreamOutputFrameSchemaZ, PaneStreamCursorFrameSchemaZ, BoundedDisplayNameSchemaZ, PaneDisplayNameSourceSchemaZ, PaneStreamLayoutFrameSchemaZ, PaneStreamLayoutSnapshotV1FrameSchemaZ, PaneStreamLayoutSnapshotV2FrameSchemaZ, PaneStreamLayoutSnapshotFrameSchemaZ, PaneStreamFlowFrameSchemaZ, PaneStreamClosedFrameSchemaZ, PaneStreamInputAckFrameSchemaZ, PaneStreamClockProbeAckFrameSchemaZ, PaneStreamCausalCellProofFrameSchemaZ, PaneStreamCausalCellFailureFrameSchemaZ, PaneStreamTerminalDeliveryReadyFrameSchemaZ, PaneStreamTerminalDeliveryEnvelopeFrameSchemaZ, PaneStreamTerminalDeliveryChunkFrameSchemaZ, PaneStreamTerminalDeliveryFaultFrameSchemaZ, PaneStreamTerminalGraphicsFrameSchemaZ, PaneStreamTerminalGraphicsBlobFrameSchemaZ, PaneStreamSemanticIntentAckFrameSchemaZ, PaneStreamViewportAckFrameSchemaZ, PaneStreamAuthoritySnapshotFrameSchemaZ, PaneStreamAuthorityReceiptFrameSchemaZ, PaneStreamErrorFrameCodeSchemaZ, PaneStreamErrorFrameSchemaZ, PaneStreamServerFrameSchemaZ;
7422
7422
  var init_pane_stream = __esm({
7423
7423
  "packages/contracts/src/pane-stream.ts"() {
7424
7424
  "use strict";
@@ -7504,13 +7504,19 @@ var init_pane_stream = __esm({
7504
7504
  deliveryAcks: z47.boolean().optional(),
7505
7505
  diagnosticCapabilities: z47.array(PaneStreamDiagnosticCapabilitySchemaZ).max(2).optional()
7506
7506
  }).strict())();
7507
+ PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION = /* @__PURE__ */ (() => 105)();
7508
+ PaneStreamInputLifetimeSchemaZ = /* @__PURE__ */ (() => z47.object({
7509
+ generation: z47.string().min(1).max(256),
7510
+ incarnation: z47.string().min(1).max(256)
7511
+ }).strict())();
7507
7512
  PaneStreamInputFrameMetadataShape = /* @__PURE__ */ (() => ({
7508
7513
  type: z47.literal("input"),
7509
7514
  pane: PaneStreamSemanticPaneIdSchemaZ,
7510
7515
  seq: z47.number().int().positive().max(PANE_STREAM_MAX_INPUT_SEQUENCE),
7511
7516
  /** Opt-in controlled next-output probe; not a general causal assertion. */
7512
7517
  performanceTraceId: z47.uuid().optional(),
7513
- causalProbe: CausalCellProbeV1SchemaZ.optional()
7518
+ causalProbe: CausalCellProbeV1SchemaZ.optional(),
7519
+ expectedLifetime: PaneStreamInputLifetimeSchemaZ.optional()
7514
7520
  }))();
7515
7521
  PaneStreamInputFrameSchemaZ = /* @__PURE__ */ (() => z47.discriminatedUnion("kind", [
7516
7522
  SessionRuntimeTerminalTextInputSchemaZ.extend(PaneStreamInputFrameMetadataShape),
@@ -7623,6 +7629,7 @@ var init_pane_stream = __esm({
7623
7629
  CellCoordinateSchemaZ = /* @__PURE__ */ (() => z47.number().int().min(0).max(PANE_STREAM_MAX_GRID_CELLS))();
7624
7630
  PaneStreamReadyFrameSchemaZ = /* @__PURE__ */ (() => z47.object({
7625
7631
  type: z47.literal("ready"),
7632
+ inputLifetime: z47.literal(true).optional(),
7626
7633
  protocolVersion: z47.literal(PANE_STREAM_PROTOCOL_VERSION),
7627
7634
  daemonInstanceId: BoundedIdentitySchemaZ,
7628
7635
  requestId: z47.uuid(),
@@ -12665,7 +12672,7 @@ var require_package = __commonJS({
12665
12672
  "package.json"(exports, module) {
12666
12673
  module.exports = {
12667
12674
  name: "tmux-ide",
12668
- version: "2.9.10",
12675
+ version: "2.9.11",
12669
12676
  description: "The open-source workspace for coding agents: run Claude Code, Codex and other agents in tmux with live status",
12670
12677
  type: "module",
12671
12678
  bin: {
@@ -30222,6 +30229,8 @@ var init_session_channel = __esm({
30222
30229
  fittedWindows = /* @__PURE__ */ new Map();
30223
30230
  cancelSync = null;
30224
30231
  syncOrdinal = 0;
30232
+ identityJoinOrdinal = 0;
30233
+ trustedInventoryJoinsMissing = false;
30225
30234
  completedSyncOrdinal = 0;
30226
30235
  lastDisplayNameSyncAtMs = 0;
30227
30236
  disposed = false;
@@ -30445,18 +30454,25 @@ var init_session_channel = __esm({
30445
30454
  }
30446
30455
  /**
30447
30456
  * Strict daemon-internal inventory from this channel's current tmux truth.
30448
- * Unlike the background discovery path, this query awaits descriptor
30449
- * reconciliation before projecting and rejects incomplete identity rather
30450
- * than returning the previous descriptor snapshot.
30457
+ * Unlike background discovery, this query verifies current native membership
30458
+ * before projecting and rejects incomplete identity. Stream admission may
30459
+ * explicitly join missing pane records after that verification; ordinary
30460
+ * inventory readers retain their existing fail-closed no-join contract.
30451
30461
  */
30452
- describeTrustedInventory(expectedRuntimeSessionId) {
30462
+ describeTrustedInventory(expectedRuntimeSessionId, joinMissingPanes = false) {
30453
30463
  if (this.disposed) {
30454
30464
  return Promise.reject(new Error(`mirror session ${this.opts.session} is disposed`));
30455
30465
  }
30456
30466
  if (this.trustedInventoryFlight) {
30467
+ if (joinMissingPanes && !this.trustedInventoryJoinsMissing && this.trustedInventoryFlightSessionId === expectedRuntimeSessionId)
30468
+ return this.trustedInventoryFlight.then(
30469
+ () => this.describeTrustedInventory(expectedRuntimeSessionId, true),
30470
+ () => this.describeTrustedInventory(expectedRuntimeSessionId, true)
30471
+ );
30457
30472
  return this.trustedInventoryFlightSessionId === expectedRuntimeSessionId ? this.trustedInventoryFlight : Promise.reject(new Error(`trusted inventory identity changed for ${this.opts.session}`));
30458
30473
  }
30459
- const flight = this.refreshTrustedInventory(expectedRuntimeSessionId).catch((error) => {
30474
+ this.trustedInventoryJoinsMissing = joinMissingPanes;
30475
+ const flight = this.refreshTrustedInventory(expectedRuntimeSessionId, 0, joinMissingPanes).catch((error) => {
30460
30476
  this.windowLinkAuthority?.invalidate();
30461
30477
  this.latestWindowStage = null;
30462
30478
  throw error;
@@ -32455,7 +32471,7 @@ var init_session_channel = __esm({
32455
32471
  }
32456
32472
  return { listed, movedWindowRuntimeIds };
32457
32473
  }
32458
- async refreshTrustedInventory(expectedRuntimeSessionId, attempt = 0) {
32474
+ async refreshTrustedInventory(expectedRuntimeSessionId, attempt = 0, joinMissingPanes = false) {
32459
32475
  const authorityOrdinal = this.windowIdentityOrdinal;
32460
32476
  const beforeLines = await this.io.request(
32461
32477
  `list-panes -s -t "${expectedRuntimeSessionId}" -F "${SESSION_PANE_DESCRIPTOR_FORMAT}"`
@@ -32523,7 +32539,11 @@ var init_session_channel = __esm({
32523
32539
  if (windowStage.repairedIdentity || confirmedWindowStage.repairedIdentity || repairedPanes || !coherent || !this.windowStageIdentitiesEqual(windowStage, confirmedWindowStage) || authorityOrdinal !== this.windowIdentityOrdinal) {
32524
32540
  if (attempt >= 1)
32525
32541
  throw new Error(`trusted inventory for ${this.opts.session} did not settle`);
32526
- return await this.refreshTrustedInventory(expectedRuntimeSessionId, attempt + 1);
32542
+ return await this.refreshTrustedInventory(
32543
+ expectedRuntimeSessionId,
32544
+ attempt + 1,
32545
+ joinMissingPanes
32546
+ );
32527
32547
  }
32528
32548
  if (this.disposed) throw new Error(`mirror session ${this.opts.session} is disposed`);
32529
32549
  const activeWindowId = activeWindowIds.values().next().value;
@@ -32551,7 +32571,22 @@ var init_session_channel = __esm({
32551
32571
  }
32552
32572
  if (confirmedWindowStage.currentWindow !== activeWindowId || confirmedWindowStage.links.length !== descriptors[0].sessionWindowCount || confirmedWindowStage.windows.size !== computedWindowCounts.size || !stagedPaneMembershipExact || stagedPaneCount !== descriptors.length || stagedPaneIds.size !== descriptors.length || [...computedWindowCounts.keys()].some(
32553
32573
  (runtimeWindowId) => !confirmedWindowStage.windows.has(runtimeWindowId)
32554
- ) || descriptors.some((descriptor) => {
32574
+ ))
32575
+ throw new Error(`trusted inventory for ${this.opts.session} lacks verified identity`);
32576
+ if (joinMissingPanes && descriptors.some(
32577
+ (pane) => this.panesByRuntime.get(pane.runtimePaneId)?.semanticId !== pane.semanticPaneId
32578
+ )) {
32579
+ this.discovery.invalidate();
32580
+ await this.reconcileIdentity(
32581
+ descriptors,
32582
+ runtimePaneIds,
32583
+ () => authorityOrdinal === this.windowIdentityOrdinal,
32584
+ false
32585
+ );
32586
+ }
32587
+ if (this.disposed || authorityOrdinal !== this.windowIdentityOrdinal)
32588
+ throw new Error(`trusted inventory for ${this.opts.session} changed during identity join`);
32589
+ if (descriptors.some((descriptor) => {
32555
32590
  const pane = this.panesByRuntime.get(descriptor.runtimePaneId);
32556
32591
  const window2 = confirmedWindowStage.windows.get(descriptor.windowId);
32557
32592
  return !pane || !window2?.semanticId || descriptor.semanticPaneId !== pane.semanticId || descriptor.semanticWindowId !== window2.semanticId || !WorkspaceIdSchemaZ.safeParse(pane.semanticId).success || !WorkspaceIdSchemaZ.safeParse(window2.semanticId).success;
@@ -32846,7 +32881,8 @@ var init_session_channel = __esm({
32846
32881
  }))
32847
32882
  };
32848
32883
  }
32849
- async reconcileIdentity(descriptors, listed) {
32884
+ async reconcileIdentity(descriptors, listed, current = () => true, publish = true) {
32885
+ const joinOrdinal = ++this.identityJoinOrdinal;
32850
32886
  if (this.disposed) return false;
32851
32887
  if (this.opts.hasSharedWindowConflict?.()) {
32852
32888
  this.settleFirstJoin();
@@ -32881,7 +32917,8 @@ var init_session_channel = __esm({
32881
32917
  )
32882
32918
  )
32883
32919
  );
32884
- if (this.disposed) return plan.stampEffects.length > 0;
32920
+ if (this.disposed || !current() || joinOrdinal !== this.identityJoinOrdinal)
32921
+ return plan.stampEffects.length > 0;
32885
32922
  const reconciliation = finalizeWorkspaceTmuxReconciliation(plan, outcomes);
32886
32923
  const descriptorByRuntime = new Map(descriptors.map((d) => [d.runtimePaneId, d]));
32887
32924
  for (const verified of reconciliation.panes) {
@@ -32968,8 +33005,10 @@ var init_session_channel = __esm({
32968
33005
  degraded: diagnostic4.degraded
32969
33006
  }));
32970
33007
  this.degraded = reconciliation.degraded;
32971
- for (const runtimeId of this.layoutByWindow.keys()) this.emitLayout(runtimeId);
32972
- this.emitLayoutAuthority();
33008
+ if (publish) {
33009
+ for (const runtimeId of this.layoutByWindow.keys()) this.emitLayout(runtimeId);
33010
+ this.emitLayoutAuthority();
33011
+ }
32973
33012
  this.settleFirstJoin();
32974
33013
  return plan.stampEffects.length > 0;
32975
33014
  }
@@ -39938,11 +39977,20 @@ var init_mirror_service = __esm({
39938
39977
  this.release(session, entry);
39939
39978
  }
39940
39979
  }
39941
- async describeSessionAuthority(session) {
39980
+ async describeSessionAuthority(session, expectedSemanticPaneIds) {
39942
39981
  const entry = await this.acquire(session);
39943
39982
  try {
39944
39983
  const identity2 = await entry.channel.attachedSessionIdentity();
39945
- return { description: entry.channel.describe(), runtimeSessionId: identity2.runtimeSessionId };
39984
+ let description = entry.channel.describe();
39985
+ if (expectedSemanticPaneIds?.some(
39986
+ (id2) => !description.panes.some((pane) => pane.semanticPaneId === id2)
39987
+ )) {
39988
+ await entry.channel.describeTrustedInventory(identity2.runtimeSessionId, true);
39989
+ description = entry.channel.describe();
39990
+ }
39991
+ if (this.disposed || entry.retired || this.channels.get(session) !== entry)
39992
+ throw new Error("Mirror authority retired during description");
39993
+ return { description, runtimeSessionId: identity2.runtimeSessionId };
39946
39994
  } finally {
39947
39995
  this.release(session, entry);
39948
39996
  }
@@ -58489,7 +58537,7 @@ function projectPlacements(rows, viewportRows, cols) {
58489
58537
  }
58490
58538
  ];
58491
58539
  }
58492
- var TerminalReplicaInterpreter;
58540
+ var MAX_INGEST_BATCH_BYTES, TerminalReplicaInterpreter;
58493
58541
  var init_terminal_replica_interpreter = __esm({
58494
58542
  "packages/daemon/src/terminal/session-runtime/terminal-replica-interpreter.ts"() {
58495
58543
  "use strict";
@@ -58502,6 +58550,7 @@ var init_terminal_replica_interpreter = __esm({
58502
58550
  init_xterm_terminal_interpreter_backend();
58503
58551
  init_causal_cell_ledger();
58504
58552
  init_kitty_graphics();
58553
+ MAX_INGEST_BATCH_BYTES = 256 * 1024;
58505
58554
  TerminalReplicaInterpreter = class {
58506
58555
  #nativeSeedBackingCandidate;
58507
58556
  #generation;
@@ -58529,8 +58578,7 @@ var init_terminal_replica_interpreter = __esm({
58529
58578
  #needsSeed = true;
58530
58579
  #closed = false;
58531
58580
  #walkCount = 0;
58532
- #pendingWrites = [];
58533
- #writeFlushScheduled = false;
58581
+ #pendingWrites = null;
58534
58582
  #widgetGate = false;
58535
58583
  // kitty graphics: images outlive reseeds; the scanner owns split APCs.
58536
58584
  #kittyScanner = new KittyApcScanner();
@@ -58601,15 +58649,22 @@ var init_terminal_replica_interpreter = __esm({
58601
58649
  if (operation.type === "write") {
58602
58650
  const data = operation.data.slice();
58603
58651
  const trace = operation.trace ?? null;
58604
- const pendingTrace = this.#pendingWrites[0]?.trace ?? null;
58605
- if (this.#pendingWrites.length > 0 && (pendingTrace?.traceId ?? null) !== (trace?.traceId ?? null))
58652
+ if (this.#pendingWrites && (this.#pendingWrites.trace?.traceId ?? null) !== (trace?.traceId ?? null))
58606
58653
  this.#flushWrites();
58654
+ const group = this.#pendingWrites ??= {
58655
+ entries: [],
58656
+ bytes: 0,
58657
+ scheduled: false,
58658
+ flushQueued: false,
58659
+ trace
58660
+ };
58607
58661
  const promise = new Promise((resolve44, reject) => {
58608
- this.#pendingWrites.push({ data, trace, resolve: resolve44, reject });
58662
+ group.entries.push({ data, offset: 0, resolve: resolve44, reject });
58663
+ group.bytes += data.length;
58609
58664
  });
58610
- if (!this.#writeFlushScheduled) {
58611
- this.#writeFlushScheduled = true;
58612
- this.#scheduler.microtask(() => this.#flushWrites());
58665
+ if (!group.scheduled && !group.flushQueued) {
58666
+ group.flushQueued = true;
58667
+ this.#scheduler.microtask(() => this.#scheduleWriteGroup(group));
58613
58668
  }
58614
58669
  return promise;
58615
58670
  }
@@ -58815,7 +58870,18 @@ var init_terminal_replica_interpreter = __esm({
58815
58870
  for (const command3 of scanned.commands) this.#kittyPending.set(command3.marker, command3);
58816
58871
  const parseStarted = this.#observability.enabled ? this.#observability.nowMicros() : 0;
58817
58872
  if (scanned.forward.byteLength === 0) return;
58818
- await this.#writeToBackend(this.#backend, scanned.forward);
58873
+ for (let offset = 0; offset < scanned.forward.length; offset += MAX_INGEST_BATCH_BYTES) {
58874
+ await this.#writeToBackend(
58875
+ this.#backend,
58876
+ scanned.forward.subarray(offset, offset + MAX_INGEST_BATCH_BYTES)
58877
+ );
58878
+ const dirty = this.#backend.dirtyRange();
58879
+ const pending = this.#pendingWriteDirty;
58880
+ this.#pendingWriteDirty = pending === null ? dirty : pending === void 0 || dirty === void 0 ? void 0 : {
58881
+ start: Math.min(pending.start, dirty.start),
58882
+ end: Math.max(pending.end, dirty.end)
58883
+ };
58884
+ }
58819
58885
  if (this.#observability.enabled)
58820
58886
  this.#observability.recordSpan(
58821
58887
  "parse",
@@ -58824,12 +58890,6 @@ var init_terminal_replica_interpreter = __esm({
58824
58890
  this.#observability.nowMicros(),
58825
58891
  trace
58826
58892
  );
58827
- const dirty = this.#backend.dirtyRange();
58828
- const pending = this.#pendingWriteDirty;
58829
- this.#pendingWriteDirty = pending === null ? dirty : pending === void 0 || dirty === void 0 ? void 0 : {
58830
- start: Math.min(pending.start, dirty.start),
58831
- end: Math.max(pending.end, dirty.end)
58832
- };
58833
58893
  if (this.#backend.requiresNativeReseed()) {
58834
58894
  this.#commit(false);
58835
58895
  return;
@@ -58852,6 +58912,7 @@ var init_terminal_replica_interpreter = __esm({
58852
58912
  if (this.#syncRecovery || this.#closed) return;
58853
58913
  this.#syncRecovery = this.#scheduler.timer(() => {
58854
58914
  this.#syncRecovery = null;
58915
+ this.#flushWrites();
58855
58916
  const run = this.#tail.then(async () => {
58856
58917
  if (this.#closed || !this.#backend.modes().synchronizedOutput) return;
58857
58918
  await this.#backend.write("\x1B[?2026l");
@@ -59093,24 +59154,51 @@ var init_terminal_replica_interpreter = __esm({
59093
59154
  }
59094
59155
  }
59095
59156
  }
59157
+ /** Seal the current group at every trace, control and idle barrier. */
59096
59158
  #flushWrites() {
59097
- this.#writeFlushScheduled = false;
59098
- if (this.#pendingWrites.length === 0) return;
59099
- const pending = this.#pendingWrites.splice(0);
59100
- const length = pending.reduce((total, entry) => total + entry.data.length, 0);
59101
- const data = new Uint8Array(length);
59102
- let offset = 0;
59103
- for (const entry of pending) {
59104
- data.set(entry.data, offset);
59105
- offset += entry.data.length;
59106
- }
59107
- const trace = pending.find(({ trace: trace2 }) => trace2 !== null)?.trace ?? null;
59108
- const run = this.#tail.then(() => this.#write(data, trace));
59159
+ const group = this.#pendingWrites;
59160
+ this.#pendingWrites = null;
59161
+ if (group) this.#scheduleWriteGroup(group);
59162
+ }
59163
+ #scheduleWriteGroup(group) {
59164
+ if (group.scheduled) return;
59165
+ group.scheduled = true;
59166
+ const run = this.#tail.then(async () => {
59167
+ try {
59168
+ while (group.entries.length > 0) {
59169
+ const length = Math.min(group.bytes, MAX_INGEST_BATCH_BYTES);
59170
+ const data = new Uint8Array(length);
59171
+ const completed = [];
59172
+ let offset = 0;
59173
+ for (const entry of group.entries) {
59174
+ const take = Math.min(entry.data.length - entry.offset, length - offset);
59175
+ data.set(entry.data.subarray(entry.offset, entry.offset + take), offset);
59176
+ offset += take;
59177
+ entry.offset += take;
59178
+ if (entry.offset === entry.data.length) completed.push(entry);
59179
+ else break;
59180
+ if (offset === length && length > 0) break;
59181
+ }
59182
+ group.entries.splice(0, completed.length);
59183
+ group.bytes -= length;
59184
+ try {
59185
+ await this.#write(data, group.trace);
59186
+ } catch (error) {
59187
+ for (const entry of completed) entry.reject(error);
59188
+ throw error;
59189
+ }
59190
+ for (const entry of completed) entry.resolve();
59191
+ }
59192
+ } catch (error) {
59193
+ for (const entry of group.entries) entry.reject(error);
59194
+ group.entries.length = 0;
59195
+ group.bytes = 0;
59196
+ throw error;
59197
+ } finally {
59198
+ if (this.#pendingWrites === group) this.#pendingWrites = null;
59199
+ }
59200
+ });
59109
59201
  this.#tail = run.catch(() => void 0);
59110
- void run.then(
59111
- () => pending.forEach((entry) => entry.resolve()),
59112
- (error) => pending.forEach((entry) => entry.reject(error))
59113
- );
59114
59202
  }
59115
59203
  #observeMarkerBytes(data) {
59116
59204
  if (this.#widgetGate) return;
@@ -59291,6 +59379,10 @@ var init_terminal_replica_owner = __esm({
59291
59379
  inputDispatchIncarnation() {
59292
59380
  return this.#disposed ? null : this.#publishedIncarnation;
59293
59381
  }
59382
+ /** Scalar admission fence; unavailable while canonical replacement is pending. */
59383
+ inputAdmissionIncarnation() {
59384
+ return this.#disposed || this.#reseed || this.#waitingForGeometryCapture ? null : this.#publishedIncarnation;
59385
+ }
59294
59386
  qualificationSnapshot() {
59295
59387
  const seed = this.#interpreter.currentSeed();
59296
59388
  return Object.freeze({
@@ -62271,10 +62363,10 @@ var init_registry2 = __esm({
62271
62363
  if (this.#disposed || this.#sessions.get(session) !== runtime) return { status: "retired" };
62272
62364
  return result2;
62273
62365
  }
62274
- async describeSessionAuthority(session) {
62366
+ async describeSessionAuthority(session, expectedSemanticPaneIds) {
62275
62367
  const runtime = this.#runtime(session);
62276
62368
  await runtime.whenReady();
62277
- const authority2 = await this.#mirror.describeSessionAuthority(session);
62369
+ const authority2 = await this.#mirror.describeSessionAuthority(session, expectedSemanticPaneIds);
62278
62370
  if (this.#disposed || this.#sessions.get(session) !== runtime) {
62279
62371
  const error = new Error(`session runtime ${session} changed topology`);
62280
62372
  error.name = "MirrorTopologyChangedError";
@@ -62805,7 +62897,7 @@ var init_registry2 = __esm({
62805
62897
  return Promise.reject(error);
62806
62898
  }
62807
62899
  }
62808
- sendInput(clientId, lease, semanticPaneId3, rawInput, performanceTraceId, rawCausalProbe, onCausalResult) {
62900
+ sendInput(clientId, lease, semanticPaneId3, rawInput, performanceTraceId, rawCausalProbe, onCausalResult, expectedLifetime) {
62809
62901
  this.assertController(lease, clientId);
62810
62902
  const inputLease = this.#authority.leaseFor(clientId, "input");
62811
62903
  if (!inputLease) {
@@ -62832,7 +62924,8 @@ var init_registry2 = __esm({
62832
62924
  incarnation: null
62833
62925
  }) : null;
62834
62926
  const started = this.#observability.enabled ? this.#observability.nowMicros() : 0;
62835
- const replicaOwner = this.#terminalReplicaOwner(semanticPaneId3);
62927
+ const replicaOwner = expectedLifetime ? this.#terminalReplicas.get(semanticPaneId3) : this.#terminalReplicaOwner(semanticPaneId3);
62928
+ if (!replicaOwner) throw new Error("Input target lifetime unavailable");
62836
62929
  if (causalProbe) {
62837
62930
  this.#activeCausalCellProbes += 1;
62838
62931
  let settled = false;
@@ -62855,6 +62948,8 @@ var init_registry2 = __esm({
62855
62948
  this.#outputTraces.arm(semanticPaneId3, trace);
62856
62949
  }
62857
62950
  try {
62951
+ if (expectedLifetime && (expectedLifetime.generation !== this.generation || this.#terminalReplicas.get(semanticPaneId3) !== replicaOwner || replicaOwner.inputAdmissionIncarnation() !== expectedLifetime.incarnation))
62952
+ throw new Error("Input target lifetime changed");
62858
62953
  if (input.kind === "text")
62859
62954
  this.#mirror.sendText(
62860
62955
  this.session,
@@ -63388,7 +63483,7 @@ var init_registry2 = __esm({
63388
63483
  this.#assertOpen();
63389
63484
  return this.#runtime.submitIntent(this.clientId, lease, operationId, intent);
63390
63485
  }
63391
- sendInput(lease, semanticPaneId3, input, performanceTraceId, causalProbe, onCausalResult) {
63486
+ sendInput(lease, semanticPaneId3, input, performanceTraceId, causalProbe, onCausalResult, expectedLifetime) {
63392
63487
  this.#assertOpen();
63393
63488
  this.#runtime.sendInput(
63394
63489
  this.clientId,
@@ -63397,7 +63492,8 @@ var init_registry2 = __esm({
63397
63492
  input,
63398
63493
  performanceTraceId,
63399
63494
  causalProbe,
63400
- onCausalResult
63495
+ onCausalResult,
63496
+ expectedLifetime
63401
63497
  );
63402
63498
  }
63403
63499
  failCausalCellProbe(semanticPaneId3, traceId, reason) {
@@ -63818,7 +63914,7 @@ var init_transport_binding = __esm({
63818
63914
  authorize();
63819
63915
  return authorize;
63820
63916
  }
63821
- sendInput(semanticPaneId3, input, performanceTraceId, causalProbe, onCausalResult) {
63917
+ sendInput(semanticPaneId3, input, performanceTraceId, causalProbe, onCausalResult, expectedLifetime) {
63822
63918
  this.assertController(semanticPaneId3);
63823
63919
  const lease = this.#shared.lease;
63824
63920
  if (!lease) {
@@ -63838,7 +63934,8 @@ var init_transport_binding = __esm({
63838
63934
  causalProbe ? (result2) => {
63839
63935
  this.#causalCellProbes.delete(causalProbe.traceId);
63840
63936
  onCausalResult?.(result2);
63841
- } : onCausalResult
63937
+ } : onCausalResult,
63938
+ expectedLifetime
63842
63939
  );
63843
63940
  } catch (error) {
63844
63941
  if (causalProbe) this.#causalCellProbes.delete(causalProbe.traceId);
@@ -70131,6 +70228,7 @@ var init_pane_stream_websocket = __esm({
70131
70228
  "use strict";
70132
70229
  init_src2();
70133
70230
  init_src2();
70231
+ init_src2();
70134
70232
  init_admission_util();
70135
70233
  init_registry2();
70136
70234
  init_terminal_delivery_observation_identity();
@@ -70259,7 +70357,10 @@ var init_pane_stream_websocket = __esm({
70259
70357
  try {
70260
70358
  const describeStartedAtMicros = trace ? this.#observability.nowMicros() : 0;
70261
70359
  if (this.#mirror.describeSessionAuthority) {
70262
- const authority2 = await this.#mirror.describeSessionAuthority(context.sessionName);
70360
+ const authority2 = await this.#mirror.describeSessionAuthority(
70361
+ context.sessionName,
70362
+ request3.panes
70363
+ );
70263
70364
  described = authority2.description;
70264
70365
  runtimeSessionId = authority2.runtimeSessionId;
70265
70366
  } else {
@@ -70839,6 +70940,9 @@ var init_pane_stream_websocket = __esm({
70839
70940
  try {
70840
70941
  sendControl2(this.#socket, {
70841
70942
  type: "ready",
70943
+ ...this.#sessionRuntimeBinding && this.#descriptor.terminalDelivery?.protocolVersions.includes(
70944
+ PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION
70945
+ ) ? { inputLifetime: true } : {},
70842
70946
  protocolVersion: PANE_STREAM_PROTOCOL_VERSION,
70843
70947
  daemonInstanceId: this.#binding.daemonInstanceId,
70844
70948
  requestId: this.#binding.requestId,
@@ -71896,7 +72000,8 @@ var init_pane_stream_websocket = __esm({
71896
72000
  frame.causalProbe,
71897
72001
  ingressAtMicros,
71898
72002
  callbackAtSharedMicros,
71899
- ingressAtSharedMicros
72003
+ ingressAtSharedMicros,
72004
+ frame.expectedLifetime
71900
72005
  );
71901
72006
  };
71902
72007
  #acceptAuthorityGeneration(generation) {
@@ -71989,7 +72094,13 @@ var init_pane_stream_websocket = __esm({
71989
72094
  this.#ledger.give(this.#clientId, pane, "renderer-backlog", returned);
71990
72095
  this.#evaluateResume(pane);
71991
72096
  }
71992
- #acceptInput(pane, seq, kind, data, frameBytes, performanceTraceId, causalProbe, ingressAtMicros = null, callbackAtSharedMicros = null, ingressAtSharedMicros = null) {
72097
+ #acceptInput(pane, seq, kind, data, frameBytes, performanceTraceId, causalProbe, ingressAtMicros = null, callbackAtSharedMicros = null, ingressAtSharedMicros = null, expectedLifetime) {
72098
+ if (expectedLifetime && (!this.#sessionRuntimeBinding || !this.#descriptor.terminalDelivery?.protocolVersions.includes(
72099
+ PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION
72100
+ ))) {
72101
+ this.#failProtocol("input-rejected");
72102
+ return;
72103
+ }
71993
72104
  if (this.#descriptor.viewerMode !== "interactive") {
71994
72105
  this.#failProtocol("input-rejected");
71995
72106
  return;
@@ -72081,7 +72192,8 @@ var init_pane_stream_websocket = __esm({
72081
72192
  }
72082
72193
  });
72083
72194
  }
72084
- } : void 0
72195
+ } : void 0,
72196
+ expectedLifetime
72085
72197
  );
72086
72198
  else if (kind === "text") channel.sub.sendText(data);
72087
72199
  else channel.sub.sendKey(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-ide",
3
- "version": "2.9.10",
3
+ "version": "2.9.11",
4
4
  "description": "The open-source workspace for coding agents: run Claude Code, Codex and other agents in tmux with live status",
5
5
  "type": "module",
6
6
  "bin": {
@@ -230,6 +230,16 @@ export type PaneStreamRedeemFrame = z.infer<typeof PaneStreamRedeemFrameSchemaZ>
230
230
  /** @deprecated Import SessionRuntimeTerminalKeyNameSchemaZ for new code. */
231
231
  export const PaneStreamKeyNameSchemaZ = SessionRuntimeTerminalKeyNameSchemaZ;
232
232
 
233
+ /** Negotiated only with callers offering this additive delivery capability. */
234
+ export const PANE_STREAM_INPUT_LIFETIME_CAPABILITY_VERSION = 105;
235
+ export const PaneStreamInputLifetimeSchemaZ = z
236
+ .object({
237
+ generation: z.string().min(1).max(256),
238
+ incarnation: z.string().min(1).max(256),
239
+ })
240
+ .strict();
241
+ export type PaneStreamInputLifetime = z.infer<typeof PaneStreamInputLifetimeSchemaZ>;
242
+
233
243
  const PaneStreamInputFrameMetadataShape = {
234
244
  type: z.literal("input"),
235
245
  pane: PaneStreamSemanticPaneIdSchemaZ,
@@ -237,6 +247,7 @@ const PaneStreamInputFrameMetadataShape = {
237
247
  /** Opt-in controlled next-output probe; not a general causal assertion. */
238
248
  performanceTraceId: z.uuid().optional(),
239
249
  causalProbe: CausalCellProbeV1SchemaZ.optional(),
250
+ expectedLifetime: PaneStreamInputLifetimeSchemaZ.optional(),
240
251
  } as const;
241
252
 
242
253
  export const PaneStreamInputFrameSchemaZ = z
@@ -409,6 +420,7 @@ const CellCoordinateSchemaZ = z.number().int().min(0).max(PANE_STREAM_MAX_GRID_C
409
420
  export const PaneStreamReadyFrameSchemaZ = z
410
421
  .object({
411
422
  type: z.literal("ready"),
423
+ inputLifetime: z.literal(true).optional(),
412
424
  protocolVersion: z.literal(PANE_STREAM_PROTOCOL_VERSION),
413
425
  daemonInstanceId: BoundedIdentitySchemaZ,
414
426
  requestId: z.uuid(),
@@ -7,6 +7,8 @@ import { createBufferedFnv64, type BufferedFnv64 } from "./terminal-fnv64-wasm.t
7
7
 
8
8
  const ROW_HASH_CACHE = new WeakMap<object, string>();
9
9
  const DEEPLY_FROZEN_ROWS = new WeakSet<object>();
10
+ // Provenance from scalar construction only, never generic frozen-object checks.
11
+ const DECODED_ROWS = new WeakSet<object>();
10
12
  const UTF8_ENCODER = new TextEncoder();
11
13
  // Fixed ASCII headers cover common terminal strings without retaining values.
12
14
  const SHORT_ASCII_HEADERS = Array.from({ length: 33 }, (_, length) => `s${length}:`);
@@ -600,8 +602,9 @@ class DecodedTerminalReplicaRowBuilder {
600
602
  cells: Object.freeze(cells),
601
603
  wrapped,
602
604
  }) as unknown as TerminalReplicaRow;
603
- // Earn only deep immutability. Existing row hashing remains lazy and unchanged.
605
+ // Existing row hashing remains lazy and unchanged.
604
606
  DEEPLY_FROZEN_ROWS.add(row);
607
+ DECODED_ROWS.add(row);
605
608
  return row;
606
609
  }
607
610
 
@@ -610,6 +613,10 @@ class DecodedTerminalReplicaRowBuilder {
610
613
  }
611
614
  }
612
615
 
616
+ export function isDecodedTerminalReplicaRow(row: unknown): row is TerminalReplicaRow {
617
+ return typeof row === "object" && row !== null && DECODED_ROWS.has(row);
618
+ }
619
+
613
620
  export function createDecodedTerminalReplicaRowBuilder() {
614
621
  return new DecodedTerminalReplicaRowBuilder();
615
622
  }
@@ -21,9 +21,9 @@
21
21
  <key>CFBundlePackageType</key>
22
22
  <string>APPL</string>
23
23
  <key>CFBundleShortVersionString</key>
24
- <string>2.9.10</string>
24
+ <string>2.9.11</string>
25
25
  <key>CFBundleVersion</key>
26
- <string>2.9.10</string>
26
+ <string>2.9.11</string>
27
27
  <key>LSMinimumSystemVersion</key>
28
28
  <string>11.0</string>
29
29
  <key>LSUIElement</key>
@@ -10,7 +10,7 @@
10
10
  </data>
11
11
  <key>Resources/Assets.car</key>
12
12
  <data>
13
- Kf7QJzoSccEOCKFhIjar9ueKYOw=
13
+ nBfyKmj9/xOSU1E6fMrLP0j34to=
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
- vnlBBSBJPJsi3mG+WLEDphcEeoj84MEVZeasfTAn6ls=
29
+ BH5ZBbufHUMGSzMRXcEqBgur+e94BeWVItaM9FDWrFA=
30
30
  </data>
31
31
  </dict>
32
32
  </dict>
@@ -84,11 +84,21 @@ export class MirrorService {
84
84
  this.release(session, entry);
85
85
  }
86
86
  }
87
- async describeSessionAuthority(session) {
87
+ async describeSessionAuthority(session, expectedSemanticPaneIds) {
88
88
  const entry = await this.acquire(session);
89
89
  try {
90
90
  const identity = await entry.channel.attachedSessionIdentity();
91
- return { description: entry.channel.describe(), runtimeSessionId: identity.runtimeSessionId };
91
+ let description = entry.channel.describe();
92
+ if (expectedSemanticPaneIds?.some((id) => !description.panes.some((pane) => pane.semanticPaneId === id))) {
93
+ // A mutation receipt and fresh catalog can precede debounced mirror
94
+ // discovery. Join the verified native inventory before declaring a
95
+ // requested pane absent; never substitute receipt IDs for tmux truth.
96
+ await entry.channel.describeTrustedInventory(identity.runtimeSessionId, true);
97
+ description = entry.channel.describe();
98
+ }
99
+ if (this.disposed || entry.retired || this.channels.get(session) !== entry)
100
+ throw new Error("Mirror authority retired during description");
101
+ return { description, runtimeSessionId: identity.runtimeSessionId };
92
102
  }
93
103
  finally {
94
104
  this.release(session, entry);