deskbuddy 0.2.0-beta.39 → 0.2.0-beta.40

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/commands/enable.ts
4
- import { dirname as dirname19, join as join36 } from "path";
4
+ import { dirname as dirname19, join as join37 } from "path";
5
5
 
6
6
  // src/core/config.ts
7
7
  import { randomUUID } from "crypto";
@@ -162,9 +162,12 @@ function loadConfig() {
162
162
  dumateCdpPort: portOrUndefined(parsed.dumateCdpPort),
163
163
  dumateShortcuts: typeof parsed.dumateShortcuts === "boolean" ? parsed.dumateShortcuts : void 0,
164
164
  qoderShortcuts: typeof parsed.qoderShortcuts === "boolean" ? parsed.qoderShortcuts : void 0,
165
+ qwenworkShortcuts: typeof parsed.qwenworkShortcuts === "boolean" ? parsed.qwenworkShortcuts : void 0,
165
166
  qoderLaunchPort: typeof parsed.qoderLaunchPort === "boolean" ? parsed.qoderLaunchPort : void 0,
166
167
  cozeApp: typeof parsed.cozeApp === "boolean" ? parsed.cozeApp : void 0,
167
- cozeCdpPort: portOrUndefined(parsed.cozeCdpPort)
168
+ cozeCdpPort: portOrUndefined(parsed.cozeCdpPort),
169
+ chatgptAppPort: typeof parsed.chatgptAppPort === "boolean" ? parsed.chatgptAppPort : void 0,
170
+ chatgptCdpPort: portOrUndefined(parsed.chatgptCdpPort)
168
171
  };
169
172
  } catch {
170
173
  return fallback;
@@ -2062,7 +2065,7 @@ function isAppLnk(l, exe) {
2062
2065
  if (typeof exe === "function") return exe(l);
2063
2066
  return win322.basename(l.target || "").toLowerCase() === exe.toLowerCase();
2064
2067
  }
2065
- function lnkMatcher(app, readText = readSmall, restore = false) {
2068
+ function lnkMatcher(app, readText2 = readSmall, restore = false) {
2066
2069
  const exe = exeNameOf(app);
2067
2070
  let located = null;
2068
2071
  try {
@@ -2074,10 +2077,16 @@ function lnkMatcher(app, readText = readSmall, restore = false) {
2074
2077
  return (l) => {
2075
2078
  const target = l.target || "";
2076
2079
  if (win322.basename(target).toLowerCase() === exe.toLowerCase()) return true;
2080
+ if (app.isLauncher && isValidWinPath(target) && /\.exe$/i.test(target)) {
2081
+ try {
2082
+ if (app.isLauncher(target, located, readText2)) return true;
2083
+ } catch {
2084
+ }
2085
+ }
2077
2086
  if (!located && !restore || !isValidWinPath(target) || !/\.exe$/i.test(target)) return false;
2078
2087
  const k = target.toLowerCase();
2079
2088
  if (!cache2.has(k)) {
2080
- const ini = readText(win322.join(win322.dirname(target), "install.ini"));
2089
+ const ini = readText2(win322.join(win322.dirname(target), "install.ini"));
2081
2090
  const to = ini ? launcherTarget(ini, exe) : null;
2082
2091
  cache2.set(k, !!to && (restore || !!located && to.toLowerCase() === located.toLowerCase()));
2083
2092
  }
@@ -2246,7 +2255,7 @@ function applyResults(app, d, writes, results, records, prev) {
2246
2255
  return out;
2247
2256
  }
2248
2257
  function restoreWith(app, d, list, records, write3) {
2249
- const writes = planRestoreFor(matcherOf(app, d, true), list, records, portOf(app, d));
2258
+ const writes = planRestoreFor(app.restoreByRecord ? () => true : matcherOf(app, d, true), list, records, portOf(app, d));
2250
2259
  const finish = (results) => {
2251
2260
  const ok = new Set((results ?? []).filter((r2) => r2 && r2.ok === true && typeof r2.path === "string").map((r2) => keyOf(r2.path)));
2252
2261
  const keep = {};
@@ -2477,7 +2486,15 @@ var CLAUDE_TEXT = {
2477
2486
  /** 编辑类 setMode acceptEdits:整句作 label(101 字,用户拍板不拆;不含快捷键提示 `(shift+tab)`) */
2478
2487
  acceptEdits: "Yes, and switch to accept edits (auto-approve file edits and common file commands) for this session",
2479
2488
  /** Bash 的切 auto 模式(只在默认 / acceptEdits 模式下出现;非 workflow 来源时界面上带 ` · auto mode handles these prompts for you`) */
2480
- autoMode: "Yes, and switch to auto mode \xB7 auto mode handles these prompts for you"
2489
+ autoMode: "Yes, and switch to auto mode \xB7 auto mode handles these prompts for you",
2490
+ /** 设备上给「切 auto 模式」的说明(问题表 272:它会把整个会话切过去,要写清楚) */
2491
+ autoModeDesc: "\u5141\u8BB8\u8FD9\u4E00\u6B21\uFF0C\u5E76\u628A\u6574\u4E2A\u4F1A\u8BDD\u5207\u5230\u81EA\u52A8\u6A21\u5F0F\uFF1A\u4E4B\u540E\u8FD9\u7C7B\u786E\u8BA4\u7531 Claude \u81EA\u5DF1\u5224\u65AD\u653E\u884C\uFF0C\u4E0D\u518D\u9010\u6761\u95EE\u4F60",
2492
+ /**
2493
+ * Bash 碰到工作区外的目录(2.1.295 实测,问题表 272):建议是 addDirectories(session) + setMode acceptEdits(session),
2494
+ * 界面合成一项 `Yes, and always allow access to <目录> from this project`,选中两条一起生效
2495
+ */
2496
+ dirAccessHead: "Yes, and always allow access to ",
2497
+ dirAccessTail: " from this project"
2481
2498
  };
2482
2499
  var CLAUDE_AUTO_MODE_UPDATE = { type: "setMode", mode: "auto", destination: "session" };
2483
2500
  var CLAUDE_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
@@ -2489,19 +2506,44 @@ function claudeYesNo(middle, action, auto = false) {
2489
2506
  actions[middle.id] = action;
2490
2507
  }
2491
2508
  if (auto) {
2492
- options.push({ id: "auto", label: CLAUDE_TEXT.autoMode, kind: "allow_session" });
2509
+ options.push({ id: "auto", label: CLAUDE_TEXT.autoMode, description: CLAUDE_TEXT.autoModeDesc, kind: "allow_session" });
2493
2510
  actions.auto = { decision: "allow", updatedPermissions: [{ ...CLAUDE_AUTO_MODE_UPDATE }] };
2494
2511
  }
2495
2512
  options.push({ id: "deny", label: CLAUDE_TEXT.no, description: CLAUDE_TEXT.noInput, kind: "deny", input: true });
2496
2513
  actions.deny = { decision: "deny" };
2497
2514
  return { options, actions };
2498
2515
  }
2516
+ function claudeDirAccess(sugg) {
2517
+ if (sugg.length < 1 || sugg.length > 2) return null;
2518
+ let dir2 = null;
2519
+ let mode = 0;
2520
+ for (const x of sugg) {
2521
+ const s = x;
2522
+ if (s && s.type === "addDirectories" && s.destination === "session" && Array.isArray(s.directories) && s.directories.length === 1 && typeof s.directories[0] === "string" && s.directories[0]) {
2523
+ if (dir2 !== null) return null;
2524
+ dir2 = s.directories[0];
2525
+ } else if (s && s.type === "setMode" && s.mode === "acceptEdits" && s.destination === "session") mode++;
2526
+ else return null;
2527
+ }
2528
+ if (!dir2 || mode > 1 || /[\u0000-\u001f\u007f]/.test(dir2)) return null;
2529
+ return dir2;
2530
+ }
2499
2531
  function claudeOptions(toolName, suggestions, ctx = {}) {
2500
2532
  const sugg = suggestions === void 0 || suggestions === null ? [] : suggestions;
2501
2533
  if (!Array.isArray(sugg)) return null;
2502
2534
  if (toolName === "Bash") {
2503
2535
  const auto = ctx.autoModeAllowed === true && (ctx.permissionMode === "default" || ctx.permissionMode === "acceptEdits");
2504
2536
  if (sugg.length === 0) return checkOptions(claudeYesNo(null, void 0, auto));
2537
+ const dir2 = claudeDirAccess(sugg);
2538
+ if (dir2) {
2539
+ return checkOptions(
2540
+ claudeYesNo(
2541
+ { id: "dir", label: CLAUDE_TEXT.dirAccessHead + dir2 + CLAUDE_TEXT.dirAccessTail, kind: "allow_session" },
2542
+ { decision: "allow", updatedPermissions: sugg },
2543
+ auto
2544
+ )
2545
+ );
2546
+ }
2505
2547
  if (sugg.length !== 1) return null;
2506
2548
  const s = sugg[0];
2507
2549
  if (!s || s.type !== "addRules" || s.behavior !== "allow" || s.destination !== "localSettings") return null;
@@ -2544,6 +2586,69 @@ var CODEX_TEXT = {
2544
2586
  decline: "No, continue without running it",
2545
2587
  cancel: "No, and tell Codex what to do differently"
2546
2588
  };
2589
+ var CODEX_PERMISSIONS_TOOL = "RequestPermissions";
2590
+ function grantOf(req2) {
2591
+ if (!req2 || typeof req2 !== "object" || Array.isArray(req2)) return null;
2592
+ const r = req2;
2593
+ const out = {};
2594
+ const net = r.network;
2595
+ if (net && typeof net === "object" && net.enabled === true) out.network = { enabled: true };
2596
+ const fs = r.fileSystem;
2597
+ if (fs && typeof fs === "object") {
2598
+ const f = {};
2599
+ for (const k of ["read", "write", "entries"]) if (Array.isArray(fs[k]) && fs[k].length > 0) f[k] = fs[k];
2600
+ if (fs.globScanMaxDepth !== void 0 && fs.globScanMaxDepth !== null) f.globScanMaxDepth = fs.globScanMaxDepth;
2601
+ if (Object.keys(f).length > 0) out.fileSystem = f;
2602
+ }
2603
+ return Object.keys(out).length > 0 ? out : null;
2604
+ }
2605
+ var SPECIAL_PATH = {
2606
+ root: "\u6574\u4E2A\u78C1\u76D8\uFF08/\uFF09",
2607
+ minimal: "\u7CFB\u7EDF\u57FA\u7840\u76EE\u5F55",
2608
+ project_roots: "\u9879\u76EE\u76EE\u5F55",
2609
+ tmpdir: "\u4E34\u65F6\u76EE\u5F55",
2610
+ slash_tmp: "/tmp"
2611
+ };
2612
+ function fsEntryText(e) {
2613
+ const raw = () => `\u8BBF\u95EE\u6587\u4EF6\u7CFB\u7EDF ${JSON.stringify(e).slice(0, 200)}`;
2614
+ if (!e || typeof e !== "object") return raw();
2615
+ const { access, path } = e;
2616
+ const verb = access === "write" ? "\u8BFB\u5199" : access === "read" ? "\u8BFB\u53D6" : access === "deny" ? "\u7981\u6B62\u8BBF\u95EE" : "";
2617
+ if (!verb || !path || typeof path !== "object") return raw();
2618
+ const p = path;
2619
+ let where = "";
2620
+ if (p.type === "path" && typeof p.path === "string") where = p.path;
2621
+ else if (p.type === "glob_pattern" && typeof p.pattern === "string") where = p.pattern;
2622
+ else if (p.type === "special" && p.value && typeof p.value === "object") {
2623
+ const v = p.value;
2624
+ const base = typeof v.kind === "string" ? SPECIAL_PATH[v.kind] ?? (typeof v.path === "string" ? v.path : "") : "";
2625
+ if (base) where = typeof v.subpath === "string" && v.subpath ? `${base} \u4E0B\u7684 ${v.subpath}` : base;
2626
+ }
2627
+ return where ? `${verb} ${where}` : raw();
2628
+ }
2629
+ function codexPermissionsCard(p) {
2630
+ const grant = grantOf(p.permissions);
2631
+ if (!grant) return null;
2632
+ const parts = [];
2633
+ if (grant.network) parts.push("\u8054\u7F51");
2634
+ const fs = grant.fileSystem;
2635
+ const paths = (k) => Array.isArray(fs?.[k]) ? (fs?.[k]).filter((x) => typeof x === "string") : [];
2636
+ if (paths("write").length) parts.push(`\u8BFB\u5199 ${paths("write").join(", ")}`);
2637
+ if (paths("read").length) parts.push(`\u8BFB\u53D6 ${paths("read").join(", ")}`);
2638
+ if (Array.isArray(fs?.entries)) for (const e of fs.entries) parts.push(fsEntryText(e));
2639
+ const reason = typeof p.reason === "string" ? cleanOptionText(p.reason) : "";
2640
+ const summary = `\u7533\u8BF7${parts.join("\u3001")}${reason ? `\uFF1A${reason}` : ""}`;
2641
+ const options = [
2642
+ { id: "allow", label: "Allow once", description: "\u8FD9\u4E00\u8F6E\u653E\u5F00\u7533\u8BF7\u7684\u6743\u9650", kind: "allow" },
2643
+ { id: "deny", label: "Deny", kind: "deny" }
2644
+ ];
2645
+ const actions = {
2646
+ allow: { decision: "allow", native: { permissions: grant, scope: "turn" } },
2647
+ deny: { decision: "deny", native: { permissions: {}, scope: "turn" } }
2648
+ };
2649
+ const set = checkOptions({ options, actions });
2650
+ return set ? { summary, toolInput: { request: summary, permissions: grant }, options: set } : null;
2651
+ }
2547
2652
  function codexMcpOptions(persist) {
2548
2653
  const list = persist === void 0 || persist === null ? [] : Array.isArray(persist) ? persist : [persist];
2549
2654
  if (list.some((v) => v !== "session" && v !== "always")) return null;
@@ -5725,11 +5830,18 @@ var WsCdpClient = class {
5725
5830
  this.#waiting.delete(m.id);
5726
5831
  clearTimeout(w.timer);
5727
5832
  if (m.error) return w.reject(new Error(m.error.message ?? "CDP \u51FA\u9519"));
5833
+ if (w.raw) return w.resolve(m.result);
5728
5834
  const ex = m.result?.exceptionDetails;
5729
5835
  if (ex) return w.reject(new Error((ex.exception?.description ?? ex.text ?? "\u9875\u9762\u811A\u672C\u51FA\u9519").slice(0, 300)));
5730
5836
  w.resolve(m.result?.result?.value);
5731
5837
  }
5732
5838
  evaluate(expression, timeoutMs = 1e4) {
5839
+ return this.#rpc("Runtime.evaluate", { expression, awaitPromise: true, returnByValue: true }, timeoutMs, false);
5840
+ }
5841
+ call(method, params = {}, timeoutMs = 1e4) {
5842
+ return this.#rpc(method, params, timeoutMs, true);
5843
+ }
5844
+ #rpc(method, params, timeoutMs, raw) {
5733
5845
  if (this.#closed) return Promise.reject(new Error("CDP \u8FDE\u63A5\u5DF2\u65AD\u5F00"));
5734
5846
  const id = ++this.#id;
5735
5847
  return new Promise((resolve6, reject) => {
@@ -5737,9 +5849,9 @@ var WsCdpClient = class {
5737
5849
  this.#waiting.delete(id);
5738
5850
  reject(new Error("\u9875\u9762\u811A\u672C\u8D85\u65F6"));
5739
5851
  }, timeoutMs);
5740
- this.#waiting.set(id, { resolve: resolve6, reject, timer });
5852
+ this.#waiting.set(id, { resolve: resolve6, reject, timer, ...raw ? { raw } : {} });
5741
5853
  try {
5742
- this.#ws.send(JSON.stringify({ id, method: "Runtime.evaluate", params: { expression, awaitPromise: true, returnByValue: true } }));
5854
+ this.#ws.send(JSON.stringify({ id, method, params }));
5743
5855
  } catch (e) {
5744
5856
  clearTimeout(timer);
5745
5857
  this.#waiting.delete(id);
@@ -7394,6 +7506,7 @@ var PtySummaryWatch = class {
7394
7506
 
7395
7507
  // src/daemon/dumateWatch.ts
7396
7508
  var APP_NOT_RUNNING = "app_not_running";
7509
+ var APP_PORT_MISSING = "app_port_missing";
7397
7510
  function unavailableMessage(reason) {
7398
7511
  if (reason === APP_PORT_HUNG_REASON) return "\u767E\u5EA6\u642D\u5B50\u8C03\u8BD5\u7AEF\u53E3\u65E0\u54CD\u5E94\uFF08App \u53EF\u80FD\u5361\u4F4F\u4E86\uFF09\uFF0C\u8BF7\u5728\u7535\u8111\u4E0A\u91CD\u5F00\u767E\u5EA6\u642D\u5B50";
7399
7512
  if (reason === APP_IN_USE_REASON) return "\u767E\u5EA6\u642D\u5B50\u6B63\u5728\u4F7F\u7528\u3001\u6CA1\u6709\u5F00\u8C03\u8BD5\u7AEF\u53E3\uFF08\u4F60\u5728\u7535\u8111\u524D\u6216\u5B83\u6B63\u5FD9\uFF0C\u6682\u4E0D\u66FF\u4F60\u91CD\u5F00\uFF09\uFF0C\u8BF7\u5728\u7535\u8111\u4E0A\u7EE7\u7EED";
@@ -9259,16 +9372,237 @@ function restoreQoderShortcutsSync(tool, d, ps = defaultPsSync) {
9259
9372
  restoreAppShortcutsSync(qoderShortcutApp(tool), d, ps);
9260
9373
  }
9261
9374
 
9375
+ // src/daemon/qwenworkApp/shortcuts.ts
9376
+ import { existsSync as existsSync21 } from "fs";
9377
+ import { win32 as win329 } from "path";
9378
+
9379
+ // src/daemon/qwenworkApp/keeper.ts
9380
+ import { readFileSync as readFileSync26 } from "fs";
9381
+ import { join as join27, win32 as win328 } from "path";
9382
+ var QW_DEFAULT_CDP_PORT = 39237;
9383
+ var QW_WIN_EXE = "QwenWorkCN.exe";
9384
+ var QW_WIN_LAUNCHER = "Launcher.exe";
9385
+ function readText(p) {
9386
+ try {
9387
+ return readFileSync26(p, "utf8");
9388
+ } catch {
9389
+ return null;
9390
+ }
9391
+ }
9392
+ function qwUpdaterTarget(text, root, strict = false) {
9393
+ if (!text) return null;
9394
+ try {
9395
+ const v = JSON.parse(text.replace(/^\uFEFF/, ""));
9396
+ const ver = typeof v.currentVersion === "string" ? v.currentVersion.trim() : "";
9397
+ if (strict && typeof v.appExecutableName !== "string") return null;
9398
+ const exe = typeof v.appExecutableName === "string" ? v.appExecutableName.trim() : QW_WIN_EXE;
9399
+ if (!/^[0-9a-z][0-9a-z._-]*$/i.test(ver) || exe.toLowerCase() !== QW_WIN_EXE.toLowerCase()) return null;
9400
+ return win328.join(root, ver, QW_WIN_EXE);
9401
+ } catch {
9402
+ return null;
9403
+ }
9404
+ }
9405
+ var QWENWORK_BRAND = {
9406
+ tool: "qwenwork",
9407
+ label: "\u5343\u95EE\u529E\u516C",
9408
+ macApp: "/Applications/QwenWorkCN.app",
9409
+ macExe: "/Applications/QwenWorkCN.app/Contents/MacOS/QwenWorkCN",
9410
+ appName: "QwenWorkCN",
9411
+ bundleId: "cn.qwenwork.desktop.mac",
9412
+ // Electron 默认 UA 带 `<应用名>/<版本>`;包里 package.json 的 name 是 qwen-work-cn、bundle 名是 QwenWorkCN(待真机核对是哪一个)
9413
+ ua: /\b(QwenWorkCN|qwen-work-cn)\/\d/i,
9414
+ comm: /\/QwenWorkCN\.app\//,
9415
+ defaultPort: QW_DEFAULT_CDP_PORT,
9416
+ // Windows(Bug 表 274):%LOCALAPPDATA%\Programs\QwenWorkCN\Launcher.exe 是启动器,主程序在版本目录 <版本>\QwenWorkCN.exe(updater.cfg 记 currentVersion / appExecutableName)
9417
+ win: {
9418
+ exe: QW_WIN_EXE,
9419
+ fgName: /^QwenWorkCN$/i,
9420
+ installPaths: () => {
9421
+ const la = process.env.LOCALAPPDATA;
9422
+ if (!la) return [];
9423
+ const root = win328.join(la, "Programs", "QwenWorkCN");
9424
+ const p = qwUpdaterTarget(readText(win328.join(root, "updater.cfg")), root);
9425
+ return p ? [p] : [];
9426
+ }
9427
+ }
9428
+ };
9429
+ var QW_DOWN_ROUNDS = 2;
9430
+ function qwKeeperThrottleFile() {
9431
+ return join27(deskbuddyHome(), "qwapp", "keeper.json");
9432
+ }
9433
+ var QwenworkKeeper = class {
9434
+ #d;
9435
+ #inner;
9436
+ #down = 0;
9437
+ #lastResult = "";
9438
+ constructor(deps) {
9439
+ this.#d = deps;
9440
+ this.#inner = deps.inner ?? new QoderCdpKeeper({
9441
+ ...deps,
9442
+ brand: deps.brand ?? QWENWORK_BRAND,
9443
+ throttleFile: deps.throttleFile ?? qwKeeperThrottleFile,
9444
+ skipSystem: deps.skipSystem ?? (() => process.env.DESKBUDDY_SKIP_QW_CDP === "1"),
9445
+ busy: () => (deps.busy ? deps.busy() : toolBusy("qwenwork")) || deps.hasCards?.() === true
9446
+ });
9447
+ }
9448
+ #platform() {
9449
+ return this.#d.platform ?? process.platform;
9450
+ }
9451
+ #skip() {
9452
+ return !this.#d.inner && (this.#d.skipSystem ? this.#d.skipSystem() : process.env.DESKBUDDY_SKIP_QW_CDP === "1");
9453
+ }
9454
+ /** 千问办公主进程在不在(测试兜底 / 不支持的平台按不在) */
9455
+ async appRunning() {
9456
+ const p = this.#platform();
9457
+ if (p !== "darwin" && p !== "win32" || this.#skip()) return false;
9458
+ return await this.#inner.appRunning().catch(() => false);
9459
+ }
9460
+ /**
9461
+ * Windows:千问办公主进程号(与 appRunning 同一口径:映像 QwenWorkCN.exe、没有 --type=、不跑脚本)。
9462
+ * 非 Windows / 测试兜底 / 取不到进程表 → null(快捷方式重补据此判新启动,Bug 表 274)
9463
+ */
9464
+ async winMainPid() {
9465
+ if (this.#platform() !== "win32" || this.#skip()) return null;
9466
+ try {
9467
+ let procs = this.#d.procs ? await this.#d.procs() : null;
9468
+ if (!this.#d.procs) {
9469
+ const r = await (this.#d.exec ?? defaultExec)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", WIN_PS_SCRIPT], 15e3);
9470
+ procs = r.code === 0 ? parseWinProcJson(r.stdout) : null;
9471
+ }
9472
+ return procs ? winBrandMainProc(procs, QW_WIN_EXE)?.pid ?? null : null;
9473
+ } catch {
9474
+ return null;
9475
+ }
9476
+ }
9477
+ async tick() {
9478
+ const p = this.#platform();
9479
+ if (p !== "darwin" && p !== "win32") return "untrusted";
9480
+ if (this.#skip()) return "down";
9481
+ const st = await this.#inner.tick();
9482
+ if (st !== "down") {
9483
+ this.#down = 0;
9484
+ return st;
9485
+ }
9486
+ this.#down++;
9487
+ if (this.#down >= QW_DOWN_ROUNDS) await this.#maybeRestart().catch((e) => this.#d.log(`\u5343\u95EE\u529E\u516C\u8C03\u8BD5\u7AEF\u53E3\uFF1A\u91CD\u542F\u51FA\u9519 ${e?.message ?? e}`));
9488
+ return "down";
9489
+ }
9490
+ async #maybeRestart() {
9491
+ if (this.#d.hasCards?.() === true) return;
9492
+ if (!await this.#inner.appRunning()) {
9493
+ this.#lastResult = "";
9494
+ return;
9495
+ }
9496
+ const r = await this.#inner.wakeForTask();
9497
+ if (r === "restarted") this.#down = 0;
9498
+ if (r !== this.#lastResult) {
9499
+ this.#lastResult = r;
9500
+ const why = {
9501
+ hung: "\u7AEF\u53E3\u5728\u76D1\u542C\u4F46\u65E0\u54CD\u5E94\uFF08App \u53EF\u80FD\u5361\u4F4F\u4E86\uFF09\uFF0C\u6309\u5361\u6B7B\u7B56\u7565\u5904\u7406\uFF1A\u8FDE\u7EED\u6EE1 20 \u5206\u949F\u3001\u7528\u6237\u4E0D\u5728\u573A\u4E14\u7A7A\u95F2\u624D\u7ED3\u675F\u5E76\u5E26\u7AEF\u53E3\u91CD\u542F\uFF0C\u5426\u5219\u8BF7\u5728\u7535\u8111\u4E0A\u91CD\u5F00\u5343\u95EE\u529E\u516C",
9502
+ restarted: "\u5DF2\u9000\u51FA\u5E76\u5E26\u7AEF\u53E3\u91CD\u542F",
9503
+ busy: "\u6B63\u5728\u8DD1\u4EFB\u52A1\uFF0C\u7B49\u7A7A\u95F2\u518D\u91CD\u542F",
9504
+ present: "\u7528\u6237\u5728\u7535\u8111\u524D\uFF0C\u4E0D\u6253\u65AD",
9505
+ failed: "\u91CD\u542F\u5931\u8D25\u6216\u4ECA\u5929\u7684\u91CD\u542F\u6B21\u6570\u5DF2\u7528\u5B8C",
9506
+ launched: "\u521A\u62C9\u8D77\u8FC7\uFF0C\u7B49\u5B83\u8D77\u6765",
9507
+ not_installed: "\u6CA1\u627E\u5230 App \u672C\u4F53"
9508
+ };
9509
+ if (why[r]) this.#d.log(`\u5343\u95EE\u529E\u516C\u8C03\u8BD5\u7AEF\u53E3 ${this.#d.port()} \u4E0D\u5728\uFF1A${why[r]}`);
9510
+ }
9511
+ }
9512
+ };
9513
+
9514
+ // src/daemon/qwenworkApp/shortcuts.ts
9515
+ var QW_SHORTCUT_EVERY_MS = 10 * 60 * 1e3;
9516
+ var QW_RELAUNCH_FIX_DELAYS_MS = [15 * 1e3, 60 * 1e3];
9517
+ var QW_PID_POLL_MS = 10 * 1e3;
9518
+ var QwShortcutRelaunchFixer = class {
9519
+ #d;
9520
+ #pid = null;
9521
+ #polledAt = 0;
9522
+ #polling = false;
9523
+ #due = [];
9524
+ constructor(d) {
9525
+ this.#d = d;
9526
+ }
9527
+ async tick() {
9528
+ if ((this.#d.platform ?? process.platform) !== "win32" || !this.#d.wanted()) return;
9529
+ const now = this.#d.now();
9530
+ if (!this.#polling && (this.#polledAt === 0 || now - this.#polledAt >= QW_PID_POLL_MS)) {
9531
+ this.#polling = true;
9532
+ this.#polledAt = now;
9533
+ try {
9534
+ const pid = await this.#d.mainPid();
9535
+ if (pid !== null && pid !== this.#pid) this.#due = QW_RELAUNCH_FIX_DELAYS_MS.map((ms) => now + ms);
9536
+ this.#pid = pid;
9537
+ } catch {
9538
+ } finally {
9539
+ this.#polling = false;
9540
+ }
9541
+ }
9542
+ const t = this.#d.now();
9543
+ if (this.#due.length > 0 && t >= this.#due[0]) {
9544
+ this.#due = this.#due.filter((x) => x > t);
9545
+ await this.#d.ensure().catch(() => void 0);
9546
+ }
9547
+ }
9548
+ };
9549
+ function qwPort() {
9550
+ try {
9551
+ return loadConfig().qwenworkCdpPort ?? QW_DEFAULT_CDP_PORT;
9552
+ } catch {
9553
+ return QW_DEFAULT_CDP_PORT;
9554
+ }
9555
+ }
9556
+ function qwenworkShortcutsWanted() {
9557
+ try {
9558
+ const c = loadConfig();
9559
+ return c.enabledTools.includes("qwenwork") && c.qwenworkShortcuts !== false;
9560
+ } catch {
9561
+ return false;
9562
+ }
9563
+ }
9564
+ function isQwenworkLauncher(target, located, readText2, exists = existsSync21) {
9565
+ if (win329.basename(target).toLowerCase() !== QW_WIN_LAUNCHER.toLowerCase()) return false;
9566
+ const dir2 = win329.dirname(target);
9567
+ if (located && win329.basename(located).toLowerCase() === QW_WIN_EXE.toLowerCase() && win329.dirname(win329.dirname(located)).toLowerCase() === dir2.toLowerCase()) return true;
9568
+ const main = qwUpdaterTarget(readText2(win329.join(dir2, "updater.cfg")), dir2, true);
9569
+ return main !== null && exists(main);
9570
+ }
9571
+ var QWENWORK_SHORTCUT_APP = {
9572
+ label: "\u5343\u95EE\u529E\u516C",
9573
+ appName: "\u5343\u95EE\u529E\u516C",
9574
+ exe: QW_WIN_EXE,
9575
+ dir: "qwapp",
9576
+ stem: "shortcuts",
9577
+ port: qwPort,
9578
+ wanted: qwenworkShortcutsWanted,
9579
+ off: () => loadConfig().qwenworkShortcuts === false,
9580
+ skipEnv: "DESKBUDDY_SKIP_QW_LNK",
9581
+ locatedExe: () => cachedWinAppExe("qwenwork"),
9582
+ isLauncher: isQwenworkLauncher,
9583
+ // disable 还原按 qwapp/shortcuts.json 的记录来:主程序卸了 / 认不出 Launcher 也能把我们加的端口摘掉
9584
+ restoreByRecord: true
9585
+ };
9586
+ function ensureQwenworkShortcuts(d, ps = defaultPs) {
9587
+ return ensureAppShortcuts(QWENWORK_SHORTCUT_APP, d, ps);
9588
+ }
9589
+ function ensureQwenworkShortcutsSync(d, ps = defaultPsSync) {
9590
+ ensureAppShortcutsSync(QWENWORK_SHORTCUT_APP, d, ps);
9591
+ }
9592
+ function restoreQwenworkShortcutsSync(d, ps = defaultPsSync) {
9593
+ restoreAppShortcutsSync(QWENWORK_SHORTCUT_APP, d, ps);
9594
+ }
9595
+
9262
9596
  // src/adapters/traeHook.ts
9263
- import { chmodSync as chmodSync5, existsSync as existsSync21, mkdirSync as mkdirSync23, readFileSync as readFileSync26, realpathSync as realpathSync5, renameSync as renameSync17, rmSync as rmSync13, statSync as statSync12, writeFileSync as writeFileSync23 } from "fs";
9264
- import { dirname as dirname13, join as join27 } from "path";
9597
+ import { chmodSync as chmodSync5, existsSync as existsSync22, mkdirSync as mkdirSync23, readFileSync as readFileSync27, realpathSync as realpathSync5, renameSync as renameSync17, rmSync as rmSync13, statSync as statSync12, writeFileSync as writeFileSync23 } from "fs";
9598
+ import { dirname as dirname13, join as join28 } from "path";
9265
9599
  var TRAE_EVENTS = ["UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop", "Notification"];
9266
9600
  var TRAE_NOTICE_TYPES = ["permission_prompt", "ask_user_question", "document_review", "browser_interaction"];
9267
9601
  var TRAE_NOTICE_MATCHER = `^(${TRAE_NOTICE_TYPES.join("|")})$`;
9268
9602
  var TRAE_NOTICE_TIMEOUT_S = 7 * 24 * 60 * 60;
9269
9603
  function readHooksFile(path) {
9270
- if (!existsSync21(path)) return {};
9271
- const raw = readFileSync26(path, "utf8");
9604
+ if (!existsSync22(path)) return {};
9605
+ const raw = readFileSync27(path, "utf8");
9272
9606
  if (raw.trim() === "") return {};
9273
9607
  let parsed;
9274
9608
  try {
@@ -9349,7 +9683,7 @@ function strip(f, scripts) {
9349
9683
  }
9350
9684
  function installTraeHook(path, hookPath, events = TRAE_EVENTS, platform = process.platform) {
9351
9685
  const f = readHooksFile(path);
9352
- const gatePath = join27(dirname13(hookPath), "gate.cjs");
9686
+ const gatePath = join28(dirname13(hookPath), "gate.cjs");
9353
9687
  const before = JSON.stringify(f);
9354
9688
  strip(f, [hookPath, gatePath]);
9355
9689
  if (f.version === void 0) f.version = 1;
@@ -9366,13 +9700,13 @@ function installTraeHook(path, hookPath, events = TRAE_EVENTS, platform = proces
9366
9700
  if (JSON.stringify(f) !== before) writeHooksFile(path, f);
9367
9701
  }
9368
9702
  function uninstallTraeHook(path, hookPath) {
9369
- if (!existsSync21(path)) return;
9703
+ if (!existsSync22(path)) return;
9370
9704
  const f = readHooksFile(path);
9371
- if (strip(f, [hookPath, join27(dirname13(hookPath), "gate.cjs")])) writeHooksFile(path, f);
9705
+ if (strip(f, [hookPath, join28(dirname13(hookPath), "gate.cjs")])) writeHooksFile(path, f);
9372
9706
  }
9373
9707
  function isTraeHookInstalled(path, hookPath) {
9374
9708
  try {
9375
- if (!existsSync21(path)) return false;
9709
+ if (!existsSync22(path)) return false;
9376
9710
  const f = readHooksFile(path);
9377
9711
  return Object.values(f.hooks ?? {}).some((groups) => (groups ?? []).some((g) => (g?.hooks ?? []).some((h) => mentions2(h?.command, hookPath))));
9378
9712
  } catch {
@@ -9382,19 +9716,19 @@ function isTraeHookInstalled(path, hookPath) {
9382
9716
  var TRAE_NOTICE = " TRAE\uFF1A\u8BF7\u5728 TRAE \u7684 \u8BBE\u7F6E > Hooks \u91CC\u786E\u8BA4\u300C\u5168\u5C40\u300DHooks \u5DF2\u542F\u7528\u3001\u8FD0\u884C\u65B9\u5F0F\u9009\u300C\u672C\u5730\u81EA\u52A8\u8FD0\u884C\u300D\uFF08\u6C99\u7BB1\u91CC hook \u8FDE\u4E0D\u4E0A\u5B88\u62A4\u8FDB\u7A0B\uFF09\uFF1B\u7535\u8111\u4E0A\u5F39\u6388\u6743\u6846\u65F6\u8BBE\u5907\u4E0A\u4F1A\u51FA\u73B0\u63D0\u793A\u5361\uFF0C\u9700\u56DE\u5230\u7535\u8111\u4E0A\u5904\u7406";
9383
9717
 
9384
9718
  // src/commands/tools.ts
9385
- import { existsSync as existsSync23, readFileSync as readFileSync28 } from "fs";
9719
+ import { existsSync as existsSync24, readFileSync as readFileSync29 } from "fs";
9386
9720
 
9387
9721
  // src/adapters/cbChannel.ts
9388
- import { chmodSync as chmodSync6, existsSync as existsSync22, lstatSync as lstatSync2, mkdirSync as mkdirSync24, readFileSync as readFileSync27, realpathSync as realpathSync6, renameSync as renameSync18, statSync as statSync13, writeFileSync as writeFileSync24 } from "fs";
9389
- import { dirname as dirname14, join as join28 } from "path";
9722
+ import { chmodSync as chmodSync6, existsSync as existsSync23, lstatSync as lstatSync2, mkdirSync as mkdirSync24, readFileSync as readFileSync28, realpathSync as realpathSync6, renameSync as renameSync18, statSync as statSync13, writeFileSync as writeFileSync24 } from "fs";
9723
+ import { dirname as dirname14, join as join29 } from "path";
9390
9724
  var CB_MCP_NAME = "deskbuddy";
9391
9725
  var CB_CHANNEL_SCRIPT = "cbchannel.cjs";
9392
9726
  function cbChannelScript(hookPath) {
9393
- return join28(dirname14(hookPath), CB_CHANNEL_SCRIPT);
9727
+ return join29(dirname14(hookPath), CB_CHANNEL_SCRIPT);
9394
9728
  }
9395
9729
  function read(path) {
9396
- if (!existsSync22(path)) return {};
9397
- const raw = readFileSync27(path, "utf8");
9730
+ if (!existsSync23(path)) return {};
9731
+ const raw = readFileSync28(path, "utf8");
9398
9732
  if (raw.trim() === "") return {};
9399
9733
  let v;
9400
9734
  try {
@@ -9441,7 +9775,7 @@ function installCbChannel(mcpPath, scriptPath, nodePath = CB_NODE) {
9441
9775
  write2(mcpPath, f);
9442
9776
  }
9443
9777
  function uninstallCbChannel(mcpPath) {
9444
- if (!existsSync22(mcpPath)) return;
9778
+ if (!existsSync23(mcpPath)) return;
9445
9779
  const f = read(mcpPath);
9446
9780
  const servers = f.mcpServers;
9447
9781
  if (!servers || typeof servers !== "object" || Array.isArray(servers) || !ours(servers[CB_MCP_NAME])) return;
@@ -9462,8 +9796,8 @@ function codebuddyWanted(d = { standalone: () => standaloneProbe() }) {
9462
9796
  }
9463
9797
  function fileContains(path, needle) {
9464
9798
  try {
9465
- if (!existsSync23(path)) return false;
9466
- return readFileSync28(path, "utf8").includes(needle);
9799
+ if (!existsSync24(path)) return false;
9800
+ return readFileSync29(path, "utf8").includes(needle);
9467
9801
  } catch {
9468
9802
  return false;
9469
9803
  }
@@ -9493,10 +9827,12 @@ var ADAPTERS = {
9493
9827
  install: (p, hook, events, tool) => {
9494
9828
  installCcHook(p, hook, events, tool);
9495
9829
  if ((tool === "qoder_cn" || tool === "qoder") && pathResolve(p) === pathResolve(CC_CONFIG_PATHS[tool]())) ensureQoderShortcutsSync(tool, { log: qoderLnkLog });
9830
+ if (tool === "qwenwork" && pathResolve(p) === pathResolve(CC_CONFIG_PATHS.qwenwork())) ensureQwenworkShortcutsSync({ log: qoderLnkLog });
9496
9831
  },
9497
9832
  uninstall: (p, hook) => {
9498
9833
  uninstallCcHook(p, hook);
9499
9834
  for (const tool of ["qoder_cn", "qoder"]) if (pathResolve(p) === pathResolve(CC_CONFIG_PATHS[tool]())) restoreQoderShortcutsSync(tool, { log: qoderLnkLog });
9835
+ if (pathResolve(p) === pathResolve(CC_CONFIG_PATHS.qwenwork())) restoreQwenworkShortcutsSync({ log: qoderLnkLog });
9500
9836
  if (pathResolve(pathDirname(p)) === pathResolve(codebuddyConfigDir())) uninstallCbChannel(codebuddyMcpPath());
9501
9837
  },
9502
9838
  // Windows 上装出去的是正斜杠形式;JSON 里的反斜杠还会被转义成两个,原样搜不到
@@ -9565,7 +9901,7 @@ ADAPTERS["dumate-http"] = {
9565
9901
  uninstall: () => restoreDumateShortcutsSync({ log: dmLnkLog }),
9566
9902
  isInstalled: (p) => {
9567
9903
  try {
9568
- const enabled = JSON.parse(readFileSync28(p, "utf8")).enabledTools;
9904
+ const enabled = JSON.parse(readFileSync29(p, "utf8")).enabledTools;
9569
9905
  return Array.isArray(enabled) && enabled.includes("dumate");
9570
9906
  } catch {
9571
9907
  return false;
@@ -9586,7 +9922,7 @@ ADAPTERS["trae-hooks"] = {
9586
9922
  extraConfigPaths: (tool, purpose) => {
9587
9923
  if (tool !== "trae") return [];
9588
9924
  const primary = pathResolve(traeHooksPath());
9589
- return traeHooksPaths().filter((p) => pathResolve(p) !== primary && (purpose === "uninstall" || existsSync23(pathDirname(p))));
9925
+ return traeHooksPaths().filter((p) => pathResolve(p) !== primary && (purpose === "uninstall" || existsSync24(pathDirname(p))));
9590
9926
  }
9591
9927
  };
9592
9928
  var COZE_NOTICE = " \u6263\u5B50\u4E0D\u9700\u8981\u6539\u5B83\u7684\u4EFB\u4F55\u914D\u7F6E\uFF1A\u5B88\u62A4\u8FDB\u7A0B\u5728\u8DD1\u65F6\u4F1A\u8BA9\u6263\u5B50\u5E26\u8C03\u8BD5\u7AEF\u53E3\u542F\u52A8\uFF08\u4F60\u4E0D\u5728\u7535\u8111\u524D\u4E14\u6263\u5B50\u7A7A\u95F2\u65F6\u624D\u4F1A\u91CD\u5F00\u5B83\uFF09\uFF0C\u72B6\u6001\u548C\u5F85\u786E\u8BA4\u90FD\u4F1A\u63A8\u5230\u8BBE\u5907";
@@ -9598,7 +9934,7 @@ ADAPTERS["coze-cdp"] = {
9598
9934
  },
9599
9935
  isInstalled: (p) => {
9600
9936
  try {
9601
- const enabled = JSON.parse(readFileSync28(p, "utf8")).enabledTools;
9937
+ const enabled = JSON.parse(readFileSync29(p, "utf8")).enabledTools;
9602
9938
  return Array.isArray(enabled) && enabled.includes("coze");
9603
9939
  } catch {
9604
9940
  return false;
@@ -9629,9 +9965,9 @@ function subscribedEvents(registry, tool, fallback) {
9629
9965
  }
9630
9966
 
9631
9967
  // src/wrap/pty.ts
9632
- import { chmodSync as chmodSync7, existsSync as existsSync24, statSync as statSync14 } from "fs";
9968
+ import { chmodSync as chmodSync7, existsSync as existsSync25, statSync as statSync14 } from "fs";
9633
9969
  import { createRequire as createRequire4 } from "module";
9634
- import { dirname as dirname15, join as join29 } from "path";
9970
+ import { dirname as dirname15, join as join30 } from "path";
9635
9971
  import { fileURLToPath as fileURLToPath4 } from "url";
9636
9972
  var req = createRequire4(import.meta.url);
9637
9973
  var VENDORED_PTY_PLATFORMS = ["darwin-arm64", "darwin-x64", "win32-arm64", "win32-x64"];
@@ -9641,8 +9977,8 @@ function hasVendoredPty(platform = process.platform, arch = process.arch) {
9641
9977
  function vendoredPtyDir(from = dirname15(fileURLToPath4(import.meta.url))) {
9642
9978
  let dir2 = from;
9643
9979
  for (let i = 0; i < 4; i++) {
9644
- const cand = join29(dir2, "vendor", "node-pty");
9645
- if (existsSync24(join29(cand, "package.json"))) return cand;
9980
+ const cand = join30(dir2, "vendor", "node-pty");
9981
+ if (existsSync25(join30(cand, "package.json"))) return cand;
9646
9982
  const up = dirname15(dir2);
9647
9983
  if (up === dir2) break;
9648
9984
  dir2 = up;
@@ -9652,8 +9988,8 @@ function vendoredPtyDir(from = dirname15(fileURLToPath4(import.meta.url))) {
9652
9988
  function fixSpawnHelper(ptyDir) {
9653
9989
  if (process.platform !== "darwin") return;
9654
9990
  try {
9655
- const helper = join29(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
9656
- if (existsSync24(helper) && (statSync14(helper).mode & 73) === 0) chmodSync7(helper, 493);
9991
+ const helper = join30(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
9992
+ if (existsSync25(helper) && (statSync14(helper).mode & 73) === 0) chmodSync7(helper, 493);
9657
9993
  } catch {
9658
9994
  }
9659
9995
  }
@@ -9757,10 +10093,10 @@ function accentLine(term, tabRow = /←.*[☐☒].*Submit.*→/) {
9757
10093
  }
9758
10094
 
9759
10095
  // src/commands/migrateQoder.ts
9760
- import { dirname as dirname17, join as join30 } from "path";
10096
+ import { dirname as dirname17, join as join31 } from "path";
9761
10097
 
9762
10098
  // src/core/detect.ts
9763
- import { existsSync as existsSync25 } from "fs";
10099
+ import { existsSync as existsSync26 } from "fs";
9764
10100
  import { dirname as dirname16 } from "path";
9765
10101
 
9766
10102
  // src/daemon/cozeApp/brand.ts
@@ -9840,7 +10176,7 @@ function toolDetectDirs(tool) {
9840
10176
  }
9841
10177
  var defaultDetectDeps = () => ({
9842
10178
  located: (tool) => locate(tool) != null,
9843
- exists: existsSync25,
10179
+ exists: existsSync26,
9844
10180
  env: process.env
9845
10181
  });
9846
10182
  function callerTool(env) {
@@ -9861,7 +10197,7 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
9861
10197
  try {
9862
10198
  const cfg = loadConfig();
9863
10199
  const hookPath = installedHookPath();
9864
- const scripts = [hookPath, join30(dirname17(hookPath), "gate.cjs")];
10200
+ const scripts = [hookPath, join31(dirname17(hookPath), "gate.cjs")];
9865
10201
  if (!retagCcHook(qoderCnSettingsPath(), scripts, "qoder", "qoder_cn")) return false;
9866
10202
  const hadQoder = cfg.enabledTools.includes("qoder");
9867
10203
  let intl = false;
@@ -9890,26 +10226,26 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
9890
10226
 
9891
10227
  // src/daemon/loginGuide.ts
9892
10228
  import { execFile as execFile9, execFileSync as execFileSync13 } from "child_process";
9893
- import { chmodSync as chmodSync9, existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync29, writeFileSync as writeFileSync26 } from "fs";
10229
+ import { chmodSync as chmodSync9, existsSync as existsSync27, mkdirSync as mkdirSync26, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
9894
10230
  import { homedir as homedir9 } from "os";
9895
- import { join as join34 } from "path";
10231
+ import { join as join35 } from "path";
9896
10232
 
9897
10233
  // src/daemon/executor.ts
9898
10234
  import { execFile as execFile7, execFileSync as execFileSync11 } from "child_process";
9899
10235
  import { homedir as homedir8 } from "os";
9900
- import { join as join32 } from "path";
10236
+ import { join as join33 } from "path";
9901
10237
 
9902
10238
  // src/core/codebuddyDirs.ts
9903
- import { join as join31, win32 as win328, posix as posix3 } from "path";
10239
+ import { join as join32, win32 as win3210, posix as posix3 } from "path";
9904
10240
  function same(a, b, platform) {
9905
- const pa = platform === "win32" ? win328.resolve(a).toLowerCase() : posix3.resolve(a);
9906
- const pb = platform === "win32" ? win328.resolve(b).toLowerCase() : posix3.resolve(b);
10241
+ const pa = platform === "win32" ? win3210.resolve(a).toLowerCase() : posix3.resolve(a);
10242
+ const pb = platform === "win32" ? win3210.resolve(b).toLowerCase() : posix3.resolve(b);
9907
10243
  return pa === pb;
9908
10244
  }
9909
10245
  function workbuddyRunConfigDir(stateDir2, home, platform = process.platform) {
9910
- const wb = join31(home, ".workbuddy");
10246
+ const wb = join32(home, ".workbuddy");
9911
10247
  if (typeof stateDir2 !== "string" || !stateDir2) return wb;
9912
- const cb = join31(home, ".codebuddy");
10248
+ const cb = join32(home, ".codebuddy");
9913
10249
  if (same(stateDir2, cb, platform)) return cb;
9914
10250
  return wb;
9915
10251
  }
@@ -10001,7 +10337,7 @@ function buildSpawnPlan(cmd, cwd, gate, home = homedir8(), configDir, platform =
10001
10337
  file: file3,
10002
10338
  args: workbuddyPlan(cmd, gate),
10003
10339
  cwd,
10004
- env: { CODEBUDDY_CONFIG_DIR: cmd.sessionId ? workbuddyRunConfigDir(configDir, home, platform) : join32(home, ".workbuddy") }
10340
+ env: { CODEBUDDY_CONFIG_DIR: cmd.sessionId ? workbuddyRunConfigDir(configDir, home, platform) : join33(home, ".workbuddy") }
10005
10341
  };
10006
10342
  case "qoder_cn":
10007
10343
  case "qoder":
@@ -10271,7 +10607,7 @@ function killTree(child) {
10271
10607
  import { execFile as execFile8, execFileSync as execFileSync12, spawn as spawn4 } from "child_process";
10272
10608
  import { chmodSync as chmodSync8, mkdirSync as mkdirSync25, rmSync as rmSync14, writeFileSync as writeFileSync25 } from "fs";
10273
10609
  import { userInfo } from "os";
10274
- import { join as join33 } from "path";
10610
+ import { join as join34 } from "path";
10275
10611
  function safePath(p) {
10276
10612
  return /^(?:[A-Za-z]:[\\/]|\/)/.test(p) && !/[\r\n\0"'`$%;\u2018-\u201b]/.test(p);
10277
10613
  }
@@ -10371,7 +10707,7 @@ async function openTerminal(t, d) {
10371
10707
  checkTarget(t);
10372
10708
  if (d.platform === "darwin") {
10373
10709
  mkdirSync25(launchDir(t.home), { recursive: true, mode: 448 });
10374
- const file3 = join33(launchDir(t.home), `${t.runId}.command`);
10710
+ const file3 = join34(launchDir(t.home), `${t.runId}.command`);
10375
10711
  writeFileSync25(file3, macCommandScript(t), { encoding: "utf8", mode: 448 });
10376
10712
  chmodSync8(file3, 448);
10377
10713
  await d.run("open", ["-a", "Terminal", file3]);
@@ -10391,7 +10727,7 @@ async function openTerminal(t, d) {
10391
10727
  function removeCommandFile(home, runId) {
10392
10728
  if (!RUN_ID_RE.test(runId)) return;
10393
10729
  try {
10394
- rmSync14(join33(launchDir(home), `${runId}.command`), { force: true });
10730
+ rmSync14(join34(launchDir(home), `${runId}.command`), { force: true });
10395
10731
  } catch {
10396
10732
  }
10397
10733
  }
@@ -10473,8 +10809,8 @@ var WORKBUDDY_PROBE_ARGS = ["-p", PROBE_TEXT, "--output-format", "json", "--no-s
10473
10809
  var WORKBUDDY_AUTH_FILE = "Tencent-Cloud.coding-copilot.info";
10474
10810
  function workbuddyAuthFile(home, platform, localAppData = "") {
10475
10811
  const tail = ["CodeBuddyExtension", "Data", "Public", "auth", WORKBUDDY_AUTH_FILE];
10476
- if (platform === "darwin") return join34(home, "Library", "Application Support", ...tail);
10477
- if (platform === "win32") return localAppData ? join34(localAppData, ...tail) : null;
10812
+ if (platform === "darwin") return join35(home, "Library", "Application Support", ...tail);
10813
+ if (platform === "win32") return localAppData ? join35(localAppData, ...tail) : null;
10478
10814
  return null;
10479
10815
  }
10480
10816
  var WORKBUDDY_VIA_APP_NOTE = "WorkBuddy \u5C06\u901A\u8FC7\u684C\u9762 App \u8FD0\u884C\uFF0C\u5728 App \u91CC\u767B\u5F55\u5373\u53EF";
@@ -10488,7 +10824,7 @@ async function checkWorkbuddy(d) {
10488
10824
  const auth = d.workbuddyAuthFile?.() ?? null;
10489
10825
  if (auth && d.exists?.(auth)) return { tool, state: "logged_in", note: "\u72EC\u7ACB\u7248\u51ED\u636E\u6587\u4EF6\u5728" };
10490
10826
  }
10491
- const env = envFor(d, loc, { CODEBUDDY_CONFIG_DIR: join34(d.home, ".workbuddy"), DESKBUDDY_NO_WAKE: "1", [PROBE_ENV]: "1" });
10827
+ const env = envFor(d, loc, { CODEBUDDY_CONFIG_DIR: join35(d.home, ".workbuddy"), DESKBUDDY_NO_WAKE: "1", [PROBE_ENV]: "1" });
10492
10828
  const r = await d.run(loc.file, [...loc.prefixArgs, ...WORKBUDDY_PROBE_ARGS], env, WORKBUDDY_PROBE_TIMEOUT_MS);
10493
10829
  const bad = failedRun(r);
10494
10830
  if (bad) return { tool, state: "unknown", note: bad };
@@ -10573,7 +10909,7 @@ var defaultCheckDeps = () => ({
10573
10909
  home: homedir9(),
10574
10910
  codexConfig: () => {
10575
10911
  try {
10576
- return readFileSync29(join34(codexHome(), "config.toml"), "utf8");
10912
+ return readFileSync30(join35(codexHome(), "config.toml"), "utf8");
10577
10913
  } catch {
10578
10914
  return null;
10579
10915
  }
@@ -10583,7 +10919,7 @@ var defaultCheckDeps = () => ({
10583
10919
  // 与设备任务唤起 App 同一个 locate(locateWorkbuddyAppExe:注册表卸载项 / App Paths / 开始菜单快捷方式…);App 自带 CLI 找得到也算
10584
10920
  workbuddyAppInstalled: () => locateWorkbuddyAppExe() !== null || locateWorkbuddyApp() !== null,
10585
10921
  workbuddyAuthFile: () => workbuddyAuthFile(homedir9(), process.platform, process.env.LOCALAPPDATA ?? ""),
10586
- exists: (p) => existsSync26(p)
10922
+ exists: (p) => existsSync27(p)
10587
10923
  });
10588
10924
  function daemonCheckDeps(base = defaultLocateDeps(), exeHintsAsync = winWorkbuddyLocatorHints) {
10589
10925
  const noPs = { ...base, winAppHints: void 0, winAppExeHints: void 0 };
@@ -10687,7 +11023,7 @@ function winLoginScript(cmd) {
10687
11023
  return lines.join("\r\n") + "\r\n";
10688
11024
  }
10689
11025
  function loginScriptPath(home, tool, platform) {
10690
- return join34(launchDir(home), `login-${tool}.${platform === "win32" ? "ps1" : "command"}`);
11026
+ return join35(launchDir(home), `login-${tool}.${platform === "win32" ? "ps1" : "command"}`);
10691
11027
  }
10692
11028
  function winLoginWtArgs(script) {
10693
11029
  if (!safePath(script)) throw new Error("\u811A\u672C\u8DEF\u5F84\u91CC\u6709\u4E0D\u80FD\u8FDB\u547D\u4EE4\u884C\u7684\u5B57\u7B26");
@@ -10724,14 +11060,14 @@ var defaultLoginOpenDeps = () => ({
10724
11060
  home: deskbuddyHome(),
10725
11061
  pathDirs: () => childPath().split(":"),
10726
11062
  write: (file3, content) => {
10727
- mkdirSync26(join34(file3, ".."), { recursive: true, mode: 448 });
11063
+ mkdirSync26(join35(file3, ".."), { recursive: true, mode: 448 });
10728
11064
  writeFileSync26(file3, content, { mode: 448 });
10729
11065
  chmodSync9(file3, 448);
10730
11066
  }
10731
11067
  });
10732
11068
  async function installCodebuddyHooks(log) {
10733
11069
  try {
10734
- const { installTools: installTools2 } = await import("./enable-UNMUBPWP.js");
11070
+ const { installTools: installTools2 } = await import("./enable-QGQVV2TC.js");
10735
11071
  installTools2(["workbuddy"], () => {
10736
11072
  }, null, { auto: true });
10737
11073
  } catch (e) {
@@ -10916,8 +11252,8 @@ async function autoEnableLoginLog(tools, check, log) {
10916
11252
 
10917
11253
  // src/daemon/workbuddySetup.ts
10918
11254
  import { execFile as execFile10, spawn as spawn5 } from "child_process";
10919
- import { existsSync as existsSync27 } from "fs";
10920
- import { dirname as dirname18, join as join35 } from "path";
11255
+ import { existsSync as existsSync28 } from "fs";
11256
+ import { dirname as dirname18, join as join36 } from "path";
10921
11257
  var DIALOG_TITLE = "DeskBuddy";
10922
11258
  var BTN_INSTALL = "\u5B89\u88C5";
10923
11259
  var BTN_LATER = "\u6682\u4E0D";
@@ -11056,9 +11392,9 @@ function npmPlan(d) {
11056
11392
  for (const f of whichAllIn("npm", d)) {
11057
11393
  if (!/\.cmd$/i.test(f)) continue;
11058
11394
  const dir2 = dirname18(f);
11059
- const cli = join35(dir2, "node_modules", "npm", "bin", "npm-cli.js");
11395
+ const cli = join36(dir2, "node_modules", "npm", "bin", "npm-cli.js");
11060
11396
  if (!d.exists(cli)) continue;
11061
- const node = join35(dir2, "node.exe");
11397
+ const node = join36(dir2, "node.exe");
11062
11398
  return { file: d.exists(node) ? node : d.nodePath, args: [cli, ...NPM_INSTALL_ARGS] };
11063
11399
  }
11064
11400
  return null;
@@ -11175,7 +11511,7 @@ async function runOffer(source, d, opts = {}) {
11175
11511
  }
11176
11512
  }
11177
11513
  function lockPath() {
11178
- return join35(deskbuddyHome(), "workbuddy-setup.lock");
11514
+ return join36(deskbuddyHome(), "workbuddy-setup.lock");
11179
11515
  }
11180
11516
  var defaultLockDeps = () => ({ path: lockPath(), pid: process.pid, now: () => Date.now(), alive: pidAlive2 });
11181
11517
  var WorkbuddyOffer = class {
@@ -11245,7 +11581,7 @@ function defaultOfferDeps(log) {
11245
11581
  }),
11246
11582
  openLogin: () => defaultOpenLogin(platform),
11247
11583
  installHooks: async () => {
11248
- const { installTools: installTools2 } = await import("./enable-UNMUBPWP.js");
11584
+ const { installTools: installTools2 } = await import("./enable-QGQVV2TC.js");
11249
11585
  installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
11250
11586
  },
11251
11587
  log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
@@ -11334,7 +11670,7 @@ function defaultPromptStartDeps(env = process.env) {
11334
11670
  gui: () => guiAvailable(defaultGuiDeps()),
11335
11671
  spawnChild: (source) => {
11336
11672
  const cli = process.argv[1];
11337
- if (!cli || !existsSync27(cli)) throw new Error("\u627E\u4E0D\u5230 deskbuddy \u81EA\u5DF1\u7684\u5165\u53E3\u6587\u4EF6");
11673
+ if (!cli || !existsSync28(cli)) throw new Error("\u627E\u4E0D\u5230 deskbuddy \u81EA\u5DF1\u7684\u5165\u53E3\u6587\u4EF6");
11338
11674
  const c = spawn5(process.execPath, [cli, "workbuddy-setup", "--from", source], {
11339
11675
  detached: true,
11340
11676
  stdio: "ignore",
@@ -11414,14 +11750,14 @@ function installTools(tools, out, shim = defaultShimEnvForInstall(), opts = {})
11414
11750
  installed.push(tool);
11415
11751
  out(`\u2705 ${tool}\uFF1Ahook \u5DF2\u88C5\u8FDB ${configPath2}\uFF08${events.length} \u4E2A\u4E8B\u4EF6\uFF09`);
11416
11752
  try {
11417
- if (adapter.installWindowGate?.(configPath2, join36(dirname19(hookPath), "gate.cjs"), tool)) {
11753
+ if (adapter.installWindowGate?.(configPath2, join37(dirname19(hookPath), "gate.cjs"), tool)) {
11418
11754
  out(` \u7A97\u53E3\u91CC\u5F39\u6388\u6743\u6846\u65F6\uFF0C\u8BBE\u5907\u4E0A\u4E5F\u80FD\u786E\u8BA4\uFF08\u5B88\u62A4\u8FDB\u7A0B\u5728\u8DD1\u65F6\u751F\u6548\uFF09`);
11419
11755
  }
11420
11756
  } catch (e) {
11421
11757
  out(`\u26A0\uFE0F ${tool}\uFF1A\u8BBE\u5907\u786E\u8BA4\u6388\u6743\u6CA1\u88C5\u4E0A\uFF1A${e.message}`);
11422
11758
  }
11423
11759
  try {
11424
- if (adapter.installRewake?.(configPath2, join36(dirname19(hookPath), "wake.cjs"), tool)) {
11760
+ if (adapter.installRewake?.(configPath2, join37(dirname19(hookPath), "wake.cjs"), tool)) {
11425
11761
  out(` \u7A97\u53E3\u5F00\u7740\u65F6\uFF0C\u8BBE\u5907\u6307\u4EE4\u76F4\u63A5\u5728\u8FD9\u4E2A\u7A97\u53E3\u91CC\u6267\u884C\uFF08\u5B88\u62A4\u8FDB\u7A0B\u5728\u8DD1\u65F6\u751F\u6548\uFF09`);
11426
11762
  }
11427
11763
  } catch (e) {
@@ -11586,6 +11922,8 @@ export {
11586
11922
  isOcPluginInstalled,
11587
11923
  checkOptions,
11588
11924
  claudeOptions,
11925
+ CODEX_PERMISSIONS_TOOL,
11926
+ codexPermissionsCard,
11589
11927
  codexMcpOptions,
11590
11928
  codexCommandOptions,
11591
11929
  codexFileOptions,
@@ -11697,6 +12035,7 @@ export {
11697
12035
  replyVerdict,
11698
12036
  PtySummaryWatch,
11699
12037
  APP_NOT_RUNNING,
12038
+ APP_PORT_MISSING,
11700
12039
  DumateWatch,
11701
12040
  runHook,
11702
12041
  toolBusy,
@@ -11709,6 +12048,12 @@ export {
11709
12048
  isQoderDesktopPid,
11710
12049
  QODER_SHORTCUT_EVERY_MS,
11711
12050
  ensureQoderShortcuts,
12051
+ QW_DEFAULT_CDP_PORT,
12052
+ QwenworkKeeper,
12053
+ QW_SHORTCUT_EVERY_MS,
12054
+ QwShortcutRelaunchFixer,
12055
+ qwenworkShortcutsWanted,
12056
+ ensureQwenworkShortcuts,
11712
12057
  adapterFor,
11713
12058
  migrateLegacyQoder,
11714
12059
  EXEC_TIMEOUT_MS,