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
|
|
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,
|
|
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 =
|
|
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
|
|
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
|
|
9264
|
-
import { dirname as dirname13, join as
|
|
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 (!
|
|
9271
|
-
const raw =
|
|
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 =
|
|
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 (!
|
|
9703
|
+
if (!existsSync22(path)) return;
|
|
9370
9704
|
const f = readHooksFile(path);
|
|
9371
|
-
if (strip(f, [hookPath,
|
|
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 (!
|
|
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
|
|
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
|
|
9389
|
-
import { dirname as dirname14, join as
|
|
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
|
|
9727
|
+
return join29(dirname14(hookPath), CB_CHANNEL_SCRIPT);
|
|
9394
9728
|
}
|
|
9395
9729
|
function read(path) {
|
|
9396
|
-
if (!
|
|
9397
|
-
const raw =
|
|
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 (!
|
|
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 (!
|
|
9466
|
-
return
|
|
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(
|
|
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" ||
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
9645
|
-
if (
|
|
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 =
|
|
9656
|
-
if (
|
|
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
|
|
10096
|
+
import { dirname as dirname17, join as join31 } from "path";
|
|
9761
10097
|
|
|
9762
10098
|
// src/core/detect.ts
|
|
9763
|
-
import { existsSync as
|
|
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:
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
10236
|
+
import { join as join33 } from "path";
|
|
9901
10237
|
|
|
9902
10238
|
// src/core/codebuddyDirs.ts
|
|
9903
|
-
import { join as
|
|
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" ?
|
|
9906
|
-
const pb = platform === "win32" ?
|
|
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 =
|
|
10246
|
+
const wb = join32(home, ".workbuddy");
|
|
9911
10247
|
if (typeof stateDir2 !== "string" || !stateDir2) return wb;
|
|
9912
|
-
const cb =
|
|
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) :
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
10477
|
-
if (platform === "win32") return localAppData ?
|
|
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:
|
|
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
|
|
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) =>
|
|
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
|
|
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(
|
|
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-
|
|
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
|
|
10920
|
-
import { dirname as dirname18, join as
|
|
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 =
|
|
11395
|
+
const cli = join36(dir2, "node_modules", "npm", "bin", "npm-cli.js");
|
|
11060
11396
|
if (!d.exists(cli)) continue;
|
|
11061
|
-
const node =
|
|
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
|
|
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-
|
|
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 || !
|
|
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,
|
|
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,
|
|
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,
|