@linkshell/gateway 0.2.47 → 0.3.0

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 (40) hide show
  1. package/README.md +14 -13
  2. package/dist/gateway/src/agent-permission-http.d.ts +10 -37
  3. package/dist/gateway/src/agent-permission-http.js +16 -56
  4. package/dist/gateway/src/agent-permission-http.js.map +1 -1
  5. package/dist/gateway/src/embedded.js +121 -57
  6. package/dist/gateway/src/embedded.js.map +1 -1
  7. package/dist/gateway/src/index.js +161 -94
  8. package/dist/gateway/src/index.js.map +1 -1
  9. package/dist/gateway/src/pairings.d.ts +3 -3
  10. package/dist/gateway/src/pairings.js +4 -5
  11. package/dist/gateway/src/pairings.js.map +1 -1
  12. package/dist/gateway/src/relay.d.ts +2 -2
  13. package/dist/gateway/src/relay.js +27 -38
  14. package/dist/gateway/src/relay.js.map +1 -1
  15. package/dist/gateway/src/sessions.d.ts +31 -28
  16. package/dist/gateway/src/sessions.js +163 -145
  17. package/dist/gateway/src/sessions.js.map +1 -1
  18. package/dist/gateway/src/state-store.d.ts +9 -6
  19. package/dist/gateway/src/state-store.js +26 -19
  20. package/dist/gateway/src/state-store.js.map +1 -1
  21. package/dist/gateway/src/tokens.d.ts +27 -7
  22. package/dist/gateway/src/tokens.js +86 -60
  23. package/dist/gateway/src/tokens.js.map +1 -1
  24. package/dist/gateway/src/tunnel.d.ts +11 -13
  25. package/dist/gateway/src/tunnel.js +36 -36
  26. package/dist/gateway/src/tunnel.js.map +1 -1
  27. package/dist/gateway/tsconfig.tsbuildinfo +1 -1
  28. package/dist/shared-protocol/src/index.d.ts +3961 -5788
  29. package/dist/shared-protocol/src/index.js +19 -84
  30. package/dist/shared-protocol/src/index.js.map +1 -1
  31. package/package.json +10 -10
  32. package/src/agent-permission-http.ts +20 -63
  33. package/src/embedded.ts +124 -56
  34. package/src/index.ts +165 -94
  35. package/src/pairings.ts +6 -7
  36. package/src/relay.ts +38 -48
  37. package/src/sessions.ts +174 -150
  38. package/src/state-store.ts +41 -25
  39. package/src/tokens.ts +109 -63
  40. package/src/tunnel.ts +49 -43
package/src/relay.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "@linkshell/protocol";
9
9
  import type { Envelope, ProtocolMessageType } from "@linkshell/protocol";
10
10
  import { ZodError } from "zod";
11
- import type { SessionManager, ConnectedDevice } from "./sessions.js";
11
+ import type { DeviceManager, ConnectedDevice } from "./sessions.js";
12
12
  import {
13
13
  handleTunnelResponse,
14
14
  handleTunnelWsData,
@@ -20,31 +20,31 @@ export function handleSocketMessage(
20
20
  socket: WebSocket,
21
21
  raw: string,
22
22
  role: "host" | "client",
23
- sessionId: string,
23
+ hostDeviceId: string,
24
24
  deviceId: string,
25
- sessions: SessionManager,
25
+ sessions: DeviceManager,
26
26
  ): void {
27
27
  let envelope: Envelope;
28
28
  try {
29
29
  envelope = parseEnvelope(raw);
30
30
  } catch {
31
- sendSessionError(socket, sessionId, "invalid_message", "Failed to parse envelope");
31
+ sendSessionError(socket, hostDeviceId, "invalid_message", "Failed to parse envelope");
32
32
  return;
33
33
  }
34
34
 
35
- if (envelope.sessionId !== sessionId) {
35
+ if (envelope.hostDeviceId !== hostDeviceId) {
36
36
  sendSessionError(
37
37
  socket,
38
- sessionId,
38
+ hostDeviceId,
39
39
  "invalid_message",
40
- "Envelope sessionId does not match connection sessionId",
40
+ "Envelope hostDeviceId does not match connection hostDeviceId",
41
41
  );
42
42
  return;
43
43
  }
44
44
 
45
- const session = sessions.get(sessionId);
45
+ const session = sessions.get(hostDeviceId);
46
46
  if (!session) {
47
- sendSessionError(socket, sessionId, "session_not_found", "Session not found");
47
+ sendSessionError(socket, hostDeviceId, "device_not_found", "Device not found");
48
48
  return;
49
49
  }
50
50
 
@@ -65,13 +65,13 @@ export function handleSocketMessage(
65
65
  if (error instanceof ZodError) {
66
66
  sendSessionError(
67
67
  socket,
68
- sessionId,
68
+ hostDeviceId,
69
69
  "invalid_message",
70
70
  error.errors[0]?.message ?? "Invalid message payload",
71
71
  );
72
72
  return;
73
73
  }
74
- sendSessionError(socket, sessionId, "invalid_message", "Failed to handle message");
74
+ sendSessionError(socket, hostDeviceId, "invalid_message", "Failed to handle message");
75
75
  }
76
76
  }
77
77
 
@@ -81,7 +81,7 @@ function isProtocolMessageType(type: string): type is ProtocolMessageType {
81
81
 
82
82
  function sendSessionError(
83
83
  socket: WebSocket,
84
- sessionId: string,
84
+ hostDeviceId: string,
85
85
  code: string,
86
86
  message: string,
87
87
  ): void {
@@ -89,8 +89,8 @@ function sendSessionError(
89
89
  socket.send(
90
90
  serializeEnvelope(
91
91
  createEnvelope({
92
- type: "session.error",
93
- sessionId,
92
+ type: "device.error",
93
+ hostDeviceId,
94
94
  payload: { code, message },
95
95
  }),
96
96
  ),
@@ -99,22 +99,23 @@ function sendSessionError(
99
99
 
100
100
  function handleHostMessage(
101
101
  envelope: Envelope,
102
- session: ReturnType<SessionManager["get"]> & {},
103
- sessions: SessionManager,
102
+ session: ReturnType<DeviceManager["get"]> & {},
103
+ sessions: DeviceManager,
104
104
  ): void {
105
105
  switch (envelope.type) {
106
- case "session.connect": {
106
+ case "device.connect": {
107
107
  // Extract metadata from host's connect message
108
- const p = parseTypedPayload("session.connect", envelope.payload);
109
- if (p.provider || p.machineId || p.hostname || p.platform || p.cwd || p.projectName) {
108
+ const p = parseTypedPayload("device.connect", envelope.payload);
109
+ if (p.machineId || p.hostname || p.platform || p.cwd || p.capabilities) {
110
110
  sessions.setMetadata(
111
111
  session.id,
112
- p.provider ?? undefined,
112
+ undefined,
113
113
  p.machineId ?? undefined,
114
114
  p.hostname ?? undefined,
115
115
  p.platform ?? undefined,
116
116
  p.cwd ?? undefined,
117
- p.projectName ?? undefined,
117
+ undefined,
118
+ p.capabilities ?? undefined,
118
119
  );
119
120
  }
120
121
  break;
@@ -129,12 +130,12 @@ function handleHostMessage(
129
130
  broadcastToClients(session, envelope);
130
131
  break;
131
132
  }
132
- case "session.heartbeat":
133
+ case "device.heartbeat":
133
134
  break;
134
135
  case "permission.decision.result": {
135
136
  const p = parseTypedPayload("permission.decision.result", envelope.payload);
136
137
  resolveAgentPermissionHttpAck({
137
- sessionId: session.id,
138
+ hostDeviceId: session.id,
138
139
  ack: {
139
140
  requestId: p.requestId,
140
141
  decision: p.decision,
@@ -172,11 +173,7 @@ function handleHostMessage(
172
173
  case "screen.status":
173
174
  case "screen.offer":
174
175
  case "screen.ice":
175
- // Agent GUI: host → clients
176
- case "agent.capabilities":
177
- case "agent.update":
178
- case "agent.permission.request":
179
- case "agent.snapshot":
176
+ // Agent Workspace: host → clients
180
177
  case "agent.v2.capabilities":
181
178
  case "agent.v2.conversation.opened":
182
179
  case "agent.v2.conversation.list.result":
@@ -204,17 +201,17 @@ function handleHostMessage(
204
201
  function handleClientMessage(
205
202
  envelope: Envelope,
206
203
  socket: WebSocket,
207
- session: ReturnType<SessionManager["get"]> & {},
204
+ session: ReturnType<DeviceManager["get"]> & {},
208
205
  deviceId: string,
209
- sessions: SessionManager,
206
+ sessions: DeviceManager,
210
207
  ): void {
211
208
  const requireController = (): boolean => {
212
209
  if (session.controllerId === deviceId) return true;
213
210
  socket.send(
214
211
  serializeEnvelope(
215
212
  createEnvelope({
216
- type: "session.error",
217
- sessionId: session.id,
213
+ type: "device.error",
214
+ hostDeviceId: session.id,
218
215
  payload: {
219
216
  code: "control_conflict",
220
217
  message: "Not the controller",
@@ -236,13 +233,13 @@ function handleClientMessage(
236
233
  sendToHost(session, envelope);
237
234
  break;
238
235
  }
239
- case "session.ack": {
236
+ case "device.ack": {
240
237
  // Forward ACK to host
241
238
  sendToHost(session, envelope);
242
239
  break;
243
240
  }
244
- case "session.resume": {
245
- const p = parseTypedPayload("session.resume", envelope.payload);
241
+ case "device.resume": {
242
+ const p = parseTypedPayload("device.resume", envelope.payload);
246
243
  // Replay from gateway buffer first
247
244
  const replay = sessions.getReplayFrom(
248
245
  session.id,
@@ -255,7 +252,7 @@ function handleClientMessage(
255
252
  serializeEnvelope(
256
253
  createEnvelope({
257
254
  type: "terminal.output",
258
- sessionId: session.id,
255
+ hostDeviceId: session.id,
259
256
  terminalId: msg.terminalId,
260
257
  seq: msg.seq,
261
258
  payload: { ...payload, isReplay: true },
@@ -284,7 +281,7 @@ function handleClientMessage(
284
281
  sessions.claimControl(session.id, deviceId);
285
282
  const grantMsg = createEnvelope({
286
283
  type: "control.grant",
287
- sessionId: session.id,
284
+ hostDeviceId: session.id,
288
285
  payload: { deviceId },
289
286
  });
290
287
  // Broadcast to ALL clients so previous controller updates its state
@@ -296,25 +293,20 @@ function handleClientMessage(
296
293
  sessions.releaseControl(session.id, deviceId);
297
294
  const releaseMsg = createEnvelope({
298
295
  type: "control.release",
299
- sessionId: session.id,
296
+ hostDeviceId: session.id,
300
297
  payload: { deviceId },
301
298
  });
302
299
  broadcastToClients(session, releaseMsg);
303
300
  sendToHost(session, releaseMsg);
304
301
  break;
305
302
  }
306
- case "session.heartbeat":
303
+ case "device.heartbeat":
307
304
  break;
308
305
  // Screen sharing: client → host
309
306
  case "screen.start":
310
307
  case "screen.stop":
311
308
  case "screen.answer":
312
309
  case "screen.ice":
313
- case "agent.session.new":
314
- case "agent.session.load":
315
- case "agent.prompt":
316
- case "agent.cancel":
317
- case "agent.permission.response":
318
310
  case "agent.v2.conversation.open":
319
311
  case "agent.v2.prompt":
320
312
  case "agent.v2.command.execute":
@@ -334,8 +326,6 @@ function handleClientMessage(
334
326
  if (!requireController()) return;
335
327
  sendToHost(session, envelope);
336
328
  break;
337
- case "agent.initialize":
338
- case "agent.session.list":
339
329
  case "agent.v2.capabilities.request":
340
330
  case "agent.v2.conversation.list":
341
331
  case "agent.v2.snapshot.request":
@@ -348,7 +338,7 @@ function handleClientMessage(
348
338
  }
349
339
 
350
340
  function broadcastToClients(
351
- session: ReturnType<SessionManager["get"]> & {},
341
+ session: ReturnType<DeviceManager["get"]> & {},
352
342
  envelope: Envelope,
353
343
  ): void {
354
344
  const data = serializeEnvelope(envelope);
@@ -360,7 +350,7 @@ function broadcastToClients(
360
350
  }
361
351
 
362
352
  function sendToHost(
363
- session: ReturnType<SessionManager["get"]> & {},
353
+ session: ReturnType<DeviceManager["get"]> & {},
364
354
  envelope: Envelope,
365
355
  ): void {
366
356
  if (