mu-agent-bridge 1.0.71 → 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 +17 -10
- package/dist/src-ts/agent.js +35 -0
- package/dist/src-ts/channel-sessions.js +3 -2
- package/dist/src-ts/cli.js +67 -37
- package/dist/src-ts/control-server.js +12 -30
- 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 +31 -13
- package/dist/src-ts/http-agent.js +36 -0
- package/dist/src-ts/plugin-catalog.js +11 -2
- package/dist/src-ts/plugin-manager.js +351 -50
- package/dist/src-ts/plugins/abweb/index.js +1 -1
- package/dist/src-ts/plugins/abweb/public/app.js +73 -5
- package/dist/src-ts/plugins/abweb/public/index.html +15 -0
- package/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/dist/src-ts/plugins/aun/index.js +155 -21
- package/dist/src-ts/plugins/aun/messages.js +4 -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/cdp-client.js +26 -12
- package/dist/src-ts/plugins/chatgpt/index.js +80 -19
- package/dist/src-ts/plugins/claude-cli/index.js +19 -2
- package/dist/src-ts/plugins/codex-cli/index.js +19 -2
- package/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
- package/dist/src-ts/plugins/doubao/index.js +152 -8
- 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 +172 -21
- 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/local-cli/agent.js +74 -9
- package/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
- package/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
- package/dist/src-ts/plugins/personal-assistant/index.js +263 -0
- package/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
- package/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
- package/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
- package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
- package/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
- package/dist/src-ts/plugins/qwenwork/index.js +139 -24
- package/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
- package/dist/src-ts/plugins/workbuddy/index.js +124 -41
- 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 +132 -14
- package/dist/src-ts/version-manager.js +6 -3
- package/dist/tests-ts/abweb-cli.test.js +10 -2
- package/dist/tests-ts/abweb-model-config.test.js +73 -0
- package/dist/tests-ts/agent.test.js +27 -0
- 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 +20 -0
- package/dist/tests-ts/aun-plugin.test.js +292 -19
- package/dist/tests-ts/bundled-package.test.js +12 -2
- package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
- package/dist/tests-ts/channel-sessions.test.js +27 -0
- package/dist/tests-ts/chatgpt-plugin.test.js +118 -0
- package/dist/tests-ts/control-server.test.js +56 -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 +773 -12
- package/dist/tests-ts/dsh-agent.test.js +157 -8
- 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/installer-assets.test.js +1 -1
- package/dist/tests-ts/local-cli.test.js +146 -1
- package/dist/tests-ts/model-provider-cancellation.test.js +152 -0
- package/dist/tests-ts/native-session-management.test.js +8 -7
- package/dist/tests-ts/personal-assistant-coordination.test.js +92 -0
- package/dist/tests-ts/personal-assistant-extensions.test.js +35 -0
- package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
- package/dist/tests-ts/personal-assistant-owner-context.test.js +107 -0
- package/dist/tests-ts/personal-assistant-remote-ability.test.js +123 -0
- package/dist/tests-ts/personal-assistant.test.js +663 -0
- package/dist/tests-ts/platform-integration.test.js +183 -1
- package/dist/tests-ts/plugin-catalog.test.js +12 -2
- package/dist/tests-ts/plugin-manager.test.js +356 -4
- package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
- package/dist/tests-ts/publish-packages.test.js +42 -0
- package/dist/tests-ts/qwenwork-plugin.test.js +135 -1
- 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 +159 -4
- 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 +499 -4
- 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/agent.js +35 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +73 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +57 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +15 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
- 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/agent.js +35 -0
- package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +155 -21
- package/plugins/aun/dist/src-ts/plugins/aun/messages.js +4 -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/agent.js +35 -0
- package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +80 -19
- package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/chatgpt/package.json +1 -1
- package/plugins/chatgpt/plugin.json +1 -1
- package/plugins/claude-cli/dist/src-ts/agent.js +35 -0
- package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +19 -2
- package/plugins/claude-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/plugins/claude-cli/package.json +1 -1
- package/plugins/claude-cli/plugin.json +3 -2
- package/plugins/codex-cli/dist/src-ts/agent.js +35 -0
- package/plugins/codex-cli/dist/src-ts/plugins/codex-cli/index.js +19 -2
- package/plugins/codex-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/plugins/codex-cli/package.json +1 -1
- package/plugins/codex-cli/plugin.json +3 -2
- package/plugins/doubao/config.schema.json +2 -1
- package/plugins/doubao/dist/src-ts/agent.js +35 -0
- package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
- package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +152 -8
- 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 +3 -2
- package/plugins/dsh/config.schema.json +5 -2
- package/plugins/dsh/dist/src-ts/agent.js +35 -0
- package/plugins/dsh/dist/src-ts/dsh-agent.js +31 -13
- 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 +172 -21
- 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 +3 -2
- package/plugins/feishu/dist/src-ts/agent.js +35 -0
- 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 +23 -0
- package/plugins/personal-assistant/dist/src-ts/agent.js +69 -0
- package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
- package/plugins/personal-assistant/dist/src-ts/plugin.js +13 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +263 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
- 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 +167 -0
- package/plugins/personal-assistant/package.json +39 -0
- package/plugins/personal-assistant/plugin.json +15 -0
- package/plugins/qwenwork/dist/src-ts/agent.js +35 -0
- 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 +90 -18
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +139 -24
- package/plugins/qwenwork/package.json +1 -1
- package/plugins/qwenwork/plugin.json +3 -2
- package/plugins/workbuddy/config.schema.json +1 -1
- package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
- package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +124 -41
- package/plugins/workbuddy/package.json +1 -1
- package/plugins/workbuddy/plugin.json +3 -2
- 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
|
@@ -170,9 +170,11 @@ class ChatgptCdpClient {
|
|
|
170
170
|
missingReasons.push("仅包含当前页面已加载的可验证正文,页面虚拟化或未加载历史导致完整性无法确认");
|
|
171
171
|
return { supported: true, turns: result.turns, complete: false, missingReasons };
|
|
172
172
|
}
|
|
173
|
-
async switchSession(session) {
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
async switchSession(session, preserveDraft = false) {
|
|
174
|
+
if (!preserveDraft) {
|
|
175
|
+
await this.waitForGeneration();
|
|
176
|
+
await this.recoverDraft();
|
|
177
|
+
}
|
|
176
178
|
const locate = `[...document.querySelectorAll(${JSON.stringify(sidebarSelector)})].find(item =>
|
|
177
179
|
item.getAttribute('data-app-action-sidebar-thread-id') === ${JSON.stringify(session.id)}
|
|
178
180
|
&& item.getAttribute('data-app-action-sidebar-thread-host-id') === ${JSON.stringify(session.host)})`;
|
|
@@ -194,15 +196,18 @@ class ChatgptCdpClient {
|
|
|
194
196
|
&& Boolean(document.querySelector(${JSON.stringify(exports.editorSelector)}));
|
|
195
197
|
})()`, "ChatGPT 会话切换未确认,未发送消息");
|
|
196
198
|
}
|
|
197
|
-
async createSession(_name) {
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
async createSession(_name, preserveDraft = false) {
|
|
200
|
+
if (!preserveDraft) {
|
|
201
|
+
await this.waitForGeneration();
|
|
202
|
+
await this.recoverDraft();
|
|
203
|
+
}
|
|
200
204
|
const before = await this.activeSession();
|
|
201
205
|
const state = await this.evaluate(`JSON.stringify({ editor: document.querySelector(${JSON.stringify(exports.editorSelector)})?.innerText ?? null, turns: document.querySelectorAll(${JSON.stringify(exports.turnSelector)}).length, generating: Boolean(document.querySelector(${JSON.stringify(stopButtonSelector)})) })`);
|
|
202
206
|
const initial = JSON.parse(String(state));
|
|
203
207
|
if (initial.editor?.trim() || initial.generating)
|
|
204
208
|
throw new Error("ChatGPT 当前有未发送内容或正在生成回复,不能新建会话");
|
|
205
209
|
const clicked = await this.evaluate(`(() => {
|
|
210
|
+
if (document.querySelector(${JSON.stringify(exports.editorSelector)})?.innerText.trim() || document.querySelector(${JSON.stringify(stopButtonSelector)})) throw new Error('ChatGPT 当前有未发送内容或正在生成回复,不能新建会话');
|
|
206
211
|
const labels = /^(?:新聊天|新对话|new chat|new conversation)$/i;
|
|
207
212
|
const item = [...document.querySelectorAll(${JSON.stringify(newSessionSelector)})].find((node) => {
|
|
208
213
|
const label = [node.getAttribute('aria-label'), node.getAttribute('title'), node.textContent].filter(Boolean).join(' ').trim();
|
|
@@ -304,7 +309,7 @@ class ChatgptCdpClient {
|
|
|
304
309
|
this.tunnel = undefined;
|
|
305
310
|
this.rejectPending(new Error("ChatGPT CDP 已关闭"));
|
|
306
311
|
}
|
|
307
|
-
async direct(text, timeoutMs = 240_000, attachments) {
|
|
312
|
+
async direct(text, timeoutMs = 240_000, attachments, signal, preserveDraft = false) {
|
|
308
313
|
(0, attachments_1.validateAttachments)(attachments);
|
|
309
314
|
const slot = `__agentBridgeChatgpt_${(0, node_crypto_1.randomUUID)().replaceAll("-", "")}`;
|
|
310
315
|
const outputDirectory = `agent-bridge-chatgpt-${(0, node_crypto_1.randomUUID)()}`;
|
|
@@ -312,7 +317,7 @@ class ChatgptCdpClient {
|
|
|
312
317
|
const instruction = `附件回传约定:如果本轮需要返回文件、图片或视频,请把要返回的文件副本写入本轮新建的临时目录(Linux/macOS:/tmp/${outputDirectory};Windows:C:/Users/<当前用户>/AppData/Local/Temp/${outputDirectory}),并在最终回复给出文件链接。仅需文字时无需创建目录。`;
|
|
313
318
|
let failure;
|
|
314
319
|
try {
|
|
315
|
-
return await this.directTurn(`${text} ${instruction}`, timeoutMs, attachments, slot, outputDirectory, startedAt);
|
|
320
|
+
return await this.directTurn(preserveDraft ? text : `${text} ${instruction}`, timeoutMs, attachments, slot, outputDirectory, startedAt, signal, preserveDraft);
|
|
316
321
|
}
|
|
317
322
|
catch (error) {
|
|
318
323
|
failure = error;
|
|
@@ -338,10 +343,12 @@ class ChatgptCdpClient {
|
|
|
338
343
|
}
|
|
339
344
|
}
|
|
340
345
|
}
|
|
341
|
-
async directTurn(text, timeoutMs, attachments, slot, outputDirectory, startedAt) {
|
|
346
|
+
async directTurn(text, timeoutMs, attachments, slot, outputDirectory, startedAt, signal, preserveDraft = false) {
|
|
342
347
|
await this.waitFor(`Boolean(document.querySelector(${JSON.stringify(exports.editorSelector)}))`, "ChatGPT 桌面端输入框未就绪");
|
|
343
|
-
|
|
344
|
-
|
|
348
|
+
if (!preserveDraft) {
|
|
349
|
+
await this.waitForGeneration();
|
|
350
|
+
await this.recoverDraft();
|
|
351
|
+
}
|
|
345
352
|
const beforeTurnsJson = await this.evaluate(`JSON.stringify([...document.querySelectorAll(${JSON.stringify(exports.turnSelector)})].map(turn => ({ id: turn.getAttribute(${JSON.stringify(turnIdAttribute)}), users: turn.querySelectorAll(${JSON.stringify(exports.userBubbleSelector)}).length })))`);
|
|
346
353
|
const beforeTurns = JSON.parse(String(beforeTurnsJson || "[]"));
|
|
347
354
|
const beforeAssistantCount = Number(await this.evaluate(`document.querySelectorAll(${JSON.stringify(assistantMessageSelector)}).length`));
|
|
@@ -393,7 +400,9 @@ class ChatgptCdpClient {
|
|
|
393
400
|
const deadline = Date.now() + timeoutMs;
|
|
394
401
|
let previous = "";
|
|
395
402
|
let stable = 0;
|
|
396
|
-
|
|
403
|
+
let seenActive = false;
|
|
404
|
+
let inactivePolls = 0;
|
|
405
|
+
while (Date.now() < deadline || signal?.aborted) {
|
|
397
406
|
await sleep(800);
|
|
398
407
|
const raw = await this.evaluate(`(() => {
|
|
399
408
|
const previous = new Set(${JSON.stringify(Array.isArray(beforeMessages) ? beforeMessages : [])}.map(item => JSON.stringify(item)));
|
|
@@ -439,6 +448,11 @@ class ChatgptCdpClient {
|
|
|
439
448
|
})()`);
|
|
440
449
|
const state = JSON.parse(String(raw));
|
|
441
450
|
const reply = state.reply.trim();
|
|
451
|
+
seenActive ||= state.active === true;
|
|
452
|
+
inactivePolls = seenActive && state.submitted === true && state.active === false ? inactivePolls + 1 : 0;
|
|
453
|
+
if (signal?.aborted && inactivePolls >= 2 && state.artifacts?.length && !reply && !state.hasArtifacts) {
|
|
454
|
+
throw new Error("ChatGPT 请求已取消,已确认本轮桌面生成结束,未返回正文或附件");
|
|
455
|
+
}
|
|
442
456
|
const signature = JSON.stringify([reply, state.artifacts, state.hasArtifacts]);
|
|
443
457
|
stable = (reply || state.hasArtifacts) && signature === previous ? stable + 1 : 0;
|
|
444
458
|
previous = signature;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ChatgptCdpClient = exports.ChatgptPlugin = exports.chatgptManifest = void 0;
|
|
4
|
+
const agent_1 = require("../../agent");
|
|
4
5
|
const node_crypto_1 = require("node:crypto");
|
|
5
6
|
const cdp_client_1 = require("./cdp-client");
|
|
6
7
|
const session_store_1 = require("./session-store");
|
|
@@ -9,13 +10,13 @@ const node_path_1 = require("node:path");
|
|
|
9
10
|
const node_os_1 = require("node:os");
|
|
10
11
|
exports.chatgptManifest = {
|
|
11
12
|
id: "chatgpt",
|
|
12
|
-
version: "1.0.
|
|
13
|
+
version: "1.0.12",
|
|
13
14
|
displayName: "ChatGPT(Codex)",
|
|
14
15
|
type: "agent",
|
|
15
16
|
entry: "dist/index.js",
|
|
16
17
|
apiVersion: "1",
|
|
17
18
|
process: "in-process",
|
|
18
|
-
capabilities: ["chat", "health"],
|
|
19
|
+
capabilities: ["chat", "health", "model-provider"],
|
|
19
20
|
configSchema: "config.schema.json",
|
|
20
21
|
};
|
|
21
22
|
function port(value, fallback) {
|
|
@@ -26,6 +27,11 @@ function port(value, fallback) {
|
|
|
26
27
|
class ChatgptPlugin {
|
|
27
28
|
options;
|
|
28
29
|
manifest = exports.chatgptManifest;
|
|
30
|
+
get modelProvider() {
|
|
31
|
+
if (!this.client?.createSession || !this.client.listSessions || !this.client.activeSession || !this.client.switchSession || !this.store)
|
|
32
|
+
return undefined;
|
|
33
|
+
return { complete: (request) => this.completeModelProvider(request) };
|
|
34
|
+
}
|
|
29
35
|
sessionOperations = [];
|
|
30
36
|
get attachmentInput() { return this.client?.attachmentInput === true; }
|
|
31
37
|
client;
|
|
@@ -132,11 +138,12 @@ class ChatgptPlugin {
|
|
|
132
138
|
throw connectionError;
|
|
133
139
|
}
|
|
134
140
|
}
|
|
135
|
-
async deactivate() {
|
|
141
|
+
async deactivate(_reason = "stop", options) {
|
|
136
142
|
await this.queue;
|
|
137
143
|
await this.store?.drain();
|
|
138
144
|
this.client?.close();
|
|
139
|
-
|
|
145
|
+
if (!options?.preserveDesktop)
|
|
146
|
+
await (0, desktop_launch_1.terminateOwnedProcess)(this.ownedProcess).catch(() => undefined);
|
|
140
147
|
this.ownedProcess = undefined;
|
|
141
148
|
this.reconnect = undefined;
|
|
142
149
|
this.client = undefined;
|
|
@@ -156,6 +163,51 @@ class ChatgptPlugin {
|
|
|
156
163
|
const result = await run;
|
|
157
164
|
return { ...(typeof result === "string" ? { text: result } : result), sessionId: request.sessionId };
|
|
158
165
|
}
|
|
166
|
+
async completeModelProvider(request) {
|
|
167
|
+
let stage = "ChatGPT 模型排队(queue)";
|
|
168
|
+
try {
|
|
169
|
+
request.signal.throwIfAborted();
|
|
170
|
+
const run = this.enqueue(async () => {
|
|
171
|
+
request.signal.throwIfAborted();
|
|
172
|
+
stage = "连接 ChatGPT 模型(connect)";
|
|
173
|
+
const store = this.store;
|
|
174
|
+
const client = this.client;
|
|
175
|
+
if (!store || !client?.connected())
|
|
176
|
+
throw new Error("ChatGPT CDP 未连接,模型请求不会启动或重启桌面");
|
|
177
|
+
const previous = await client.activeSession();
|
|
178
|
+
try {
|
|
179
|
+
stage = "准备 ChatGPT 模型会话(submit)";
|
|
180
|
+
if (!store.bindings[request.sessionId]) {
|
|
181
|
+
const existing = new Set((await client.listSessions()).map(item => JSON.stringify([item.host, item.id])));
|
|
182
|
+
const created = await client.createSession(undefined, true);
|
|
183
|
+
if (created) {
|
|
184
|
+
store.remember(created, "", "");
|
|
185
|
+
store.bindings[request.sessionId] = created;
|
|
186
|
+
delete store.pendingBindings[request.sessionId];
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
store.pendingBindings[request.sessionId] = [...existing];
|
|
190
|
+
}
|
|
191
|
+
this.persist();
|
|
192
|
+
}
|
|
193
|
+
request.signal.throwIfAborted();
|
|
194
|
+
stage = "等待 ChatGPT 模型生成(generate)";
|
|
195
|
+
const result = await this.run({ task: request.prompt, sessionId: request.sessionId, timeoutMs: request.timeoutMs, signal: request.signal }, true);
|
|
196
|
+
return { text: typeof result === "string" ? result : result.text };
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
if (previous && client.connected())
|
|
200
|
+
await this.select(previous, true);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
return await (0, agent_1.abortable)(run, request.signal);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
if (error instanceof agent_1.AgentOperationError)
|
|
207
|
+
throw error;
|
|
208
|
+
throw new agent_1.AgentOperationError("CHATGPT_MODEL_FAILED", stage, error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
159
211
|
async controlSession(request) {
|
|
160
212
|
if (request.operation !== "new")
|
|
161
213
|
throw new Error(`ChatGPT 不支持会话操作:${String(request.operation)}`);
|
|
@@ -281,41 +333,47 @@ class ChatgptPlugin {
|
|
|
281
333
|
persist() {
|
|
282
334
|
void this.store.save().catch(error => this.logger?.warn("ChatGPT 会话缓存保存失败", { error: String(error) }));
|
|
283
335
|
}
|
|
284
|
-
async synchronize() {
|
|
285
|
-
if (!this.client.connected())
|
|
336
|
+
async synchronize(modelRequest = false) {
|
|
337
|
+
if (!this.client.connected()) {
|
|
338
|
+
if (modelRequest)
|
|
339
|
+
throw new Error("ChatGPT CDP 已断开,模型请求不会启动或重启桌面");
|
|
286
340
|
await (this.reconnect?.() ?? this.client.connect());
|
|
341
|
+
}
|
|
287
342
|
if (!this.client.listSessions)
|
|
288
343
|
throw new Error("当前 ChatGPT 客户端不支持会话列表");
|
|
289
344
|
this.store.synchronize(await this.client.listSessions());
|
|
290
345
|
this.persist();
|
|
291
346
|
}
|
|
292
|
-
async select(session) {
|
|
293
|
-
if (!this.client.connected())
|
|
347
|
+
async select(session, modelRequest = false) {
|
|
348
|
+
if (!this.client.connected()) {
|
|
349
|
+
if (modelRequest)
|
|
350
|
+
throw new Error("ChatGPT CDP 已断开,模型请求不会启动或重启桌面");
|
|
294
351
|
await (this.reconnect?.() ?? this.client.connect());
|
|
352
|
+
}
|
|
295
353
|
if (!this.client.switchSession)
|
|
296
354
|
throw new Error("当前 ChatGPT 客户端不支持会话切换");
|
|
297
355
|
const active = await this.client.activeSession?.();
|
|
298
356
|
if (active?.id === session.id && active.host === session.host)
|
|
299
357
|
return;
|
|
300
358
|
try {
|
|
301
|
-
await this.client.switchSession(session);
|
|
359
|
+
await this.client.switchSession(session, modelRequest);
|
|
302
360
|
}
|
|
303
361
|
catch (error) {
|
|
304
362
|
// 目标消失时只重新同步一次;不在其他会话中代替发送。
|
|
305
363
|
if (!String(error).includes("找不到目标会话"))
|
|
306
364
|
throw error;
|
|
307
|
-
await this.synchronize();
|
|
365
|
+
await this.synchronize(modelRequest);
|
|
308
366
|
const updated = this.store.sessions.find(item => item.id === session.id && item.host === session.host);
|
|
309
367
|
if (!updated)
|
|
310
368
|
throw new Error("ChatGPT 目标会话已删除或不在当前侧栏,请刷新最近任务");
|
|
311
|
-
await this.client.switchSession(updated);
|
|
369
|
+
await this.client.switchSession(updated, modelRequest);
|
|
312
370
|
}
|
|
313
371
|
}
|
|
314
|
-
async run(request) {
|
|
372
|
+
async run(request, modelRequest = false) {
|
|
315
373
|
const store = this.store;
|
|
316
374
|
const text = request.task.trim();
|
|
317
|
-
const refresh = /^(?:刷新最近任务|刷新任务列表|刷新最近会话)$/.test(text);
|
|
318
|
-
const listing = /^(?:最近任务|列出最近会话|有哪些已保存的 ChatGPT 任务)[??。]?$/.test(text);
|
|
375
|
+
const refresh = !modelRequest && /^(?:刷新最近任务|刷新任务列表|刷新最近会话)$/.test(text);
|
|
376
|
+
const listing = !modelRequest && /^(?:最近任务|列出最近会话|有哪些已保存的 ChatGPT 任务)[??。]?$/.test(text);
|
|
319
377
|
if (refresh || listing) {
|
|
320
378
|
if (refresh || !store.fresh()) {
|
|
321
379
|
try {
|
|
@@ -331,7 +389,7 @@ class ChatgptPlugin {
|
|
|
331
389
|
}
|
|
332
390
|
const explicit = text.match(/^切换会话\s*[::]\s*([^;;\n]+)(?:[;;\n]\s*([\s\S]+))?$/);
|
|
333
391
|
const natural = text.match(/^(?:继续处理|接着处理|继续任务|切换到)\s*(.+?)[。]?$/);
|
|
334
|
-
const query = explicit?.[1].trim() ?? natural?.[1].trim();
|
|
392
|
+
const query = modelRequest ? undefined : explicit?.[1].trim() ?? natural?.[1].trim();
|
|
335
393
|
let selected;
|
|
336
394
|
if (query) {
|
|
337
395
|
if (!store.fresh())
|
|
@@ -355,13 +413,16 @@ class ChatgptPlugin {
|
|
|
355
413
|
}
|
|
356
414
|
else if (request.sessionId && store.bindings[request.sessionId]) {
|
|
357
415
|
selected = store.bindings[request.sessionId];
|
|
358
|
-
await this.select(selected);
|
|
416
|
+
await this.select(selected, modelRequest);
|
|
359
417
|
}
|
|
360
|
-
if (!this.client.connected())
|
|
418
|
+
if (!this.client.connected()) {
|
|
419
|
+
if (modelRequest)
|
|
420
|
+
throw new Error("ChatGPT CDP 已断开,模型请求不会启动或重启桌面");
|
|
361
421
|
await (this.reconnect?.() ?? this.client.connect());
|
|
422
|
+
}
|
|
362
423
|
selected ??= await this.client.activeSession?.();
|
|
363
|
-
const message = explicit?.[2]?.trim() || request.task;
|
|
364
|
-
const reply = await this.client.direct(message, request.timeoutMs, request.attachments);
|
|
424
|
+
const message = (modelRequest ? undefined : explicit?.[2]?.trim()) || request.task;
|
|
425
|
+
const reply = await this.client.direct(message, request.timeoutMs, request.attachments, request.signal, modelRequest);
|
|
365
426
|
const baseline = request.sessionId ? store.pendingBindings[request.sessionId] : undefined;
|
|
366
427
|
if (baseline) {
|
|
367
428
|
try {
|
|
@@ -3,12 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ClaudeCliPlugin = exports.manifest = void 0;
|
|
4
4
|
const agent_1 = require("../local-cli/agent");
|
|
5
5
|
exports.manifest = {
|
|
6
|
-
id: "claude-cli", version: "1.0.
|
|
6
|
+
id: "claude-cli", version: "1.0.3", displayName: "Claude Code CLI", type: "agent", executionMode: "cli",
|
|
7
7
|
entry: "dist/src-ts/plugins/claude-cli/index.js", apiVersion: "1", process: "in-process",
|
|
8
|
-
capabilities: ["chat", "health"], configSchema: "config.schema.json",
|
|
8
|
+
capabilities: ["chat", "health", "model-provider"], configSchema: "config.schema.json",
|
|
9
9
|
};
|
|
10
10
|
class ClaudeCliPlugin extends agent_1.LocalCliAgent {
|
|
11
11
|
constructor() { super(exports.manifest, "claude"); }
|
|
12
|
+
get modelProvider() {
|
|
13
|
+
if (!this.modelInput)
|
|
14
|
+
return undefined;
|
|
15
|
+
return { complete: (request) => this.completeModelProvider(request) };
|
|
16
|
+
}
|
|
17
|
+
async completeModelProvider(request) {
|
|
18
|
+
let responseSchema;
|
|
19
|
+
try {
|
|
20
|
+
responseSchema = JSON.parse(request.prompt)?.responseSchema;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error("Claude CLI 模型请求必须是包含 responseSchema 的 JSON 对象");
|
|
24
|
+
}
|
|
25
|
+
if (!responseSchema || typeof responseSchema !== "object" || Array.isArray(responseSchema))
|
|
26
|
+
throw new Error("Claude CLI 模型请求缺少有效 responseSchema");
|
|
27
|
+
return this.completeStructuredModel(request, responseSchema);
|
|
28
|
+
}
|
|
12
29
|
}
|
|
13
30
|
exports.ClaudeCliPlugin = ClaudeCliPlugin;
|
|
14
31
|
exports.default = ClaudeCliPlugin;
|
|
@@ -3,12 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CodexCliPlugin = exports.manifest = void 0;
|
|
4
4
|
const agent_1 = require("../local-cli/agent");
|
|
5
5
|
exports.manifest = {
|
|
6
|
-
id: "codex-cli", version: "1.0.
|
|
6
|
+
id: "codex-cli", version: "1.0.2", displayName: "Codex CLI", type: "agent", executionMode: "cli",
|
|
7
7
|
entry: "dist/src-ts/plugins/codex-cli/index.js", apiVersion: "1", process: "in-process",
|
|
8
|
-
capabilities: ["chat", "health"], configSchema: "config.schema.json",
|
|
8
|
+
capabilities: ["chat", "health", "model-provider"], configSchema: "config.schema.json",
|
|
9
9
|
};
|
|
10
10
|
class CodexCliPlugin extends agent_1.LocalCliAgent {
|
|
11
11
|
constructor() { super(exports.manifest, "codex"); }
|
|
12
|
+
get modelProvider() {
|
|
13
|
+
if (!this.modelInput)
|
|
14
|
+
return undefined;
|
|
15
|
+
return { complete: (request) => this.completeModelProvider(request) };
|
|
16
|
+
}
|
|
17
|
+
async completeModelProvider(request) {
|
|
18
|
+
let responseSchema;
|
|
19
|
+
try {
|
|
20
|
+
responseSchema = JSON.parse(request.prompt)?.responseSchema;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error("Codex CLI 模型请求必须是包含 responseSchema 的 JSON 对象");
|
|
24
|
+
}
|
|
25
|
+
if (!responseSchema || typeof responseSchema !== "object" || Array.isArray(responseSchema))
|
|
26
|
+
throw new Error("Codex CLI 模型请求缺少有效 responseSchema");
|
|
27
|
+
return this.completeStructuredModel(request, responseSchema);
|
|
28
|
+
}
|
|
12
29
|
}
|
|
13
30
|
exports.CodexCliPlugin = CodexCliPlugin;
|
|
14
31
|
exports.default = CodexCliPlugin;
|
|
@@ -16,8 +16,8 @@ const node_path_1 = require("node:path");
|
|
|
16
16
|
const node_util_1 = require("node:util");
|
|
17
17
|
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
18
18
|
const versionDirectory = /^(?:app[-_ ]?)?v?\d+(?:[.-]\d+)+$/i;
|
|
19
|
-
/**
|
|
20
|
-
async function findWindowsExecutable(fileName, configured) {
|
|
19
|
+
/** 先从 Windows 注册信息和开始菜单解析,失败时再查常见安装目录。 */
|
|
20
|
+
async function findWindowsExecutable(fileName, configured, run = execFileAsync) {
|
|
21
21
|
if (configured?.trim()) {
|
|
22
22
|
const configuredPath = (0, node_path_1.resolve)(configured);
|
|
23
23
|
if (fileName.toLowerCase() === "doubao.exe") {
|
|
@@ -42,12 +42,16 @@ async function findWindowsExecutable(fileName, configured) {
|
|
|
42
42
|
}
|
|
43
43
|
if (process.platform !== "win32")
|
|
44
44
|
return undefined;
|
|
45
|
-
const
|
|
45
|
+
const registered = await findRegisteredWindowsExecutable(fileName, run);
|
|
46
|
+
if (registered)
|
|
47
|
+
return registered;
|
|
48
|
+
const pattern = /doubao|豆包|qwen|qwwork|千问|deepseek|harness|dsh|zcode/i;
|
|
46
49
|
const roots = [...new Set([
|
|
47
50
|
process.env.DSH_INSTALL_DIR,
|
|
48
51
|
"D:\\Programs\\DeepSeek Harness",
|
|
49
52
|
"D:\\DSH",
|
|
50
53
|
process.env.LOCALAPPDATA && (0, node_path_1.join)(process.env.LOCALAPPDATA, "Programs"),
|
|
54
|
+
process.env.LOCALAPPDATA,
|
|
51
55
|
process.env.ProgramFiles,
|
|
52
56
|
process.env["ProgramFiles(x86)"],
|
|
53
57
|
...Array.from({ length: 24 }, (_, index) => `${String.fromCharCode(67 + index)}:\\`),
|
|
@@ -59,6 +63,36 @@ async function findWindowsExecutable(fileName, configured) {
|
|
|
59
63
|
}
|
|
60
64
|
return undefined;
|
|
61
65
|
}
|
|
66
|
+
async function findRegisteredWindowsExecutable(fileName, run) {
|
|
67
|
+
const target = fileName.replace(/'/g, "''");
|
|
68
|
+
const script = `$ErrorActionPreference='SilentlyContinue';[Console]::OutputEncoding=[Text.Encoding]::UTF8;$target='${target}'
|
|
69
|
+
function Emit-Path($value){if(-not $value){return};$value=[Environment]::ExpandEnvironmentVariables(([string]$value).Trim());if($value.StartsWith('"')){$end=$value.IndexOf('"',1);if($end -gt 1){$value=$value.Substring(1,$end-1)}}elseif($value -match '^(\S+?\.exe)(?:\s|$)'){$value=$Matches[1]};if($value -match '(?i)\.exe$'){[Console]::WriteLine($value)}}
|
|
70
|
+
$keys=@("HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\$target","HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\$target","HKLM:\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\$target","HKCU:\\Software\\Classes\\Applications\\$target\\shell\\open\\command","HKLM:\\Software\\Classes\\Applications\\$target\\shell\\open\\command")
|
|
71
|
+
foreach($key in $keys){$item=Get-Item $key -ErrorAction SilentlyContinue;if($item){Emit-Path $item.GetValue('')}}
|
|
72
|
+
$dirs=@();if($env:APPDATA){$dirs+=[IO.Path]::Combine($env:APPDATA,'Microsoft\\Windows\\Start Menu\\Programs')};if($env:ProgramData){$dirs+=[IO.Path]::Combine($env:ProgramData,'Microsoft\\Windows\\Start Menu\\Programs')};$shell=New-Object -ComObject WScript.Shell
|
|
73
|
+
foreach($dir in $dirs){Get-ChildItem $dir -Filter '*.lnk' -File -Recurse -ErrorAction SilentlyContinue|ForEach-Object{$link=$shell.CreateShortcut($_.FullName);if($link.TargetPath -and [IO.Path]::GetFileName($link.TargetPath) -ieq $target){Emit-Path $link.TargetPath}}}`;
|
|
74
|
+
try {
|
|
75
|
+
const { stdout } = await run("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], { timeout: 10_000, windowsHide: true });
|
|
76
|
+
for (const candidate of stdout.split(/\r?\n/).map(value => value.trim()).filter(Boolean)) {
|
|
77
|
+
const found = await resolveRegisteredCandidate(fileName, candidate);
|
|
78
|
+
if (found)
|
|
79
|
+
return found;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch { /* 注册表或开始菜单不可读时继续使用目录兜底 */ }
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
async function resolveRegisteredCandidate(fileName, candidate) {
|
|
86
|
+
const candidatePath = (0, node_path_1.resolve)(candidate.replace(/^"|"$/g, ""));
|
|
87
|
+
if (fileName.toLowerCase() === "doubao.exe" && (0, node_path_1.basename)((0, node_path_1.dirname)(candidatePath)).toLowerCase() === "application") {
|
|
88
|
+
const client = (0, node_path_1.join)((0, node_path_1.dirname)(candidatePath), "app", fileName);
|
|
89
|
+
if ((0, node_fs_1.existsSync)(client))
|
|
90
|
+
return client;
|
|
91
|
+
}
|
|
92
|
+
if ((0, node_fs_1.existsSync)(candidatePath) && (0, node_path_1.basename)(candidatePath).toLowerCase() === fileName.toLowerCase())
|
|
93
|
+
return candidatePath;
|
|
94
|
+
return findExecutableInTree((0, node_path_1.dirname)(candidatePath), fileName, /^/, 3);
|
|
95
|
+
}
|
|
62
96
|
async function findExecutableInTree(directory, fileName, pattern, depth) {
|
|
63
97
|
return search(directory, fileName, pattern, depth, pattern.test(directory));
|
|
64
98
|
}
|
|
@@ -104,9 +138,16 @@ async function launchManagedAndWait(executable, args, profileDirectory, connect,
|
|
|
104
138
|
if (profileDirectory)
|
|
105
139
|
await (0, promises_1.mkdir)(profileDirectory, { recursive: true });
|
|
106
140
|
const child = launch(executable, profileDirectory ? [...args, `--user-data-dir=${profileDirectory}`] : args);
|
|
141
|
+
// 先等待 spawn,避免异步 error 终止 daemon 或在启动失败后继续轮询。
|
|
142
|
+
const events = child;
|
|
143
|
+
const started = typeof events.once === "function" ? new Promise((resolve, reject) => {
|
|
144
|
+
events.once("error", reject);
|
|
145
|
+
events.once("spawn", resolve);
|
|
146
|
+
}) : Promise.resolve();
|
|
107
147
|
child.unref();
|
|
108
148
|
onProcess(child);
|
|
109
149
|
try {
|
|
150
|
+
await started;
|
|
110
151
|
return await waitFor(connect, timeoutMs, 250);
|
|
111
152
|
}
|
|
112
153
|
catch (error) {
|