@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.
- package/README.md +14 -13
- package/dist/gateway/src/agent-permission-http.d.ts +10 -37
- package/dist/gateway/src/agent-permission-http.js +16 -56
- package/dist/gateway/src/agent-permission-http.js.map +1 -1
- package/dist/gateway/src/embedded.js +121 -57
- package/dist/gateway/src/embedded.js.map +1 -1
- package/dist/gateway/src/index.js +161 -94
- package/dist/gateway/src/index.js.map +1 -1
- package/dist/gateway/src/pairings.d.ts +3 -3
- package/dist/gateway/src/pairings.js +4 -5
- package/dist/gateway/src/pairings.js.map +1 -1
- package/dist/gateway/src/relay.d.ts +2 -2
- package/dist/gateway/src/relay.js +27 -38
- package/dist/gateway/src/relay.js.map +1 -1
- package/dist/gateway/src/sessions.d.ts +31 -28
- package/dist/gateway/src/sessions.js +163 -145
- package/dist/gateway/src/sessions.js.map +1 -1
- package/dist/gateway/src/state-store.d.ts +9 -6
- package/dist/gateway/src/state-store.js +26 -19
- package/dist/gateway/src/state-store.js.map +1 -1
- package/dist/gateway/src/tokens.d.ts +27 -7
- package/dist/gateway/src/tokens.js +86 -60
- package/dist/gateway/src/tokens.js.map +1 -1
- package/dist/gateway/src/tunnel.d.ts +11 -13
- package/dist/gateway/src/tunnel.js +36 -36
- package/dist/gateway/src/tunnel.js.map +1 -1
- package/dist/gateway/tsconfig.tsbuildinfo +1 -1
- package/dist/shared-protocol/src/index.d.ts +3961 -5788
- package/dist/shared-protocol/src/index.js +19 -84
- package/dist/shared-protocol/src/index.js.map +1 -1
- package/package.json +10 -10
- package/src/agent-permission-http.ts +20 -63
- package/src/embedded.ts +124 -56
- package/src/index.ts +165 -94
- package/src/pairings.ts +6 -7
- package/src/relay.ts +38 -48
- package/src/sessions.ts +174 -150
- package/src/state-store.ts +41 -25
- package/src/tokens.ts +109 -63
- package/src/tunnel.ts +49 -43
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
LinkShell Gateway — WebSocket 消息中转服务,连接 CLI 和手机 App。
|
|
4
4
|
|
|
5
|
-
Gateway
|
|
5
|
+
Gateway 不运行任何终端进程,只负责配对、主机设备授权和消息路由。
|
|
6
6
|
|
|
7
7
|
## 部署
|
|
8
8
|
|
|
@@ -30,35 +30,36 @@ PORT=8787 node packages/gateway/dist/gateway/src/index.js
|
|
|
30
30
|
| `SUPABASE_URL` | - | Supabase 项目 URL |
|
|
31
31
|
| `SUPABASE_ANON_KEY` | - | Supabase anon key |
|
|
32
32
|
| `SUPABASE_SERVICE_ROLE_KEY` | - | 服务端订阅检查和 Gateway 状态持久化使用 |
|
|
33
|
-
| `
|
|
34
|
-
| `SUPABASE_GATEWAY_PAIRING_TABLE` | `
|
|
33
|
+
| `SUPABASE_GATEWAY_AUTHORIZATION_TABLE` | `linkshell_gateway_device_authorizations` | 客户端到主机设备的长期授权表 |
|
|
34
|
+
| `SUPABASE_GATEWAY_PAIRING_TABLE` | `linkshell_gateway_pairing_challenges` | 配对挑战持久化表 |
|
|
35
35
|
| `PAIRING_TTL_MS` | `600000` | 配对码有效期,默认 10 分钟 |
|
|
36
36
|
|
|
37
|
-
启用官方服务版部署时,先在 Supabase 执行 `docs/supabase-gateway-state.sql`。表不存在时 Gateway 会退回内存态,但 Docker
|
|
37
|
+
启用官方服务版部署时,先在 Supabase 执行 `docs/supabase-gateway-state.sql`。表不存在时 Gateway 会退回内存态,但 Docker 重启后设备授权和未过期配对挑战不会恢复。
|
|
38
38
|
|
|
39
39
|
## API
|
|
40
40
|
|
|
41
41
|
| 方法 | 路径 | 说明 |
|
|
42
42
|
|------|------|------|
|
|
43
43
|
| `GET` | `/healthz` | 健康检查 |
|
|
44
|
-
| `POST` | `/pairings` |
|
|
45
|
-
| `POST` | `/pairings/claim` |
|
|
44
|
+
| `POST` | `/pairings` | 主机设备创建配对挑战(返回 6 位 code,默认 10 分钟有效) |
|
|
45
|
+
| `POST` | `/pairings/claim` | 客户端用 code 换取 `hostDeviceId`、`deviceToken`、`authorizationId` |
|
|
46
46
|
| `GET` | `/pairings/:code/status` | 查询配对状态 |
|
|
47
|
-
| `GET` | `/
|
|
48
|
-
| `GET` | `/
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
47
|
+
| `GET` | `/devices` | 用设备 token 列出已授权主机设备 |
|
|
48
|
+
| `GET` | `/devices/:hostDeviceId` | 主机设备详情 |
|
|
49
|
+
| `DELETE` | `/devices/:hostDeviceId/authorizations/:authorizationId` | 撤销客户端设备授权 |
|
|
50
|
+
| `WS` | `/ws?hostDeviceId=&role=` | 实时连接(role=host 或 client) |
|
|
51
|
+
| `GET/POST` | `/tunnel/:hostDeviceId/:port/**` | HTTP 端口转发 |
|
|
52
|
+
| `WS` | `/tunnel/:hostDeviceId/:port/**` | WebSocket 端口转发(HMR) |
|
|
52
53
|
|
|
53
54
|
## 特性
|
|
54
55
|
|
|
55
|
-
-
|
|
56
|
+
- 内存态主机设备管理,可选 Supabase 持久化设备授权和配对挑战
|
|
56
57
|
- ACK 追踪 + 输出缓存(最近 200 条,client 重连时快速重放)
|
|
57
58
|
- 单设备控制权管理(claim/grant/reject/release)
|
|
58
59
|
- Agent Workspace v2 envelope 透传,支持 capabilities、snapshot、event、permission 和 structured input
|
|
59
60
|
- Tunnel proxy 支持 HTTP 与 WebSocket,移动端可预览本地 dev server
|
|
60
61
|
- 心跳 ping/pong 检测死连接(20s 间隔)
|
|
61
|
-
-
|
|
62
|
+
- 主机断开保留 60s,空闲 30min 清理
|
|
62
63
|
- IP 限流(配对 30 req/min,WebSocket 20 conn/min)
|
|
63
64
|
- CORS 支持
|
|
64
65
|
- 协议版本协商
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import type {
|
|
2
|
+
import type { DeviceManager } from "./sessions.js";
|
|
3
3
|
import type { TokenManager } from "./tokens.js";
|
|
4
4
|
export declare const agentPermissionHttpBodySchema: z.ZodDiscriminatedUnion<"protocol", [z.ZodObject<{
|
|
5
5
|
protocol: z.ZodLiteral<"v2">;
|
|
6
|
-
|
|
6
|
+
hostDeviceId: z.ZodString;
|
|
7
7
|
conversationId: z.ZodString;
|
|
8
8
|
requestId: z.ZodString;
|
|
9
9
|
outcome: z.ZodEnum<["allow", "deny", "cancelled"]>;
|
|
@@ -12,7 +12,7 @@ export declare const agentPermissionHttpBodySchema: z.ZodDiscriminatedUnion<"pro
|
|
|
12
12
|
agentSessionId: z.ZodOptional<z.ZodString>;
|
|
13
13
|
}, "strip", z.ZodTypeAny, {
|
|
14
14
|
protocol: "v2";
|
|
15
|
-
|
|
15
|
+
hostDeviceId: string;
|
|
16
16
|
conversationId: string;
|
|
17
17
|
requestId: string;
|
|
18
18
|
outcome: "allow" | "deny" | "cancelled";
|
|
@@ -21,43 +21,16 @@ export declare const agentPermissionHttpBodySchema: z.ZodDiscriminatedUnion<"pro
|
|
|
21
21
|
agentSessionId?: string | undefined;
|
|
22
22
|
}, {
|
|
23
23
|
protocol: "v2";
|
|
24
|
-
|
|
24
|
+
hostDeviceId: string;
|
|
25
25
|
conversationId: string;
|
|
26
26
|
requestId: string;
|
|
27
27
|
outcome: "allow" | "deny" | "cancelled";
|
|
28
28
|
optionId?: string | undefined;
|
|
29
29
|
terminalId?: string | undefined;
|
|
30
30
|
agentSessionId?: string | undefined;
|
|
31
|
-
}>, z.ZodObject<{
|
|
32
|
-
protocol: z.ZodLiteral<"legacy">;
|
|
33
|
-
sessionId: z.ZodString;
|
|
34
|
-
conversationId: z.ZodOptional<z.ZodString>;
|
|
35
|
-
agentSessionId: z.ZodOptional<z.ZodString>;
|
|
36
|
-
requestId: z.ZodString;
|
|
37
|
-
outcome: z.ZodEnum<["allow", "deny", "cancelled"]>;
|
|
38
|
-
optionId: z.ZodOptional<z.ZodString>;
|
|
39
|
-
terminalId: z.ZodOptional<z.ZodString>;
|
|
40
|
-
}, "strip", z.ZodTypeAny, {
|
|
41
|
-
protocol: "legacy";
|
|
42
|
-
sessionId: string;
|
|
43
|
-
requestId: string;
|
|
44
|
-
outcome: "allow" | "deny" | "cancelled";
|
|
45
|
-
conversationId?: string | undefined;
|
|
46
|
-
optionId?: string | undefined;
|
|
47
|
-
terminalId?: string | undefined;
|
|
48
|
-
agentSessionId?: string | undefined;
|
|
49
|
-
}, {
|
|
50
|
-
protocol: "legacy";
|
|
51
|
-
sessionId: string;
|
|
52
|
-
requestId: string;
|
|
53
|
-
outcome: "allow" | "deny" | "cancelled";
|
|
54
|
-
conversationId?: string | undefined;
|
|
55
|
-
optionId?: string | undefined;
|
|
56
|
-
terminalId?: string | undefined;
|
|
57
|
-
agentSessionId?: string | undefined;
|
|
58
31
|
}>, z.ZodObject<{
|
|
59
32
|
protocol: z.ZodLiteral<"terminal">;
|
|
60
|
-
|
|
33
|
+
hostDeviceId: z.ZodString;
|
|
61
34
|
conversationId: z.ZodOptional<z.ZodString>;
|
|
62
35
|
requestId: z.ZodString;
|
|
63
36
|
outcome: z.ZodEnum<["allow", "deny", "cancelled"]>;
|
|
@@ -66,7 +39,7 @@ export declare const agentPermissionHttpBodySchema: z.ZodDiscriminatedUnion<"pro
|
|
|
66
39
|
agentSessionId: z.ZodOptional<z.ZodString>;
|
|
67
40
|
}, "strip", z.ZodTypeAny, {
|
|
68
41
|
protocol: "terminal";
|
|
69
|
-
|
|
42
|
+
hostDeviceId: string;
|
|
70
43
|
requestId: string;
|
|
71
44
|
outcome: "allow" | "deny" | "cancelled";
|
|
72
45
|
conversationId?: string | undefined;
|
|
@@ -75,7 +48,7 @@ export declare const agentPermissionHttpBodySchema: z.ZodDiscriminatedUnion<"pro
|
|
|
75
48
|
agentSessionId?: string | undefined;
|
|
76
49
|
}, {
|
|
77
50
|
protocol: "terminal";
|
|
78
|
-
|
|
51
|
+
hostDeviceId: string;
|
|
79
52
|
requestId: string;
|
|
80
53
|
outcome: "allow" | "deny" | "cancelled";
|
|
81
54
|
conversationId?: string | undefined;
|
|
@@ -93,7 +66,7 @@ export type AgentPermissionHttpResult = {
|
|
|
93
66
|
ack?: AgentPermissionAck;
|
|
94
67
|
body: {
|
|
95
68
|
ok?: true;
|
|
96
|
-
error?: "unauthorized" | "
|
|
69
|
+
error?: "unauthorized" | "device_not_found" | "host_not_connected" | "invalid_payload" | "permission_not_delivered" | "permission_ack_timeout";
|
|
97
70
|
message?: string;
|
|
98
71
|
resolved?: boolean;
|
|
99
72
|
delivered?: boolean;
|
|
@@ -108,12 +81,12 @@ export type AgentPermissionAck = {
|
|
|
108
81
|
message?: string;
|
|
109
82
|
};
|
|
110
83
|
export declare function resolveAgentPermissionHttpAck(input: {
|
|
111
|
-
|
|
84
|
+
hostDeviceId: string;
|
|
112
85
|
ack: AgentPermissionAck;
|
|
113
86
|
}): boolean;
|
|
114
87
|
export declare function forwardAgentPermissionHttp(input: {
|
|
115
88
|
token: string | null;
|
|
116
89
|
body: AgentPermissionHttpBody;
|
|
117
|
-
sessionManager:
|
|
90
|
+
sessionManager: DeviceManager;
|
|
118
91
|
tokenManager: TokenManager;
|
|
119
92
|
}): Promise<AgentPermissionHttpResult>;
|
|
@@ -5,7 +5,7 @@ const PERMISSION_ACK_TIMEOUT_MS = 12_000;
|
|
|
5
5
|
export const agentPermissionHttpBodySchema = z.discriminatedUnion("protocol", [
|
|
6
6
|
z.object({
|
|
7
7
|
protocol: z.literal("v2"),
|
|
8
|
-
|
|
8
|
+
hostDeviceId: z.string().min(1),
|
|
9
9
|
conversationId: z.string().min(1),
|
|
10
10
|
requestId: z.string().min(1),
|
|
11
11
|
outcome: permissionOutcomeSchema,
|
|
@@ -13,19 +13,9 @@ export const agentPermissionHttpBodySchema = z.discriminatedUnion("protocol", [
|
|
|
13
13
|
terminalId: z.string().optional(),
|
|
14
14
|
agentSessionId: z.string().optional(),
|
|
15
15
|
}),
|
|
16
|
-
z.object({
|
|
17
|
-
protocol: z.literal("legacy"),
|
|
18
|
-
sessionId: z.string().min(1),
|
|
19
|
-
conversationId: z.string().optional(),
|
|
20
|
-
agentSessionId: z.string().optional(),
|
|
21
|
-
requestId: z.string().min(1),
|
|
22
|
-
outcome: permissionOutcomeSchema,
|
|
23
|
-
optionId: z.string().optional(),
|
|
24
|
-
terminalId: z.string().optional(),
|
|
25
|
-
}),
|
|
26
16
|
z.object({
|
|
27
17
|
protocol: z.literal("terminal"),
|
|
28
|
-
|
|
18
|
+
hostDeviceId: z.string().min(1),
|
|
29
19
|
conversationId: z.string().optional(),
|
|
30
20
|
requestId: z.string().min(1),
|
|
31
21
|
outcome: permissionOutcomeSchema,
|
|
@@ -35,11 +25,11 @@ export const agentPermissionHttpBodySchema = z.discriminatedUnion("protocol", [
|
|
|
35
25
|
}),
|
|
36
26
|
]);
|
|
37
27
|
const pendingAcks = new Map();
|
|
38
|
-
function ackKey(
|
|
39
|
-
return `${
|
|
28
|
+
function ackKey(hostDeviceId, requestId) {
|
|
29
|
+
return `${hostDeviceId}:${requestId}`;
|
|
40
30
|
}
|
|
41
31
|
export function resolveAgentPermissionHttpAck(input) {
|
|
42
|
-
const key = ackKey(input.
|
|
32
|
+
const key = ackKey(input.hostDeviceId, input.ack.requestId);
|
|
43
33
|
const pending = pendingAcks.get(key);
|
|
44
34
|
if (!pending)
|
|
45
35
|
return false;
|
|
@@ -48,8 +38,8 @@ export function resolveAgentPermissionHttpAck(input) {
|
|
|
48
38
|
pending.resolve(input.ack);
|
|
49
39
|
return true;
|
|
50
40
|
}
|
|
51
|
-
function waitForAck(
|
|
52
|
-
const key = ackKey(
|
|
41
|
+
function waitForAck(hostDeviceId, requestId) {
|
|
42
|
+
const key = ackKey(hostDeviceId, requestId);
|
|
53
43
|
const existing = pendingAcks.get(key);
|
|
54
44
|
if (existing) {
|
|
55
45
|
pendingAcks.delete(key);
|
|
@@ -72,7 +62,8 @@ function waitForAck(sessionId, requestId) {
|
|
|
72
62
|
}
|
|
73
63
|
export async function forwardAgentPermissionHttp(input) {
|
|
74
64
|
const { token, body, sessionManager, tokenManager } = input;
|
|
75
|
-
|
|
65
|
+
const { hostDeviceId } = body;
|
|
66
|
+
if (!token || !tokenManager.owns(token, hostDeviceId)) {
|
|
76
67
|
return {
|
|
77
68
|
status: 401,
|
|
78
69
|
body: {
|
|
@@ -81,13 +72,13 @@ export async function forwardAgentPermissionHttp(input) {
|
|
|
81
72
|
},
|
|
82
73
|
};
|
|
83
74
|
}
|
|
84
|
-
const session = sessionManager.get(
|
|
75
|
+
const session = sessionManager.get(hostDeviceId);
|
|
85
76
|
if (!session) {
|
|
86
77
|
return {
|
|
87
78
|
status: 404,
|
|
88
79
|
body: {
|
|
89
|
-
error: "
|
|
90
|
-
message: "
|
|
80
|
+
error: "device_not_found",
|
|
81
|
+
message: "Host device not found",
|
|
91
82
|
},
|
|
92
83
|
};
|
|
93
84
|
}
|
|
@@ -103,7 +94,7 @@ export async function forwardAgentPermissionHttp(input) {
|
|
|
103
94
|
try {
|
|
104
95
|
const envelopes = createPermissionEnvelopes(body);
|
|
105
96
|
const waitsForDelivery = envelopes.some((envelope) => envelope.type === "permission.decision");
|
|
106
|
-
const ackPromise = waitsForDelivery ? waitForAck(
|
|
97
|
+
const ackPromise = waitsForDelivery ? waitForAck(hostDeviceId, body.requestId) : null;
|
|
107
98
|
for (const envelope of envelopes) {
|
|
108
99
|
session.host.socket.send(serializeEnvelope(envelope));
|
|
109
100
|
}
|
|
@@ -173,6 +164,7 @@ export async function forwardAgentPermissionHttp(input) {
|
|
|
173
164
|
}
|
|
174
165
|
}
|
|
175
166
|
function createPermissionEnvelopes(body) {
|
|
167
|
+
const { hostDeviceId } = body;
|
|
176
168
|
if (body.protocol === "v2") {
|
|
177
169
|
const payload = parseTypedPayload("agent.v2.permission.respond", {
|
|
178
170
|
conversationId: body.conversationId,
|
|
@@ -182,50 +174,18 @@ function createPermissionEnvelopes(body) {
|
|
|
182
174
|
});
|
|
183
175
|
return [createEnvelope({
|
|
184
176
|
type: "agent.v2.permission.respond",
|
|
185
|
-
|
|
177
|
+
hostDeviceId,
|
|
186
178
|
deviceId: "live-activity",
|
|
187
179
|
payload,
|
|
188
180
|
})];
|
|
189
181
|
}
|
|
190
|
-
if (body.protocol === "legacy") {
|
|
191
|
-
const legacyPayload = parseTypedPayload("agent.permission.response", {
|
|
192
|
-
agentSessionId: body.agentSessionId || undefined,
|
|
193
|
-
requestId: body.requestId,
|
|
194
|
-
outcome: body.outcome,
|
|
195
|
-
optionId: body.optionId || undefined,
|
|
196
|
-
});
|
|
197
|
-
const envelopes = [createEnvelope({
|
|
198
|
-
type: "agent.permission.response",
|
|
199
|
-
sessionId: body.sessionId,
|
|
200
|
-
deviceId: "live-activity",
|
|
201
|
-
payload: legacyPayload,
|
|
202
|
-
})];
|
|
203
|
-
// `pr-*` requests are terminal PermissionRequest hooks surfaced through the
|
|
204
|
-
// legacy Agent UI channel. Send the terminal decision too so older hosts, and
|
|
205
|
-
// hosts that route hook permissions through terminal handling, can resolve it
|
|
206
|
-
// without involving the mobile websocket/controller path.
|
|
207
|
-
if (body.requestId.startsWith("pr-")) {
|
|
208
|
-
const decisionPayload = parseTypedPayload("permission.decision", {
|
|
209
|
-
requestId: body.requestId,
|
|
210
|
-
decision: body.outcome === "allow" ? "allow" : "deny",
|
|
211
|
-
});
|
|
212
|
-
envelopes.push(createEnvelope({
|
|
213
|
-
type: "permission.decision",
|
|
214
|
-
sessionId: body.sessionId,
|
|
215
|
-
terminalId: body.terminalId ?? "default",
|
|
216
|
-
deviceId: "live-activity",
|
|
217
|
-
payload: decisionPayload,
|
|
218
|
-
}));
|
|
219
|
-
}
|
|
220
|
-
return envelopes;
|
|
221
|
-
}
|
|
222
182
|
const payload = parseTypedPayload("permission.decision", {
|
|
223
183
|
requestId: body.requestId,
|
|
224
184
|
decision: body.outcome === "allow" ? "allow" : "deny",
|
|
225
185
|
});
|
|
226
186
|
return [createEnvelope({
|
|
227
187
|
type: "permission.decision",
|
|
228
|
-
|
|
188
|
+
hostDeviceId,
|
|
229
189
|
terminalId: body.terminalId ?? "default",
|
|
230
190
|
deviceId: "live-activity",
|
|
231
191
|
payload,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-permission-http.js","sourceRoot":"","sources":["../../../src/agent-permission-http.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,uBAAuB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AACvE,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEzC,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE;IAC5E,CAAC,CAAC,MAAM,CAAC;QACP,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;QACzB,
|
|
1
|
+
{"version":3,"file":"agent-permission-http.js","sourceRoot":"","sources":["../../../src/agent-permission-http.ts"],"names":[],"mappings":"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"}
|