@agentdeck/bridge 1.0.4 → 1.0.5
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/assets/fm-helper/agentdeck-fm-helper +0 -0
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +3 -0
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adb-reverse.d.ts.map +1 -1
- package/dist/adb-reverse.js +4 -2
- package/dist/adb-reverse.js.map +1 -1
- package/dist/apme/collector.js +2 -2
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/outcome.js +2 -2
- package/dist/apme/outcome.js.map +1 -1
- package/dist/apme/runner.js +3 -3
- package/dist/apme/runner.js.map +1 -1
- package/dist/ble-sync-spawn.js +1 -1
- package/dist/ble-sync-spawn.js.map +1 -1
- package/dist/calendar.d.ts +82 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +324 -0
- package/dist/calendar.js.map +1 -0
- package/dist/card-feed.d.ts +63 -5
- package/dist/card-feed.d.ts.map +1 -1
- package/dist/card-feed.js +218 -14
- package/dist/card-feed.js.map +1 -1
- package/dist/card-modules.d.ts +4 -0
- package/dist/card-modules.d.ts.map +1 -1
- package/dist/card-modules.js +5 -3
- package/dist/card-modules.js.map +1 -1
- package/dist/check-deps.js +4 -4
- package/dist/check-deps.js.map +1 -1
- package/dist/cli.d.ts +35 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +269 -9
- package/dist/cli.js.map +1 -1
- package/dist/codex-otel.d.ts +89 -0
- package/dist/codex-otel.d.ts.map +1 -0
- package/dist/codex-otel.js +487 -0
- package/dist/codex-otel.js.map +1 -0
- package/dist/codex-rate-limits.d.ts.map +1 -1
- package/dist/codex-rate-limits.js +15 -3
- package/dist/codex-rate-limits.js.map +1 -1
- package/dist/daemon-server.d.ts +4 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +797 -54
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon-ws-client.d.ts +108 -24
- package/dist/daemon-ws-client.d.ts.map +1 -1
- package/dist/daemon-ws-client.js +175 -39
- package/dist/daemon-ws-client.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/device-voice-reply.d.ts.map +1 -1
- package/dist/device-voice-reply.js +15 -3
- package/dist/device-voice-reply.js.map +1 -1
- package/dist/device-voice.d.ts +37 -0
- package/dist/device-voice.d.ts.map +1 -1
- package/dist/device-voice.js +130 -1
- package/dist/device-voice.js.map +1 -1
- package/dist/diag-analyzer.d.ts.map +1 -1
- package/dist/diag-analyzer.js +1 -0
- package/dist/diag-analyzer.js.map +1 -1
- package/dist/display-monitor.d.ts.map +1 -1
- package/dist/display-monitor.js +1 -0
- package/dist/display-monitor.js.map +1 -1
- package/dist/esp32-serial.d.ts +4 -0
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +6 -3
- package/dist/esp32-serial.js.map +1 -1
- package/dist/foundation-models-helper.d.ts +23 -0
- package/dist/foundation-models-helper.d.ts.map +1 -1
- package/dist/foundation-models-helper.js +32 -0
- package/dist/foundation-models-helper.js.map +1 -1
- package/dist/gateway-probe.js +1 -1
- package/dist/gateway-probe.js.map +1 -1
- package/dist/glance-frame.d.ts +64 -0
- package/dist/glance-frame.d.ts.map +1 -0
- package/dist/glance-frame.js +364 -0
- package/dist/glance-frame.js.map +1 -0
- package/dist/hook-codex-sessions.d.ts +40 -0
- package/dist/hook-codex-sessions.d.ts.map +1 -0
- package/dist/hook-codex-sessions.js +174 -0
- package/dist/hook-codex-sessions.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts.map +1 -1
- package/dist/idotmatrix/idotmatrix-discover.js +7 -4
- package/dist/idotmatrix/idotmatrix-discover.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-settings.d.ts +15 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts.map +1 -1
- package/dist/idotmatrix/idotmatrix-settings.js +21 -0
- package/dist/idotmatrix/idotmatrix-settings.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -7
- package/dist/index.js.map +1 -1
- package/dist/linux-service.d.ts +52 -0
- package/dist/linux-service.d.ts.map +1 -0
- package/dist/linux-service.js +206 -0
- package/dist/linux-service.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -1
- package/dist/mdns-discover.d.ts +19 -0
- package/dist/mdns-discover.d.ts.map +1 -0
- package/dist/mdns-discover.js +109 -0
- package/dist/mdns-discover.js.map +1 -0
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +1 -0
- package/dist/model-catalog.js.map +1 -1
- package/dist/modules/adb-module.js +1 -1
- package/dist/modules/adb-module.js.map +1 -1
- package/dist/output-parser.d.ts +9 -0
- package/dist/output-parser.d.ts.map +1 -1
- package/dist/output-parser.js +67 -16
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +57 -8
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +210 -74
- package/dist/passive-observer.js.map +1 -1
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -1
- package/dist/pixoo/pixoo-bridge.js +47 -6
- package/dist/pixoo/pixoo-bridge.js.map +1 -1
- package/dist/pixoo/pixoo-renderer.d.ts +2 -1
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +137 -8
- package/dist/pixoo/pixoo-renderer.js.map +1 -1
- package/dist/pocket-autonomy.d.ts +78 -0
- package/dist/pocket-autonomy.d.ts.map +1 -0
- package/dist/pocket-autonomy.js +529 -0
- package/dist/pocket-autonomy.js.map +1 -0
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +3 -2
- package/dist/pty-manager.js.map +1 -1
- package/dist/python-ble-runtime.d.ts +2 -0
- package/dist/python-ble-runtime.d.ts.map +1 -1
- package/dist/python-ble-runtime.js +2 -1
- package/dist/python-ble-runtime.js.map +1 -1
- package/dist/remote-sessions.d.ts +64 -0
- package/dist/remote-sessions.d.ts.map +1 -0
- package/dist/remote-sessions.js +81 -0
- package/dist/remote-sessions.js.map +1 -0
- package/dist/review-runner.js +2 -2
- package/dist/review-runner.js.map +1 -1
- package/dist/session-aggregator.d.ts +2 -0
- package/dist/session-aggregator.d.ts.map +1 -1
- package/dist/session-aggregator.js +6 -1
- package/dist/session-aggregator.js.map +1 -1
- package/dist/session-focus-relay.d.ts +47 -1
- package/dist/session-focus-relay.d.ts.map +1 -1
- package/dist/session-focus-relay.js +130 -15
- package/dist/session-focus-relay.js.map +1 -1
- package/dist/session-push-channel.d.ts +31 -0
- package/dist/session-push-channel.d.ts.map +1 -0
- package/dist/session-push-channel.js +94 -0
- package/dist/session-push-channel.js.map +1 -0
- package/dist/session-registry.d.ts +126 -0
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +180 -3
- package/dist/session-registry.js.map +1 -1
- package/dist/subagent-timeline.d.ts +34 -0
- package/dist/subagent-timeline.d.ts.map +1 -0
- package/dist/subagent-timeline.js +156 -0
- package/dist/subagent-timeline.js.map +1 -0
- package/dist/timebox/timebox-discover.js +1 -1
- package/dist/timebox/timebox-discover.js.map +1 -1
- package/dist/tui/gauge.d.ts +4 -2
- package/dist/tui/gauge.d.ts.map +1 -1
- package/dist/tui/gauge.js +8 -4
- package/dist/tui/gauge.js.map +1 -1
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +28 -0
- package/dist/tui/renderer.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/usage-api.d.ts +43 -0
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +114 -9
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts +19 -0
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +35 -0
- package/dist/usage-event.js.map +1 -1
- package/dist/utils/project-name.d.ts.map +1 -1
- package/dist/utils/project-name.js +1 -0
- package/dist/utils/project-name.js.map +1 -1
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +3 -2
- package/dist/version-check.js.map +1 -1
- package/dist/voice-assistant.d.ts.map +1 -1
- package/dist/voice-assistant.js +2 -1
- package/dist/voice-assistant.js.map +1 -1
- package/dist/voice.d.ts.map +1 -1
- package/dist/voice.js +1 -0
- package/dist/voice.js.map +1 -1
- package/dist/weather.d.ts +72 -0
- package/dist/weather.d.ts.map +1 -0
- package/dist/weather.js +206 -0
- package/dist/weather.js.map +1 -0
- package/dist/windows-service.js +5 -5
- package/dist/windows-service.js.map +1 -1
- package/fm-helper/AgentDeckFMHelper.swift +200 -0
- package/package.json +15 -13
- package/src/idotmatrix/identity_generated.py +50 -0
- package/src/idotmatrix/scan.py +33 -13
|
@@ -14,8 +14,13 @@ import WebSocket from 'ws';
|
|
|
14
14
|
import { listActive as listActiveSessions } from './session-registry.js';
|
|
15
15
|
import { debug } from './logger.js';
|
|
16
16
|
const TAG = 'focus-relay';
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Events relayed from a focused session to daemon clients. Canonical set for
|
|
19
|
+
* BOTH ends of the relay: the daemon side filters here, and the worker side
|
|
20
|
+
* (`DaemonWsClient.forwardEvent`) imports this same set — the two ends cannot
|
|
21
|
+
* drift on which events ride the push socket.
|
|
22
|
+
*/
|
|
23
|
+
export const RELAYED_EVENTS = new Set([
|
|
19
24
|
'state_update',
|
|
20
25
|
'prompt_options',
|
|
21
26
|
'usage_update',
|
|
@@ -33,37 +38,136 @@ const ROUTED_COMMANDS = new Set([
|
|
|
33
38
|
export class SessionFocusRelay {
|
|
34
39
|
ws = null;
|
|
35
40
|
focusedSessionId = null;
|
|
36
|
-
|
|
41
|
+
focusedTarget = null;
|
|
37
42
|
onEvent = null;
|
|
38
43
|
closed = false;
|
|
44
|
+
/** Resolver for a remote session's live push socket (same-socket reverse control). */
|
|
45
|
+
sameSocketResolver = null;
|
|
46
|
+
/** When focused via same-socket, the worker's push socket we drive commands down. */
|
|
47
|
+
focusedSender = null;
|
|
39
48
|
/** Set handler for relayed events. Daemon should merge and broadcast. */
|
|
40
49
|
setEventHandler(handler) {
|
|
41
50
|
this.onEvent = handler;
|
|
42
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Install a resolver mapping a sessionId to its live push socket. This is the
|
|
54
|
+
* ONLY reverse path for remote (cross-machine) sessions: the daemon drives the
|
|
55
|
+
* session by writing `session_command_down` frames back down the socket the
|
|
56
|
+
* worker already opened — so NAT'd / SSH-only workers need no inbound
|
|
57
|
+
* reachability, and the daemon never dials back.
|
|
58
|
+
*/
|
|
59
|
+
setSameSocketResolver(resolver) {
|
|
60
|
+
this.sameSocketResolver = resolver;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Feed a `session_event_up` event that rode back up a worker's push socket
|
|
64
|
+
* (same-socket reverse control). Only applied while that session is focused.
|
|
65
|
+
*/
|
|
66
|
+
ingestReverseEvent(sessionId, event) {
|
|
67
|
+
if (sessionId !== this.focusedSessionId || !this.focusedSender)
|
|
68
|
+
return;
|
|
69
|
+
if (!RELAYED_EVENTS.has(event.type))
|
|
70
|
+
return;
|
|
71
|
+
debug(TAG, `Relay(same-socket) ${event.type} from session ${sessionId}`);
|
|
72
|
+
// prompt_options used to be source-less, allowing a late event from the
|
|
73
|
+
// previous focus to become buttons for the newly selected session. Stamp
|
|
74
|
+
// the relay identity before it leaves this boundary (parity with the
|
|
75
|
+
// local dial path's stamping in connect()).
|
|
76
|
+
const tagged = event.type === 'prompt_options'
|
|
77
|
+
? { ...event, sessionId, focusedSessionId: sessionId }
|
|
78
|
+
: event;
|
|
79
|
+
this.onEvent?.(tagged);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Drop the same-socket focus when the focused worker's push socket goes away.
|
|
83
|
+
* `closedSocket` guards against the stale-socket race: when a worker
|
|
84
|
+
* reconnects, the NEW socket takes over focus (see `migrateSender`) before
|
|
85
|
+
* the OLD one finishes closing — the old close must not tear the new focus
|
|
86
|
+
* down. A no-arg call (legacy) unfocuses unconditionally.
|
|
87
|
+
*/
|
|
88
|
+
handleSenderClosed(sessionId, closedSocket) {
|
|
89
|
+
if (sessionId !== this.focusedSessionId || !this.focusedSender)
|
|
90
|
+
return;
|
|
91
|
+
if (closedSocket !== undefined && closedSocket !== this.focusedSender)
|
|
92
|
+
return;
|
|
93
|
+
this.unfocus();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A currently-focused session re-registered with a new push socket (worker
|
|
97
|
+
* reconnect). Move the focus to the new socket so control continues without
|
|
98
|
+
* an unfocus/refocus cycle: stop the old sender's forwarding (best-effort),
|
|
99
|
+
* swap, and re-send `session_focus_down` down the new socket.
|
|
100
|
+
*/
|
|
101
|
+
migrateSender(sessionId, newSender) {
|
|
102
|
+
if (sessionId !== this.focusedSessionId || !this.focusedSender)
|
|
103
|
+
return;
|
|
104
|
+
if (this.focusedSender === newSender)
|
|
105
|
+
return;
|
|
106
|
+
if (this.focusedSender.readyState === WebSocket.OPEN) {
|
|
107
|
+
try {
|
|
108
|
+
this.focusedSender.send(JSON.stringify({ type: 'session_unfocus_down', sessionId }));
|
|
109
|
+
}
|
|
110
|
+
catch { /* closing */ }
|
|
111
|
+
}
|
|
112
|
+
this.focusedSender = newSender;
|
|
113
|
+
debug(TAG, `Migrated focus for ${sessionId} to new push socket`);
|
|
114
|
+
try {
|
|
115
|
+
newSender.send(JSON.stringify({ type: 'session_focus_down', sessionId }));
|
|
116
|
+
}
|
|
117
|
+
catch { /* closing */ }
|
|
118
|
+
}
|
|
43
119
|
/** Get currently focused session ID */
|
|
44
120
|
getFocusedSessionId() {
|
|
45
121
|
return this.focusedSessionId;
|
|
46
122
|
}
|
|
47
123
|
/** Focus a session by ID. Disconnects from previous session. */
|
|
48
124
|
focus(sessionId) {
|
|
49
|
-
|
|
125
|
+
const stillLive = (this.focusedSender && this.focusedSender.readyState === WebSocket.OPEN) ||
|
|
126
|
+
this.ws?.readyState === WebSocket.OPEN;
|
|
127
|
+
if (this.focusedSessionId === sessionId && stillLive) {
|
|
50
128
|
debug(TAG, `Already focused on ${sessionId}`);
|
|
51
129
|
return;
|
|
52
130
|
}
|
|
53
131
|
this.unfocus();
|
|
54
|
-
|
|
55
|
-
|
|
132
|
+
// 1. Same-socket: if the worker has a live push socket, drive it down that
|
|
133
|
+
// socket. No inbound dial, works for NAT'd / SSH-only workers. This is
|
|
134
|
+
// the ONLY path for remote sessions — a remote session whose socket
|
|
135
|
+
// dropped stays unfocusable until its worker reconnects.
|
|
136
|
+
const sender = this.sameSocketResolver?.(sessionId) ?? null;
|
|
137
|
+
if (sender && sender.readyState === WebSocket.OPEN) {
|
|
138
|
+
this.focusedSessionId = sessionId;
|
|
139
|
+
this.focusedSender = sender;
|
|
140
|
+
debug(TAG, `Focusing session ${sessionId} via same-socket reverse control`);
|
|
141
|
+
try {
|
|
142
|
+
sender.send(JSON.stringify({ type: 'session_focus_down', sessionId }));
|
|
143
|
+
}
|
|
144
|
+
catch { /* closing */ }
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// 2. Local sessions: dial the bridge's loopback port from sessions.json
|
|
148
|
+
// (the pre-existing local focus mechanism).
|
|
149
|
+
const session = listActiveSessions().find(s => s.id === sessionId && s.agentType !== 'daemon');
|
|
56
150
|
if (!session) {
|
|
57
|
-
debug(TAG, `Session ${sessionId} not found or is daemon`);
|
|
151
|
+
debug(TAG, `Session ${sessionId} not found, not local, or is daemon`);
|
|
58
152
|
return;
|
|
59
153
|
}
|
|
60
154
|
this.focusedSessionId = sessionId;
|
|
61
|
-
this.
|
|
62
|
-
debug(TAG, `Focusing session ${
|
|
155
|
+
this.focusedTarget = { host: '127.0.0.1', port: session.port };
|
|
156
|
+
debug(TAG, `Focusing session ${sessionId} at 127.0.0.1:${session.port}`);
|
|
63
157
|
this.connect();
|
|
64
158
|
}
|
|
65
159
|
/** Unfocus current session. */
|
|
66
160
|
unfocus() {
|
|
161
|
+
// Same-socket: tell the worker to stop forwarding events up its push socket.
|
|
162
|
+
if (this.focusedSender) {
|
|
163
|
+
if (this.focusedSender.readyState === WebSocket.OPEN && this.focusedSessionId) {
|
|
164
|
+
try {
|
|
165
|
+
this.focusedSender.send(JSON.stringify({ type: 'session_unfocus_down', sessionId: this.focusedSessionId }));
|
|
166
|
+
}
|
|
167
|
+
catch { /* closing */ }
|
|
168
|
+
}
|
|
169
|
+
this.focusedSender = null;
|
|
170
|
+
}
|
|
67
171
|
if (this.ws) {
|
|
68
172
|
this.ws.removeAllListeners();
|
|
69
173
|
this.ws.close();
|
|
@@ -73,14 +177,23 @@ export class SessionFocusRelay {
|
|
|
73
177
|
debug(TAG, `Unfocused session ${this.focusedSessionId}`);
|
|
74
178
|
}
|
|
75
179
|
this.focusedSessionId = null;
|
|
76
|
-
this.
|
|
180
|
+
this.focusedTarget = null;
|
|
77
181
|
}
|
|
78
182
|
/** Route a command to the focused session. Returns true if handled. */
|
|
79
183
|
routeCommand(cmd) {
|
|
80
|
-
if (!this.focusedSessionId || !
|
|
184
|
+
if (!this.focusedSessionId || !ROUTED_COMMANDS.has(cmd.type)) {
|
|
81
185
|
return false;
|
|
82
186
|
}
|
|
83
|
-
|
|
187
|
+
// Same-socket (remote sessions): send the command down the worker's push socket.
|
|
188
|
+
if (this.focusedSender) {
|
|
189
|
+
if (this.focusedSender.readyState !== WebSocket.OPEN)
|
|
190
|
+
return false;
|
|
191
|
+
debug(TAG, `Routing(same-socket) ${cmd.type} → session ${this.focusedSessionId}`);
|
|
192
|
+
this.focusedSender.send(JSON.stringify({ type: 'session_command_down', sessionId: this.focusedSessionId, command: cmd }));
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
// Local sessions: the loopback WS dialed in connect().
|
|
196
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
84
197
|
return false;
|
|
85
198
|
}
|
|
86
199
|
debug(TAG, `Routing ${cmd.type} → session ${this.focusedSessionId}`);
|
|
@@ -93,13 +206,15 @@ export class SessionFocusRelay {
|
|
|
93
206
|
this.unfocus();
|
|
94
207
|
}
|
|
95
208
|
connect() {
|
|
96
|
-
if (this.closed || !this.
|
|
209
|
+
if (this.closed || !this.focusedTarget)
|
|
97
210
|
return;
|
|
98
|
-
const
|
|
211
|
+
const { port } = this.focusedTarget;
|
|
212
|
+
// Local sessions only — loopback, no token (same-machine is authenticated).
|
|
213
|
+
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
|
|
99
214
|
this.ws = ws;
|
|
100
215
|
const sessionId = this.focusedSessionId;
|
|
101
216
|
ws.on('open', () => {
|
|
102
|
-
debug(TAG, `Connected to session ${sessionId}
|
|
217
|
+
debug(TAG, `Connected to session ${sessionId} at 127.0.0.1:${port}`);
|
|
103
218
|
});
|
|
104
219
|
ws.on('message', (raw) => {
|
|
105
220
|
if (this.focusedSessionId !== sessionId)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-focus-relay.js","sourceRoot":"","sources":["../src/session-focus-relay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEzE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"session-focus-relay.js","sourceRoot":"","sources":["../src/session-focus-relay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push-channel message handling — the daemon side of the session bridge's
|
|
3
|
+
* `DaemonWsClient` socket (`session_push_register` / `session_push_state` /
|
|
4
|
+
* `session_event_up`).
|
|
5
|
+
*
|
|
6
|
+
* Extracted from the `startDaemon` closure so the REAL registration /
|
|
7
|
+
* state-update / reverse-event logic is integration-testable with fake
|
|
8
|
+
* sockets: the reviewer-required regressions (ssh -L loopback registration,
|
|
9
|
+
* overlapping old/new sockets, event ownership) drive this exact handler.
|
|
10
|
+
*/
|
|
11
|
+
import type { WebSocket } from 'ws';
|
|
12
|
+
import type { SessionFocusRelay } from './session-focus-relay.js';
|
|
13
|
+
/** The slice of BridgeCore the push channel needs — keeps tests free of the real core. */
|
|
14
|
+
export interface PushChannelCore {
|
|
15
|
+
broadcastSessionsList(): Promise<void>;
|
|
16
|
+
maybeBroadcastSessionsList(): void;
|
|
17
|
+
}
|
|
18
|
+
export interface PushChannelDeps {
|
|
19
|
+
core: PushChannelCore;
|
|
20
|
+
focusRelay: SessionFocusRelay;
|
|
21
|
+
/** Production reads the socket's remote address; tests inject a fake. */
|
|
22
|
+
getSenderIp?: (sender: WebSocket) => string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns a handler for push-channel frames. The daemon calls it from its WS
|
|
26
|
+
* message dispatch; a `true` return means the frame was consumed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createPushChannelHandler(deps: PushChannelDeps): (msg: {
|
|
29
|
+
type?: string;
|
|
30
|
+
}, sender: WebSocket) => boolean;
|
|
31
|
+
//# sourceMappingURL=session-push-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-push-channel.d.ts","sourceRoot":"","sources":["../src/session-push-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAUpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAC9B,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,0BAA0B,IAAI,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,yEAAyE;IACzE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,MAAM,CAAC;CAC7C;AAMD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,IAInB,KAAK;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,SAAS,KAAG,OAAO,CA2E7F"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { debug } from './logger.js';
|
|
2
|
+
import { isLocalConnection } from './auth.js';
|
|
3
|
+
import { updatePushState } from './session-aggregator.js';
|
|
4
|
+
import { registerRemoteSession, updateRemoteSessionState, removeRemoteSession, getRemoteSession, } from './remote-sessions.js';
|
|
5
|
+
function defaultGetSenderIp(sender) {
|
|
6
|
+
return sender._socket?.remoteAddress ?? '';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns a handler for push-channel frames. The daemon calls it from its WS
|
|
10
|
+
* message dispatch; a `true` return means the frame was consumed.
|
|
11
|
+
*/
|
|
12
|
+
export function createPushChannelHandler(deps) {
|
|
13
|
+
const { core, focusRelay } = deps;
|
|
14
|
+
const getSenderIp = deps.getSenderIp ?? defaultGetSenderIp;
|
|
15
|
+
return function handlePushChannelMessage(msg, sender) {
|
|
16
|
+
if (msg.type === 'session_push_register') {
|
|
17
|
+
const { sessionId, port: sessionPort, agentType: at, projectName: pn, host, remoteAttach, weight } = msg;
|
|
18
|
+
debug('daemon', `session_push_register: ${sessionId} port=${sessionPort} agent=${at} host=${host ?? '-'} remote=${remoteAttach === true}`);
|
|
19
|
+
// A session on ANOTHER machine isn't in this daemon's sessions.json, so
|
|
20
|
+
// it is tracked in memory and driven back down this very socket.
|
|
21
|
+
// Classification: the worker's explicit `remoteAttach` intent wins — an
|
|
22
|
+
// `ssh -L`-forwarded worker arrives on loopback and is indistinguishable
|
|
23
|
+
// from a local session by IP. The non-local-IP heuristic stays as
|
|
24
|
+
// back-compat for older workers that never send the flag.
|
|
25
|
+
const senderIp = getSenderIp(sender);
|
|
26
|
+
if (remoteAttach === true || (senderIp && !isLocalConnection(senderIp))) {
|
|
27
|
+
const displayHost = typeof host === 'string' && host ? host : senderIp.replace(/^::ffff:/, '');
|
|
28
|
+
registerRemoteSession({
|
|
29
|
+
sessionId,
|
|
30
|
+
host: displayHost,
|
|
31
|
+
port: sessionPort,
|
|
32
|
+
agentType: at,
|
|
33
|
+
projectName: pn,
|
|
34
|
+
weight,
|
|
35
|
+
sender,
|
|
36
|
+
});
|
|
37
|
+
// If this session is currently focused via an OLDER socket (worker
|
|
38
|
+
// reconnect), move the focus to the new one before the old close fires.
|
|
39
|
+
focusRelay.migrateSender(sessionId, sender);
|
|
40
|
+
// Prune when the worker's push socket drops (process exit / network
|
|
41
|
+
// loss) — but only if this socket is still the registered sender: a
|
|
42
|
+
// reconnected worker's NEW registration must survive the OLD close.
|
|
43
|
+
sender.once('close', () => {
|
|
44
|
+
removeRemoteSession(sessionId, sender);
|
|
45
|
+
focusRelay.handleSenderClosed(sessionId, sender);
|
|
46
|
+
core.broadcastSessionsList().catch(() => { });
|
|
47
|
+
});
|
|
48
|
+
core.broadcastSessionsList().catch(() => { });
|
|
49
|
+
}
|
|
50
|
+
// Acknowledge registration — unconditionally, local registrations too:
|
|
51
|
+
// the worker's `registered` / `isConnected` flags depend on this ack.
|
|
52
|
+
try {
|
|
53
|
+
sender.send(JSON.stringify({ type: 'session_push_ack', sessionId }));
|
|
54
|
+
}
|
|
55
|
+
catch { /* client disconnecting */ }
|
|
56
|
+
return true; // consumed
|
|
57
|
+
}
|
|
58
|
+
if (msg.type === 'session_push_state') {
|
|
59
|
+
const { sessionId, state, modelName, effortLevel, permissionMode } = msg;
|
|
60
|
+
if (sessionId && state) {
|
|
61
|
+
// Whenever a remote registration exists, the WHOLE update is keyed to
|
|
62
|
+
// its registered sender socket — the aggregator cache included. In the
|
|
63
|
+
// local + --remote-daemon dual-registration case the sessions list
|
|
64
|
+
// dedups to the local row (daemon-server.ts) whose displayed state
|
|
65
|
+
// comes from this cache (session-aggregator.ts enricher via
|
|
66
|
+
// getPushState), so a stale pre-reconnect socket poisoning it would
|
|
67
|
+
// show through despite the registry's own guard. Sessions with no
|
|
68
|
+
// remote registration keep the plain unguarded local path.
|
|
69
|
+
const rs = getRemoteSession(sessionId);
|
|
70
|
+
const staleSender = rs?.sender !== undefined && rs.sender !== sender;
|
|
71
|
+
if (!staleSender) {
|
|
72
|
+
updatePushState(sessionId, state, modelName, effortLevel, permissionMode);
|
|
73
|
+
updateRemoteSessionState(sessionId, state, modelName, effortLevel, permissionMode, sender);
|
|
74
|
+
// Trigger sessions list broadcast so clients get fresh state
|
|
75
|
+
core.maybeBroadcastSessionsList();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return true; // consumed
|
|
79
|
+
}
|
|
80
|
+
if (msg.type === 'session_event_up') {
|
|
81
|
+
// A focused remote session's event rode back up its push socket
|
|
82
|
+
// (same-socket reverse control). Ownership check: only the session's
|
|
83
|
+
// registered sender may speak for it — a stale or foreign socket's
|
|
84
|
+
// events are dropped.
|
|
85
|
+
const { sessionId, event } = msg;
|
|
86
|
+
if (sessionId && event?.type && getRemoteSession(sessionId)?.sender === sender) {
|
|
87
|
+
focusRelay.ingestReverseEvent(sessionId, event);
|
|
88
|
+
}
|
|
89
|
+
return true; // consumed
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=session-push-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-push-channel.js","sourceRoot":"","sources":["../src/session-push-channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -47,6 +47,9 @@ export interface SessionEntry {
|
|
|
47
47
|
tty?: string;
|
|
48
48
|
parentTty?: string;
|
|
49
49
|
startedAt: string;
|
|
50
|
+
/** Explicit deck/tab sort override (default 0); lower sorts first. Set via
|
|
51
|
+
* `agentdeck <agent> --weight <n>`. See shared sortSessions. */
|
|
52
|
+
weight?: number;
|
|
50
53
|
}
|
|
51
54
|
/** Check if a PID is alive */
|
|
52
55
|
export declare function isProcessAlive(pid: number): boolean;
|
|
@@ -120,6 +123,7 @@ export declare function probeDaemonHealth(port: number): Promise<{
|
|
|
120
123
|
mode?: string;
|
|
121
124
|
pid?: number;
|
|
122
125
|
isSwift?: boolean;
|
|
126
|
+
sameSocketControl?: boolean;
|
|
123
127
|
} | null>;
|
|
124
128
|
/**
|
|
125
129
|
* Sweep the daemon port window for live daemons that file-based discovery
|
|
@@ -183,5 +187,127 @@ export declare function findDaemonPort(): number | null;
|
|
|
183
187
|
export declare function findDaemonPortAsync(): Promise<{
|
|
184
188
|
port: number;
|
|
185
189
|
httpPort?: number;
|
|
190
|
+
sameSocketControl?: boolean;
|
|
186
191
|
} | null>;
|
|
192
|
+
/** True if a host string refers to this machine's loopback. */
|
|
193
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
194
|
+
/** Bracket bare IPv6 literals so they're valid in an http(s)/ws URL authority. */
|
|
195
|
+
export declare function formatHostForUrl(host: string): string;
|
|
196
|
+
/**
|
|
197
|
+
* Probe `/health` at an arbitrary host:port (not just 127.0.0.1). Returns the
|
|
198
|
+
* full health JSON (so callers can read `mode` and `pairingToken`) or null.
|
|
199
|
+
*/
|
|
200
|
+
export declare function probeHealthAt(host: string, port: number, timeoutMs?: number): Promise<Record<string, unknown> | null>;
|
|
201
|
+
/** A resolved daemon endpoint, possibly on another machine. */
|
|
202
|
+
export interface DaemonTarget {
|
|
203
|
+
host: string;
|
|
204
|
+
port: number;
|
|
205
|
+
/** Pairing token — required when `host` is not this machine. */
|
|
206
|
+
token?: string;
|
|
207
|
+
httpPort?: number;
|
|
208
|
+
/**
|
|
209
|
+
* Whether the daemon's `/health` advertises same-socket reverse control
|
|
210
|
+
* (`sameSocketControl: true`). The worker only sends `remoteAttach` in its
|
|
211
|
+
* push registration when the daemon can actually drive the session back down
|
|
212
|
+
* the socket — a daemon without the capability (e.g. the Swift App Store
|
|
213
|
+
* daemon) gets a plain local-style registration instead.
|
|
214
|
+
*/
|
|
215
|
+
sameSocketControl?: boolean;
|
|
216
|
+
}
|
|
217
|
+
/** Parse a `host` or `host:port` (or `[v6]:port`) hint into host + port. */
|
|
218
|
+
export declare function parseHostHint(hint: string): {
|
|
219
|
+
host: string;
|
|
220
|
+
port: number;
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Injectable dependencies for {@link resolveDaemonTarget}. Production uses the
|
|
224
|
+
* real module functions; tests substitute fakes to assert the precedence and —
|
|
225
|
+
* critically — the opt-in gate, without touching the network. `warn` defaults
|
|
226
|
+
* to a once-per-key `logError` ({@link warnRemoteOnce}; keys are `host:port`,
|
|
227
|
+
* prefixed `local:` for the loopback branch — the only PTY-visible log
|
|
228
|
+
* primitive; this resolver re-runs on every `DaemonWsClient` reconnect
|
|
229
|
+
* backoff, so an unguarded warning would scribble over the agent TUI every
|
|
230
|
+
* ≤30s forever).
|
|
231
|
+
*/
|
|
232
|
+
export interface ResolveDaemonDeps {
|
|
233
|
+
findLocal: () => Promise<{
|
|
234
|
+
port: number;
|
|
235
|
+
httpPort?: number;
|
|
236
|
+
sameSocketControl?: boolean;
|
|
237
|
+
} | null>;
|
|
238
|
+
probeHealth: (host: string, port: number) => Promise<Record<string, unknown> | null>;
|
|
239
|
+
discover: () => Promise<Array<{
|
|
240
|
+
host: string;
|
|
241
|
+
port: number;
|
|
242
|
+
token?: string;
|
|
243
|
+
sameSocketControl?: boolean;
|
|
244
|
+
}>>;
|
|
245
|
+
warn: (key: string, message: string) => void;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Derive the remote-attach inputs from CLI flags + env — the single source that
|
|
249
|
+
* both `cli.ts` (pre-PTY "ignored" warning) and `index.ts` (target resolution)
|
|
250
|
+
* consume, so the two derivations cannot drift. `--remote-daemon` /
|
|
251
|
+
* `AGENTDECK_REMOTE_DAEMON=1` is THE opt-in; a host given without it
|
|
252
|
+
* (`ignoredHostHint`) is inert and the CLI warns before the PTY starts
|
|
253
|
+
* (post-PTY, stdout logging is swallowed).
|
|
254
|
+
*/
|
|
255
|
+
export declare function deriveRemoteAttachOpts(cliOpts: {
|
|
256
|
+
remoteDaemon?: boolean;
|
|
257
|
+
daemonHost?: string;
|
|
258
|
+
}, env?: NodeJS.ProcessEnv): {
|
|
259
|
+
remote: boolean;
|
|
260
|
+
hostHint?: string;
|
|
261
|
+
ignoredHostHint: boolean;
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Default `warn` dep: log a remote-attach warning at most once per key. The
|
|
265
|
+
* resolver re-runs on every reconnect backoff, and an unguarded warning would
|
|
266
|
+
* scribble over the agent TUI every few seconds forever.
|
|
267
|
+
* @internal Exported for tests only — the module-level Set has no reset, so
|
|
268
|
+
* tests must use keys unique to themselves.
|
|
269
|
+
*/
|
|
270
|
+
export declare function warnRemoteOnce(key: string, message: string): void;
|
|
271
|
+
/**
|
|
272
|
+
* Resolve which daemon a session bridge should attach to, optionally on another
|
|
273
|
+
* machine. Precedence:
|
|
274
|
+
* 1. Local daemon (unchanged behavior — always preferred, never opt-in gated).
|
|
275
|
+
* 2. Explicit `hostHint` (cross-subnet / SSH where mDNS doesn't propagate).
|
|
276
|
+
* 3. mDNS browse on the LAN.
|
|
277
|
+
*
|
|
278
|
+
* OPT-IN INVARIANT (security boundary): `--remote-daemon` /
|
|
279
|
+
* `AGENTDECK_REMOTE_DAEMON=1` (`remote === true`) is THE opt-in switch, and it
|
|
280
|
+
* gates BOTH remote paths. `--daemon-host` / `AGENTDECK_DAEMON_HOST` only names
|
|
281
|
+
* the endpoint — without the switch it is ignored (the CLI warns pre-PTY).
|
|
282
|
+
* Nothing below the local check ever leaves the machine unless `remote === true`:
|
|
283
|
+
* with the switch absent the function returns local-or-null and the session
|
|
284
|
+
* stays local-only — byte-for-byte the pre-remote behavior.
|
|
285
|
+
*
|
|
286
|
+
* Within `remote === true`, EVERY accepted target must advertise the
|
|
287
|
+
* `sameSocketControl` capability — including a loopback one. An ssh -L
|
|
288
|
+
* forward of a remote daemon is indistinguishable from a genuine local
|
|
289
|
+
* daemon by IP, so the local-first step enforces the capability too rather
|
|
290
|
+
* than silently accepting a tunnel to a daemon that can never drive the
|
|
291
|
+
* session (plain registration: acked but unlistable/unfocusable):
|
|
292
|
+
* - Capable local daemon ⇒ returned (a hostHint is NOT consulted — the
|
|
293
|
+
* ordinary local-preferred behavior).
|
|
294
|
+
* - Incapable local daemon + hostHint ⇒ fall through to the explicit-host
|
|
295
|
+
* step: the user named a node, so probe THAT instead of dead-ending.
|
|
296
|
+
* - Incapable local daemon, no hostHint ⇒ one-shot warning + null. No mDNS
|
|
297
|
+
* fallthrough: a deliberately-built tunnel must not silently roam to
|
|
298
|
+
* some other LAN daemon.
|
|
299
|
+
* - An explicit host that is unreachable, not a daemon, or lacks the
|
|
300
|
+
* capability returns null WITHOUT falling through to mDNS — the user
|
|
301
|
+
* named a specific node and expects to hear about failure.
|
|
302
|
+
* - mDNS selection is limited to daemons advertising `sameSocketControl`
|
|
303
|
+
* (the discover step filters), so an unsupported daemon (e.g. Swift App
|
|
304
|
+
* Store) is never selected as a remote target.
|
|
305
|
+
*
|
|
306
|
+
* Remote targets carry the daemon's advertised pairing `token`; local targets
|
|
307
|
+
* need none (the daemon treats same-machine connections as authenticated).
|
|
308
|
+
*/
|
|
309
|
+
export declare function resolveDaemonTarget(opts?: {
|
|
310
|
+
remote?: boolean;
|
|
311
|
+
hostHint?: string;
|
|
312
|
+
}, deps?: Partial<ResolveDaemonDeps>): Promise<DaemonTarget | null>;
|
|
187
313
|
//# sourceMappingURL=session-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAe/C;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAEtD;AAGD;iFACiF;AACjF,wBAAgB,kBAAkB,IAAI,MAAM,CAAgD;AAE5F,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAGxC,mGAAmG;AACnG,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAyB,CAAC;AAEnF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"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"}
|