mu-agent-bridge 1.0.73 → 1.0.78
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 +12 -8
- package/dist/src-ts/cli.js +67 -37
- package/dist/src-ts/control-server.js +7 -28
- package/dist/src-ts/core-updater.js +141 -33
- package/dist/src-ts/daemon-process.js +2 -1
- package/dist/src-ts/dsh-agent.js +7 -2
- package/dist/src-ts/http-agent.js +36 -0
- package/dist/src-ts/plugin-manager.js +185 -58
- package/dist/src-ts/plugins/abweb/index.js +1 -1
- package/dist/src-ts/plugins/abweb/public/app.js +8 -6
- package/dist/src-ts/plugins/abweb/public/index.html +3 -3
- package/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/dist/src-ts/plugins/aun/index.js +89 -11
- package/dist/src-ts/plugins/aun/messages.js +1 -1
- package/dist/src-ts/plugins/aun/public/app.js +2 -1
- package/dist/src-ts/plugins/aun/public/index.html +1 -1
- package/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/dist/src-ts/plugins/chatgpt/index.js +3 -2
- package/dist/src-ts/plugins/claude-cli/index.js +1 -1
- package/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/dist/src-ts/plugins/doubao/cdp-client.js +231 -45
- package/dist/src-ts/plugins/doubao/index.js +119 -7
- package/dist/src-ts/plugins/doubao/native-task.js +134 -0
- package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
- package/dist/src-ts/plugins/dsh/index.js +102 -23
- package/dist/src-ts/plugins/dsh/session-history.js +31 -3
- package/dist/src-ts/plugins/feishu/index.js +1 -1
- package/dist/src-ts/plugins/personal-assistant/index.js +29 -8
- package/dist/src-ts/plugins/personal-assistant/model-client.js +20 -6
- package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/dist/src-ts/plugins/personal-assistant/tools.js +4 -3
- package/dist/src-ts/plugins/qwenwork/cdp-client.js +43 -7
- package/dist/src-ts/plugins/qwenwork/index.js +52 -18
- package/dist/src-ts/plugins/workbuddy/cdp-client.js +349 -83
- package/dist/src-ts/plugins/workbuddy/index.js +24 -12
- package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
- package/dist/src-ts/plugins/zcode/index.js +97 -0
- package/dist/src-ts/session-management.js +27 -8
- package/dist/src-ts/version-manager.js +6 -3
- package/dist/tests-ts/abweb-model-config.test.js +44 -41
- package/dist/tests-ts/aun-attachments.test.js +19 -17
- package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
- package/dist/tests-ts/aun-messages.test.js +14 -0
- package/dist/tests-ts/aun-plugin.test.js +207 -19
- package/dist/tests-ts/bundled-package.test.js +1 -1
- package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
- package/dist/tests-ts/chatgpt-plugin.test.js +19 -0
- package/dist/tests-ts/control-server.test.js +20 -0
- package/dist/tests-ts/core-updater.test.js +215 -46
- package/dist/tests-ts/daemon-process.test.js +126 -1
- package/dist/tests-ts/desktop-launch.test.js +73 -0
- package/dist/tests-ts/doubao-native-task.test.js +237 -0
- package/dist/tests-ts/doubao-plugin.test.js +688 -19
- package/dist/tests-ts/dsh-agent.test.js +91 -19
- package/dist/tests-ts/dsh-cdp.test.js +148 -0
- package/dist/tests-ts/dsh-history.test.js +37 -0
- package/dist/tests-ts/feishu-plugin.test.js +1 -1
- package/dist/tests-ts/http-agent.test.js +18 -0
- package/dist/tests-ts/local-cli.test.js +29 -2
- package/dist/tests-ts/model-provider-cancellation.test.js +2 -0
- package/dist/tests-ts/native-session-management.test.js +8 -7
- package/dist/tests-ts/personal-assistant-coordination.test.js +16 -0
- package/dist/tests-ts/personal-assistant-extensions.test.js +7 -1
- package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
- package/dist/tests-ts/personal-assistant.test.js +277 -3
- package/dist/tests-ts/platform-integration.test.js +60 -1
- package/dist/tests-ts/plugin-manager.test.js +78 -6
- package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
- package/dist/tests-ts/publish-packages.test.js +1 -1
- package/dist/tests-ts/qwenwork-plugin.test.js +30 -0
- package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
- package/dist/tests-ts/qwenwork-sse.test.js +33 -0
- package/dist/tests-ts/session-access-defaults.test.js +112 -0
- package/dist/tests-ts/session-management.test.js +8 -8
- package/dist/tests-ts/version-manager.test.js +40 -0
- package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
- package/dist/tests-ts/workbuddy-plugin.test.js +356 -13
- package/dist/tests-ts/zcode-cdp.test.js +894 -0
- package/dist/tests-ts/zcode-plugin.test.js +396 -0
- package/package.json +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +8 -6
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +7 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +3 -3
- package/plugins/abweb/package.json +1 -1
- package/plugins/abweb/plugin.json +1 -1
- package/plugins/aun/config.schema.json +1 -1
- package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +89 -11
- package/plugins/aun/dist/src-ts/plugins/aun/messages.js +1 -1
- package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
- package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
- package/plugins/aun/package.json +1 -1
- package/plugins/aun/plugin.json +1 -1
- package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +3 -2
- package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +1 -1
- package/plugins/claude-cli/package.json +1 -1
- package/plugins/claude-cli/plugin.json +1 -1
- package/plugins/doubao/config.schema.json +2 -1
- package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +231 -45
- package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +119 -7
- package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
- package/plugins/doubao/package.json +1 -1
- package/plugins/doubao/plugin.json +1 -1
- package/plugins/dsh/config.schema.json +5 -2
- package/plugins/dsh/dist/src-ts/dsh-agent.js +7 -2
- package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
- package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +102 -23
- package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/plugin.json +1 -1
- package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
- package/plugins/feishu/package.json +1 -1
- package/plugins/feishu/plugin.json +1 -1
- package/plugins/personal-assistant/config.schema.json +3 -2
- package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +29 -8
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +20 -6
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +4 -3
- package/plugins/personal-assistant/package.json +2 -2
- package/plugins/personal-assistant/plugin.json +1 -1
- package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +43 -7
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +52 -18
- package/plugins/qwenwork/package.json +1 -1
- package/plugins/qwenwork/plugin.json +1 -1
- package/plugins/workbuddy/config.schema.json +1 -1
- package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +349 -83
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +24 -12
- package/plugins/workbuddy/package.json +1 -1
- package/plugins/workbuddy/plugin.json +1 -1
- package/plugins/zcode/config.schema.json +13 -0
- package/plugins/zcode/dist/src-ts/agent.js +69 -0
- package/plugins/zcode/dist/src-ts/attachments.js +62 -0
- package/plugins/zcode/dist/src-ts/plugin.js +13 -0
- package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
- package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
- package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
- package/plugins/zcode/package.json +16 -0
- package/plugins/zcode/plugin.json +11 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const cdp_client_1 = require("../src-ts/plugins/workbuddy/cdp-client");
|
|
9
|
+
const flush = () => new Promise(resolve => setImmediate(resolve));
|
|
10
|
+
async function tick(t, seconds = 1) {
|
|
11
|
+
for (let i = 0; i < seconds; i++) {
|
|
12
|
+
t.mock.timers.tick(1000);
|
|
13
|
+
await flush();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function disconnected(client) {
|
|
17
|
+
return client.cdp("Runtime.evaluate").then(() => strict_1.default.fail("断线调用必须失败"), (error) => error);
|
|
18
|
+
}
|
|
19
|
+
(0, node_test_1.default)("WorkBuddy 每 30 秒回传等待提示,完成后不再提示且不混入最终正文", async (t) => {
|
|
20
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
21
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
22
|
+
let finished = false;
|
|
23
|
+
const messages = [];
|
|
24
|
+
client.evaluate = async () => JSON.stringify([{ id: "new", text: finished ? "完成结果" : "", finished, stopped: false }]);
|
|
25
|
+
client.readInteraction = async () => undefined;
|
|
26
|
+
client.readArtifacts = async () => [];
|
|
27
|
+
const result = client.waitForReply(new Set(), 1_200_000, undefined, undefined, "peer", async (text) => { messages.push(text); });
|
|
28
|
+
await tick(t, 29);
|
|
29
|
+
strict_1.default.deepEqual(messages, []);
|
|
30
|
+
await tick(t);
|
|
31
|
+
strict_1.default.equal(messages.length, 1);
|
|
32
|
+
strict_1.default.match(messages[0], /WorkBuddy.*30 秒.*未.*完成/);
|
|
33
|
+
await tick(t, 30);
|
|
34
|
+
strict_1.default.equal(messages.length, 2);
|
|
35
|
+
strict_1.default.match(messages[1], /60 秒/);
|
|
36
|
+
finished = true;
|
|
37
|
+
await tick(t);
|
|
38
|
+
strict_1.default.deepEqual(await result, { text: "完成结果" });
|
|
39
|
+
await tick(t, 60);
|
|
40
|
+
strict_1.default.equal(messages.length, 2);
|
|
41
|
+
});
|
|
42
|
+
(0, node_test_1.default)("WorkBuddy CDP 超时清理待处理请求和定时器", async (t) => {
|
|
43
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
44
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ timeoutMs: 2000 });
|
|
45
|
+
client.socket = { readyState: WebSocket.OPEN, send() { } };
|
|
46
|
+
const result = strict_1.default.rejects(client.cdp("Runtime.evaluate"), /CDP.*Runtime.evaluate.*超时/);
|
|
47
|
+
await tick(t, 2);
|
|
48
|
+
await result;
|
|
49
|
+
strict_1.default.equal(client.pending.size, 0);
|
|
50
|
+
});
|
|
51
|
+
for (const kind of ["断线", "发送失败", "请求超时", "发送确认丢失"]) {
|
|
52
|
+
(0, node_test_1.default)(`WorkBuddy ${kind}后重连继续读取原任务,保留已回传正文且只发送一次`, async (t) => {
|
|
53
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
54
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ timeoutMs: 1000 });
|
|
55
|
+
let failure;
|
|
56
|
+
if (kind === "断线")
|
|
57
|
+
failure = await disconnected(client);
|
|
58
|
+
else {
|
|
59
|
+
client.socket = { readyState: WebSocket.OPEN, send() { if (kind !== "请求超时")
|
|
60
|
+
throw new Error("socket 已关闭"); }, close() { } };
|
|
61
|
+
const pending = client.cdp("Runtime.evaluate").catch((error) => error);
|
|
62
|
+
if (kind === "请求超时")
|
|
63
|
+
await tick(t);
|
|
64
|
+
failure = await pending;
|
|
65
|
+
}
|
|
66
|
+
let polls = 0;
|
|
67
|
+
let sends = 0;
|
|
68
|
+
let inputs = 0;
|
|
69
|
+
let reconnects = 0;
|
|
70
|
+
client.socket = { readyState: WebSocket.OPEN, close() { } };
|
|
71
|
+
const messages = [];
|
|
72
|
+
const attachment = { kind: "file", filename: "结果.pdf", contentType: "application/pdf", data: new Uint8Array([1]) };
|
|
73
|
+
client.cdp = async (method) => { if (method === "Input.insertText")
|
|
74
|
+
inputs++; };
|
|
75
|
+
client.connect = async () => { reconnects++; };
|
|
76
|
+
client.conversationId = async () => "original";
|
|
77
|
+
client.readInteraction = async () => undefined;
|
|
78
|
+
client.readArtifacts = async () => [attachment];
|
|
79
|
+
client.evaluate = async (expression) => {
|
|
80
|
+
if (expression.includes("finished:")) {
|
|
81
|
+
polls++;
|
|
82
|
+
if (polls === 3 && kind !== "发送确认丢失")
|
|
83
|
+
throw failure;
|
|
84
|
+
return JSON.stringify([{ id: "new", text: "已完成第一步", finished: polls >= 4, stopped: false, conversationId: "original" }]);
|
|
85
|
+
}
|
|
86
|
+
if (expression.includes("button.click(); return true;")) {
|
|
87
|
+
sends++;
|
|
88
|
+
if (kind === "发送确认丢失")
|
|
89
|
+
throw failure;
|
|
90
|
+
}
|
|
91
|
+
if (expression.includes(".map(element => ({ id:"))
|
|
92
|
+
return "[]";
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
95
|
+
const result = client.complete({ task: "生成 PDF", sessionId: "peer", timeoutMs: 20_000, onMessage: async (text) => { messages.push(text); } }, undefined, false, "original");
|
|
96
|
+
void result.catch(() => undefined);
|
|
97
|
+
await flush();
|
|
98
|
+
await tick(t, 5);
|
|
99
|
+
strict_1.default.deepEqual(await result, { text: "", attachments: [attachment] });
|
|
100
|
+
strict_1.default.equal(reconnects, 1);
|
|
101
|
+
strict_1.default.equal(inputs, 1);
|
|
102
|
+
strict_1.default.equal(sends, 1);
|
|
103
|
+
strict_1.default.equal(messages.filter(text => text === "已完成第一步").length, 1);
|
|
104
|
+
strict_1.default.ok(messages.some(text => /CDP.*恢复/.test(text)));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
(0, node_test_1.default)("WorkBuddy CDP 重连失败报告端口和具体原因并有界重试", async (t) => {
|
|
108
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
109
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ port: 19229, fetchImpl: async () => new Response("[]") });
|
|
110
|
+
let attempts = 0;
|
|
111
|
+
client.fetchImpl = async () => { attempts++; return new Response("[]"); };
|
|
112
|
+
const failure = await disconnected(client);
|
|
113
|
+
client.evaluate = async () => { throw failure; };
|
|
114
|
+
client.conversationId = async () => "original";
|
|
115
|
+
const messages = [];
|
|
116
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(["old"]), 20_000, undefined, undefined, "peer", async (text) => { messages.push(text); }, undefined, "original"), /WORKBUDDY_CDP_RECOVERY_FAILED.*19229.*未找到 WorkBuddy 页面 target.*未.*停止/);
|
|
117
|
+
void result.catch(() => undefined);
|
|
118
|
+
await tick(t, 5);
|
|
119
|
+
await result;
|
|
120
|
+
strict_1.default.equal(attempts, 3);
|
|
121
|
+
strict_1.default.ok(messages.some(text => /CDP/.test(text)));
|
|
122
|
+
});
|
|
123
|
+
(0, node_test_1.default)("WorkBuddy 页面脚本错误不会当成断线重连", async (t) => {
|
|
124
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
125
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
126
|
+
client.evaluate = async () => { throw new Error("WorkBuddy 页面 JS 异常:socket 已关闭"); };
|
|
127
|
+
client.connect = () => strict_1.default.fail("页面错误不能重连");
|
|
128
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 2000), /页面 JS 异常/);
|
|
129
|
+
await tick(t);
|
|
130
|
+
await result;
|
|
131
|
+
});
|
|
132
|
+
(0, node_test_1.default)("WorkBuddy CDP 成功、发送失败和主动关闭均清理 pending", async (t) => {
|
|
133
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
134
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
135
|
+
client.socket = { readyState: WebSocket.OPEN, send(raw) { client.onMessage(JSON.stringify({ id: JSON.parse(raw).id, result: {} })); }, close() { } };
|
|
136
|
+
await client.cdp("Runtime.evaluate");
|
|
137
|
+
strict_1.default.equal(client.pending.size, 0);
|
|
138
|
+
client.socket.send = () => { throw new Error("socket 写入失败"); };
|
|
139
|
+
await strict_1.default.rejects(client.cdp("Runtime.evaluate"), /socket 写入失败/);
|
|
140
|
+
strict_1.default.equal(client.pending.size, 0);
|
|
141
|
+
client.socket.send = () => undefined;
|
|
142
|
+
const result = strict_1.default.rejects(client.cdp("Runtime.evaluate"), /CDP.*关闭/);
|
|
143
|
+
client.close();
|
|
144
|
+
await result;
|
|
145
|
+
strict_1.default.equal(client.pending.size, 0);
|
|
146
|
+
await tick(t, 60);
|
|
147
|
+
});
|
|
148
|
+
(0, node_test_1.default)("WorkBuddy 重连后桌面会话变化时不读取或切换另一个任务", async (t) => {
|
|
149
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
150
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
151
|
+
const failure = await disconnected(client);
|
|
152
|
+
let polls = 0;
|
|
153
|
+
client.evaluate = async () => { polls++; throw failure; };
|
|
154
|
+
client.connect = async () => undefined;
|
|
155
|
+
client.conversationId = async () => "other";
|
|
156
|
+
client.activateConversation = () => strict_1.default.fail("重连不得切换桌面任务");
|
|
157
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 20_000, undefined, undefined, "peer", undefined, undefined, "original"), /WORKBUDDY_CDP_RECOVERY_FAILED.*会话.*不一致/);
|
|
158
|
+
void result.catch(() => undefined);
|
|
159
|
+
await tick(t, 5);
|
|
160
|
+
await result;
|
|
161
|
+
strict_1.default.equal(polls, 1);
|
|
162
|
+
});
|
|
163
|
+
(0, node_test_1.default)("WorkBuddy AUN 进度发送失败不触发 CDP 重连", async (t) => {
|
|
164
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
165
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
166
|
+
client.evaluate = async () => JSON.stringify([]);
|
|
167
|
+
client.readInteraction = async () => undefined;
|
|
168
|
+
client.connect = () => strict_1.default.fail("AUN 发送失败不是 CDP 断线");
|
|
169
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 60_000, undefined, undefined, "peer", async () => { throw new Error("AUN_TEXT_SEND_FAILED"); }), /AUN_TEXT_SEND_FAILED/);
|
|
170
|
+
void result.catch(() => undefined);
|
|
171
|
+
await tick(t, 60);
|
|
172
|
+
await result;
|
|
173
|
+
});
|
|
174
|
+
(0, node_test_1.default)("WorkBuddy CDP 恢复不重新计算任务的截止时间", async (t) => {
|
|
175
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
176
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
177
|
+
const failure = await disconnected(client);
|
|
178
|
+
let polls = 0;
|
|
179
|
+
client.evaluate = async () => { if (++polls === 1)
|
|
180
|
+
throw failure; return "[]"; };
|
|
181
|
+
client.readInteraction = async () => undefined;
|
|
182
|
+
client.connect = async () => undefined;
|
|
183
|
+
client.conversationId = async () => "original";
|
|
184
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 2000, undefined, undefined, "peer", undefined, undefined, "original"), /WORKBUDDY_REPLY_TIMEOUT.*2 秒/);
|
|
185
|
+
void result.catch(() => undefined);
|
|
186
|
+
await tick(t, 2);
|
|
187
|
+
await result;
|
|
188
|
+
});
|
|
189
|
+
for (const cancelled of [false, true]) {
|
|
190
|
+
(0, node_test_1.default)(`WorkBuddy ${cancelled ? "取消后的收尾" : "旧版长等待"}也不超过二十分钟`, async (t) => {
|
|
191
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
192
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
193
|
+
const controller = new AbortController();
|
|
194
|
+
const messages = [];
|
|
195
|
+
client.evaluate = async () => "[]";
|
|
196
|
+
client.readInteraction = async () => undefined;
|
|
197
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), cancelled ? 10 : 3_600_000, undefined, undefined, "peer", async (text) => { messages.push(text); }, controller.signal), /WORKBUDDY_REPLY_TIMEOUT.*1200 秒/);
|
|
198
|
+
if (cancelled)
|
|
199
|
+
controller.abort();
|
|
200
|
+
await tick(t, 1200);
|
|
201
|
+
await result;
|
|
202
|
+
if (cancelled)
|
|
203
|
+
strict_1.default.deepEqual(messages, []);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
(0, node_test_1.default)("WorkBuddy 缺少原会话标识时拒绝猜测或切换任务", async (t) => {
|
|
207
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
208
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
209
|
+
const failure = await disconnected(client);
|
|
210
|
+
client.evaluate = async () => { throw failure; };
|
|
211
|
+
client.connect = async () => undefined;
|
|
212
|
+
client.conversationId = async () => "unknown";
|
|
213
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 20_000), /WORKBUDDY_CDP_RECOVERY_FAILED.*原会话 未知/);
|
|
214
|
+
await tick(t, 5);
|
|
215
|
+
await result;
|
|
216
|
+
});
|
|
217
|
+
(0, node_test_1.default)("WorkBuddy 读取已完成产物断线后只重读原任务产物", async (t) => {
|
|
218
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
219
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
220
|
+
const failure = await disconnected(client);
|
|
221
|
+
let attempts = 0;
|
|
222
|
+
client.evaluate = async () => JSON.stringify([{ id: "new", text: "完成结果", finished: true, conversationId: "original" }]);
|
|
223
|
+
client.readInteraction = async () => undefined;
|
|
224
|
+
client.readArtifacts = async (ids) => { strict_1.default.deepEqual([...ids], ["new"]); if (++attempts === 1)
|
|
225
|
+
throw failure; return []; };
|
|
226
|
+
client.connect = async () => undefined;
|
|
227
|
+
client.conversationId = async () => "original";
|
|
228
|
+
const result = client.waitForReply(new Set(), 20_000);
|
|
229
|
+
await tick(t);
|
|
230
|
+
strict_1.default.deepEqual(await result, { text: "完成结果" });
|
|
231
|
+
strict_1.default.equal(attempts, 2);
|
|
232
|
+
});
|
|
233
|
+
(0, node_test_1.default)("WorkBuddy CDP WebSocket 建连不响应时也有超时", async (t) => {
|
|
234
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
235
|
+
let closed = false;
|
|
236
|
+
const OriginalWebSocket = globalThis.WebSocket;
|
|
237
|
+
t.after(() => { globalThis.WebSocket = OriginalWebSocket; });
|
|
238
|
+
globalThis.WebSocket = class {
|
|
239
|
+
static OPEN = 1;
|
|
240
|
+
readyState = 0;
|
|
241
|
+
close() { closed = true; }
|
|
242
|
+
};
|
|
243
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ timeoutMs: 2000, fetchImpl: async () => new Response(JSON.stringify([{ type: "page", title: "WorkBuddy", webSocketDebuggerUrl: "ws://127.0.0.1:9229/page" }])) });
|
|
244
|
+
const result = strict_1.default.rejects(client.connect(), /CDP WebSocket 连接超时.*9229/);
|
|
245
|
+
await flush();
|
|
246
|
+
await tick(t, 2);
|
|
247
|
+
await result;
|
|
248
|
+
strict_1.default.equal(closed, true);
|
|
249
|
+
strict_1.default.equal(client.connected(), false);
|
|
250
|
+
});
|
|
251
|
+
(0, node_test_1.default)("WorkBuddy 截止时 CDP 超时仍报告端口和具体方法", async (t) => {
|
|
252
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
253
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ port: 19229, timeoutMs: 10_000 });
|
|
254
|
+
client.socket = { readyState: WebSocket.OPEN, send() { }, close() { } };
|
|
255
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 2000), /WORKBUDDY_REPLY_TIMEOUT.*19229.*Runtime.evaluate.*超时/);
|
|
256
|
+
await tick(t, 2);
|
|
257
|
+
await result;
|
|
258
|
+
});
|
|
259
|
+
(0, node_test_1.default)("WorkBuddy CDP 读取阻塞期间仍每三十秒提示", async (t) => {
|
|
260
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
261
|
+
const client = new cdp_client_1.WorkbuddyCdpClient();
|
|
262
|
+
const messages = [];
|
|
263
|
+
let release;
|
|
264
|
+
client.evaluate = () => new Promise(resolve => { release = resolve; });
|
|
265
|
+
client.readInteraction = async () => undefined;
|
|
266
|
+
client.readArtifacts = async () => [];
|
|
267
|
+
const result = client.waitForReply(new Set(), 120_000, undefined, undefined, "peer", async (text) => { messages.push(text); });
|
|
268
|
+
await tick(t, 60);
|
|
269
|
+
try {
|
|
270
|
+
strict_1.default.equal(messages.length, 2);
|
|
271
|
+
strict_1.default.match(messages[0], /30 秒/);
|
|
272
|
+
strict_1.default.match(messages[1], /60 秒/);
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
release(JSON.stringify([{ id: "new", text: "完成结果", finished: true }]));
|
|
276
|
+
await result;
|
|
277
|
+
}
|
|
278
|
+
await tick(t, 60);
|
|
279
|
+
strict_1.default.equal(messages.length, 2);
|
|
280
|
+
});
|
|
281
|
+
(0, node_test_1.default)("WorkBuddy 恢复耗尽截止时间仍保留首次故障和末次恢复原因", async (t) => {
|
|
282
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
283
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ port: 19229 });
|
|
284
|
+
client.socket = { readyState: WebSocket.OPEN, send() { throw new Error("EPIPE"); }, close() { } };
|
|
285
|
+
const failure = await disconnected(client);
|
|
286
|
+
client.evaluate = async () => { throw failure; };
|
|
287
|
+
client.connect = async () => { await new Promise(resolve => setTimeout(resolve, 2000)); throw new Error("ECONNREFUSED"); };
|
|
288
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 3000), /WORKBUDDY_REPLY_TIMEOUT.*19229.*EPIPE.*ECONNREFUSED/);
|
|
289
|
+
void result.catch(() => undefined);
|
|
290
|
+
await tick(t, 3);
|
|
291
|
+
await result;
|
|
292
|
+
});
|
|
293
|
+
(0, node_test_1.default)("WorkBuddy 再次断线耗尽重试时保留整个任务的首次故障", async (t) => {
|
|
294
|
+
t.mock.timers.enable({ apis: ["setTimeout", "setInterval", "Date"] });
|
|
295
|
+
const client = new cdp_client_1.WorkbuddyCdpClient({ port: 19229 });
|
|
296
|
+
client.socket = { readyState: WebSocket.OPEN, send() { throw new Error("FIRST_EPIPE"); }, close() { } };
|
|
297
|
+
const first = await disconnected(client);
|
|
298
|
+
client.socket.send = () => { throw new Error("SECOND_DISCONNECT"); };
|
|
299
|
+
const second = await disconnected(client);
|
|
300
|
+
let polls = 0;
|
|
301
|
+
let attempts = 0;
|
|
302
|
+
client.evaluate = async () => { throw ++polls === 1 ? first : second; };
|
|
303
|
+
client.connect = async () => { if (++attempts > 1)
|
|
304
|
+
throw new Error("LAST_ECONNREFUSED"); };
|
|
305
|
+
client.conversationId = async () => "original";
|
|
306
|
+
const result = strict_1.default.rejects(client.waitForReply(new Set(), 20_000, undefined, undefined, "peer", undefined, undefined, "original"), /WORKBUDDY_CDP_RECOVERY_FAILED.*首次故障:.*FIRST_EPIPE.*LAST_ECONNREFUSED/);
|
|
307
|
+
void result.catch(() => undefined);
|
|
308
|
+
await tick(t, 5);
|
|
309
|
+
await result;
|
|
310
|
+
strict_1.default.equal(attempts, 3);
|
|
311
|
+
});
|