tmux-ide 2.9.2 → 2.9.3
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/README.md +1 -1
- package/bin/cli.js +2071 -625
- package/package.json +14 -5
- package/packages/contracts/src/desktop-host.ts +3 -0
- package/packages/contracts/src/saved-machines.ts +19 -0
- package/packages/contracts/src/terminal-replica.ts +1 -1
- package/packages/core/package.json +3 -2
- package/packages/core/src/terminal-delivery.ts +51 -3
- package/packages/core/src/terminal-fnv64-wasm.ts +4 -3
- package/packages/core/src/terminal-replica-hash-cache.ts +129 -31
- package/packages/core/src/terminal-replica-owned-row.ts +27 -0
- package/packages/core/src/terminal-replica.ts +13 -28
- package/packages/daemon/dist/command-center/daemon-fleet-facts-observer.js +96 -10
- package/packages/daemon/dist/command-center/resources/saved-machine-route.js +40 -1
- package/packages/daemon/dist/command-center/ws-events.js +5 -24
- package/packages/daemon/dist/lib/canonical-daemon-bootstrap.js +8 -0
- package/packages/daemon/dist/lib/canonical-daemon.js +28 -2
- package/packages/daemon/dist/lib/daemon-embed.js +1 -1
- package/packages/daemon/dist/lib/daemon-service-manager.js +122 -0
- package/packages/daemon/dist/lib/daemon-service-plan.js +127 -0
- package/packages/daemon/dist/lib/daemon-service.js +259 -0
- package/packages/daemon/dist/lib/install-origin.js +2 -0
- package/packages/daemon/dist/lib/local-fleet-request.js +9 -3
- package/packages/daemon/dist/lib/log.js +6 -10
- package/packages/daemon/dist/lib/managed-installer-update.js +67 -0
- package/packages/daemon/dist/lib/{tui-download-lock.js → private-operation-lock.js} +11 -11
- package/packages/daemon/dist/lib/remote-daemon-info.js +3 -2
- package/packages/daemon/dist/lib/remote-daemon-lifecycle.js +4 -4
- package/packages/daemon/dist/lib/remote-tmux-command.js +10 -0
- package/packages/daemon/dist/lib/runtime-namespace.js +28 -16
- package/packages/daemon/dist/lib/saved-machines.js +40 -2
- package/packages/daemon/dist/lib/ssh-daemon-transport.js +24 -9
- package/packages/daemon/dist/lib/tmux-server-owner.js +1 -1
- package/packages/daemon/dist/lib/tmux-server-registration.js +21 -3
- package/packages/daemon/dist/lib/tui-binary.js +2 -2
- package/packages/daemon/dist/lib/update.js +18 -0
- package/packages/daemon/dist/lib/workspace-multiplexer-verbs.js +24 -1
- package/packages/daemon/dist/machines.js +40 -4
- 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/terminal/attachments/direct-websocket.js +4 -1
- package/packages/daemon/dist/terminal/attachments/native-runtime.js +22 -13
- package/packages/daemon/dist/terminal/mirror/mirror-service.js +101 -3
- package/packages/daemon/dist/terminal/mirror/registered-window-guard.js +62 -0
- package/packages/daemon/dist/terminal/mirror/session-channel.js +75 -4
- package/packages/daemon/dist/terminal/mirror/shared-window-index.js +45 -0
- package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +11 -1
- package/packages/daemon/dist/terminal/session-runtime/multiplexer-backend.js +1 -0
- package/packages/daemon/dist/terminal/session-runtime/registry.js +56 -7
- package/packages/daemon/dist/terminal/session-runtime/semantic-mutation-executor.js +3 -1
- package/packages/daemon/dist/tui/mirror/dialog-model.js +2 -35
- package/packages/daemon/dist/tui/mirror/runtime/application-daemon-authority-owner.js +8 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-home-fleet.js +20 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-agents.js +7 -1
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-authority.js +59 -9
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-navigation.js +27 -19
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-sidebar.jsx +23 -18
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-startup.js +31 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-palette-search-owner.js +7 -3
- package/packages/daemon/dist/tui/mirror/runtime/application-performance-log.js +3 -0
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-input-ingress.js +146 -2
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +201 -50
- package/packages/daemon/dist/tui/mirror/runtime/bounded-performance-record-writer.js +50 -10
- package/packages/daemon/dist/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.js +6 -5
- package/packages/daemon/dist/tui/mirror/runtime/terminal-pane-input-router.js +3 -0
- package/packages/daemon/dist/tui/mirror/runtime/workspace-terminal-fast-lane.js +8 -2
- package/packages/daemon/dist/tui/mirror/terminal-text.js +35 -0
- package/packages/daemon/dist/tui/mirror/workspace/connection-feedback.js +5 -3
- package/packages/daemon/src/command-center/daemon-fleet-facts-observer.ts +100 -10
- package/packages/daemon/src/command-center/resources/saved-machine-route.ts +48 -1
- package/packages/daemon/src/command-center/ws-events.ts +5 -25
- package/packages/daemon/src/lib/canonical-daemon-bootstrap.ts +12 -0
- package/packages/daemon/src/lib/canonical-daemon.ts +44 -2
- package/packages/daemon/src/lib/daemon-embed.ts +1 -0
- package/packages/daemon/src/lib/daemon-service-manager.ts +152 -0
- package/packages/daemon/src/lib/daemon-service-plan.ts +153 -0
- package/packages/daemon/src/lib/daemon-service.ts +301 -0
- package/packages/daemon/src/lib/install-origin.ts +5 -0
- package/packages/daemon/src/lib/local-fleet-request.ts +19 -3
- package/packages/daemon/src/lib/log.ts +13 -9
- package/packages/daemon/src/lib/managed-installer-update.ts +79 -0
- package/packages/daemon/src/lib/{tui-download-lock.ts → private-operation-lock.ts} +15 -11
- package/packages/daemon/src/lib/remote-daemon-info.ts +3 -3
- package/packages/daemon/src/lib/remote-daemon-lifecycle.ts +4 -4
- package/packages/daemon/src/lib/remote-tmux-command.ts +12 -0
- package/packages/daemon/src/lib/runtime-namespace.ts +27 -18
- package/packages/daemon/src/lib/saved-machines.ts +40 -1
- package/packages/daemon/src/lib/ssh-daemon-transport.ts +25 -7
- package/packages/daemon/src/lib/tmux-server-owner.ts +1 -0
- package/packages/daemon/src/lib/tmux-server-registration.ts +21 -3
- package/packages/daemon/src/lib/tui-binary.ts +2 -2
- package/packages/daemon/src/lib/update.ts +24 -0
- package/packages/daemon/src/lib/workspace-multiplexer-verbs.ts +22 -0
- package/packages/daemon/src/machines.ts +53 -5
- package/packages/daemon/src/terminal/attachments/direct-websocket.ts +8 -2
- package/packages/daemon/src/terminal/attachments/native-runtime.ts +28 -13
- package/packages/daemon/src/terminal/mirror/mirror-service.ts +105 -3
- package/packages/daemon/src/terminal/mirror/registered-window-guard.ts +66 -0
- package/packages/daemon/src/terminal/mirror/session-channel.ts +92 -4
- package/packages/daemon/src/terminal/mirror/shared-window-index.ts +42 -0
- package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +12 -1
- package/packages/daemon/src/terminal/session-runtime/multiplexer-backend.ts +2 -0
- package/packages/daemon/src/terminal/session-runtime/registry.ts +70 -8
- package/packages/daemon/src/terminal/session-runtime/semantic-mutation-executor.ts +3 -1
- package/packages/daemon/src/tui/mirror/dialog-model.ts +2 -32
- package/packages/daemon/src/tui/mirror/runtime/application-daemon-authority-owner.ts +8 -0
- package/packages/daemon/src/tui/mirror/runtime/application-home-fleet.ts +19 -2
- package/packages/daemon/src/tui/mirror/runtime/application-machine-agents.ts +6 -1
- package/packages/daemon/src/tui/mirror/runtime/application-machine-authority.ts +60 -11
- package/packages/daemon/src/tui/mirror/runtime/application-machine-navigation.ts +39 -33
- package/packages/daemon/src/tui/mirror/runtime/application-machine-sidebar.tsx +31 -23
- package/packages/daemon/src/tui/mirror/runtime/application-machine-startup.ts +38 -2
- package/packages/daemon/src/tui/mirror/runtime/application-palette-search-owner.ts +7 -4
- package/packages/daemon/src/tui/mirror/runtime/application-performance-log.ts +3 -0
- package/packages/daemon/src/tui/mirror/runtime/application-root-v2.tsx +1 -1
- package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +47 -46
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-input-ingress.ts +165 -2
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +207 -53
- package/packages/daemon/src/tui/mirror/runtime/bounded-performance-record-writer.ts +49 -9
- package/packages/daemon/src/tui/mirror/runtime/terminal-fast-lane-renderer-adapter.ts +6 -5
- package/packages/daemon/src/tui/mirror/runtime/terminal-pane-input-router.ts +4 -0
- package/packages/daemon/src/tui/mirror/runtime/workspace-terminal-fast-lane.ts +8 -3
- package/packages/daemon/src/tui/mirror/terminal-text.ts +32 -0
- package/packages/daemon/src/tui/mirror/workspace/connection-feedback.ts +6 -3
- package/packages/daemon-client/src/fleet-connection-status.ts +10 -1
- package/packages/daemon-client/src/workspace-client.ts +4 -1
- package/packages/contracts/src/__tests__/actions-contract.test.ts +0 -119
- package/packages/contracts/src/__tests__/agent-graph-overlay.test.ts +0 -428
- package/packages/contracts/src/__tests__/app-window-mutation.test.ts +0 -51
- package/packages/contracts/src/__tests__/app-window-state.test.ts +0 -34
- package/packages/contracts/src/__tests__/application-shell.test.ts +0 -645
- package/packages/contracts/src/__tests__/automation-operations.test.ts +0 -78
- package/packages/contracts/src/__tests__/causal-cell.test.ts +0 -47
- package/packages/contracts/src/__tests__/client-view-state.test.ts +0 -115
- package/packages/contracts/src/__tests__/cohesion-fixture.test.ts +0 -106
- package/packages/contracts/src/__tests__/commands.test.ts +0 -86
- package/packages/contracts/src/__tests__/control.test.ts +0 -154
- package/packages/contracts/src/__tests__/daemon-events.test.ts +0 -405
- package/packages/contracts/src/__tests__/daemon-resources.test.ts +0 -143
- package/packages/contracts/src/__tests__/daemon-wire.test.ts +0 -149
- package/packages/contracts/src/__tests__/desktop-host.test.ts +0 -269
- package/packages/contracts/src/__tests__/desktop-missions.test.ts +0 -215
- package/packages/contracts/src/__tests__/experience-conformance.test.ts +0 -153
- package/packages/contracts/src/__tests__/experience-kernel-boundary.test.ts +0 -113
- package/packages/contracts/src/__tests__/experience-shell.test.ts +0 -65
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v2.json +0 -35
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v3.json +0 -35
- package/packages/contracts/src/__tests__/fixtures/daemon-wire-v4.json +0 -35
- package/packages/contracts/src/__tests__/fixtures/scoped-receipt.ts +0 -62
- package/packages/contracts/src/__tests__/fleet-agent-graph.test.ts +0 -231
- package/packages/contracts/src/__tests__/fleet-catalog.test.ts +0 -270
- package/packages/contracts/src/__tests__/fleet-lifecycle.test.ts +0 -62
- package/packages/contracts/src/__tests__/focus-overlay.test.ts +0 -110
- package/packages/contracts/src/__tests__/ide-config.test.ts +0 -64
- package/packages/contracts/src/__tests__/interaction-evidence.test.ts +0 -288
- package/packages/contracts/src/__tests__/interaction-receipt-v2.test.ts +0 -72
- package/packages/contracts/src/__tests__/issue-error.test.ts +0 -78
- package/packages/contracts/src/__tests__/mission-projections.test.ts +0 -186
- package/packages/contracts/src/__tests__/missions.test.ts +0 -272
- package/packages/contracts/src/__tests__/multiplexer-verbs.test.ts +0 -242
- package/packages/contracts/src/__tests__/pane-appearance.test.ts +0 -146
- package/packages/contracts/src/__tests__/pane-read-result.test.ts +0 -55
- package/packages/contracts/src/__tests__/pane-stream.test.ts +0 -536
- package/packages/contracts/src/__tests__/pane-widget-marker.test.ts +0 -327
- package/packages/contracts/src/__tests__/performance-metrics.test.ts +0 -73
- package/packages/contracts/src/__tests__/performance-qualification.test.ts +0 -137
- package/packages/contracts/src/__tests__/rich-card-widget.test.ts +0 -29
- package/packages/contracts/src/__tests__/session-runtime.test.ts +0 -512
- package/packages/contracts/src/__tests__/startup-readiness.test.ts +0 -409
- package/packages/contracts/src/__tests__/terminal-attachment-stream.test.ts +0 -72
- package/packages/contracts/src/__tests__/terminal-attachments.test.ts +0 -329
- package/packages/contracts/src/__tests__/terminal-delivery.test.ts +0 -88
- package/packages/contracts/src/__tests__/terminal-runtime-inventory.test.ts +0 -68
- package/packages/contracts/src/__tests__/terminals.test.ts +0 -87
- package/packages/contracts/src/__tests__/tmux-server-scope.test.ts +0 -166
- package/packages/contracts/src/__tests__/transport-contract-loading.test.ts +0 -91
- package/packages/contracts/src/__tests__/visual-tokens.test.ts +0 -224
- package/packages/contracts/src/__tests__/window-links.test.ts +0 -243
- package/packages/contracts/src/__tests__/workspace-changes-resource.test.ts +0 -317
- package/packages/contracts/src/__tests__/workspace-changes-view.test.ts +0 -122
- package/packages/contracts/src/__tests__/workspace-config.test.ts +0 -294
- package/packages/contracts/src/__tests__/workspace-files-resource.test.ts +0 -261
- package/packages/contracts/src/__tests__/workspace-files-tree.test.ts +0 -147
- package/packages/contracts/src/__tests__/workspace-pane-creation.test.ts +0 -249
- package/packages/contracts/src/__tests__/workspace-promotion.test.ts +0 -94
- package/packages/contracts/src/__tests__/workspace-resource-identity.test.ts +0 -90
- package/packages/contracts/src/daemon-resource-request.test.ts +0 -192
- package/packages/contracts/src/native-operation-identity.test.ts +0 -23
- package/packages/contracts/src/workspace-admission.test.ts +0 -21
- package/packages/contracts/src/workspace-catalog-resource.test.ts +0 -146
- package/packages/core/src/agent-provisioning.test.ts +0 -42
- package/packages/core/src/application-shell-session.test.ts +0 -105
- package/packages/core/src/interaction-evidence.test.ts +0 -134
- package/packages/core/src/interaction-flow.test.ts +0 -66
- package/packages/core/src/interaction-receipts.test.ts +0 -671
- package/packages/core/src/navigator.test.ts +0 -34
- package/packages/core/src/optimistic-projection-conformance.test.ts +0 -75
- package/packages/core/src/optimistic-projection.test.ts +0 -118
- package/packages/core/src/performance-metrics.test.ts +0 -121
- package/packages/core/src/performance-qualification.test.ts +0 -283
- package/packages/core/src/saved-machines.test.ts +0 -80
- package/packages/core/src/terminal-compact-cold.test.ts +0 -87
- package/packages/core/src/terminal-conformance.test.ts +0 -48
- package/packages/core/src/terminal-delivery-cache-lifetime.test.ts +0 -167
- package/packages/core/src/terminal-delivery-encode-cooperative.test.ts +0 -140
- package/packages/core/src/terminal-delivery-representation-hash.test.ts +0 -77
- package/packages/core/src/terminal-delivery.test.ts +0 -1471
- package/packages/core/src/terminal-fnv64-wasm.test.ts +0 -61
- package/packages/core/src/terminal-replica-cold.test.ts +0 -31
- package/packages/core/src/terminal-replica-cooperative.test.ts +0 -170
- package/packages/core/src/terminal-replica-hash-cache.test.ts +0 -283
- package/packages/core/src/terminal-replica.test.ts +0 -347
- package/packages/core/src/workspace-selection.test.ts +0 -63
- package/packages/daemon/dist/__tests__/support.js +0 -33
- package/packages/daemon/dist/lib/__tests__/fixtures/workspace-state-writer.js +0 -58
- package/packages/daemon/dist/lib/__tests__/installed-recovery-fixture.js +0 -400
- package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.js +0 -182
- package/packages/daemon/dist/terminal/mirror/__tests__/scripted-channel.js +0 -98
- package/packages/daemon/dist/terminal/mirror/__tests__/simulated-channel.js +0 -156
- package/packages/daemon/src/tui/mirror/__snapshots__/activity-surface-renderer.test.tsx.snap +0 -42
- package/packages/daemon/src/tui/mirror/__snapshots__/changes-terminal-surface-renderer.test.tsx.snap +0 -267
- package/packages/daemon/src/tui/mirror/__snapshots__/home-files-surface-renderer.test.tsx.snap +0 -267
- package/packages/daemon/src/tui/mirror/__snapshots__/missions-surface-renderer.test.tsx.snap +0 -134
- package/packages/daemon/src/tui/mirror/__snapshots__/recipes-gallery-renderer.test.tsx.snap +0 -141
- package/packages/daemon/src/tui/mirror/__snapshots__/shell-chrome-renderer.test.tsx.snap +0 -134
- package/packages/daemon/src/tui/mirror/runtime/__snapshots__/application-shell-view-renderer.test.tsx.snap +0 -87
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/agent-terminal-canvas-renderer.test.tsx.snap +0 -348
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/application-shell-renderer.test.tsx.snap +0 -134
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/command-palette-surface-renderer.test.tsx.snap +0 -255
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/pane-frame-renderer.test.tsx.snap +0 -525
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/terminal-pane-header-polish-renderer.test.tsx.snap +0 -31
- package/packages/daemon/src/tui/mirror/workspace/__snapshots__/workbench-shell-renderer.test.tsx.snap +0 -134
- package/packages/daemon-client/src/application-shell-session.test.ts +0 -196
- package/packages/daemon-client/src/automation-client.test.ts +0 -214
- package/packages/daemon-client/src/bootstrap-coordinator.test.ts +0 -145
- package/packages/daemon-client/src/connection-supervisor.test.ts +0 -109
- package/packages/daemon-client/src/direct-application-shell-transport.test.ts +0 -941
- package/packages/daemon-client/src/first-latest-coordinator.test.ts +0 -175
- package/packages/daemon-client/src/fleet-dial-scheduler.test.ts +0 -114
- package/packages/daemon-client/src/fleet-environments.test.ts +0 -40
- package/packages/daemon-client/src/generation-bound-store-timers.test.ts +0 -74
- package/packages/daemon-client/src/owner-action-client.test.ts +0 -245
- package/packages/daemon-client/src/pane-stream-client.test.ts +0 -2841
- package/packages/daemon-client/src/pane-stream-clock-calibration.test.ts +0 -207
- package/packages/daemon-client/src/pane-stream-loopback-benchmark.test.ts +0 -51
- package/packages/daemon-client/src/push-resource-session.test.ts +0 -509
- package/packages/daemon-client/src/resource-replica.test.ts +0 -186
- package/packages/daemon-client/src/runtime-resource-ledger.test.ts +0 -18
- package/packages/daemon-client/src/scoped-tmux-server-transport.test.ts +0 -114
- package/packages/daemon-client/src/terminal-fast-lane.test.ts +0 -835
- package/packages/daemon-client/src/tmux-server-client.test.ts +0 -279
- package/packages/daemon-client/src/tmux-server-interaction-events.test.ts +0 -230
- package/packages/daemon-client/src/workspace-catalog-v2.test.ts +0 -109
- package/packages/daemon-client/src/workspace-client-boundaries.test.ts +0 -59
- package/packages/daemon-client/src/workspace-client-operations.test.ts +0 -96
- package/packages/daemon-client/src/workspace-client.test.ts +0 -2912
- package/packages/daemon-client/src/workspace-event-supervisor.test.ts +0 -1086
- package/packages/daemon-client/src/workspace-pane-client.test.ts +0 -80
- package/packages/presentation/src/presentation-contract.test.ts +0 -63
- package/packages/tmux-bridge/src/runner.test.ts +0 -614
- package/packages/tmux-bridge/src/targeting.test.ts +0 -107
|
@@ -2,20 +2,25 @@
|
|
|
2
2
|
export class BoundedPerformanceRecordWriter {
|
|
3
3
|
#sink;
|
|
4
4
|
#criticalLimit;
|
|
5
|
-
#pendingCritical = new
|
|
5
|
+
#pendingCritical = new Set();
|
|
6
|
+
#pending = [];
|
|
7
|
+
#pendingByteLimit;
|
|
8
|
+
#pendingBytes = 0;
|
|
9
|
+
#flushPromise = null;
|
|
10
|
+
#resolveFlush = null;
|
|
6
11
|
#saturated = false;
|
|
7
12
|
#failed = false;
|
|
8
13
|
#droppedRecords = 0;
|
|
9
|
-
constructor(sink, criticalLimit = 16) {
|
|
14
|
+
constructor(sink, criticalLimit = 16, pendingByteLimit = 64 * 1024) {
|
|
10
15
|
this.#sink = sink;
|
|
11
16
|
this.#criticalLimit = criticalLimit;
|
|
17
|
+
this.#pendingByteLimit = pendingByteLimit;
|
|
12
18
|
}
|
|
13
19
|
write(record) {
|
|
14
20
|
if (this.#failed)
|
|
15
21
|
return false;
|
|
16
22
|
if (this.#saturated) {
|
|
17
|
-
this.#
|
|
18
|
-
return false;
|
|
23
|
+
return this.#enqueue(record);
|
|
19
24
|
}
|
|
20
25
|
return this.#writeAccepted(record);
|
|
21
26
|
}
|
|
@@ -30,22 +35,57 @@ export class BoundedPerformanceRecordWriter {
|
|
|
30
35
|
this.#droppedRecords += 1;
|
|
31
36
|
return false;
|
|
32
37
|
}
|
|
33
|
-
this.#
|
|
34
|
-
return true;
|
|
38
|
+
return this.#enqueue(record, key);
|
|
35
39
|
}
|
|
36
40
|
drain() {
|
|
37
41
|
if (this.#failed)
|
|
38
42
|
return;
|
|
39
43
|
this.#saturated = false;
|
|
40
|
-
|
|
41
|
-
this.#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
while (this.#pending.length > 0 && !this.#saturated && !this.#failed) {
|
|
45
|
+
const next = this.#pending.shift();
|
|
46
|
+
this.#pendingBytes -= next.bytes;
|
|
47
|
+
if (next.key !== undefined)
|
|
48
|
+
this.#pendingCritical.delete(next.key);
|
|
49
|
+
this.#writeAccepted(next.record);
|
|
44
50
|
}
|
|
51
|
+
if (this.#pending.length === 0)
|
|
52
|
+
this.#finishFlush();
|
|
53
|
+
}
|
|
54
|
+
/** Wait until retained records reach the stream; its owner then flushes/end()s it. */
|
|
55
|
+
flush() {
|
|
56
|
+
if (this.#failed || this.#pending.length === 0)
|
|
57
|
+
return Promise.resolve();
|
|
58
|
+
this.#flushPromise ??= new Promise((resolve) => {
|
|
59
|
+
this.#resolveFlush = resolve;
|
|
60
|
+
});
|
|
61
|
+
return this.#flushPromise;
|
|
45
62
|
}
|
|
46
63
|
fail() {
|
|
47
64
|
this.#failed = true;
|
|
48
65
|
this.#pendingCritical.clear();
|
|
66
|
+
this.#pending.length = 0;
|
|
67
|
+
this.#pendingBytes = 0;
|
|
68
|
+
this.#finishFlush();
|
|
69
|
+
}
|
|
70
|
+
#enqueue(record, key) {
|
|
71
|
+
const bytes = Buffer.byteLength(record);
|
|
72
|
+
// Ordinary bursts get one extra stream-sized buffer. Critical records have
|
|
73
|
+
// a separate byte reserve as well as their existing key-count limit.
|
|
74
|
+
const limit = this.#pendingByteLimit + (key === undefined ? 0 : 64 * 1024);
|
|
75
|
+
if (this.#pending.length >= 1024 || this.#pendingBytes + bytes > limit) {
|
|
76
|
+
this.#droppedRecords += 1;
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (key !== undefined)
|
|
80
|
+
this.#pendingCritical.add(key);
|
|
81
|
+
this.#pending.push({ record, bytes, ...(key === undefined ? {} : { key }) });
|
|
82
|
+
this.#pendingBytes += bytes;
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
#finishFlush() {
|
|
86
|
+
this.#resolveFlush?.();
|
|
87
|
+
this.#resolveFlush = null;
|
|
88
|
+
this.#flushPromise = null;
|
|
49
89
|
}
|
|
50
90
|
diagnostics() {
|
|
51
91
|
return Object.freeze({
|
|
@@ -271,12 +271,13 @@ export class TerminalFastLaneRendererAdapter {
|
|
|
271
271
|
]);
|
|
272
272
|
if (seen.has(key))
|
|
273
273
|
continue;
|
|
274
|
+
// Bound retained de-duplication history, not the renderer's lifetime.
|
|
275
|
+
// An evicted identity may be reported again only after another real paint.
|
|
276
|
+
// Pending identities still have their separate per-frame admission limit.
|
|
274
277
|
if (seen.size >= 256)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
identities.push(identity);
|
|
279
|
-
}
|
|
278
|
+
seen.delete(seen.values().next().value);
|
|
279
|
+
seen.add(key);
|
|
280
|
+
identities.push(identity);
|
|
280
281
|
}
|
|
281
282
|
const dropped = this.#droppedCanonicalHostFrames;
|
|
282
283
|
this.#droppedCanonicalHostFrames = 0;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createTerminalFastLane, createWorkspaceClientTerminalSource, } from "@tmux-ide/daemon-client/terminal-fast-lane";
|
|
2
2
|
import { currentTuiPerformanceEventSink } from "../performance-events.js";
|
|
3
|
+
// Limit outstanding low-water sampling chains, not completed observations over
|
|
4
|
+
// the lifetime of a renderer. Each chain owns at most one pending timeout.
|
|
3
5
|
const TERMINAL_RESOURCE_SAMPLE_LIMIT = 512;
|
|
4
6
|
// The ProductRig idle proof reads after 10.1s. Emit just before that boundary
|
|
5
7
|
// so the operation-scoped sample cannot race the proof read.
|
|
@@ -227,7 +229,7 @@ function createOpenTuiTerminalResourceSampler(lane, sink) {
|
|
|
227
229
|
heartbeatTimer = setTimeout(heartbeat, TERMINAL_RESOURCE_HEARTBEAT_MS);
|
|
228
230
|
heartbeatTimer.unref?.();
|
|
229
231
|
const emit = (operation, identity, expectedAt, sampled) => {
|
|
230
|
-
if (disposed || resourceEpochIdentity === null
|
|
232
|
+
if (disposed || resourceEpochIdentity === null)
|
|
231
233
|
return;
|
|
232
234
|
ordinal += 1;
|
|
233
235
|
const now = readDiagnosticNow();
|
|
@@ -373,8 +375,12 @@ function createOpenTuiTerminalResourceSampler(lane, sink) {
|
|
|
373
375
|
};
|
|
374
376
|
return {
|
|
375
377
|
afterFence(identity) {
|
|
376
|
-
if (disposed
|
|
378
|
+
if (disposed)
|
|
379
|
+
return;
|
|
380
|
+
if (pending.size >= TERMINAL_RESOURCE_SAMPLE_LIMIT) {
|
|
381
|
+
recordSamplingFailure();
|
|
377
382
|
return;
|
|
383
|
+
}
|
|
378
384
|
latestIdentity = identity;
|
|
379
385
|
let now;
|
|
380
386
|
if (resourceEpochIdentity === null) {
|
|
@@ -50,3 +50,38 @@ function graphemes(text) {
|
|
|
50
50
|
return [...new Segmenter(undefined, { granularity: "grapheme" }).segment(text)].map((entry) => entry.segment);
|
|
51
51
|
return [...text];
|
|
52
52
|
}
|
|
53
|
+
/** PURE — greedy word-wrap for terminal prose (never returns empty for
|
|
54
|
+
* non-empty text; words longer than the width hard-break). */
|
|
55
|
+
export function wrapText(text, width) {
|
|
56
|
+
if (width <= 0)
|
|
57
|
+
return [text];
|
|
58
|
+
const out = [];
|
|
59
|
+
for (const para of text.split("\n")) {
|
|
60
|
+
let line = "";
|
|
61
|
+
for (const word of para.split(/\s+/).filter(Boolean)) {
|
|
62
|
+
if (line.length === 0) {
|
|
63
|
+
let w = word;
|
|
64
|
+
while (w.length > width) {
|
|
65
|
+
out.push(w.slice(0, width));
|
|
66
|
+
w = w.slice(width);
|
|
67
|
+
}
|
|
68
|
+
line = w;
|
|
69
|
+
}
|
|
70
|
+
else if (line.length + 1 + word.length <= width) {
|
|
71
|
+
line += ` ${word}`;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
out.push(line);
|
|
75
|
+
let w = word;
|
|
76
|
+
while (w.length > width) {
|
|
77
|
+
out.push(w.slice(0, width));
|
|
78
|
+
w = w.slice(width);
|
|
79
|
+
}
|
|
80
|
+
line = w;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (line.length > 0 || para.length === 0)
|
|
84
|
+
out.push(line);
|
|
85
|
+
}
|
|
86
|
+
return out.length > 0 ? out : [""];
|
|
87
|
+
}
|
|
@@ -156,9 +156,11 @@ export function createApplicationConnectionFeedback(onPublish = () => undefined)
|
|
|
156
156
|
failure,
|
|
157
157
|
...(inventory
|
|
158
158
|
? {
|
|
159
|
-
recovery:
|
|
160
|
-
? "A
|
|
161
|
-
:
|
|
159
|
+
recovery: failure.reason === "duplicate-runtime-pane-binding"
|
|
160
|
+
? "A terminal is shared by multiple workspace entries. Unlink shared tmux windows so each belongs to one session, then select Retry."
|
|
161
|
+
: missing
|
|
162
|
+
? "A registered session may have been recreated. Choose that session to restore its identity, then retry here. It may be a different session."
|
|
163
|
+
: "Terminal identities conflict or cannot be verified. Copy connection details for diagnosis; Retry does not repair identity conflicts.",
|
|
162
164
|
}
|
|
163
165
|
: {}),
|
|
164
166
|
};
|
|
@@ -546,16 +546,7 @@ export function createDefaultFleetFactsReaders(): Pick<
|
|
|
546
546
|
return null;
|
|
547
547
|
}
|
|
548
548
|
};
|
|
549
|
-
return
|
|
550
|
-
readSessions: async (signal) => {
|
|
551
|
-
const raw = await execute(SESSION_COMPOSITION_TMUX_ARGS, signal);
|
|
552
|
-
return raw === null ? null : parseSessionCompositionFacts(raw);
|
|
553
|
-
},
|
|
554
|
-
readAgents: async (signal) => {
|
|
555
|
-
const raw = await execute(AGENT_STATE_TMUX_ARGS, signal);
|
|
556
|
-
return raw === null ? null : parseAgentStateFacts(raw);
|
|
557
|
-
},
|
|
558
|
-
};
|
|
549
|
+
return createSharedFleetFactsReaders(execute);
|
|
559
550
|
}
|
|
560
551
|
|
|
561
552
|
export const SESSION_COMPOSITION_TMUX_ARGS = [
|
|
@@ -593,3 +584,102 @@ export const AGENT_STATE_TMUX_ARGS = [
|
|
|
593
584
|
export async function readAgentStateFacts(signal?: AbortSignal): Promise<AgentStateReading | null> {
|
|
594
585
|
return createDefaultFleetFactsReaders().readAgents(signal);
|
|
595
586
|
}
|
|
587
|
+
|
|
588
|
+
/** Agent columns are excluded from the session topology projection. */
|
|
589
|
+
export const FLEET_FACTS_TMUX_ARGS = [
|
|
590
|
+
"list-panes",
|
|
591
|
+
"-a",
|
|
592
|
+
"-F",
|
|
593
|
+
`${SESSION_COMPOSITION_TMUX_ARGS[3]}\t#{@agent_state}\t#{pane_current_command}`,
|
|
594
|
+
] as const;
|
|
595
|
+
|
|
596
|
+
/** Share only an outstanding read; completed snapshots are never cached. */
|
|
597
|
+
export function createSharedFleetFactsReaders(
|
|
598
|
+
run: (args: readonly string[], signal?: AbortSignal) => string | null | Promise<string | null>,
|
|
599
|
+
isAbsentServer: (error: unknown) => boolean = () => false,
|
|
600
|
+
): Pick<DaemonFleetFactsObserverOptions, "readSessions" | "readAgents"> {
|
|
601
|
+
interface Pending {
|
|
602
|
+
controller: AbortController;
|
|
603
|
+
result: Promise<string | null>;
|
|
604
|
+
readers: number;
|
|
605
|
+
}
|
|
606
|
+
let pending: Pending | null = null;
|
|
607
|
+
const read = async (signal?: AbortSignal): Promise<string | null> => {
|
|
608
|
+
if (signal?.aborted) return null;
|
|
609
|
+
if (!pending) {
|
|
610
|
+
const controller = new AbortController();
|
|
611
|
+
const entry: Pending = {
|
|
612
|
+
controller,
|
|
613
|
+
readers: 0,
|
|
614
|
+
result: Promise.resolve().then(() => run(FLEET_FACTS_TMUX_ARGS, controller.signal)),
|
|
615
|
+
};
|
|
616
|
+
entry.result = entry.result.finally(() => {
|
|
617
|
+
if (pending === entry) pending = null;
|
|
618
|
+
});
|
|
619
|
+
pending = entry;
|
|
620
|
+
}
|
|
621
|
+
const entry = pending;
|
|
622
|
+
entry.readers += 1;
|
|
623
|
+
let released = false;
|
|
624
|
+
const release = () => {
|
|
625
|
+
if (released) return;
|
|
626
|
+
released = true;
|
|
627
|
+
entry.readers -= 1;
|
|
628
|
+
if (entry.readers === 0) {
|
|
629
|
+
if (pending === entry) pending = null;
|
|
630
|
+
entry.controller.abort();
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
signal?.addEventListener("abort", release, { once: true });
|
|
634
|
+
try {
|
|
635
|
+
// Keep the promise outstanding for a noncooperative runner so the
|
|
636
|
+
// observer's per-kind quarantine remains effective after cancellation.
|
|
637
|
+
const raw = await entry.result;
|
|
638
|
+
return signal?.aborted ? null : raw;
|
|
639
|
+
} catch (error) {
|
|
640
|
+
if (signal?.aborted) return null;
|
|
641
|
+
throw error;
|
|
642
|
+
} finally {
|
|
643
|
+
signal?.removeEventListener("abort", release);
|
|
644
|
+
release();
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
return {
|
|
648
|
+
readSessions: async (signal) => {
|
|
649
|
+
try {
|
|
650
|
+
const raw = await read(signal);
|
|
651
|
+
return raw === null
|
|
652
|
+
? null
|
|
653
|
+
: parseSessionCompositionFacts(
|
|
654
|
+
raw
|
|
655
|
+
.split("\n")
|
|
656
|
+
.map((line) => line.split("\t").slice(0, 11).join("\t"))
|
|
657
|
+
.join("\n"),
|
|
658
|
+
);
|
|
659
|
+
} catch (error) {
|
|
660
|
+
// Socket absence is an authoritative empty catalog, but must not
|
|
661
|
+
// manufacture agent turn completions from a failed agent observation.
|
|
662
|
+
return isAbsentServer(error) ? parseSessionCompositionFacts("") : null;
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
readAgents: async (signal) => {
|
|
666
|
+
try {
|
|
667
|
+
const raw = await read(signal);
|
|
668
|
+
return raw === null
|
|
669
|
+
? null
|
|
670
|
+
: parseAgentStateFacts(
|
|
671
|
+
raw
|
|
672
|
+
.split("\n")
|
|
673
|
+
.map((line) => {
|
|
674
|
+
const fields = line.split("\t");
|
|
675
|
+
if (fields.length !== 13) return "";
|
|
676
|
+
return [fields[0], fields[6], fields[9], fields[11], fields[12]].join("\t");
|
|
677
|
+
})
|
|
678
|
+
.join("\n"),
|
|
679
|
+
);
|
|
680
|
+
} catch {
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
};
|
|
685
|
+
}
|
|
@@ -2,13 +2,22 @@ import type { Hono } from "hono";
|
|
|
2
2
|
import { bodyLimit } from "hono/body-limit";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { SavedMachineRegistrySchema, type DaemonInstanceIdentity } from "@tmux-ide/contracts";
|
|
5
|
-
import {
|
|
5
|
+
import { SavedMachineMutationSchema } from "@tmux-ide/contracts/saved-machines";
|
|
6
|
+
import {
|
|
7
|
+
loadSavedMachines,
|
|
8
|
+
mergeSavedMachines,
|
|
9
|
+
updateSavedMachines,
|
|
10
|
+
} from "../../lib/saved-machines.ts";
|
|
6
11
|
import { ownerAuthorityGate } from "../owner-authority.ts";
|
|
7
12
|
|
|
8
13
|
const Request = z.strictObject({
|
|
9
14
|
expectedInstanceId: z.uuid(),
|
|
10
15
|
registry: SavedMachineRegistrySchema,
|
|
11
16
|
});
|
|
17
|
+
const MutationRequest = z.strictObject({
|
|
18
|
+
expectedInstanceId: z.uuid(),
|
|
19
|
+
change: SavedMachineMutationSchema,
|
|
20
|
+
});
|
|
12
21
|
export function mountSavedMachineRoute(
|
|
13
22
|
app: Hono,
|
|
14
23
|
options: {
|
|
@@ -16,6 +25,7 @@ export function mountSavedMachineRoute(
|
|
|
16
25
|
ownerToken: string | null;
|
|
17
26
|
read?: typeof loadSavedMachines;
|
|
18
27
|
merge?: typeof mergeSavedMachines;
|
|
28
|
+
update?: typeof updateSavedMachines;
|
|
19
29
|
},
|
|
20
30
|
) {
|
|
21
31
|
const authorize = ownerAuthorityGate(options.ownerToken, {
|
|
@@ -56,4 +66,41 @@ export function mountSavedMachineRoute(
|
|
|
56
66
|
);
|
|
57
67
|
}
|
|
58
68
|
});
|
|
69
|
+
app.patch("/api/resources/saved-machines", bodyLimit({ maxSize: 1024 }), async (c) => {
|
|
70
|
+
const gate = authorize(c);
|
|
71
|
+
if (gate) return gate;
|
|
72
|
+
c.header("Cache-Control", "no-store");
|
|
73
|
+
let parsed;
|
|
74
|
+
try {
|
|
75
|
+
parsed = MutationRequest.safeParse(await c.req.json());
|
|
76
|
+
} catch {
|
|
77
|
+
return c.json({ error: "Invalid machine mutation" }, 400);
|
|
78
|
+
}
|
|
79
|
+
if (!parsed.success) return c.json({ error: "Invalid machine mutation" }, 400);
|
|
80
|
+
if (parsed.data.expectedInstanceId !== options.daemon.instanceId)
|
|
81
|
+
return c.json({ error: "Daemon generation changed" }, 409);
|
|
82
|
+
const change = parsed.data.change;
|
|
83
|
+
const { id, operation } = change;
|
|
84
|
+
try {
|
|
85
|
+
const registry = (options.update ?? updateSavedMachines)(
|
|
86
|
+
operation === "remove"
|
|
87
|
+
? { type: "remove", id }
|
|
88
|
+
: {
|
|
89
|
+
type: "update",
|
|
90
|
+
id,
|
|
91
|
+
patch:
|
|
92
|
+
change.operation === "edit" ? change.patch : { enabled: operation === "enable" },
|
|
93
|
+
},
|
|
94
|
+
);
|
|
95
|
+
return c.json({ daemon: options.daemon, registry });
|
|
96
|
+
} catch {
|
|
97
|
+
return c.json(
|
|
98
|
+
{
|
|
99
|
+
error:
|
|
100
|
+
"Machine not found, edit conflicts with another profile, or registry unavailable; nothing changed",
|
|
101
|
+
},
|
|
102
|
+
409,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
59
106
|
}
|
|
@@ -17,11 +17,8 @@ import { discoverSessions, buildOverviews, buildProjectDetail } from "./discover
|
|
|
17
17
|
import type { AgentTurnCompletion } from "./agent-status-watch.ts";
|
|
18
18
|
import {
|
|
19
19
|
DaemonFleetFactsObserver,
|
|
20
|
-
AGENT_STATE_TMUX_ARGS,
|
|
21
|
-
parseAgentStateFacts,
|
|
22
|
-
parseSessionCompositionFacts,
|
|
23
20
|
createDefaultFleetFactsReaders,
|
|
24
|
-
|
|
21
|
+
createSharedFleetFactsReaders,
|
|
25
22
|
type DaemonFleetFactsObserverOptions,
|
|
26
23
|
type DaemonFleetFactsObserverDiagnostic,
|
|
27
24
|
} from "./daemon-fleet-facts-observer.ts";
|
|
@@ -431,28 +428,11 @@ export function setFleetFactsTmuxRunner(
|
|
|
431
428
|
runTmux: ((args: readonly string[], signal?: AbortSignal) => string | Promise<string>) | null,
|
|
432
429
|
): void {
|
|
433
430
|
stopFleetFactsObserver();
|
|
434
|
-
|
|
435
|
-
?
|
|
436
|
-
try {
|
|
437
|
-
return parseSessionCompositionFacts(await runTmux(SESSION_COMPOSITION_TMUX_ARGS, signal));
|
|
438
|
-
} catch (error) {
|
|
439
|
-
// A daemon may legitimately precede the first tmux server. Socket
|
|
440
|
-
// absence is an authoritative empty fleet baseline, not a failed
|
|
441
|
-
// observation: catalog clients must be allowed to render their
|
|
442
|
-
// actionable first-run state while the observer waits for tmux.
|
|
443
|
-
return isTmuxServerUnavailableError(error) ? parseSessionCompositionFacts("") : null;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
: null;
|
|
447
|
-
agentStateReaderOverride = runTmux
|
|
448
|
-
? async (signal) => {
|
|
449
|
-
try {
|
|
450
|
-
return parseAgentStateFacts(await runTmux(AGENT_STATE_TMUX_ARGS, signal));
|
|
451
|
-
} catch {
|
|
452
|
-
return null;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
431
|
+
const readers = runTmux
|
|
432
|
+
? createSharedFleetFactsReaders(runTmux, isTmuxServerUnavailableError)
|
|
455
433
|
: null;
|
|
434
|
+
sessionCompositionReaderOverride = readers?.readSessions ?? null;
|
|
435
|
+
agentStateReaderOverride = readers?.readAgents ?? null;
|
|
456
436
|
}
|
|
457
437
|
|
|
458
438
|
interface ResourceObservationHandle {
|
|
@@ -236,6 +236,18 @@ async function replaceOlderCanonicalDaemon(
|
|
|
236
236
|
reason: "identity-mismatch",
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
|
+
const supervisor = latest.info.provenance?.supervisor;
|
|
240
|
+
if (!latest.info.supervisionId && (supervisor === "systemd" || supervisor === "launchd")) {
|
|
241
|
+
throw new DaemonBootstrapError(
|
|
242
|
+
"incompatible",
|
|
243
|
+
`The older canonical daemon is managed by ${supervisor} without a supervisor reservation. ` +
|
|
244
|
+
"Stop and disable the old service, reserve the stopped namespace with " +
|
|
245
|
+
"tmux-ide daemon reserve-supervisor <id>, then configure the service to run " +
|
|
246
|
+
"tmux-ide --headless --supervised <id> before restarting it. " +
|
|
247
|
+
"The existing daemon has been left running.",
|
|
248
|
+
{ reason: "canonical-record-invalid" },
|
|
249
|
+
);
|
|
250
|
+
}
|
|
239
251
|
await deps.shutdownOlderOwner(info);
|
|
240
252
|
const deadline = deps.now() + timeoutMs;
|
|
241
253
|
while (deps.now() < deadline) {
|
|
@@ -115,7 +115,12 @@ export type CanonicalDaemonInfoState =
|
|
|
115
115
|
};
|
|
116
116
|
|
|
117
117
|
export function getCanonicalDaemonInfoPath(): string {
|
|
118
|
-
|
|
118
|
+
const namespace = resolveRuntimeNamespace();
|
|
119
|
+
const path = join(namespace.daemonInfoDir, DAEMON_INFO_FILE);
|
|
120
|
+
// Resolution already validates ordinary and isolated namespaces. Only
|
|
121
|
+
// development adds a per-path containment check; do not resolve twice on
|
|
122
|
+
// every ordinary daemon read. Each call still resolves the current namespace.
|
|
123
|
+
return namespace.development ? runtimeOwnedPath(path) : path;
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
export function getCanonicalDaemonClaimPath(): string {
|
|
@@ -687,11 +692,48 @@ export function assertCanonicalDaemonSupervision(supervisionId: string): void {
|
|
|
687
692
|
}
|
|
688
693
|
|
|
689
694
|
/** Explicit installation only; startup never calls this to recreate a reservation. */
|
|
695
|
+
/** Sanitized reservation guidance; never includes credentials or filesystem errors. */
|
|
696
|
+
export class CanonicalDaemonReservationError extends Error {
|
|
697
|
+
constructor(message: string) {
|
|
698
|
+
super(`Supervisor reservation refused: ${message}`);
|
|
699
|
+
this.name = "CanonicalDaemonReservationError";
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function reservationRefusal(
|
|
704
|
+
attempt: Exclude<CanonicalDaemonClaimAttempt, { status: "acquired" }>,
|
|
705
|
+
): CanonicalDaemonReservationError {
|
|
706
|
+
if (attempt.status === "busy")
|
|
707
|
+
return new CanonicalDaemonReservationError(
|
|
708
|
+
`another lifecycle operation holds the namespace (PID ${attempt.owner.pid}). Wait for it to finish, then retry.`,
|
|
709
|
+
);
|
|
710
|
+
const state = inspectCanonicalDaemonInfo();
|
|
711
|
+
if (state.status === "valid")
|
|
712
|
+
return new CanonicalDaemonReservationError(
|
|
713
|
+
`the recorded ${state.info.supervisionId ? "supervised" : "unsupervised"} daemon (PID ${state.info.pid}) has not been released. Inspect it with tmux-ide daemon info --json, then stop it through its owning process or service before reserving.`,
|
|
714
|
+
);
|
|
715
|
+
if (state.status === "reserved")
|
|
716
|
+
return new CanonicalDaemonReservationError(
|
|
717
|
+
`this namespace is reserved for supervisor ${state.reservation.supervisionId}. Remove that service and release its reservation before assigning a different ID.`,
|
|
718
|
+
);
|
|
719
|
+
if (state.status === "invalid")
|
|
720
|
+
return new CanonicalDaemonReservationError(
|
|
721
|
+
`the namespace record cannot be trusted (${state.reason}). Run tmux-ide daemon info --json for diagnosis; repair ownership or permissions before retrying.`,
|
|
722
|
+
);
|
|
723
|
+
return new CanonicalDaemonReservationError(
|
|
724
|
+
"the namespace changed or its lifecycle claim is unavailable. Run tmux-ide daemon info --json, then retry after the owning operation finishes.",
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
|
|
690
728
|
export function reserveCanonicalDaemonSupervision(
|
|
691
729
|
supervisionId: string,
|
|
692
730
|
): CanonicalDaemonReservation {
|
|
731
|
+
if (!DaemonSupervisionIdSchema.safeParse(supervisionId).success)
|
|
732
|
+
throw new CanonicalDaemonReservationError(
|
|
733
|
+
"use a 1–128 character ID starting with a letter or digit and containing only letters, digits, periods, underscores or hyphens.",
|
|
734
|
+
);
|
|
693
735
|
const attempt = tryAcquireCanonicalDaemonClaim({ kind: "reserve", supervisionId });
|
|
694
|
-
if (attempt.status !== "acquired") throw
|
|
736
|
+
if (attempt.status !== "acquired") throw reservationRefusal(attempt);
|
|
695
737
|
const claim = attempt.claim;
|
|
696
738
|
try {
|
|
697
739
|
const before = inspectCanonicalDaemonInfo();
|
|
@@ -1436,6 +1436,7 @@ async function startEmbeddedDaemonGeneration(
|
|
|
1436
1436
|
if (!sessionRuntimeRegistry) throw new Error("Session runtime unavailable");
|
|
1437
1437
|
return sessionRuntimeRegistry.executeWindowLinkAction(session, action);
|
|
1438
1438
|
},
|
|
1439
|
+
timing,
|
|
1439
1440
|
);
|
|
1440
1441
|
}
|
|
1441
1442
|
if (intent.verb === "workspace.pane.resize") {
|