agentdev 0.1.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/LICENSE +21 -0
- package/README.md +384 -0
- package/dist/BasicAgent-UDSHJE5H.js +12 -0
- package/dist/BasicAgent-UDSHJE5H.js.map +1 -0
- package/dist/ExplorerAgent-X6QECX65.js +12 -0
- package/dist/ExplorerAgent-X6QECX65.js.map +1 -0
- package/dist/chunk-3BPSNNK3.js +926 -0
- package/dist/chunk-3BPSNNK3.js.map +1 -0
- package/dist/chunk-BDS2QGZ5.js +22 -0
- package/dist/chunk-BDS2QGZ5.js.map +1 -0
- package/dist/chunk-BVF7RUXV.js +136 -0
- package/dist/chunk-BVF7RUXV.js.map +1 -0
- package/dist/chunk-DI5EGMGG.js +87 -0
- package/dist/chunk-DI5EGMGG.js.map +1 -0
- package/dist/chunk-FZGM6EMW.js +7578 -0
- package/dist/chunk-FZGM6EMW.js.map +1 -0
- package/dist/chunk-N7J76R5P.js +7659 -0
- package/dist/chunk-N7J76R5P.js.map +1 -0
- package/dist/chunk-TSASFMRF.js +12 -0
- package/dist/chunk-TSASFMRF.js.map +1 -0
- package/dist/chunk-XAJ6L4GA.js +98 -0
- package/dist/chunk-XAJ6L4GA.js.map +1 -0
- package/dist/cli/server.cmd +2 -0
- package/dist/cli/server.d.ts +1 -0
- package/dist/cli/server.js +46 -0
- package/dist/cli/server.js.map +1 -0
- package/dist/cli/viewer.cmd +2 -0
- package/dist/cli/viewer.d.ts +1 -0
- package/dist/cli/viewer.js +45 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/index.d.ts +3836 -0
- package/dist/index.js +273 -0
- package/dist/index.js.map +1 -0
- package/dist/notification-3VEAP7YF.js +89 -0
- package/dist/notification-3VEAP7YF.js.map +1 -0
- package/dist/resolver-5H6QIGVA.js +8 -0
- package/dist/resolver-5H6QIGVA.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,926 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getDefaultUDSPath
|
|
3
|
+
} from "./chunk-TSASFMRF.js";
|
|
4
|
+
import {
|
|
5
|
+
__require
|
|
6
|
+
} from "./chunk-BDS2QGZ5.js";
|
|
7
|
+
|
|
8
|
+
// src/core/debug-transport.ts
|
|
9
|
+
function resolveDebugTransportMode() {
|
|
10
|
+
return process.env.AGENTDEV_DEBUG_TRANSPORT === "claw" ? "claw" : "viewer-worker";
|
|
11
|
+
}
|
|
12
|
+
function getClawRuntimeUrl() {
|
|
13
|
+
return process.env.AGENTDEV_CLAW_RUNTIME_URL || "http://127.0.0.1:3030";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/core/debug-capabilities.ts
|
|
17
|
+
function getDebugCapabilities() {
|
|
18
|
+
const transportMode = resolveDebugTransportMode();
|
|
19
|
+
const isClaw = transportMode === "claw";
|
|
20
|
+
return {
|
|
21
|
+
transportMode,
|
|
22
|
+
interactiveInput: true,
|
|
23
|
+
runtimeUrl: isClaw ? getClawRuntimeUrl() : null,
|
|
24
|
+
viewerCompatibleApi: isClaw,
|
|
25
|
+
debuggerMcpMetadata: isClaw
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/core/debug-hub.ts
|
|
30
|
+
import { connect } from "net";
|
|
31
|
+
|
|
32
|
+
// src/core/claw-debug-client.ts
|
|
33
|
+
var ClawDebugClient = class {
|
|
34
|
+
runtimeUrl;
|
|
35
|
+
processId;
|
|
36
|
+
projectRoot;
|
|
37
|
+
sessionByAgentId = /* @__PURE__ */ new Map();
|
|
38
|
+
pendingSessionByAgentId = /* @__PURE__ */ new Map();
|
|
39
|
+
constructor(options = {}) {
|
|
40
|
+
this.runtimeUrl = (options.runtimeUrl ?? getClawRuntimeUrl()).replace(/\/$/, "");
|
|
41
|
+
this.processId = options.processId ?? String(process.pid);
|
|
42
|
+
this.projectRoot = options.projectRoot ?? process.cwd();
|
|
43
|
+
}
|
|
44
|
+
async ping() {
|
|
45
|
+
await this.requestJson("/health");
|
|
46
|
+
}
|
|
47
|
+
async registerAgent(input) {
|
|
48
|
+
const sessionId = `${this.processId}:${input.agentId}`;
|
|
49
|
+
const existing = this.pendingSessionByAgentId.get(input.agentId);
|
|
50
|
+
if (existing) {
|
|
51
|
+
return existing;
|
|
52
|
+
}
|
|
53
|
+
const pending = (async () => {
|
|
54
|
+
const registration = {
|
|
55
|
+
sessionId,
|
|
56
|
+
runtime: "agentdev",
|
|
57
|
+
agentName: input.name,
|
|
58
|
+
projectRoot: input.projectRoot ?? this.projectRoot,
|
|
59
|
+
metadata: {
|
|
60
|
+
adapter: "agentdev-debug-hub",
|
|
61
|
+
agentId: input.agentId,
|
|
62
|
+
featureTemplates: input.featureTemplates ?? {}
|
|
63
|
+
},
|
|
64
|
+
state: {
|
|
65
|
+
hookInspector: input.hookInspector ?? null,
|
|
66
|
+
overview: input.overview ?? null
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
await this.requestJson("/api/sessions/register", {
|
|
70
|
+
method: "POST",
|
|
71
|
+
body: JSON.stringify(registration)
|
|
72
|
+
});
|
|
73
|
+
this.sessionByAgentId.set(input.agentId, sessionId);
|
|
74
|
+
await this.pushLifecycle(input.agentId, {
|
|
75
|
+
phase: "agent-registered",
|
|
76
|
+
agentId: input.agentId,
|
|
77
|
+
name: input.name
|
|
78
|
+
});
|
|
79
|
+
return sessionId;
|
|
80
|
+
})();
|
|
81
|
+
this.pendingSessionByAgentId.set(input.agentId, pending);
|
|
82
|
+
try {
|
|
83
|
+
return await pending;
|
|
84
|
+
} finally {
|
|
85
|
+
this.pendingSessionByAgentId.delete(input.agentId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async unregisterAgent(agentId) {
|
|
89
|
+
await this.pushLifecycle(agentId, {
|
|
90
|
+
phase: "agent-unregistered",
|
|
91
|
+
agentId
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async selectAgent(agentId) {
|
|
95
|
+
const sessionId = await this.requireSessionId(agentId);
|
|
96
|
+
await this.requestJson("/api/agents/current", {
|
|
97
|
+
method: "PUT",
|
|
98
|
+
body: JSON.stringify({ agentId: sessionId })
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async pushMessages(agentId, messages) {
|
|
102
|
+
await this.pushEvent(agentId, "message", { messages });
|
|
103
|
+
}
|
|
104
|
+
async registerTools(agentId, tools) {
|
|
105
|
+
await this.pushEvent(agentId, "tools", { tools });
|
|
106
|
+
}
|
|
107
|
+
async updateInspector(agentId, hookInspector) {
|
|
108
|
+
await this.pushEvent(agentId, "snapshot", {
|
|
109
|
+
scope: "hookInspector",
|
|
110
|
+
hookInspector
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async updateOverview(agentId, overview) {
|
|
114
|
+
await this.pushEvent(agentId, "snapshot", {
|
|
115
|
+
scope: "overview",
|
|
116
|
+
overview
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async pushNotification(agentId, notification) {
|
|
120
|
+
await this.pushEvent(agentId, "notification", { notification });
|
|
121
|
+
}
|
|
122
|
+
async requestUserInput(_agentId, request, timeout) {
|
|
123
|
+
const agentId = _agentId;
|
|
124
|
+
const requestId = `input-${agentId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
125
|
+
await this.pushEvent(agentId, "input", {
|
|
126
|
+
requestId,
|
|
127
|
+
request,
|
|
128
|
+
timeout,
|
|
129
|
+
status: "pending"
|
|
130
|
+
});
|
|
131
|
+
const sessionId = await this.requireSessionId(agentId);
|
|
132
|
+
const startedAt = Date.now();
|
|
133
|
+
const pollIntervalMs = 400;
|
|
134
|
+
while (true) {
|
|
135
|
+
if (timeout !== Infinity && Date.now() - startedAt > timeout) {
|
|
136
|
+
throw new Error(`User input timeout after ${timeout}ms`);
|
|
137
|
+
}
|
|
138
|
+
let response;
|
|
139
|
+
try {
|
|
140
|
+
response = await fetch(
|
|
141
|
+
`${this.runtimeUrl}/api/agents/${encodeURIComponent(sessionId)}/input-response?requestId=${encodeURIComponent(requestId)}`
|
|
142
|
+
);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
145
|
+
throw new Error(`Unable to reach Claw runtime at ${this.runtimeUrl} while waiting for user input: ${message}`);
|
|
146
|
+
}
|
|
147
|
+
if (response.ok) {
|
|
148
|
+
const body = await response.json();
|
|
149
|
+
return body.response;
|
|
150
|
+
}
|
|
151
|
+
if (response.status !== 404) {
|
|
152
|
+
const text = await response.text();
|
|
153
|
+
throw new Error(`Input bridge request failed: ${response.status} ${response.statusText} ${text}`);
|
|
154
|
+
}
|
|
155
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async pushLifecycle(agentId, payload) {
|
|
159
|
+
await this.pushEvent(agentId, "lifecycle", payload);
|
|
160
|
+
}
|
|
161
|
+
async pushEvent(agentId, kind, payload) {
|
|
162
|
+
const sessionId = await this.requireSessionId(agentId);
|
|
163
|
+
const event = {
|
|
164
|
+
sessionId,
|
|
165
|
+
kind,
|
|
166
|
+
payload
|
|
167
|
+
};
|
|
168
|
+
await this.requestJson("/api/events", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body: JSON.stringify(event)
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
async requireSessionId(agentId) {
|
|
174
|
+
const sessionId = this.sessionByAgentId.get(agentId);
|
|
175
|
+
if (!sessionId) {
|
|
176
|
+
const pending = this.pendingSessionByAgentId.get(agentId);
|
|
177
|
+
if (pending) {
|
|
178
|
+
return pending;
|
|
179
|
+
}
|
|
180
|
+
throw new Error(`No Claw session registered for agentId '${agentId}'`);
|
|
181
|
+
}
|
|
182
|
+
return sessionId;
|
|
183
|
+
}
|
|
184
|
+
async requestJson(path, init) {
|
|
185
|
+
let response;
|
|
186
|
+
try {
|
|
187
|
+
response = await fetch(`${this.runtimeUrl}${path}`, {
|
|
188
|
+
...init,
|
|
189
|
+
headers: {
|
|
190
|
+
"content-type": "application/json",
|
|
191
|
+
...init?.headers ?? {}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
196
|
+
throw new Error(`Unable to reach Claw runtime at ${this.runtimeUrl}: ${message}`);
|
|
197
|
+
}
|
|
198
|
+
if (!response.ok) {
|
|
199
|
+
const body = await response.text();
|
|
200
|
+
throw new Error(`Claw runtime request failed: ${response.status} ${response.statusText} ${body}`);
|
|
201
|
+
}
|
|
202
|
+
if (response.status === 204) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
return response.json();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// src/core/debug-hub.ts
|
|
210
|
+
var DebugHub = class _DebugHub {
|
|
211
|
+
static instance;
|
|
212
|
+
transportMode;
|
|
213
|
+
clawClient;
|
|
214
|
+
// ========== 状态 ==========
|
|
215
|
+
agents = /* @__PURE__ */ new Map();
|
|
216
|
+
currentAgentId = null;
|
|
217
|
+
nextId = 1;
|
|
218
|
+
processId;
|
|
219
|
+
// 进程唯一标识
|
|
220
|
+
// 输入请求回调映射:requestId → resolver
|
|
221
|
+
pendingInputRequests = /* @__PURE__ */ new Map();
|
|
222
|
+
// 活跃的输入请求元数据(用于重连恢复):agentId → requestInfo
|
|
223
|
+
activeInputRequests = /* @__PURE__ */ new Map();
|
|
224
|
+
// UDS 客户端连接
|
|
225
|
+
udsClient;
|
|
226
|
+
udsPath;
|
|
227
|
+
workerPort = null;
|
|
228
|
+
clientReady = false;
|
|
229
|
+
// 注册锁(防止并发竞争)
|
|
230
|
+
registrationLock = false;
|
|
231
|
+
// 待发送的消息队列(连接建立前)
|
|
232
|
+
messageQueue = [];
|
|
233
|
+
// 重连机制
|
|
234
|
+
reconnectTimer;
|
|
235
|
+
reconnectAttempts = 0;
|
|
236
|
+
MAX_RECONNECT_ATTEMPTS = 10;
|
|
237
|
+
RECONNECT_DELAY = 2e3;
|
|
238
|
+
// 缓存每个 Agent 的 featureTemplates(用于重连后重新注册)
|
|
239
|
+
agentFeatureTemplates = /* @__PURE__ */ new Map();
|
|
240
|
+
// ========== 单例 ==========
|
|
241
|
+
constructor() {
|
|
242
|
+
this.udsPath = process.env.AGENTDEV_UDS_PATH || getDefaultUDSPath();
|
|
243
|
+
this.processId = String(process.pid);
|
|
244
|
+
this.transportMode = resolveDebugTransportMode();
|
|
245
|
+
if (this.transportMode === "claw") {
|
|
246
|
+
this.clawClient = new ClawDebugClient({
|
|
247
|
+
processId: this.processId,
|
|
248
|
+
projectRoot: process.cwd()
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
static getInstance() {
|
|
253
|
+
if (!_DebugHub.instance) {
|
|
254
|
+
_DebugHub.instance = new _DebugHub();
|
|
255
|
+
}
|
|
256
|
+
return _DebugHub.instance;
|
|
257
|
+
}
|
|
258
|
+
// ========== 公开 API ==========
|
|
259
|
+
/**
|
|
260
|
+
* 启动调试服务器
|
|
261
|
+
* @param port HTTP 端口(默认 2026,仅用于显示)
|
|
262
|
+
* @param openBrowser 是否自动打开浏览器(默认 true,已废弃参数)
|
|
263
|
+
*/
|
|
264
|
+
async start(port = 2026, openBrowser = true) {
|
|
265
|
+
if (this.transportMode === "claw") {
|
|
266
|
+
this.workerPort = port;
|
|
267
|
+
try {
|
|
268
|
+
await this.clawClient?.ping();
|
|
269
|
+
this.clientReady = true;
|
|
270
|
+
console.log(`[DebugHub] \u5DF2\u8FDE\u63A5\u5230 Claw runtime: ${getClawRuntimeUrl()}`);
|
|
271
|
+
} catch (err) {
|
|
272
|
+
console.warn(`[DebugHub] \u65E0\u6CD5\u8FDE\u63A5\u5230 Claw runtime: ${err.message}`);
|
|
273
|
+
console.warn("[DebugHub] \u8C03\u8BD5\u529F\u80FD\u5C06\u88AB\u7981\u7528\u3002\u8BF7\u5148\u542F\u52A8 AgentDevClaw runtime\u3002");
|
|
274
|
+
this.clientReady = false;
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (this.udsClient) {
|
|
279
|
+
console.log(`[DebugHub] \u5DF2\u8FDE\u63A5\u5230 ViewerWorker`);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
this.workerPort = port;
|
|
283
|
+
this.openBrowser = openBrowser;
|
|
284
|
+
try {
|
|
285
|
+
await this.connectToWorker();
|
|
286
|
+
console.log(`[DebugHub] \u8C03\u8BD5\u670D\u52A1\u5668\u5DF2\u8FDE\u63A5: http://localhost:${port}`);
|
|
287
|
+
} catch (err) {
|
|
288
|
+
console.log(`[DebugHub] ViewerWorker \u672A\u8FD0\u884C\uFF0C\u6B63\u5728\u81EA\u52A8\u542F\u52A8...`);
|
|
289
|
+
try {
|
|
290
|
+
await this.spawnViewerWorker();
|
|
291
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
292
|
+
await this.connectToWorker();
|
|
293
|
+
console.log(`[DebugHub] \u8C03\u8BD5\u670D\u52A1\u5668\u5DF2\u8FDE\u63A5: http://localhost:${port}`);
|
|
294
|
+
} catch (spawnErr) {
|
|
295
|
+
console.warn(`[DebugHub] \u65E0\u6CD5\u542F\u52A8 ViewerWorker: ${spawnErr.message}`);
|
|
296
|
+
console.warn(`[DebugHub] \u8C03\u8BD5\u529F\u80FD\u5C06\u88AB\u7981\u7528\u3002\u8BF7\u624B\u52A8\u8FD0\u884C 'agentdev-viewer' \u542F\u52A8\u8C03\u8BD5\u670D\u52A1\u5668\u3002`);
|
|
297
|
+
this.clientReady = false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 自动启动 ViewerWorker 进程
|
|
303
|
+
*/
|
|
304
|
+
openBrowser = true;
|
|
305
|
+
viewerWorkerProcess;
|
|
306
|
+
async spawnViewerWorker() {
|
|
307
|
+
const { spawn } = await import("child_process");
|
|
308
|
+
const { existsSync } = await import("fs");
|
|
309
|
+
const { fileURLToPath } = await import("url");
|
|
310
|
+
const { dirname, join } = await import("path");
|
|
311
|
+
let viewerPath;
|
|
312
|
+
try {
|
|
313
|
+
const agentdevPath = __require.resolve("agentdev/package.json");
|
|
314
|
+
viewerPath = join(dirname(agentdevPath), "dist", "cli", "viewer.js");
|
|
315
|
+
} catch {
|
|
316
|
+
try {
|
|
317
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
318
|
+
viewerPath = join(currentDir, "..", "cli", "viewer.js");
|
|
319
|
+
} catch {
|
|
320
|
+
viewerPath = "agentdev-viewer";
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (viewerPath !== "agentdev-viewer" && !existsSync(viewerPath)) {
|
|
324
|
+
viewerPath = "agentdev-viewer";
|
|
325
|
+
}
|
|
326
|
+
return new Promise((resolve, reject) => {
|
|
327
|
+
try {
|
|
328
|
+
const env = {
|
|
329
|
+
...process.env,
|
|
330
|
+
AGENTDEV_PORT: String(this.workerPort || 2026),
|
|
331
|
+
AGENTDEV_OPEN_BROWSER: this.openBrowser ? "true" : "false",
|
|
332
|
+
AGENTDEV_UDS_PATH: this.udsPath
|
|
333
|
+
};
|
|
334
|
+
console.log(`[DebugHub] \u542F\u52A8 ViewerWorker: ${viewerPath}`);
|
|
335
|
+
const isBinCommand = viewerPath === "agentdev-viewer" || viewerPath === "agentdev-server";
|
|
336
|
+
const command = isBinCommand ? viewerPath : "node";
|
|
337
|
+
const args = isBinCommand ? [] : [viewerPath];
|
|
338
|
+
this.viewerWorkerProcess = spawn(command, args, {
|
|
339
|
+
env,
|
|
340
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
341
|
+
detached: false,
|
|
342
|
+
shell: isBinCommand
|
|
343
|
+
// bin 命令需要 shell 来解析
|
|
344
|
+
});
|
|
345
|
+
this.viewerWorkerProcess.on("error", (err) => {
|
|
346
|
+
console.error("[DebugHub] ViewerWorker \u8FDB\u7A0B\u9519\u8BEF:", err.message);
|
|
347
|
+
reject(err);
|
|
348
|
+
});
|
|
349
|
+
this.viewerWorkerProcess.stdout?.on("data", (data) => {
|
|
350
|
+
const lines = data.toString().trim().split("\n");
|
|
351
|
+
for (const line of lines) {
|
|
352
|
+
console.log(`[ViewerWorker] ${line}`);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
this.viewerWorkerProcess.stderr?.on("data", (data) => {
|
|
356
|
+
const lines = data.toString().trim().split("\n");
|
|
357
|
+
for (const line of lines) {
|
|
358
|
+
console.error(`[ViewerWorker] ${line}`);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
setTimeout(() => {
|
|
362
|
+
if (this.viewerWorkerProcess && !this.viewerWorkerProcess.killed) {
|
|
363
|
+
resolve();
|
|
364
|
+
} else {
|
|
365
|
+
reject(new Error("ViewerWorker \u8FDB\u7A0B\u542F\u52A8\u5931\u8D25"));
|
|
366
|
+
}
|
|
367
|
+
}, 500);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
reject(err);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 停止调试服务器
|
|
375
|
+
*/
|
|
376
|
+
stop() {
|
|
377
|
+
if (this.transportMode === "claw") {
|
|
378
|
+
this.clientReady = false;
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (this.reconnectTimer) {
|
|
382
|
+
clearTimeout(this.reconnectTimer);
|
|
383
|
+
this.reconnectTimer = void 0;
|
|
384
|
+
}
|
|
385
|
+
if (this.udsClient) {
|
|
386
|
+
this.sendToWorker({ type: "stop" });
|
|
387
|
+
this.udsClient.end();
|
|
388
|
+
this.udsClient = void 0;
|
|
389
|
+
this.clientReady = false;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* 手动重连(可选)
|
|
394
|
+
* 如果已经连接,则不执行任何操作
|
|
395
|
+
*/
|
|
396
|
+
async reconnect() {
|
|
397
|
+
if (this.transportMode === "claw") {
|
|
398
|
+
await this.start(this.workerPort ?? 2026, false);
|
|
399
|
+
if (!this.clientReady) {
|
|
400
|
+
throw new Error("Claw runtime reconnect failed");
|
|
401
|
+
}
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (this.clientReady && this.udsClient) {
|
|
405
|
+
console.log("[DebugHub] \u5DF2\u7ECF\u8FDE\u63A5\uFF0C\u65E0\u9700\u91CD\u8FDE");
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
this.reconnectAttempts = 0;
|
|
409
|
+
if (this.reconnectTimer) {
|
|
410
|
+
clearTimeout(this.reconnectTimer);
|
|
411
|
+
this.reconnectTimer = void 0;
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
await this.connectToWorker();
|
|
415
|
+
console.log("[DebugHub] \u2705 \u624B\u52A8\u91CD\u8FDE\u6210\u529F");
|
|
416
|
+
} catch (error) {
|
|
417
|
+
console.error(`[DebugHub] \u624B\u52A8\u91CD\u8FDE\u5931\u8D25: ${error.message}`);
|
|
418
|
+
throw error;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* 注册 Agent
|
|
423
|
+
* @param agent Agent 实例
|
|
424
|
+
* @param name 显示名称(可选,默认使用类名)
|
|
425
|
+
* @param featureTemplates Feature 模板路径映射(可选)
|
|
426
|
+
* @returns 分配的 agentId
|
|
427
|
+
*/
|
|
428
|
+
registerAgent(agent, name, featureTemplates, hookInspector, overview) {
|
|
429
|
+
while (this.registrationLock) {
|
|
430
|
+
}
|
|
431
|
+
this.registrationLock = true;
|
|
432
|
+
try {
|
|
433
|
+
const id = `agent-${this.nextId++}-${this.processId}`;
|
|
434
|
+
const info = {
|
|
435
|
+
id,
|
|
436
|
+
name: name || agent.constructor.name,
|
|
437
|
+
registeredAt: Date.now()
|
|
438
|
+
};
|
|
439
|
+
this.agents.set(id, { info, agent });
|
|
440
|
+
if (featureTemplates) {
|
|
441
|
+
this.agentFeatureTemplates.set(id, featureTemplates);
|
|
442
|
+
}
|
|
443
|
+
if (this.agents.size === 1) {
|
|
444
|
+
this.currentAgentId = id;
|
|
445
|
+
}
|
|
446
|
+
if (this.transportMode === "claw") {
|
|
447
|
+
void this.clawClient?.registerAgent({
|
|
448
|
+
agentId: id,
|
|
449
|
+
name: info.name,
|
|
450
|
+
projectRoot: process.cwd(),
|
|
451
|
+
featureTemplates,
|
|
452
|
+
hookInspector,
|
|
453
|
+
overview
|
|
454
|
+
}).catch((error) => {
|
|
455
|
+
console.error(`[DebugHub] Claw registerAgent \u5931\u8D25: ${error.message}`);
|
|
456
|
+
});
|
|
457
|
+
} else {
|
|
458
|
+
this.sendToWorker({
|
|
459
|
+
type: "register-agent",
|
|
460
|
+
agentId: id,
|
|
461
|
+
name: info.name,
|
|
462
|
+
createdAt: info.registeredAt,
|
|
463
|
+
projectRoot: process.cwd(),
|
|
464
|
+
// 传递项目根目录,用于模板文件加载
|
|
465
|
+
featureTemplates,
|
|
466
|
+
// 传递 Feature 模板路径映射
|
|
467
|
+
hookInspector,
|
|
468
|
+
overview
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
console.log(`[DebugHub] Agent \u5DF2\u6CE8\u518C: ${id} (${info.name})`);
|
|
472
|
+
return id;
|
|
473
|
+
} finally {
|
|
474
|
+
this.registrationLock = false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* 注销 Agent
|
|
479
|
+
* @param agentId Agent ID
|
|
480
|
+
*/
|
|
481
|
+
unregisterAgent(agentId) {
|
|
482
|
+
const deleted = this.agents.delete(agentId);
|
|
483
|
+
if (deleted) {
|
|
484
|
+
if (this.transportMode === "claw") {
|
|
485
|
+
void this.clawClient?.unregisterAgent(agentId).catch((error) => {
|
|
486
|
+
console.error(`[DebugHub] Claw unregisterAgent \u5931\u8D25: ${error.message}`);
|
|
487
|
+
});
|
|
488
|
+
} else {
|
|
489
|
+
this.sendToWorker({ type: "unregister-agent", agentId });
|
|
490
|
+
}
|
|
491
|
+
console.log(`[DebugHub] Agent \u5DF2\u6CE8\u9500: ${agentId}`);
|
|
492
|
+
if (this.currentAgentId === agentId) {
|
|
493
|
+
const remaining = Array.from(this.agents.keys());
|
|
494
|
+
this.currentAgentId = remaining.length > 0 ? remaining[0] : null;
|
|
495
|
+
if (this.currentAgentId) {
|
|
496
|
+
if (this.transportMode === "claw") {
|
|
497
|
+
void this.clawClient?.selectAgent(this.currentAgentId).catch((error) => {
|
|
498
|
+
console.error(`[DebugHub] Claw selectAgent \u5931\u8D25: ${error.message}`);
|
|
499
|
+
});
|
|
500
|
+
} else if (this.transportMode === "viewer-worker") {
|
|
501
|
+
this.sendToWorker({
|
|
502
|
+
type: "set-current-agent",
|
|
503
|
+
agentId: this.currentAgentId
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* 切换当前选中的 Agent
|
|
512
|
+
* @param agentId Agent ID
|
|
513
|
+
* @returns 是否成功
|
|
514
|
+
*/
|
|
515
|
+
selectAgent(agentId) {
|
|
516
|
+
if (!this.agents.has(agentId)) {
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
this.currentAgentId = agentId;
|
|
520
|
+
if (this.transportMode === "claw") {
|
|
521
|
+
void this.clawClient?.selectAgent(agentId).catch((error) => {
|
|
522
|
+
console.error(`[DebugHub] Claw selectAgent \u5931\u8D25: ${error.message}`);
|
|
523
|
+
});
|
|
524
|
+
console.log(`[DebugHub] \u5F53\u524D Agent \u5DF2\u5207\u6362: ${agentId}`);
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
if (this.transportMode === "viewer-worker") {
|
|
528
|
+
this.sendToWorker({
|
|
529
|
+
type: "set-current-agent",
|
|
530
|
+
agentId
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
console.log(`[DebugHub] \u5F53\u524D Agent \u5DF2\u5207\u6362: ${agentId}`);
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* 推送 Agent 消息
|
|
538
|
+
* @param agentId Agent ID
|
|
539
|
+
* @param messages 消息数组
|
|
540
|
+
*/
|
|
541
|
+
pushMessages(agentId, messages) {
|
|
542
|
+
if (this.transportMode === "claw") {
|
|
543
|
+
void this.clawClient?.pushMessages(agentId, messages).catch((error) => {
|
|
544
|
+
console.error(`[DebugHub] Claw pushMessages \u5931\u8D25: ${error.message}`);
|
|
545
|
+
});
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
this.sendToWorker({
|
|
549
|
+
type: "push-messages",
|
|
550
|
+
agentId,
|
|
551
|
+
messages
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* 注册 Agent 工具
|
|
556
|
+
* @param agentId Agent ID
|
|
557
|
+
* @param tools 工具数组
|
|
558
|
+
*/
|
|
559
|
+
registerAgentTools(agentId, tools) {
|
|
560
|
+
if (this.transportMode === "claw") {
|
|
561
|
+
void this.clawClient?.registerTools(agentId, tools).catch((error) => {
|
|
562
|
+
console.error(`[DebugHub] Claw registerTools \u5931\u8D25: ${error.message}`);
|
|
563
|
+
});
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
this.sendToWorker({
|
|
567
|
+
type: "register-tools",
|
|
568
|
+
agentId,
|
|
569
|
+
tools
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
updateAgentInspector(agentId, hookInspector) {
|
|
573
|
+
if (this.transportMode === "claw") {
|
|
574
|
+
void this.clawClient?.updateInspector(agentId, hookInspector).catch((error) => {
|
|
575
|
+
console.error(`[DebugHub] Claw updateInspector \u5931\u8D25: ${error.message}`);
|
|
576
|
+
});
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
this.sendToWorker({
|
|
580
|
+
type: "update-agent-inspector",
|
|
581
|
+
agentId,
|
|
582
|
+
hookInspector
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
updateAgentOverview(agentId, overview) {
|
|
586
|
+
if (this.transportMode === "claw") {
|
|
587
|
+
void this.clawClient?.updateOverview(agentId, overview).catch((error) => {
|
|
588
|
+
console.error(`[DebugHub] Claw updateOverview \u5931\u8D25: ${error.message}`);
|
|
589
|
+
});
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
this.sendToWorker({
|
|
593
|
+
type: "update-agent-overview",
|
|
594
|
+
agentId,
|
|
595
|
+
overview
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* 获取所有已注册的 Agent 信息
|
|
600
|
+
*/
|
|
601
|
+
getAgentList() {
|
|
602
|
+
return Array.from(this.agents.values()).map((v) => v.info);
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* 获取当前选中的 Agent ID
|
|
606
|
+
*/
|
|
607
|
+
getCurrentAgentId() {
|
|
608
|
+
return this.currentAgentId;
|
|
609
|
+
}
|
|
610
|
+
getTransportMode() {
|
|
611
|
+
return this.transportMode;
|
|
612
|
+
}
|
|
613
|
+
getCapabilities() {
|
|
614
|
+
return getDebugCapabilities();
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* 根据 Agent 实例获取其 ID
|
|
618
|
+
*/
|
|
619
|
+
getAgentId(agent) {
|
|
620
|
+
for (const [id, data] of this.agents) {
|
|
621
|
+
if (data.agent === agent) {
|
|
622
|
+
return id;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return void 0;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* 获取 Worker 端口
|
|
629
|
+
*/
|
|
630
|
+
getPort() {
|
|
631
|
+
return this.workerPort;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* 检查是否已连接到 ViewerWorker
|
|
635
|
+
*/
|
|
636
|
+
isConnected() {
|
|
637
|
+
if (this.transportMode === "claw") {
|
|
638
|
+
return this.clientReady;
|
|
639
|
+
}
|
|
640
|
+
return this.clientReady && !!this.udsClient;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* 推送通知
|
|
644
|
+
* @param agentId Agent ID
|
|
645
|
+
* @param notification 通知对象
|
|
646
|
+
*/
|
|
647
|
+
pushNotification(agentId, notification) {
|
|
648
|
+
if (this.transportMode === "claw") {
|
|
649
|
+
void this.clawClient?.pushNotification(agentId, notification).catch((error) => {
|
|
650
|
+
console.error(`[DebugHub] Claw pushNotification \u5931\u8D25: ${error.message}`);
|
|
651
|
+
});
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
this.sendToWorker({
|
|
655
|
+
type: "push-notification",
|
|
656
|
+
agentId,
|
|
657
|
+
notification
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* 请求用户输入
|
|
662
|
+
* @param agentId Agent ID
|
|
663
|
+
* @param prompt 提示信息
|
|
664
|
+
* @param timeout 超时时间(毫秒),默认 Infinity(无限等待)
|
|
665
|
+
* @returns Promise<string> 用户输入内容
|
|
666
|
+
*/
|
|
667
|
+
requestUserInput(agentId, prompt, timeout = Infinity) {
|
|
668
|
+
return this.requestUserInputEvent(agentId, { prompt }, timeout).then((response) => {
|
|
669
|
+
if (response.kind !== "text") {
|
|
670
|
+
throw new Error(`Expected text user input but received action '${response.actionId ?? "unknown"}'`);
|
|
671
|
+
}
|
|
672
|
+
return response.text ?? "";
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
requestUserInputEvent(agentId, request, timeout = Infinity) {
|
|
676
|
+
if (this.transportMode === "claw") {
|
|
677
|
+
return this.clawClient?.requestUserInput(agentId, request, timeout) ?? Promise.reject(new Error("Claw client is not available"));
|
|
678
|
+
}
|
|
679
|
+
const requestId = `input-${agentId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
680
|
+
return new Promise((resolve, reject) => {
|
|
681
|
+
let timer;
|
|
682
|
+
if (timeout !== Infinity) {
|
|
683
|
+
timer = setTimeout(() => {
|
|
684
|
+
this.pendingInputRequests.delete(requestId);
|
|
685
|
+
this.activeInputRequests.delete(agentId);
|
|
686
|
+
reject(new Error(`User input timeout after ${timeout}ms`));
|
|
687
|
+
}, timeout);
|
|
688
|
+
}
|
|
689
|
+
this.pendingInputRequests.set(requestId, (response) => {
|
|
690
|
+
if (timer) clearTimeout(timer);
|
|
691
|
+
this.activeInputRequests.delete(agentId);
|
|
692
|
+
resolve(response);
|
|
693
|
+
});
|
|
694
|
+
this.activeInputRequests.set(agentId, {
|
|
695
|
+
requestId,
|
|
696
|
+
prompt: request.prompt,
|
|
697
|
+
placeholder: request.placeholder,
|
|
698
|
+
initialValue: request.initialValue,
|
|
699
|
+
actions: request.actions,
|
|
700
|
+
timestamp: Date.now()
|
|
701
|
+
});
|
|
702
|
+
this.sendToWorker({
|
|
703
|
+
type: "request-input",
|
|
704
|
+
agentId,
|
|
705
|
+
requestId,
|
|
706
|
+
prompt: request.prompt,
|
|
707
|
+
placeholder: request.placeholder,
|
|
708
|
+
initialValue: request.initialValue,
|
|
709
|
+
actions: request.actions,
|
|
710
|
+
timeout
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
// ========== 内部方法 ==========
|
|
715
|
+
/**
|
|
716
|
+
* 连接到 UDS 服务器
|
|
717
|
+
*/
|
|
718
|
+
async connectToWorker() {
|
|
719
|
+
return new Promise((resolve, reject) => {
|
|
720
|
+
this.udsClient = connect(this.udsPath);
|
|
721
|
+
this.udsClient.on("connect", () => {
|
|
722
|
+
this.clientReady = true;
|
|
723
|
+
this.reconnectAttempts = 0;
|
|
724
|
+
console.log(`[DebugHub] \u5DF2\u8FDE\u63A5\u5230 ViewerWorker: ${this.udsPath}`);
|
|
725
|
+
for (const msg of this.messageQueue) {
|
|
726
|
+
this.sendViaUDS(msg);
|
|
727
|
+
}
|
|
728
|
+
this.messageQueue = [];
|
|
729
|
+
this.reregisterAllAgents();
|
|
730
|
+
if (this.currentAgentId) {
|
|
731
|
+
this.sendToWorker({
|
|
732
|
+
type: "set-current-agent",
|
|
733
|
+
agentId: this.currentAgentId
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
resolve();
|
|
737
|
+
});
|
|
738
|
+
this.udsClient.on("data", (data) => {
|
|
739
|
+
const lines = data.toString().split("\n");
|
|
740
|
+
for (const line of lines) {
|
|
741
|
+
if (!line.trim()) continue;
|
|
742
|
+
try {
|
|
743
|
+
const msg = JSON.parse(line);
|
|
744
|
+
this.handleWorkerMessage(msg);
|
|
745
|
+
} catch (err) {
|
|
746
|
+
console.error("[DebugHub] Worker \u6D88\u606F\u89E3\u6790\u5931\u8D25:", err);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
this.udsClient.on("error", (err) => {
|
|
751
|
+
reject(new Error(`\u8FDE\u63A5 ViewerWorker \u5931\u8D25 (${this.udsPath}): ${err.message}
|
|
752
|
+
\u8BF7\u5148\u542F\u52A8 ViewerWorker \u670D\u52A1\u5668`));
|
|
753
|
+
});
|
|
754
|
+
this.udsClient.on("close", () => {
|
|
755
|
+
this.clientReady = false;
|
|
756
|
+
console.warn("[DebugHub] \u4E0E ViewerWorker \u7684\u8FDE\u63A5\u5DF2\u65AD\u5F00");
|
|
757
|
+
this.scheduleReconnect();
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* 处理来自 Worker 的消息
|
|
763
|
+
*/
|
|
764
|
+
handleWorkerMessage(msg) {
|
|
765
|
+
switch (msg.type) {
|
|
766
|
+
case "agent-switched":
|
|
767
|
+
console.log(`[DebugHub] \u5F53\u524D Agent \u5DF2\u5207\u6362: ${msg.agentId}`);
|
|
768
|
+
break;
|
|
769
|
+
// 处理用户输入响应
|
|
770
|
+
case "input-response":
|
|
771
|
+
const resolver = this.pendingInputRequests.get(msg.requestId);
|
|
772
|
+
if (resolver) {
|
|
773
|
+
resolver(msg.response ?? {
|
|
774
|
+
kind: "text",
|
|
775
|
+
text: msg.input
|
|
776
|
+
});
|
|
777
|
+
this.pendingInputRequests.delete(msg.requestId);
|
|
778
|
+
} else {
|
|
779
|
+
console.warn(`[DebugHub] \u672A\u77E5\u8F93\u5165\u54CD\u5E94: ${msg.requestId}`);
|
|
780
|
+
}
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* 重新注册所有 Agent(重连后调用)
|
|
786
|
+
* 确保 ViewerWorker 能够恢复所有 Agent 的注册信息
|
|
787
|
+
*/
|
|
788
|
+
reregisterAllAgents() {
|
|
789
|
+
if (this.transportMode === "claw") {
|
|
790
|
+
for (const [id, data] of this.agents) {
|
|
791
|
+
const hookInspector = data.agent.buildHookInspectorSnapshot?.() || data.agent.hookInspector;
|
|
792
|
+
const overview = data.agent.buildOverviewSnapshot?.();
|
|
793
|
+
const featureTemplates = this.agentFeatureTemplates.get(id) || {};
|
|
794
|
+
void this.clawClient?.registerAgent({
|
|
795
|
+
agentId: id,
|
|
796
|
+
name: data.info.name,
|
|
797
|
+
projectRoot: process.cwd(),
|
|
798
|
+
featureTemplates,
|
|
799
|
+
hookInspector,
|
|
800
|
+
overview
|
|
801
|
+
}).then(async () => {
|
|
802
|
+
const tools = data.agent.tools;
|
|
803
|
+
if (tools && typeof tools.getEntries === "function") {
|
|
804
|
+
const entries = tools.getEntries();
|
|
805
|
+
const toolList = entries.map((e) => e.tool);
|
|
806
|
+
if (toolList.length > 0) {
|
|
807
|
+
await this.clawClient?.registerTools(id, toolList);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
const context = data.agent.getContext?.();
|
|
811
|
+
if (context && typeof context.getAll === "function") {
|
|
812
|
+
const messages = context.getAll();
|
|
813
|
+
if (messages.length > 0) {
|
|
814
|
+
await this.clawClient?.pushMessages(id, messages);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}).catch((error) => {
|
|
818
|
+
console.error(`[DebugHub] Claw re-register \u5931\u8D25: ${error.message}`);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
if (this.agents.size === 0) {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
console.log(`[DebugHub] \u91CD\u65B0\u6CE8\u518C ${this.agents.size} \u4E2A Agent...`);
|
|
827
|
+
for (const [id, data] of this.agents) {
|
|
828
|
+
const hookInspector = data.agent.buildHookInspectorSnapshot?.() || data.agent.hookInspector;
|
|
829
|
+
const overview = data.agent.buildOverviewSnapshot?.();
|
|
830
|
+
const featureTemplates = this.agentFeatureTemplates.get(id) || {};
|
|
831
|
+
const activeInputRequest = this.activeInputRequests.get(id);
|
|
832
|
+
if (activeInputRequest) {
|
|
833
|
+
console.log(`[DebugHub] \u53D1\u73B0\u6D3B\u8DC3\u8F93\u5165\u8BF7\u6C42: ${activeInputRequest.requestId}`);
|
|
834
|
+
}
|
|
835
|
+
this.sendToWorker({
|
|
836
|
+
type: "register-agent",
|
|
837
|
+
agentId: id,
|
|
838
|
+
name: data.info.name,
|
|
839
|
+
createdAt: data.info.registeredAt,
|
|
840
|
+
projectRoot: process.cwd(),
|
|
841
|
+
featureTemplates,
|
|
842
|
+
hookInspector,
|
|
843
|
+
overview,
|
|
844
|
+
activeInputRequest
|
|
845
|
+
// 携带活跃输入请求
|
|
846
|
+
});
|
|
847
|
+
const tools = data.agent.tools;
|
|
848
|
+
if (tools && typeof tools.getEntries === "function") {
|
|
849
|
+
const entries = tools.getEntries();
|
|
850
|
+
const toolList = entries.map((e) => e.tool);
|
|
851
|
+
if (toolList.length > 0) {
|
|
852
|
+
this.sendToWorker({
|
|
853
|
+
type: "register-tools",
|
|
854
|
+
agentId: id,
|
|
855
|
+
tools: toolList
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
const context = data.agent.getContext?.();
|
|
860
|
+
if (context && typeof context.getAll === "function") {
|
|
861
|
+
const messages = context.getAll();
|
|
862
|
+
if (messages.length > 0) {
|
|
863
|
+
this.sendToWorker({
|
|
864
|
+
type: "push-messages",
|
|
865
|
+
agentId: id,
|
|
866
|
+
messages
|
|
867
|
+
});
|
|
868
|
+
console.log(`[DebugHub] \u6062\u590D Agent ${id} \u7684 ${messages.length} \u6761\u6D88\u606F`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
console.log(`[DebugHub] \u2705 \u91CD\u65B0\u6CE8\u518C\u5B8C\u6210`);
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* 安排重连(指数退避)
|
|
876
|
+
*/
|
|
877
|
+
scheduleReconnect() {
|
|
878
|
+
if (this.reconnectTimer) {
|
|
879
|
+
clearTimeout(this.reconnectTimer);
|
|
880
|
+
}
|
|
881
|
+
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
882
|
+
console.error(`[DebugHub] \u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570 (${this.MAX_RECONNECT_ATTEMPTS})\uFF0C\u505C\u6B62\u91CD\u8FDE`);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
this.reconnectAttempts++;
|
|
886
|
+
const delay = Math.min(
|
|
887
|
+
this.RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts - 1),
|
|
888
|
+
3e4
|
|
889
|
+
);
|
|
890
|
+
console.log(`[DebugHub] ${delay}ms \u540E\u5C1D\u8BD5\u7B2C ${this.reconnectAttempts} \u6B21\u91CD\u8FDE...`);
|
|
891
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
892
|
+
try {
|
|
893
|
+
await this.connectToWorker();
|
|
894
|
+
console.log("[DebugHub] \u2705 \u91CD\u8FDE\u6210\u529F\uFF0C\u8C03\u8BD5\u529F\u80FD\u5DF2\u6062\u590D");
|
|
895
|
+
} catch (error) {
|
|
896
|
+
console.error(`[DebugHub] \u91CD\u8FDE\u5931\u8D25: ${error.message}`);
|
|
897
|
+
this.scheduleReconnect();
|
|
898
|
+
}
|
|
899
|
+
}, delay);
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* 通过 UDS 发送消息
|
|
903
|
+
*/
|
|
904
|
+
sendViaUDS(msg) {
|
|
905
|
+
if (this.udsClient && this.clientReady) {
|
|
906
|
+
this.udsClient.write(JSON.stringify(msg) + "\n");
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* 发送消息到 Worker
|
|
911
|
+
*/
|
|
912
|
+
sendToWorker(msg) {
|
|
913
|
+
if (!this.udsClient) {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
this.sendViaUDS(msg);
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
export {
|
|
921
|
+
resolveDebugTransportMode,
|
|
922
|
+
getClawRuntimeUrl,
|
|
923
|
+
getDebugCapabilities,
|
|
924
|
+
DebugHub
|
|
925
|
+
};
|
|
926
|
+
//# sourceMappingURL=chunk-3BPSNNK3.js.map
|