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.
Files changed (195) hide show
  1. package/README.md +17 -10
  2. package/dist/src-ts/agent.js +35 -0
  3. package/dist/src-ts/channel-sessions.js +3 -2
  4. package/dist/src-ts/cli.js +67 -37
  5. package/dist/src-ts/control-server.js +12 -30
  6. package/dist/src-ts/core-updater.js +141 -33
  7. package/dist/src-ts/daemon-process.js +2 -1
  8. package/dist/src-ts/dsh-agent.js +31 -13
  9. package/dist/src-ts/http-agent.js +36 -0
  10. package/dist/src-ts/plugin-catalog.js +11 -2
  11. package/dist/src-ts/plugin-manager.js +351 -50
  12. package/dist/src-ts/plugins/abweb/index.js +1 -1
  13. package/dist/src-ts/plugins/abweb/public/app.js +73 -5
  14. package/dist/src-ts/plugins/abweb/public/index.html +15 -0
  15. package/dist/src-ts/plugins/abweb/public/style.css +4 -0
  16. package/dist/src-ts/plugins/aun/attachments.js +3 -21
  17. package/dist/src-ts/plugins/aun/index.js +155 -21
  18. package/dist/src-ts/plugins/aun/messages.js +4 -1
  19. package/dist/src-ts/plugins/aun/public/app.js +2 -1
  20. package/dist/src-ts/plugins/aun/public/index.html +1 -1
  21. package/dist/src-ts/plugins/cdp-draft.js +5 -2
  22. package/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
  23. package/dist/src-ts/plugins/chatgpt/index.js +80 -19
  24. package/dist/src-ts/plugins/claude-cli/index.js +19 -2
  25. package/dist/src-ts/plugins/codex-cli/index.js +19 -2
  26. package/dist/src-ts/plugins/desktop-launch.js +44 -3
  27. package/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
  28. package/dist/src-ts/plugins/doubao/index.js +152 -8
  29. package/dist/src-ts/plugins/doubao/native-task.js +134 -0
  30. package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  31. package/dist/src-ts/plugins/dsh/index.js +172 -21
  32. package/dist/src-ts/plugins/dsh/session-history.js +31 -3
  33. package/dist/src-ts/plugins/feishu/index.js +1 -1
  34. package/dist/src-ts/plugins/local-cli/agent.js +74 -9
  35. package/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
  36. package/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
  37. package/dist/src-ts/plugins/personal-assistant/index.js +263 -0
  38. package/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
  39. package/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
  40. package/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
  41. package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  42. package/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
  43. package/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
  44. package/dist/src-ts/plugins/qwenwork/index.js +139 -24
  45. package/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
  46. package/dist/src-ts/plugins/workbuddy/index.js +124 -41
  47. package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  48. package/dist/src-ts/plugins/zcode/index.js +97 -0
  49. package/dist/src-ts/session-management.js +132 -14
  50. package/dist/src-ts/version-manager.js +6 -3
  51. package/dist/tests-ts/abweb-cli.test.js +10 -2
  52. package/dist/tests-ts/abweb-model-config.test.js +73 -0
  53. package/dist/tests-ts/agent.test.js +27 -0
  54. package/dist/tests-ts/aun-attachments.test.js +19 -17
  55. package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
  56. package/dist/tests-ts/aun-messages.test.js +20 -0
  57. package/dist/tests-ts/aun-plugin.test.js +292 -19
  58. package/dist/tests-ts/bundled-package.test.js +12 -2
  59. package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
  60. package/dist/tests-ts/channel-sessions.test.js +27 -0
  61. package/dist/tests-ts/chatgpt-plugin.test.js +118 -0
  62. package/dist/tests-ts/control-server.test.js +56 -0
  63. package/dist/tests-ts/core-updater.test.js +215 -46
  64. package/dist/tests-ts/daemon-process.test.js +126 -1
  65. package/dist/tests-ts/desktop-launch.test.js +73 -0
  66. package/dist/tests-ts/doubao-native-task.test.js +237 -0
  67. package/dist/tests-ts/doubao-plugin.test.js +773 -12
  68. package/dist/tests-ts/dsh-agent.test.js +157 -8
  69. package/dist/tests-ts/dsh-cdp.test.js +148 -0
  70. package/dist/tests-ts/dsh-history.test.js +37 -0
  71. package/dist/tests-ts/feishu-plugin.test.js +1 -1
  72. package/dist/tests-ts/http-agent.test.js +18 -0
  73. package/dist/tests-ts/installer-assets.test.js +1 -1
  74. package/dist/tests-ts/local-cli.test.js +146 -1
  75. package/dist/tests-ts/model-provider-cancellation.test.js +152 -0
  76. package/dist/tests-ts/native-session-management.test.js +8 -7
  77. package/dist/tests-ts/personal-assistant-coordination.test.js +92 -0
  78. package/dist/tests-ts/personal-assistant-extensions.test.js +35 -0
  79. package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
  80. package/dist/tests-ts/personal-assistant-owner-context.test.js +107 -0
  81. package/dist/tests-ts/personal-assistant-remote-ability.test.js +123 -0
  82. package/dist/tests-ts/personal-assistant.test.js +663 -0
  83. package/dist/tests-ts/platform-integration.test.js +183 -1
  84. package/dist/tests-ts/plugin-catalog.test.js +12 -2
  85. package/dist/tests-ts/plugin-manager.test.js +356 -4
  86. package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
  87. package/dist/tests-ts/publish-packages.test.js +42 -0
  88. package/dist/tests-ts/qwenwork-plugin.test.js +135 -1
  89. package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
  90. package/dist/tests-ts/qwenwork-sse.test.js +33 -0
  91. package/dist/tests-ts/session-access-defaults.test.js +112 -0
  92. package/dist/tests-ts/session-management.test.js +159 -4
  93. package/dist/tests-ts/version-manager.test.js +40 -0
  94. package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
  95. package/dist/tests-ts/workbuddy-plugin.test.js +499 -4
  96. package/dist/tests-ts/zcode-cdp.test.js +894 -0
  97. package/dist/tests-ts/zcode-plugin.test.js +396 -0
  98. package/package.json +1 -1
  99. package/plugins/abweb/dist/src-ts/agent.js +35 -0
  100. package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
  101. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +73 -5
  102. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +57 -5
  103. package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +15 -0
  104. package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
  105. package/plugins/abweb/package.json +1 -1
  106. package/plugins/abweb/plugin.json +1 -1
  107. package/plugins/aun/config.schema.json +1 -1
  108. package/plugins/aun/dist/src-ts/agent.js +35 -0
  109. package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
  110. package/plugins/aun/dist/src-ts/plugins/aun/index.js +155 -21
  111. package/plugins/aun/dist/src-ts/plugins/aun/messages.js +4 -1
  112. package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
  113. package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
  114. package/plugins/aun/package.json +1 -1
  115. package/plugins/aun/plugin.json +1 -1
  116. package/plugins/chatgpt/dist/src-ts/agent.js +35 -0
  117. package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
  118. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
  119. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +80 -19
  120. package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
  121. package/plugins/chatgpt/package.json +1 -1
  122. package/plugins/chatgpt/plugin.json +1 -1
  123. package/plugins/claude-cli/dist/src-ts/agent.js +35 -0
  124. package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +19 -2
  125. package/plugins/claude-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
  126. package/plugins/claude-cli/package.json +1 -1
  127. package/plugins/claude-cli/plugin.json +3 -2
  128. package/plugins/codex-cli/dist/src-ts/agent.js +35 -0
  129. package/plugins/codex-cli/dist/src-ts/plugins/codex-cli/index.js +19 -2
  130. package/plugins/codex-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
  131. package/plugins/codex-cli/package.json +1 -1
  132. package/plugins/codex-cli/plugin.json +3 -2
  133. package/plugins/doubao/config.schema.json +2 -1
  134. package/plugins/doubao/dist/src-ts/agent.js +35 -0
  135. package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
  136. package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
  137. package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +152 -8
  138. package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
  139. package/plugins/doubao/package.json +1 -1
  140. package/plugins/doubao/plugin.json +3 -2
  141. package/plugins/dsh/config.schema.json +5 -2
  142. package/plugins/dsh/dist/src-ts/agent.js +35 -0
  143. package/plugins/dsh/dist/src-ts/dsh-agent.js +31 -13
  144. package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
  145. package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  146. package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +172 -21
  147. package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
  148. package/plugins/dsh/package.json +1 -1
  149. package/plugins/dsh/plugin.json +3 -2
  150. package/plugins/feishu/dist/src-ts/agent.js +35 -0
  151. package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
  152. package/plugins/feishu/package.json +1 -1
  153. package/plugins/feishu/plugin.json +1 -1
  154. package/plugins/personal-assistant/config.schema.json +23 -0
  155. package/plugins/personal-assistant/dist/src-ts/agent.js +69 -0
  156. package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
  157. package/plugins/personal-assistant/dist/src-ts/plugin.js +13 -0
  158. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
  159. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
  160. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +263 -0
  161. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
  162. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
  163. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
  164. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  165. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
  166. package/plugins/personal-assistant/package.json +39 -0
  167. package/plugins/personal-assistant/plugin.json +15 -0
  168. package/plugins/qwenwork/dist/src-ts/agent.js +35 -0
  169. package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
  170. package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
  171. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
  172. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +139 -24
  173. package/plugins/qwenwork/package.json +1 -1
  174. package/plugins/qwenwork/plugin.json +3 -2
  175. package/plugins/workbuddy/config.schema.json +1 -1
  176. package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
  177. package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
  178. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
  179. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +124 -41
  180. package/plugins/workbuddy/package.json +1 -1
  181. package/plugins/workbuddy/plugin.json +3 -2
  182. package/plugins/zcode/config.schema.json +13 -0
  183. package/plugins/zcode/dist/src-ts/agent.js +69 -0
  184. package/plugins/zcode/dist/src-ts/attachments.js +62 -0
  185. package/plugins/zcode/dist/src-ts/plugin.js +13 -0
  186. package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
  187. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
  188. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
  189. package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
  190. package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
  191. package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  192. package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  193. package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
  194. package/plugins/zcode/package.json +16 -0
  195. package/plugins/zcode/plugin.json +11 -0
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findWindowsExecutable = findWindowsExecutable;
4
+ exports.findExecutableInTree = findExecutableInTree;
5
+ exports.launchAndWait = launchAndWait;
6
+ exports.launchManagedAndWait = launchManagedAndWait;
7
+ exports.restartOwnedAndWait = restartOwnedAndWait;
8
+ exports.terminateWindowsDesktop = terminateWindowsDesktop;
9
+ exports.terminateOwnedProcess = terminateOwnedProcess;
10
+ exports.findChatgptExecutable = findChatgptExecutable;
11
+ exports.waitFor = waitFor;
12
+ const node_child_process_1 = require("node:child_process");
13
+ const promises_1 = require("node:fs/promises");
14
+ const node_fs_1 = require("node:fs");
15
+ const node_path_1 = require("node:path");
16
+ const node_util_1 = require("node:util");
17
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
18
+ const versionDirectory = /^(?:app[-_ ]?)?v?\d+(?:[.-]\d+)+$/i;
19
+ /** 先从 Windows 注册信息和开始菜单解析,失败时再查常见安装目录。 */
20
+ async function findWindowsExecutable(fileName, configured, run = execFileAsync) {
21
+ if (configured?.trim()) {
22
+ const configuredPath = (0, node_path_1.resolve)(configured);
23
+ if (fileName.toLowerCase() === "doubao.exe") {
24
+ let root = (0, node_path_1.dirname)(configuredPath);
25
+ while (/^(?:app|launcher|doubao_update)$/i.test((0, node_path_1.basename)(root)) || versionDirectory.test((0, node_path_1.basename)(root)))
26
+ root = (0, node_path_1.dirname)(root);
27
+ const updated = (0, node_path_1.join)(root, "Doubao_update", fileName);
28
+ if ((0, node_fs_1.existsSync)(updated))
29
+ return updated;
30
+ const latest = await findExecutableInTree(root, fileName, /^/, 3);
31
+ if (latest)
32
+ return latest;
33
+ }
34
+ // 千问升级会保留或删除旧版本目录,从同一安装位置重新定位新版。
35
+ if (fileName.toLowerCase() === "qwenworkcn.exe" && /^v?\d+(?:[.-]\d+)+$/i.test((0, node_path_1.basename)((0, node_path_1.dirname)(configuredPath)))) {
36
+ const latest = await findExecutableInTree((0, node_path_1.dirname)((0, node_path_1.dirname)(configuredPath)), fileName, /^/, 1);
37
+ if (latest)
38
+ return latest;
39
+ }
40
+ if ((0, node_fs_1.existsSync)(configuredPath))
41
+ return configuredPath;
42
+ }
43
+ if (process.platform !== "win32")
44
+ return undefined;
45
+ const registered = await findRegisteredWindowsExecutable(fileName, run);
46
+ if (registered)
47
+ return registered;
48
+ const pattern = /doubao|豆包|qwen|qwwork|千问|deepseek|harness|dsh|zcode/i;
49
+ const roots = [...new Set([
50
+ process.env.DSH_INSTALL_DIR,
51
+ "D:\\Programs\\DeepSeek Harness",
52
+ "D:\\DSH",
53
+ process.env.LOCALAPPDATA && (0, node_path_1.join)(process.env.LOCALAPPDATA, "Programs"),
54
+ process.env.LOCALAPPDATA,
55
+ process.env.ProgramFiles,
56
+ process.env["ProgramFiles(x86)"],
57
+ ...Array.from({ length: 24 }, (_, index) => `${String.fromCharCode(67 + index)}:\\`),
58
+ ].filter((value) => typeof value === "string" && (0, node_fs_1.existsSync)(value)))];
59
+ for (const root of roots) {
60
+ const found = await findExecutableInTree(root, fileName, pattern, 6);
61
+ if (found)
62
+ return found;
63
+ }
64
+ return undefined;
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
+ }
96
+ async function findExecutableInTree(directory, fileName, pattern, depth) {
97
+ return search(directory, fileName, pattern, depth, pattern.test(directory));
98
+ }
99
+ async function search(directory, fileName, pattern, depth, insideProduct) {
100
+ try {
101
+ const entries = await (0, promises_1.readdir)(directory, { withFileTypes: true });
102
+ // 豆包上层文件是启动器,优先查找新版目录或 app 中的实际程序。
103
+ if (insideProduct && depth > 0 && fileName.toLowerCase() === "doubao.exe") {
104
+ const versions = entries.filter(entry => entry.isDirectory() && (versionDirectory.test(entry.name) || /^(?:app|doubao_update)$/i.test(entry.name)));
105
+ versions.sort((left, right) => {
106
+ const rank = (name) => /^doubao_update$/i.test(name) ? 2 : /^app$/i.test(name) ? 0 : 1;
107
+ return rank(right.name) - rank(left.name) || right.name.replace(/^\D+/, "").localeCompare(left.name.replace(/^\D+/, ""), "en", { numeric: true });
108
+ });
109
+ for (const entry of versions) {
110
+ const found = await search((0, node_path_1.join)(directory, entry.name), fileName, pattern, depth - 1, true);
111
+ if (found)
112
+ return found;
113
+ }
114
+ }
115
+ for (const entry of entries)
116
+ if (entry.isFile() && insideProduct && entry.name.toLowerCase() === fileName.toLowerCase() && !(fileName.toLowerCase() === "doubao.exe" && /^(?:launcher|doubao)$/i.test((0, node_path_1.basename)(directory))))
117
+ return (0, node_path_1.join)(directory, entry.name);
118
+ if (depth <= 0)
119
+ return undefined;
120
+ // 按数字比较版本目录,避免 1.2.5 排在 1.2.10 之前。
121
+ entries.sort((left, right) => right.name.localeCompare(left.name, "en", { numeric: true }));
122
+ for (const entry of entries)
123
+ if (entry.isDirectory() && !entry.name.startsWith(".") && (insideProduct || pattern.test(entry.name) || /^(?:Program Files(?: \(x86\))?|Programs)$/i.test(entry.name))) {
124
+ const found = await search((0, node_path_1.join)(directory, entry.name), fileName, pattern, depth - 1, insideProduct || pattern.test(entry.name));
125
+ if (found)
126
+ return found;
127
+ }
128
+ }
129
+ catch { /* 无权限或目录在扫描期间消失时继续查找 */ }
130
+ return undefined;
131
+ }
132
+ async function launchAndWait(executable, args, connect, timeoutMs, launch = (file, argv) => (0, node_child_process_1.spawn)(file, argv, { detached: true, stdio: "ignore", windowsHide: false })) {
133
+ const child = launch(executable, args);
134
+ child.unref();
135
+ return waitFor(connect, timeoutMs, 250);
136
+ }
137
+ async function launchManagedAndWait(executable, args, profileDirectory, connect, timeoutMs, onProcess, launch = (file, argv) => (0, node_child_process_1.spawn)(file, argv, { detached: true, stdio: "ignore", windowsHide: false })) {
138
+ if (profileDirectory)
139
+ await (0, promises_1.mkdir)(profileDirectory, { recursive: true });
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();
147
+ child.unref();
148
+ onProcess(child);
149
+ try {
150
+ await started;
151
+ return await waitFor(connect, timeoutMs, 250);
152
+ }
153
+ catch (error) {
154
+ await terminateOwnedProcess(child).catch(() => undefined);
155
+ onProcess(undefined);
156
+ throw error;
157
+ }
158
+ }
159
+ async function restartOwnedAndWait(child, executable, args, profileDirectory, connect, timeoutMs, onProcess) {
160
+ await terminateOwnedProcess(child);
161
+ onProcess(undefined);
162
+ return launchManagedAndWait(executable, args, profileDirectory, connect, timeoutMs, onProcess);
163
+ }
164
+ /** 仅在用户确认重启后清理同一用户、同一安装路径的桌面进程。 */
165
+ async function terminateWindowsDesktop(executable) {
166
+ if (process.platform !== "win32")
167
+ return [];
168
+ const script = `
169
+ $ErrorActionPreference = 'Stop'
170
+ $target = '${(0, node_path_1.resolve)(executable).replace(/'/g, "''")}'
171
+ $sid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
172
+ $processes = @(Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -ieq $target } | Where-Object { (Invoke-CimMethod -InputObject $_ -MethodName GetOwnerSid).Sid -eq $sid })
173
+ $ids = @($processes.ProcessId)
174
+ $roots = @($processes | Where-Object { $ids -notcontains $_.ParentProcessId })
175
+ foreach ($item in $roots) {
176
+ $current = Get-CimInstance Win32_Process -Filter "ProcessId=$($item.ProcessId)"
177
+ if (-not $current -or $current.CreationDate -ne $item.CreationDate) { continue }
178
+ & taskkill.exe /PID $item.ProcessId /T /F | Out-Null
179
+ if ($LASTEXITCODE -ne 0 -and (Get-Process -Id $item.ProcessId -ErrorAction SilentlyContinue)) { throw "无法结束桌面进程 $($item.ProcessId)" }
180
+ $remaining = Get-Process -Id $item.ProcessId -ErrorAction SilentlyContinue
181
+ if ($remaining -and -not $remaining.WaitForExit(10000)) { throw "等待桌面进程退出超时 $($item.ProcessId)" }
182
+ }
183
+ ConvertTo-Json -Compress -InputObject @($roots | ForEach-Object { [int]$_.ProcessId })
184
+ `;
185
+ const { stdout } = await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], { timeout: 30_000, windowsHide: true });
186
+ return JSON.parse(stdout.trim());
187
+ }
188
+ async function terminateOwnedProcess(child, platform = process.platform, run = async (file, args) => execFileAsync(file, args, { timeout: 10_000 })) {
189
+ const pid = child?.pid;
190
+ if (!Number.isSafeInteger(pid) || !pid || child?.exitCode !== null && child?.exitCode !== undefined || child?.signalCode)
191
+ return;
192
+ if (platform === "win32") {
193
+ try {
194
+ await run("taskkill.exe", ["/PID", String(pid), "/T", "/F"]);
195
+ }
196
+ catch (error) {
197
+ if (!child.exitCode && !child.signalCode && error.code !== "ESRCH")
198
+ throw error;
199
+ }
200
+ }
201
+ else {
202
+ try {
203
+ process.kill(pid, "SIGTERM");
204
+ }
205
+ catch (error) {
206
+ if (error.code !== "ESRCH")
207
+ throw error;
208
+ }
209
+ }
210
+ }
211
+ async function findChatgptExecutable(configured) {
212
+ if (configured?.trim() && (0, node_fs_1.existsSync)((0, node_path_1.resolve)(configured)))
213
+ return (0, node_path_1.resolve)(configured);
214
+ if (process.platform !== "win32")
215
+ return undefined;
216
+ const script = "$candidates = foreach ($package in (Get-AppxPackage | Where-Object { $_.Name -like 'OpenAI.Codex*' })) { $appDir = Join-Path $package.InstallLocation 'app'; $path = Join-Path $appDir 'ChatGPT.exe'; if (-not (Test-Path -LiteralPath $path)) { $path = Get-ChildItem -LiteralPath $appDir -Filter 'ChatGPT*.exe' -File -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName }; if ($path) { [pscustomobject]@{ Version = [version]$package.Version; Executable = $path } } }; $candidate = $candidates | Sort-Object Version -Descending | Select-Object -First 1; if ($candidate) { $candidate.Executable }";
217
+ try {
218
+ const { stdout } = await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { timeout: 10_000 });
219
+ return stdout.trim().split(/\r?\n/).at(-1)?.trim() || undefined;
220
+ }
221
+ catch {
222
+ return undefined;
223
+ }
224
+ }
225
+ async function waitFor(action, timeoutMs, intervalMs = 500) {
226
+ const deadline = Date.now() + timeoutMs;
227
+ let last;
228
+ while (Date.now() < deadline) {
229
+ try {
230
+ return await action();
231
+ }
232
+ catch (error) {
233
+ last = error;
234
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
235
+ }
236
+ }
237
+ throw last instanceof Error ? last : new Error("桌面程序启动超时");
238
+ }