deskbuddy 0.2.0-beta.29 → 0.2.0-beta.30

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 join34 } from "path";
4
+ import { dirname as dirname19, join as join35 } from "path";
5
5
 
6
6
  // src/core/config.ts
7
7
  import { randomUUID } from "crypto";
@@ -157,6 +157,7 @@ function loadConfig() {
157
157
  qwenworkNewTask: typeof parsed.qwenworkNewTask === "boolean" ? parsed.qwenworkNewTask : void 0,
158
158
  dumateCdpPort: portOrUndefined(parsed.dumateCdpPort),
159
159
  dumateShortcuts: typeof parsed.dumateShortcuts === "boolean" ? parsed.dumateShortcuts : void 0,
160
+ qoderShortcuts: typeof parsed.qoderShortcuts === "boolean" ? parsed.qoderShortcuts : void 0,
160
161
  cozeApp: typeof parsed.cozeApp === "boolean" ? parsed.cozeApp : void 0,
161
162
  cozeCdpPort: portOrUndefined(parsed.cozeCdpPort)
162
163
  };
@@ -1870,9 +1871,12 @@ function isDshPluginInstalled(patchPath) {
1870
1871
  var DSH_NOTICE = " \u5DF2\u5F00\u7740\u7684 DeepSeek Harness\uFF08dsh web / \u684C\u9762\u7AEF\uFF09\u91CD\u542F\u540E\u751F\u6548";
1871
1872
 
1872
1873
  // src/daemon/dumateApp/shortcuts.ts
1873
- import { execFile as execFile6, execFileSync as execFileSync10 } from "child_process";
1874
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync23, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
1875
- import { join as join24, win32 as win325 } from "path";
1874
+ import { join as join25 } from "path";
1875
+
1876
+ // src/daemon/appShortcuts.ts
1877
+ import { execFile as execFile2, execFileSync as execFileSync4 } from "child_process";
1878
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync12, renameSync as renameSync8, writeFileSync as writeFileSync11 } from "fs";
1879
+ import { join as join10, win32 } from "path";
1876
1880
 
1877
1881
  // src/core/fileLock.ts
1878
1882
  import { existsSync as existsSync10, mkdirSync as mkdirSync10, readFileSync as readFileSync11, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync10 } from "fs";
@@ -1933,15 +1937,298 @@ function pidAlive2(pid) {
1933
1937
  }
1934
1938
  }
1935
1939
 
1940
+ // src/daemon/appShortcuts.ts
1941
+ var LNK_LIST_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
1942
+ $s = New-Object -ComObject WScript.Shell
1943
+ $dirs = @(@([Environment]::GetFolderPath('Programs'), $true), @([Environment]::GetFolderPath('CommonPrograms'), $true), @([Environment]::GetFolderPath('Desktop'), $false), @([Environment]::GetFolderPath('CommonDesktopDirectory'), $false), @((Join-Path $env:APPDATA 'Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar'), $false))
1944
+ $out = @()
1945
+ foreach ($d in $dirs) {
1946
+ if (-not $d[0] -or -not (Test-Path -LiteralPath $d[0])) { continue }
1947
+ foreach ($f in (Get-ChildItem -LiteralPath $d[0] -Filter *.lnk -Recurse:$d[1] -ErrorAction SilentlyContinue)) {
1948
+ try { $l = $s.CreateShortcut($f.FullName); $out += [pscustomobject]@{ path = $f.FullName; target = [string]$l.TargetPath; args = [string]$l.Arguments } } catch {}
1949
+ }
1950
+ }
1951
+ ConvertTo-Json -InputObject @($out) -Compress`;
1952
+ var LNK_WRITE_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
1953
+ $ops = $env:DB_LNK_OPS | ConvertFrom-Json
1954
+ $s = New-Object -ComObject WScript.Shell
1955
+ $out = @()
1956
+ foreach ($o in @($ops)) {
1957
+ $ok = $false
1958
+ try {
1959
+ $l = $s.CreateShortcut([string]$o.path)
1960
+ if ([IO.Path]::GetFileName([string]$l.TargetPath) -ieq [string]$env:DB_LNK_EXE) { $l.Arguments = [string]$o.args; $l.Save(); $ok = $true }
1961
+ } catch {}
1962
+ $out += [pscustomobject]@{ path = [string]$o.path; ok = $ok }
1963
+ }
1964
+ ConvertTo-Json -InputObject @($out) -Compress`;
1965
+ function portFlag(port) {
1966
+ return `--remote-debugging-port=${port}`;
1967
+ }
1968
+ function hasPortFlag(args) {
1969
+ return /(^|\s)--remote-debugging-port(=|\s|$)/.test(args);
1970
+ }
1971
+ function isAppLnk(l, exe) {
1972
+ return win32.basename(l.target || "").toLowerCase() === exe.toLowerCase();
1973
+ }
1974
+ var keyOf = (p) => p.toLowerCase();
1975
+ function planPatchFor(exe, list, records, port) {
1976
+ const out = { ...records };
1977
+ const writes = [];
1978
+ for (const l of list) {
1979
+ if (!isAppLnk(l, exe) || hasPortFlag(l.args)) continue;
1980
+ const orig = l.args;
1981
+ const patched = orig.trim() ? `${orig.trim()} ${portFlag(port)}` : portFlag(port);
1982
+ writes.push({ path: l.path, args: patched });
1983
+ out[keyOf(l.path)] = { path: l.path, orig, patched };
1984
+ }
1985
+ return { writes, records: out };
1986
+ }
1987
+ function planRestoreFor(exe, list, records, port) {
1988
+ const byKey = new Map(list.map((l) => [keyOf(l.path), l]));
1989
+ const flag = portFlag(port);
1990
+ const writes = [];
1991
+ for (const r of Object.values(records)) {
1992
+ const cur = byKey.get(keyOf(r.path));
1993
+ if (!cur || !isAppLnk(cur, exe)) continue;
1994
+ if (cur.args === r.patched) writes.push({ path: cur.path, args: r.orig });
1995
+ else if (cur.args.split(/\s+/).includes(flag)) writes.push({ path: cur.path, args: cur.args.split(/\s+/).filter((x) => x && x !== flag).join(" ") });
1996
+ }
1997
+ return writes;
1998
+ }
1999
+ function recordsFile(app) {
2000
+ return join10(deskbuddyHome(), app.dir, `${app.stem}.json`);
2001
+ }
2002
+ function loadRecords(file3) {
2003
+ try {
2004
+ const v = JSON.parse(readFileSync12(file3, "utf8"));
2005
+ if (!v || typeof v !== "object") return {};
2006
+ const out = {};
2007
+ for (const [k, r] of Object.entries(v)) {
2008
+ if (r && typeof r.path === "string" && typeof r.orig === "string" && typeof r.patched === "string") out[k] = { path: r.path, orig: r.orig, patched: r.patched };
2009
+ }
2010
+ return out;
2011
+ } catch {
2012
+ return {};
2013
+ }
2014
+ }
2015
+ function saveRecords(r, file3) {
2016
+ try {
2017
+ mkdirSync11(join10(file3, ".."), { recursive: true });
2018
+ writeFileSync11(file3 + ".tmp", JSON.stringify(r, null, 2));
2019
+ renameSync8(file3 + ".tmp", file3);
2020
+ } catch {
2021
+ }
2022
+ }
2023
+ function parseJsonArray(out) {
2024
+ if (out === null) return null;
2025
+ try {
2026
+ const v = JSON.parse(out.trim() || "[]");
2027
+ return Array.isArray(v) ? v : null;
2028
+ } catch {
2029
+ return null;
2030
+ }
2031
+ }
2032
+ function parseList(out) {
2033
+ const arr = parseJsonArray(out);
2034
+ if (!arr) return null;
2035
+ return arr.filter((x) => !!x && typeof x.path === "string" && typeof x.target === "string").map((x) => ({ path: x.path, target: x.target, args: typeof x.args === "string" ? x.args : "" }));
2036
+ }
2037
+ var psArgs = (script) => ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script];
2038
+ var defaultPs = (script, env) => new Promise((done) => {
2039
+ execFile2(
2040
+ "powershell.exe",
2041
+ psArgs(script),
2042
+ { timeout: 2e4, windowsHide: true, encoding: "utf8", maxBuffer: 8 * 1024 * 1024, env: { ...process.env, ...env ?? {} } },
2043
+ (err, stdout2) => done(err ? null : String(stdout2 ?? ""))
2044
+ );
2045
+ });
2046
+ var defaultPsSync = (script, env) => {
2047
+ try {
2048
+ return execFileSync4("powershell.exe", psArgs(script), { timeout: 2e4, windowsHide: true, encoding: "utf8", maxBuffer: 8 * 1024 * 1024, env: { ...process.env, ...env ?? {} }, stdio: ["ignore", "pipe", "ignore"] });
2049
+ } catch {
2050
+ return null;
2051
+ }
2052
+ };
2053
+ var FAIL_RETRY_MS = 24 * 60 * 60 * 1e3;
2054
+ function active(app, d) {
2055
+ if ((d.platform ?? process.platform) !== "win32") return false;
2056
+ return !(d.skip ? d.skip() : process.env[app.skipEnv] === "1");
2057
+ }
2058
+ function portOf(app, d) {
2059
+ return d.port ? d.port() : app.port();
2060
+ }
2061
+ var nowOf = (d) => d.now ? d.now() : Date.now();
2062
+ var fileOf = (app, d) => d.file ?? recordsFile(app);
2063
+ var failFileOf = (app, d) => d.failFile ?? join10(deskbuddyHome(), app.dir, `${app.stem}-fail.json`);
2064
+ var lockFileOf = (app, d) => d.lockFile ?? join10(deskbuddyHome(), app.dir, `${app.stem}.lock`);
2065
+ var writeEnv = (app, ops) => ({ DB_LNK_OPS: JSON.stringify(ops), DB_LNK_EXE: app.exe });
2066
+ function loadFails(app, d) {
2067
+ try {
2068
+ const v = JSON.parse(readFileSync12(failFileOf(app, d), "utf8"));
2069
+ const out = {};
2070
+ for (const [k, t] of Object.entries(v ?? {})) if (typeof t === "number") out[k] = t;
2071
+ return out;
2072
+ } catch {
2073
+ return {};
2074
+ }
2075
+ }
2076
+ function saveFails(app, d, f) {
2077
+ const file3 = failFileOf(app, d);
2078
+ try {
2079
+ mkdirSync11(join10(file3, ".."), { recursive: true });
2080
+ writeFileSync11(file3 + ".tmp", JSON.stringify(f));
2081
+ renameSync8(file3 + ".tmp", file3);
2082
+ } catch {
2083
+ }
2084
+ }
2085
+ function lock(app, d) {
2086
+ return acquireLock({ path: lockFileOf(app, d), pid: process.pid, now: () => nowOf(d), alive: pidAlive2 });
2087
+ }
2088
+ function sleepSync(ms) {
2089
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
2090
+ }
2091
+ function lockSync(app, d, waitMs = 3e4) {
2092
+ for (let waited = 0; ; waited += 500) {
2093
+ const r = lock(app, d);
2094
+ if (r || waited >= waitMs) return r;
2095
+ sleepSync(500);
2096
+ }
2097
+ }
2098
+ function applyResults(app, d, writes, results, records, prev) {
2099
+ const okSet = new Set((results ?? []).filter((r) => r && r.ok === true && typeof r.path === "string").map((r) => keyOf(r.path)));
2100
+ const out = { ...records };
2101
+ const fails = loadFails(app, d);
2102
+ const now = nowOf(d);
2103
+ for (const w of writes) {
2104
+ const k = keyOf(w.path);
2105
+ if (okSet.has(k)) {
2106
+ d.log(`${app.label}\u5FEB\u6377\u65B9\u5F0F\u5DF2\u5E26\u4E0A\u8C03\u8BD5\u7AEF\u53E3\uFF1A${w.path}`);
2107
+ delete fails[k];
2108
+ continue;
2109
+ }
2110
+ if (!fails[k] || now - fails[k] >= FAIL_RETRY_MS) d.log(`${app.label}\u5FEB\u6377\u65B9\u5F0F\u6539\u4E0D\u4E86\uFF08\u53EF\u80FD\u8981\u7BA1\u7406\u5458\u6743\u9650\u6216\u88AB\u5360\u7528\uFF09\uFF0C\u8FD9\u4E2A\u5165\u53E3\u6253\u5F00\u7684 ${app.appName} \u4E0D\u5E26\u8C03\u8BD5\u7AEF\u53E3\uFF08\u4E00\u5929\u540E\u518D\u8BD5\uFF09\uFF1A${w.path}`);
2111
+ fails[k] = now;
2112
+ if (prev[k]) out[k] = prev[k];
2113
+ else delete out[k];
2114
+ }
2115
+ saveFails(app, d, fails);
2116
+ return out;
2117
+ }
2118
+ function restoreWith(app, d, list, records, write3) {
2119
+ const writes = planRestoreFor(app.exe, list, records, portOf(app, d));
2120
+ const finish = (results) => {
2121
+ const ok = new Set((results ?? []).filter((r2) => r2 && r2.ok === true && typeof r2.path === "string").map((r2) => keyOf(r2.path)));
2122
+ const keep = {};
2123
+ for (const w of writes) {
2124
+ if (ok.has(keyOf(w.path))) d.log(`${app.label}\u5FEB\u6377\u65B9\u5F0F\u5DF2\u8FD8\u539F\uFF1A${w.path}`);
2125
+ else {
2126
+ d.log(`${app.label}\u5FEB\u6377\u65B9\u5F0F\u8FD8\u539F\u5931\u8D25\uFF1A${w.path}`);
2127
+ const r2 = records[keyOf(w.path)];
2128
+ if (r2) keep[keyOf(w.path)] = r2;
2129
+ }
2130
+ }
2131
+ return keep;
2132
+ };
2133
+ if (writes.length === 0) return {};
2134
+ const r = write3(writes);
2135
+ return r instanceof Promise ? r.then(finish) : finish(r);
2136
+ }
2137
+ async function ensureAppShortcuts(app, d, ps = defaultPs) {
2138
+ if (!active(app, d)) return;
2139
+ const wanted = d.enabled ?? (() => app.wanted());
2140
+ if (!wanted()) return;
2141
+ const release2 = lock(app, d);
2142
+ if (!release2) return;
2143
+ try {
2144
+ const list = parseList(await ps(LNK_LIST_PS));
2145
+ if (!list) return;
2146
+ const prev = loadRecords(fileOf(app, d));
2147
+ const fails = loadFails(app, d);
2148
+ const now = nowOf(d);
2149
+ const plan = planPatchFor(app.exe, list, prev, portOf(app, d));
2150
+ const writes = plan.writes.filter((w) => {
2151
+ const t = fails[keyOf(w.path)];
2152
+ return !t || now - t >= FAIL_RETRY_MS;
2153
+ });
2154
+ if (writes.length === 0) return;
2155
+ const skipped = new Set(plan.writes.filter((w) => !writes.includes(w)).map((w) => keyOf(w.path)));
2156
+ const records = { ...plan.records };
2157
+ for (const k of skipped) {
2158
+ if (prev[k]) records[k] = prev[k];
2159
+ else delete records[k];
2160
+ }
2161
+ const results = parseJsonArray(await ps(LNK_WRITE_PS, writeEnv(app, writes)));
2162
+ let next = applyResults(app, d, writes, results, records, prev);
2163
+ if (!wanted()) {
2164
+ const list2 = parseList(await ps(LNK_LIST_PS));
2165
+ if (list2) next = await restoreWith(app, d, list2, next, async (ops) => parseJsonArray(await ps(LNK_WRITE_PS, writeEnv(app, ops))));
2166
+ }
2167
+ saveRecords(next, fileOf(app, d));
2168
+ } finally {
2169
+ release2();
2170
+ }
2171
+ }
2172
+ function ensureAppShortcutsSync(app, d, ps = defaultPsSync) {
2173
+ if (!active(app, d)) return;
2174
+ let off = false;
2175
+ try {
2176
+ off = app.off();
2177
+ } catch {
2178
+ off = false;
2179
+ }
2180
+ if (off) return restoreAppShortcutsSync(app, d, ps);
2181
+ const release2 = lockSync(app, d);
2182
+ if (!release2) {
2183
+ d.log(`${app.label}\u5FEB\u6377\u65B9\u5F0F\u6B63\u88AB\u53E6\u4E00\u4E2A DeskBuddy \u8FDB\u7A0B\u4FEE\u6539\uFF0C\u8FD9\u6B21\u6CA1\u6539\uFF08\u5B88\u62A4\u8FDB\u7A0B\u4F1A\u518D\u8865\uFF09`);
2184
+ return;
2185
+ }
2186
+ try {
2187
+ const list = parseList(ps(LNK_LIST_PS));
2188
+ if (!list) {
2189
+ d.log(`\u8BFB\u4E0D\u4E86\u5F00\u59CB\u83DC\u5355 / \u684C\u9762\u7684\u5FEB\u6377\u65B9\u5F0F\uFF0C${app.label}\u7684\u5FEB\u6377\u65B9\u5F0F\u6CA1\u6539\uFF08\u5B88\u62A4\u8FDB\u7A0B\u4F1A\u518D\u8BD5\uFF09`);
2190
+ return;
2191
+ }
2192
+ const prev = loadRecords(fileOf(app, d));
2193
+ const { writes, records } = planPatchFor(app.exe, list, prev, portOf(app, d));
2194
+ if (writes.length === 0) return;
2195
+ const results = parseJsonArray(ps(LNK_WRITE_PS, writeEnv(app, writes)));
2196
+ saveRecords(applyResults(app, d, writes, results, records, prev), fileOf(app, d));
2197
+ } finally {
2198
+ release2();
2199
+ }
2200
+ }
2201
+ function restoreAppShortcutsSync(app, d, ps = defaultPsSync) {
2202
+ if (!active(app, d)) return;
2203
+ const records = loadRecords(fileOf(app, d));
2204
+ if (Object.keys(records).length === 0) return;
2205
+ const release2 = lockSync(app, d);
2206
+ if (!release2) {
2207
+ d.log(`${app.label}\u5FEB\u6377\u65B9\u5F0F\u6B63\u88AB\u53E6\u4E00\u4E2A DeskBuddy \u8FDB\u7A0B\u4FEE\u6539\uFF0C\u8FD9\u6B21\u6CA1\u8FD8\u539F\uFF08\u8BB0\u5F55\u4FDD\u7559\uFF0C\u4E0B\u6B21 disable \u518D\u8BD5\uFF09`);
2208
+ return;
2209
+ }
2210
+ try {
2211
+ const list = parseList(ps(LNK_LIST_PS));
2212
+ if (!list) {
2213
+ d.log(`\u8BFB\u4E0D\u4E86\u5FEB\u6377\u65B9\u5F0F\uFF0C${app.label}\u5FEB\u6377\u65B9\u5F0F\u6CA1\u8FD8\u539F\uFF08\u8BB0\u5F55\u4FDD\u7559\uFF0C\u4E0B\u6B21 disable \u518D\u8BD5\uFF09`);
2214
+ return;
2215
+ }
2216
+ const keep = restoreWith(app, d, list, loadRecords(fileOf(app, d)), (ops) => parseJsonArray(ps(LNK_WRITE_PS, writeEnv(app, ops))));
2217
+ saveRecords(keep, fileOf(app, d));
2218
+ } finally {
2219
+ release2();
2220
+ }
2221
+ }
2222
+
1936
2223
  // src/daemon/dumateApp/keeper.ts
1937
2224
  import { readdirSync as readdirSync12, statSync as statSync10 } from "fs";
1938
- import { join as join23 } from "path";
2225
+ import { join as join24 } from "path";
1939
2226
 
1940
2227
  // src/daemon/dumateWatch.ts
1941
- import { execFileSync as execFileSync9, spawn as spawn3 } from "child_process";
2228
+ import { execFileSync as execFileSync10, spawn as spawn3 } from "child_process";
1942
2229
  import { readdirSync as readdirSync10, realpathSync as realpathSync4, statSync as statSync9 } from "fs";
1943
2230
  import { request as httpRequest } from "http";
1944
- import { join as join21 } from "path";
2231
+ import { join as join22 } from "path";
1945
2232
 
1946
2233
  // hook/ocTranslate.mjs
1947
2234
  function toCcTool(tool, args) {
@@ -2655,17 +2942,17 @@ function traeNoticeSummary(toolName, toolInput, described, notice) {
2655
2942
  }
2656
2943
 
2657
2944
  // src/daemon/workbuddyApp/keeper.ts
2658
- import { execFile as execFile5, spawn as spawn2 } from "child_process";
2659
- import { existsSync as existsSync18, mkdirSync as mkdirSync19, readdirSync as readdirSync9, readFileSync as readFileSync21, renameSync as renameSync13, writeFileSync as writeFileSync19 } from "fs";
2660
- import { delimiter as delimiter3, join as join20, resolve as resolve4 } from "path";
2945
+ import { execFile as execFile6, spawn as spawn2 } from "child_process";
2946
+ import { existsSync as existsSync18, mkdirSync as mkdirSync20, readdirSync as readdirSync9, readFileSync as readFileSync22, renameSync as renameSync14, writeFileSync as writeFileSync20 } from "fs";
2947
+ import { delimiter as delimiter3, join as join21, resolve as resolve4 } from "path";
2661
2948
 
2662
2949
  // src/core/process.ts
2663
- import { execFileSync as execFileSync4 } from "child_process";
2950
+ import { execFileSync as execFileSync5 } from "child_process";
2664
2951
  var WIN = process.platform === "win32";
2665
2952
  function processName(pid) {
2666
2953
  if (WIN) return winProcs()?.find((p) => p.pid === pid)?.name ?? null;
2667
2954
  try {
2668
- const out = execFileSync4("ps", ["-p", String(pid), "-o", "comm="], {
2955
+ const out = execFileSync5("ps", ["-p", String(pid), "-o", "comm="], {
2669
2956
  encoding: "utf8",
2670
2957
  stdio: ["ignore", "pipe", "ignore"]
2671
2958
  });
@@ -2681,7 +2968,7 @@ function parentPid(pid) {
2681
2968
  return pp > 4 && pp !== pid ? pp : null;
2682
2969
  }
2683
2970
  try {
2684
- const out = execFileSync4("ps", ["-p", String(pid), "-o", "ppid="], {
2971
+ const out = execFileSync5("ps", ["-p", String(pid), "-o", "ppid="], {
2685
2972
  encoding: "utf8",
2686
2973
  stdio: ["ignore", "pipe", "ignore"]
2687
2974
  });
@@ -2719,11 +3006,11 @@ function isAlive(pid, expectName, kill = process.kill.bind(process)) {
2719
3006
  }
2720
3007
 
2721
3008
  // src/core/state.ts
2722
- import { existsSync as existsSync13, mkdirSync as mkdirSync14, readdirSync as readdirSync5, readFileSync as readFileSync14, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "fs";
2723
- import { join as join13 } from "path";
3009
+ import { existsSync as existsSync13, mkdirSync as mkdirSync15, readdirSync as readdirSync5, readFileSync as readFileSync15, renameSync as renameSync10, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
3010
+ import { join as join14 } from "path";
2724
3011
 
2725
3012
  // src/core/codexServer.ts
2726
- import { execFileSync as execFileSync5 } from "child_process";
3013
+ import { execFileSync as execFileSync6 } from "child_process";
2727
3014
  function isAppServerArgs(args, url) {
2728
3015
  return /\bapp-server\b/.test(args) && new RegExp(`--listen[= ]${url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:\\s|$)`).test(args);
2729
3016
  }
@@ -2734,7 +3021,7 @@ function processArgs(pid, platform = process.platform, procs, fresh = false) {
2734
3021
  return p?.args || null;
2735
3022
  }
2736
3023
  try {
2737
- const out = execFileSync5("ps", ["-ww", "-o", "args=", "-p", String(pid)], {
3024
+ const out = execFileSync6("ps", ["-ww", "-o", "args=", "-p", String(pid)], {
2738
3025
  encoding: "utf8",
2739
3026
  stdio: ["ignore", "pipe", "ignore"]
2740
3027
  });
@@ -2770,27 +3057,27 @@ function programOf(args) {
2770
3057
  }
2771
3058
 
2772
3059
  // src/core/ended.ts
2773
- import { closeSync, mkdirSync as mkdirSync11, openSync, readdirSync as readdirSync2, readFileSync as readFileSync12, readSync, realpathSync, renameSync as renameSync8, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync11 } from "fs";
2774
- import { join as join10 } from "path";
3060
+ import { closeSync, mkdirSync as mkdirSync12, openSync, readdirSync as readdirSync2, readFileSync as readFileSync13, readSync, realpathSync, renameSync as renameSync9, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync12 } from "fs";
3061
+ import { join as join11 } from "path";
2775
3062
  var ENDED_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
2776
3063
  var SID_RE = /^[A-Za-z0-9_-]{1,64}$/;
2777
3064
  function endedDir(home = deskbuddyHome()) {
2778
- return join10(home, "ended");
3065
+ return join11(home, "ended");
2779
3066
  }
2780
3067
  function writeEnded(s, now = Date.now()) {
2781
3068
  if (!SID_RE.test(s.sessionId)) return;
2782
3069
  try {
2783
3070
  const dir2 = endedDir();
2784
- mkdirSync11(dir2, { recursive: true, mode: 448 });
3071
+ mkdirSync12(dir2, { recursive: true, mode: 448 });
2785
3072
  const rec = { sessionId: s.sessionId, tool: s.tool, cwd: s.cwd ?? "", interactive: s.interactive === true, endedAt: now };
2786
3073
  if (Number.isInteger(s.turns) && s.turns >= 0) rec.turns = s.turns;
2787
3074
  if (typeof s.firstPrompt === "string" && s.firstPrompt) rec.firstPrompt = s.firstPrompt;
2788
- const file3 = join10(dir2, `${s.sessionId}.json`);
3075
+ const file3 = join11(dir2, `${s.sessionId}.json`);
2789
3076
  const tmp = `${file3}.${process.pid}.tmp`;
2790
- writeFileSync11(tmp, JSON.stringify(rec), { encoding: "utf8", mode: 384 });
2791
- renameSync8(tmp, file3);
3077
+ writeFileSync12(tmp, JSON.stringify(rec), { encoding: "utf8", mode: 384 });
3078
+ renameSync9(tmp, file3);
2792
3079
  for (const n of readdirSync2(dir2)) {
2793
- const f = join10(dir2, n);
3080
+ const f = join11(dir2, n);
2794
3081
  try {
2795
3082
  if (now - statSync4(f).mtimeMs > ENDED_TTL_MS) rmSync5(f, { force: true });
2796
3083
  } catch {
@@ -2802,7 +3089,7 @@ function writeEnded(s, now = Date.now()) {
2802
3089
  function readEnded(sessionId, now = Date.now()) {
2803
3090
  if (!SID_RE.test(sessionId)) return null;
2804
3091
  try {
2805
- const r = JSON.parse(readFileSync12(join10(endedDir(), `${sessionId}.json`), "utf8"));
3092
+ const r = JSON.parse(readFileSync13(join11(endedDir(), `${sessionId}.json`), "utf8"));
2806
3093
  if (!r || r.sessionId !== sessionId || typeof r.endedAt !== "number" || now - r.endedAt > ENDED_TTL_MS) return null;
2807
3094
  return r;
2808
3095
  } catch {
@@ -2843,12 +3130,12 @@ function claudeTranscriptCwd(sessionId, home = claudeHome()) {
2843
3130
  if (!SID_RE.test(sessionId)) return "";
2844
3131
  let dirs = [];
2845
3132
  try {
2846
- dirs = readdirSync2(join10(home, "projects"));
3133
+ dirs = readdirSync2(join11(home, "projects"));
2847
3134
  } catch {
2848
3135
  return "";
2849
3136
  }
2850
3137
  for (const d of dirs) {
2851
- const file3 = join10(home, "projects", d, `${sessionId}.jsonl`);
3138
+ const file3 = join11(home, "projects", d, `${sessionId}.jsonl`);
2852
3139
  try {
2853
3140
  statSync4(file3);
2854
3141
  } catch {
@@ -2893,23 +3180,23 @@ function isDirSync(p) {
2893
3180
  }
2894
3181
 
2895
3182
  // src/core/qoderAppSessions.ts
2896
- import { existsSync as existsSync11, mkdirSync as mkdirSync12, readdirSync as readdirSync3, readFileSync as readFileSync13, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "fs";
2897
- import { join as join11 } from "path";
3183
+ import { existsSync as existsSync11, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as readFileSync14, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "fs";
3184
+ import { join as join12 } from "path";
2898
3185
  var QODER_APP_SESSION_TOOLS = ["qoder_cn", "qoder"];
2899
3186
  var KEEPER_FILE = "keeper";
2900
3187
  function dir() {
2901
- return join11(deskbuddyHome(), "qoderapp");
3188
+ return join12(deskbuddyHome(), "qoderapp");
2902
3189
  }
2903
3190
  function file(sessionId) {
2904
3191
  const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "");
2905
- return safe ? join11(dir(), `${safe}.json`) : "";
3192
+ return safe ? join12(dir(), `${safe}.json`) : "";
2906
3193
  }
2907
3194
  function markQoderAppSession(sessionId, tool, cwd, now = Date.now()) {
2908
3195
  const f = file(sessionId);
2909
3196
  if (!f) return;
2910
3197
  try {
2911
- mkdirSync12(dir(), { recursive: true });
2912
- writeFileSync12(f, JSON.stringify({ tool, cwd, at: now }));
3198
+ mkdirSync13(dir(), { recursive: true });
3199
+ writeFileSync13(f, JSON.stringify({ tool, cwd, at: now }));
2913
3200
  } catch {
2914
3201
  }
2915
3202
  }
@@ -2937,7 +3224,7 @@ function listQoderAppSessions(tool) {
2937
3224
  for (const f of names) {
2938
3225
  let t = "";
2939
3226
  try {
2940
- t = String(JSON.parse(readFileSync13(join11(dir(), f), "utf8")).tool ?? "");
3227
+ t = String(JSON.parse(readFileSync14(join12(dir(), f), "utf8")).tool ?? "");
2941
3228
  } catch {
2942
3229
  t = "";
2943
3230
  }
@@ -2951,7 +3238,7 @@ function qoderAppMarkedAt(sessionId) {
2951
3238
  const f = file(sessionId);
2952
3239
  if (!f) return 0;
2953
3240
  try {
2954
- const at = JSON.parse(readFileSync13(f, "utf8")).at;
3241
+ const at = JSON.parse(readFileSync14(f, "utf8")).at;
2955
3242
  return typeof at === "number" ? at : 0;
2956
3243
  } catch {
2957
3244
  return 0;
@@ -2959,18 +3246,18 @@ function qoderAppMarkedAt(sessionId) {
2959
3246
  }
2960
3247
 
2961
3248
  // src/core/wbAppSessions.ts
2962
- import { existsSync as existsSync12, mkdirSync as mkdirSync13, readdirSync as readdirSync4, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
2963
- import { join as join12 } from "path";
3249
+ import { existsSync as existsSync12, mkdirSync as mkdirSync14, readdirSync as readdirSync4, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "fs";
3250
+ import { join as join13 } from "path";
2964
3251
  function file2(sessionId) {
2965
3252
  const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "");
2966
- return safe ? join12(deskbuddyHome(), "wbapp", `${safe}.json`) : "";
3253
+ return safe ? join13(deskbuddyHome(), "wbapp", `${safe}.json`) : "";
2967
3254
  }
2968
3255
  function markWbAppSession(sessionId, cwd, now = Date.now()) {
2969
3256
  const f = file2(sessionId);
2970
3257
  if (!f) return;
2971
3258
  try {
2972
- mkdirSync13(join12(deskbuddyHome(), "wbapp"), { recursive: true });
2973
- writeFileSync13(f, JSON.stringify({ cwd, at: now }));
3259
+ mkdirSync14(join13(deskbuddyHome(), "wbapp"), { recursive: true });
3260
+ writeFileSync14(f, JSON.stringify({ cwd, at: now }));
2974
3261
  } catch {
2975
3262
  }
2976
3263
  }
@@ -2988,7 +3275,7 @@ function unmarkWbAppSession(sessionId) {
2988
3275
  }
2989
3276
  function listWbAppSessions() {
2990
3277
  try {
2991
- return readdirSync4(join12(deskbuddyHome(), "wbapp")).filter((f) => f.endsWith(".json") && f !== "keeper.json").map((f) => f.slice(0, -5));
3278
+ return readdirSync4(join13(deskbuddyHome(), "wbapp")).filter((f) => f.endsWith(".json") && f !== "keeper.json").map((f) => f.slice(0, -5));
2992
3279
  } catch {
2993
3280
  return [];
2994
3281
  }
@@ -3016,28 +3303,28 @@ function appDoneTtlMs(s) {
3016
3303
 
3017
3304
  // src/core/state.ts
3018
3305
  function stateDir() {
3019
- return join13(deskbuddyHome(), "state");
3306
+ return join14(deskbuddyHome(), "state");
3020
3307
  }
3021
3308
  function statePath(sessionId) {
3022
3309
  const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "");
3023
- return join13(stateDir(), `${safe || "unknown"}.json`);
3310
+ return join14(stateDir(), `${safe || "unknown"}.json`);
3024
3311
  }
3025
3312
  function readState(sessionId) {
3026
3313
  try {
3027
- return JSON.parse(readFileSync14(statePath(sessionId), "utf8"));
3314
+ return JSON.parse(readFileSync15(statePath(sessionId), "utf8"));
3028
3315
  } catch {
3029
3316
  return null;
3030
3317
  }
3031
3318
  }
3032
3319
  var RENAME_RETRY_DELAYS_MS = [10, 20, 40, 80, 160];
3033
3320
  var RENAME_RETRY_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES"]);
3034
- function sleepSync(ms) {
3321
+ function sleepSync2(ms) {
3035
3322
  try {
3036
3323
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
3037
3324
  } catch {
3038
3325
  }
3039
3326
  }
3040
- function renameRetrying(from, to, rename = renameSync9, sleep = sleepSync) {
3327
+ function renameRetrying(from, to, rename = renameSync10, sleep = sleepSync2) {
3041
3328
  for (let i = 0; ; i++) {
3042
3329
  try {
3043
3330
  rename(from, to);
@@ -3050,9 +3337,9 @@ function renameRetrying(from, to, rename = renameSync9, sleep = sleepSync) {
3050
3337
  }
3051
3338
  }
3052
3339
  function writeState(s) {
3053
- mkdirSync14(stateDir(), { recursive: true });
3340
+ mkdirSync15(stateDir(), { recursive: true });
3054
3341
  const tmp = statePath(s.sessionId) + ".tmp";
3055
- writeFileSync14(tmp, JSON.stringify(s), "utf8");
3342
+ writeFileSync15(tmp, JSON.stringify(s), "utf8");
3056
3343
  renameRetrying(tmp, statePath(s.sessionId));
3057
3344
  }
3058
3345
  function retireState(s, now = Date.now()) {
@@ -3089,7 +3376,7 @@ var STALE_STATES = /* @__PURE__ */ new Set(["watch", "ask_approval"]);
3089
3376
  var STALE_NO_PID_LOG = "\u65E0\u8FDB\u7A0B\u53F7\u4E14 2 \u5C0F\u65F6\u65E0\u4E8B\u4EF6\uFF0C\u6309\u5DF2\u7ED3\u675F\u5904\u7406";
3090
3377
  function pendingApprovalSessions() {
3091
3378
  try {
3092
- const recs = JSON.parse(readFileSync14(join13(deskbuddyHome(), "approvals.json"), "utf8"));
3379
+ const recs = JSON.parse(readFileSync15(join14(deskbuddyHome(), "approvals.json"), "utf8"));
3093
3380
  return new Set(Array.isArray(recs) ? recs.filter((r) => r && r.status === "pending" && typeof r.sessionId === "string").map((r) => r.sessionId) : []);
3094
3381
  } catch {
3095
3382
  return /* @__PURE__ */ new Set();
@@ -3116,9 +3403,9 @@ function readAliveStates(tool, opts = {}) {
3116
3403
  if (!file3.endsWith(".json")) continue;
3117
3404
  let s;
3118
3405
  try {
3119
- s = JSON.parse(readFileSync14(join13(stateDir(), file3), "utf8"));
3406
+ s = JSON.parse(readFileSync15(join14(stateDir(), file3), "utf8"));
3120
3407
  } catch {
3121
- rmSync8(join13(stateDir(), file3), { force: true });
3408
+ rmSync8(join14(stateDir(), file3), { force: true });
3122
3409
  continue;
3123
3410
  }
3124
3411
  if (s.tool !== tool) continue;
@@ -3150,16 +3437,16 @@ function readAliveStates(tool, opts = {}) {
3150
3437
  return alive;
3151
3438
  }
3152
3439
  function noticeDir() {
3153
- return join13(deskbuddyHome(), "notice");
3440
+ return join14(deskbuddyHome(), "notice");
3154
3441
  }
3155
3442
  function writeNotice(sessionId, text, now = Date.now()) {
3156
3443
  try {
3157
3444
  const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "");
3158
3445
  if (!safe) return;
3159
- mkdirSync14(noticeDir(), { recursive: true });
3160
- const file3 = join13(noticeDir(), `${safe}.json`);
3161
- writeFileSync14(file3 + ".tmp", JSON.stringify({ text, at: now }), "utf8");
3162
- renameSync9(file3 + ".tmp", file3);
3446
+ mkdirSync15(noticeDir(), { recursive: true });
3447
+ const file3 = join14(noticeDir(), `${safe}.json`);
3448
+ writeFileSync15(file3 + ".tmp", JSON.stringify({ text, at: now }), "utf8");
3449
+ renameSync10(file3 + ".tmp", file3);
3163
3450
  } catch {
3164
3451
  }
3165
3452
  }
@@ -3168,7 +3455,7 @@ var ALIAS_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
3168
3455
  function resolveAlias(sessionId, now = Date.now()) {
3169
3456
  let map = {};
3170
3457
  try {
3171
- map = JSON.parse(readFileSync14(join13(deskbuddyHome(), "alias.json"), "utf8")) || {};
3458
+ map = JSON.parse(readFileSync15(join14(deskbuddyHome(), "alias.json"), "utf8")) || {};
3172
3459
  } catch {
3173
3460
  return sessionId;
3174
3461
  }
@@ -3182,10 +3469,10 @@ function resolveAlias(sessionId, now = Date.now()) {
3182
3469
  }
3183
3470
 
3184
3471
  // src/wrap/shim.ts
3185
- import { execFile as execFile2, execFileSync as execFileSync6 } from "child_process";
3186
- import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync15, readdirSync as readdirSync6, readFileSync as readFileSync15, rmdirSync, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "fs";
3472
+ import { execFile as execFile3, execFileSync as execFileSync7 } from "child_process";
3473
+ import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync16, readdirSync as readdirSync6, readFileSync as readFileSync16, rmdirSync, rmSync as rmSync9, writeFileSync as writeFileSync16 } from "fs";
3187
3474
  import { homedir as homedir3 } from "os";
3188
- import { delimiter, join as join14, resolve as resolve3 } from "path";
3475
+ import { delimiter, join as join15, resolve as resolve3 } from "path";
3189
3476
  var SHIM_FALLBACK_EXIT = 213;
3190
3477
  var WIN_SHIM_ENABLED = true;
3191
3478
  var SHIM_COMMANDS = { claude_code: "claude", codex: "codex" };
@@ -3196,10 +3483,10 @@ var RC_FILES = [".zshrc", ".bashrc"];
3196
3483
  var WIN_PENDING = "Windows \u7A97\u53E3\u63A5\u7BA1\u5F85\u9A8C\u8BC1\uFF0C\u6682\u672A\u5F00\u542F";
3197
3484
  var WIN_PATH_RETRY = "DeskBuddy \u540E\u53F0\u6BCF\u5C0F\u65F6\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF1B\u4E5F\u53EF\u624B\u52A8\u628A\u5B83\u52A0\u5230\u7528\u6237 PATH \u6700\u524D\u9762";
3198
3485
  function shimDir() {
3199
- return join14(deskbuddyHome(), "bin");
3486
+ return join15(deskbuddyHome(), "bin");
3200
3487
  }
3201
3488
  function shimFile(binDir, command, platform = process.platform) {
3202
- return join14(binDir, platform === "win32" ? `${command}.cmd` : command);
3489
+ return join15(binDir, platform === "win32" ? `${command}.cmd` : command);
3203
3490
  }
3204
3491
  function shQuote3(s) {
3205
3492
  return `'${s.replace(/'/g, `'\\''`)}'`;
@@ -3339,10 +3626,10 @@ function removeRcBlock(content) {
3339
3626
  return content.slice(0, start) + content.slice(end);
3340
3627
  }
3341
3628
  function readRc(p) {
3342
- return readFileSync15(p).toString("latin1");
3629
+ return readFileSync16(p).toString("latin1");
3343
3630
  }
3344
3631
  function writeRc(p, latin1) {
3345
- writeFileSync15(p, Buffer.from(latin1, "latin1"));
3632
+ writeFileSync16(p, Buffer.from(latin1, "latin1"));
3346
3633
  }
3347
3634
  function toLatin1(utf8) {
3348
3635
  return Buffer.from(utf8, "utf8").toString("latin1");
@@ -3375,7 +3662,7 @@ function psError(e) {
3375
3662
  if (err?.code === "ETIMEDOUT" || err?.signal === "SIGTERM") return `PowerShell ${PS_PATH_TIMEOUT_MS / 1e3} \u79D2\u6CA1\u54CD\u5E94`;
3376
3663
  return err?.message || String(e);
3377
3664
  }
3378
- function psWinPath(exec = execFileSync6) {
3665
+ function psWinPath(exec = execFileSync7) {
3379
3666
  const ps = (script, env) => String(
3380
3667
  exec("powershell.exe", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script], {
3381
3668
  encoding: "utf8",
@@ -3402,7 +3689,7 @@ function psWinPath(exec = execFileSync6) {
3402
3689
  }
3403
3690
  };
3404
3691
  }
3405
- function psWinPathAsync(exec = execFile2) {
3692
+ function psWinPathAsync(exec = execFile3) {
3406
3693
  const ps = (script, env) => new Promise((done, fail) => {
3407
3694
  exec(
3408
3695
  "powershell.exe",
@@ -3472,7 +3759,7 @@ var PS_EFFECTIVE_PATH = "$m=[Environment]::GetEnvironmentVariable('Path','Machin
3472
3759
  function whereExe(env = process.env) {
3473
3760
  return `${env.SystemRoot || env.SYSTEMROOT || "C:\\Windows"}\\System32\\where.exe`;
3474
3761
  }
3475
- function psWinWhere(exec = execFileSync6) {
3762
+ function psWinWhere(exec = execFileSync7) {
3476
3763
  let cached;
3477
3764
  const read2 = () => {
3478
3765
  if (cached !== void 0) return cached;
@@ -3538,11 +3825,11 @@ function installShim(tool, e) {
3538
3825
  if (!node || !cli || !bin) {
3539
3826
  return { ok: false, message: "\u7A97\u53E3\u63A5\u7BA1\u6CA1\u88C5\uFF1A\u5B89\u88C5\u8DEF\u5F84\u91CC\u6709\u975E ASCII \u5B57\u7B26\uFF0CWindows \u7684 .cmd \u8BFB\u4E0D\u4E86\uFF08\u4E0D\u5F71\u54CD\u5176\u5B83\u529F\u80FD\uFF09" };
3540
3827
  }
3541
- mkdirSync15(e.binDir, { recursive: true });
3542
- writeFileSync15(file3, cmdScript(tool, command, node, cli, bin), "utf8");
3828
+ mkdirSync16(e.binDir, { recursive: true });
3829
+ writeFileSync16(file3, cmdScript(tool, command, node, cli, bin), "utf8");
3543
3830
  } else {
3544
- mkdirSync15(e.binDir, { recursive: true, mode: 448 });
3545
- writeFileSync15(file3, shScript(tool, command, e.nodePath, e.cliPath, e.binDir), { encoding: "utf8", mode: 493 });
3831
+ mkdirSync16(e.binDir, { recursive: true, mode: 448 });
3832
+ writeFileSync16(file3, shScript(tool, command, e.nodePath, e.cliPath, e.binDir), { encoding: "utf8", mode: 493 });
3546
3833
  chmodSync3(file3, 493);
3547
3834
  }
3548
3835
  if (e.platform === "win32" && e.deferWinPath) {
@@ -3566,7 +3853,7 @@ function installShim(tool, e) {
3566
3853
  } else if (e.rcHome) {
3567
3854
  const block = toLatin1(rcBlock(e.binDir, e.rcHome));
3568
3855
  for (const name of RC_FILES) {
3569
- const rc = join14(e.rcHome, name);
3856
+ const rc = join15(e.rcHome, name);
3570
3857
  if (!existsSync14(rc)) continue;
3571
3858
  const next = addRcBlock(readRc(rc), block);
3572
3859
  if (next !== null) writeRc(rc, next);
@@ -3594,7 +3881,7 @@ function ourShims(binDir) {
3594
3881
  }
3595
3882
  return names.filter((n) => {
3596
3883
  try {
3597
- return readFileSync15(join14(binDir, n), "utf8").includes(SHIM_MARKER);
3884
+ return readFileSync16(join15(binDir, n), "utf8").includes(SHIM_MARKER);
3598
3885
  } catch {
3599
3886
  return false;
3600
3887
  }
@@ -3606,7 +3893,7 @@ function uninstallShim(tool, e) {
3606
3893
  let removed = false;
3607
3894
  const file3 = shimFile(e.binDir, command, e.platform);
3608
3895
  try {
3609
- if (existsSync14(file3) && readFileSync15(file3, "utf8").includes(SHIM_MARKER)) {
3896
+ if (existsSync14(file3) && readFileSync16(file3, "utf8").includes(SHIM_MARKER)) {
3610
3897
  rmSync9(file3, { force: true });
3611
3898
  removed = true;
3612
3899
  }
@@ -3628,7 +3915,7 @@ function uninstallShim(tool, e) {
3628
3915
  }
3629
3916
  } else if (e.rcHome) {
3630
3917
  for (const name of RC_FILES) {
3631
- const rc = join14(e.rcHome, name);
3918
+ const rc = join15(e.rcHome, name);
3632
3919
  if (!existsSync14(rc)) continue;
3633
3920
  const next = removeRcBlock(readRc(rc));
3634
3921
  if (next !== null) {
@@ -3650,7 +3937,7 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
3650
3937
  const file3 = shimFile(binDir, command, platform);
3651
3938
  let installed = false;
3652
3939
  try {
3653
- installed = readFileSync15(file3, "utf8").includes(SHIM_MARKER);
3940
+ installed = readFileSync16(file3, "utf8").includes(SHIM_MARKER);
3654
3941
  } catch {
3655
3942
  installed = false;
3656
3943
  }
@@ -3661,26 +3948,26 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
3661
3948
  }
3662
3949
 
3663
3950
  // src/daemon/workbuddyAppDb.ts
3664
- import { execFile as execFile4 } from "child_process";
3665
- import { closeSync as closeSync5, existsSync as existsSync17, mkdirSync as mkdirSync18, openSync as openSync5, readdirSync as readdirSync8, readFileSync as readFileSync20, readSync as readSync5, renameSync as renameSync12, rmSync as rmSync12, statSync as statSync8, writeFileSync as writeFileSync18 } from "fs";
3951
+ import { execFile as execFile5 } from "child_process";
3952
+ import { closeSync as closeSync5, existsSync as existsSync17, mkdirSync as mkdirSync19, openSync as openSync5, readdirSync as readdirSync8, readFileSync as readFileSync21, readSync as readSync5, renameSync as renameSync13, rmSync as rmSync12, statSync as statSync8, writeFileSync as writeFileSync19 } from "fs";
3666
3953
  import { createRequire as createRequire3 } from "module";
3667
- import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as join19 } from "path";
3954
+ import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as join20 } from "path";
3668
3955
 
3669
3956
  // src/core/launch.ts
3670
- import { mkdirSync as mkdirSync17, readFileSync as readFileSync17, renameSync as renameSync11, rmSync as rmSync11, writeFileSync as writeFileSync17 } from "fs";
3671
- import { join as join16 } from "path";
3957
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync18, renameSync as renameSync12, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
3958
+ import { join as join17 } from "path";
3672
3959
 
3673
3960
  // src/core/wake.ts
3674
- import { execFileSync as execFileSync7 } from "child_process";
3961
+ import { execFileSync as execFileSync8 } from "child_process";
3675
3962
  import { createHash as createHash2, createHmac, timingSafeEqual } from "crypto";
3676
- import { chmodSync as chmodSync4, closeSync as closeSync2, mkdirSync as mkdirSync16, openSync as openSync2, readdirSync as readdirSync7, readFileSync as readFileSync16, readSync as readSync2, renameSync as renameSync10, rmSync as rmSync10, statSync as statSync5, writeFileSync as writeFileSync16 } from "fs";
3963
+ import { chmodSync as chmodSync4, closeSync as closeSync2, mkdirSync as mkdirSync17, openSync as openSync2, readdirSync as readdirSync7, readFileSync as readFileSync17, readSync as readSync2, renameSync as renameSync11, rmSync as rmSync10, statSync as statSync5, writeFileSync as writeFileSync17 } from "fs";
3677
3964
  import { tmpdir } from "os";
3678
- import { join as join15 } from "path";
3965
+ import { join as join16 } from "path";
3679
3966
  function wakeDir(home = deskbuddyHome()) {
3680
- return join15(home, "wake");
3967
+ return join16(home, "wake");
3681
3968
  }
3682
3969
  function marksDir(home = deskbuddyHome()) {
3683
- return join15(wakeDir(home), "marks");
3970
+ return join16(wakeDir(home), "marks");
3684
3971
  }
3685
3972
  function safeSid(sessionId) {
3686
3973
  return String(sessionId).replace(/[^A-Za-z0-9_-]/g, "");
@@ -3690,10 +3977,10 @@ function homeTag(home) {
3690
3977
  }
3691
3978
  function wakeChannelPath(platform = process.platform, home = deskbuddyHome()) {
3692
3979
  if (platform === "win32") return `\\\\.\\pipe\\deskbuddy-wake-${homeTag(home)}`;
3693
- const primary = join15(wakeDir(home), "wake.sock");
3980
+ const primary = join16(wakeDir(home), "wake.sock");
3694
3981
  if (Buffer.byteLength(primary) <= 103) return primary;
3695
3982
  const uid = typeof process.getuid === "function" ? process.getuid() : 0;
3696
- return join15(tmpdir(), `deskbuddy-${uid}`, `wake-${homeTag(home)}.sock`);
3983
+ return join16(tmpdir(), `deskbuddy-${uid}`, `wake-${homeTag(home)}.sock`);
3697
3984
  }
3698
3985
  function pidExists(pid) {
3699
3986
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -3708,11 +3995,11 @@ function writeWakeMark(sessionId, agentPid, now = Date.now()) {
3708
3995
  const safe = safeSid(sessionId);
3709
3996
  if (!safe) return;
3710
3997
  try {
3711
- mkdirSync16(marksDir(), { recursive: true, mode: 448 });
3712
- const file3 = join15(marksDir(), `${safe}.json`);
3998
+ mkdirSync17(marksDir(), { recursive: true, mode: 448 });
3999
+ const file3 = join16(marksDir(), `${safe}.json`);
3713
4000
  const tmp = `${file3}.${process.pid}.tmp`;
3714
- writeFileSync16(tmp, JSON.stringify({ agentPid: agentPid ?? 0, daemonPid: process.pid, at: now }), { encoding: "utf8", mode: 384 });
3715
- renameSync10(tmp, file3);
4001
+ writeFileSync17(tmp, JSON.stringify({ agentPid: agentPid ?? 0, daemonPid: process.pid, at: now }), { encoding: "utf8", mode: 384 });
4002
+ renameSync11(tmp, file3);
3716
4003
  } catch {
3717
4004
  }
3718
4005
  }
@@ -3720,7 +4007,7 @@ function removeWakeMark(sessionId) {
3720
4007
  const safe = safeSid(sessionId);
3721
4008
  if (!safe) return;
3722
4009
  try {
3723
- rmSync10(join15(marksDir(), `${safe}.json`), { force: true });
4010
+ rmSync10(join16(marksDir(), `${safe}.json`), { force: true });
3724
4011
  } catch {
3725
4012
  }
3726
4013
  }
@@ -3733,7 +4020,7 @@ function clearWakeMarks() {
3733
4020
  }
3734
4021
  for (const n of names) {
3735
4022
  try {
3736
- rmSync10(join15(marksDir(), n), { force: true });
4023
+ rmSync10(join16(marksDir(), n), { force: true });
3737
4024
  } catch {
3738
4025
  }
3739
4026
  }
@@ -3742,7 +4029,7 @@ function isWakeMarked(sessionId, alive = pidExists) {
3742
4029
  const safe = safeSid(sessionId);
3743
4030
  if (!safe) return false;
3744
4031
  try {
3745
- const m = JSON.parse(readFileSync16(join15(marksDir(), `${safe}.json`), "utf8"));
4032
+ const m = JSON.parse(readFileSync17(join16(marksDir(), `${safe}.json`), "utf8"));
3746
4033
  const daemonPid = Number(m?.daemonPid) || 0;
3747
4034
  if (!daemonPid || !alive(daemonPid)) return false;
3748
4035
  const pid = Number(m?.agentPid) || 0;
@@ -3755,30 +4042,30 @@ function withWake(states, alive) {
3755
4042
  return states.map((s) => s.remoteWindow === true || !isWakeMarked(s.sessionId, alive) ? s : { ...s, remoteWindow: true });
3756
4043
  }
3757
4044
  function wakeSecretPath(home = deskbuddyHome()) {
3758
- return join15(wakeDir(home), "secret");
4045
+ return join16(wakeDir(home), "secret");
3759
4046
  }
3760
4047
  function writeWakeSecret(hex, platform = process.platform) {
3761
4048
  const file3 = wakeSecretPath();
3762
- mkdirSync16(wakeDir(), { recursive: true, mode: 448 });
4049
+ mkdirSync17(wakeDir(), { recursive: true, mode: 448 });
3763
4050
  const tmp = `${file3}.${process.pid}.tmp`;
3764
- writeFileSync16(tmp, hex, { encoding: "utf8", mode: 384 });
4051
+ writeFileSync17(tmp, hex, { encoding: "utf8", mode: 384 });
3765
4052
  if (platform === "win32") {
3766
4053
  try {
3767
- execFileSync7("icacls", [tmp, "/inheritance:r", "/grant:r", `${currentUserSid()}:F`], { stdio: "ignore", windowsHide: true });
4054
+ execFileSync8("icacls", [tmp, "/inheritance:r", "/grant:r", `${currentUserSid()}:F`], { stdio: "ignore", windowsHide: true });
3768
4055
  } catch {
3769
- renameSync10(tmp, file3);
4056
+ renameSync11(tmp, file3);
3770
4057
  return "\u7A97\u53E3\u5524\u9192\u5BC6\u94A5\u6587\u4EF6\u7684\u6743\u9650\u6CA1\u80FD\u6536\u7D27\uFF08icacls \u5931\u8D25\uFF09";
3771
4058
  }
3772
4059
  } else {
3773
4060
  chmodSync4(tmp, 384);
3774
4061
  }
3775
- renameSync10(tmp, file3);
4062
+ renameSync11(tmp, file3);
3776
4063
  return "";
3777
4064
  }
3778
4065
  function restrictToUser(file3, platform = process.platform) {
3779
4066
  if (platform !== "win32") return true;
3780
4067
  try {
3781
- execFileSync7("icacls", [file3, "/inheritance:r", "/grant:r", `${currentUserSid()}:F`], { stdio: "ignore", windowsHide: true });
4068
+ execFileSync8("icacls", [file3, "/inheritance:r", "/grant:r", `${currentUserSid()}:F`], { stdio: "ignore", windowsHide: true });
3782
4069
  return true;
3783
4070
  } catch {
3784
4071
  return false;
@@ -3786,7 +4073,7 @@ function restrictToUser(file3, platform = process.platform) {
3786
4073
  }
3787
4074
  function currentUserSid() {
3788
4075
  try {
3789
- const out = execFileSync7("whoami", ["/user", "/fo", "csv", "/nh"], { encoding: "utf8", windowsHide: true });
4076
+ const out = execFileSync8("whoami", ["/user", "/fo", "csv", "/nh"], { encoding: "utf8", windowsHide: true });
3790
4077
  const m = /"(S-1-[0-9-]+)"/.exec(out);
3791
4078
  if (m) return `*${m[1]}`;
3792
4079
  } catch {
@@ -3883,30 +4170,30 @@ function validPlan(p) {
3883
4170
  return true;
3884
4171
  }
3885
4172
  function launchDir(home = deskbuddyHome()) {
3886
- return join16(home, "launch");
4173
+ return join17(home, "launch");
3887
4174
  }
3888
4175
  function planFile(runId) {
3889
- return join16(launchDir(), `${runId}.json`);
4176
+ return join17(launchDir(), `${runId}.json`);
3890
4177
  }
3891
4178
  function writeLaunch(runId, plan) {
3892
4179
  if (!RUN_ID_RE.test(runId)) throw new Error("bad runId");
3893
4180
  if (!validPlan(plan)) throw new Error("bad launch plan");
3894
- mkdirSync17(launchDir(), { recursive: true, mode: 448 });
4181
+ mkdirSync18(launchDir(), { recursive: true, mode: 448 });
3895
4182
  const tmp = `${planFile(runId)}.${process.pid}.tmp`;
3896
- writeFileSync17(tmp, JSON.stringify(plan), { encoding: "utf8", mode: 384 });
4183
+ writeFileSync18(tmp, JSON.stringify(plan), { encoding: "utf8", mode: 384 });
3897
4184
  restrictToUser(tmp);
3898
- renameSync11(tmp, planFile(runId));
4185
+ renameSync12(tmp, planFile(runId));
3899
4186
  }
3900
4187
  function claimLaunch(runId) {
3901
4188
  if (!RUN_ID_RE.test(runId)) return null;
3902
- const claimed = join16(launchDir(), `${runId}.${process.pid}.claimed`);
4189
+ const claimed = join17(launchDir(), `${runId}.${process.pid}.claimed`);
3903
4190
  try {
3904
- renameSync11(planFile(runId), claimed);
4191
+ renameSync12(planFile(runId), claimed);
3905
4192
  } catch {
3906
4193
  return null;
3907
4194
  }
3908
4195
  try {
3909
- const p = JSON.parse(readFileSync17(claimed, "utf8"));
4196
+ const p = JSON.parse(readFileSync18(claimed, "utf8"));
3910
4197
  if (!p || typeof p.cwd !== "string" || typeof p.resume !== "string") return null;
3911
4198
  if (p.tool === void 0) p.tool = "claude_code";
3912
4199
  return validPlan(p) ? p : null;
@@ -3921,7 +4208,7 @@ function claimLaunch(runId) {
3921
4208
  }
3922
4209
  function launchPending(runId) {
3923
4210
  try {
3924
- readFileSync17(planFile(runId));
4211
+ readFileSync18(planFile(runId));
3925
4212
  return true;
3926
4213
  } catch {
3927
4214
  return false;
@@ -3929,16 +4216,16 @@ function launchPending(runId) {
3929
4216
  }
3930
4217
 
3931
4218
  // src/core/title.ts
3932
- import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync18, readSync as readSync3, statSync as statSync6 } from "fs";
4219
+ import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync19, readSync as readSync3, statSync as statSync6 } from "fs";
3933
4220
  import { createRequire as createRequire2 } from "module";
3934
4221
  import { homedir as homedir5 } from "os";
3935
- import { basename as basename3, dirname as dirname10, isAbsolute, join as join17 } from "path";
4222
+ import { basename as basename3, dirname as dirname10, isAbsolute, join as join18 } from "path";
3936
4223
 
3937
4224
  // src/core/dirFilter.ts
3938
4225
  import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
3939
- import { posix, win32 } from "path";
4226
+ import { posix, win32 as win322 } from "path";
3940
4227
  function norm(p, win) {
3941
- if (win) return win32.resolve(p).replace(/[\\/]+$/, "").toLowerCase();
4228
+ if (win) return win322.resolve(p).replace(/[\\/]+$/, "").toLowerCase();
3942
4229
  return posix.resolve(p).replace(/\/+$/, "");
3943
4230
  }
3944
4231
  function isUnder(p, base, win) {
@@ -3947,7 +4234,7 @@ function isUnder(p, base, win) {
3947
4234
  function isAutoWorkspace(p, opts = {}) {
3948
4235
  if (!p) return false;
3949
4236
  const win = (opts.platform ?? process.platform) === "win32";
3950
- const P = win ? win32 : posix;
4237
+ const P = win ? win322 : posix;
3951
4238
  const home = norm(opts.home ?? homedir4(), win);
3952
4239
  const full = norm(p, win);
3953
4240
  const name = P.basename(full);
@@ -3958,7 +4245,7 @@ function isAutoWorkspace(p, opts = {}) {
3958
4245
  function isReportableDir(p, opts = {}) {
3959
4246
  if (!p) return false;
3960
4247
  const win = (opts.platform ?? process.platform) === "win32";
3961
- const P = win ? win32 : posix;
4248
+ const P = win ? win322 : posix;
3962
4249
  const full = norm(p, win);
3963
4250
  if (full === norm(P.parse(P.resolve(p)).root, win)) return false;
3964
4251
  if (full === norm(opts.home ?? homedir4(), win)) return false;
@@ -3981,19 +4268,19 @@ var QODER_DATA_DIRS = { qoder_cn: "com.qodercn.app.stable", qoder: "com.qoder.ap
3981
4268
  var QODER_APP_DIR_ENV = { qoder_cn: "DESKBUDDY_QODER_CN_APP_DIR", qoder: "DESKBUDDY_QODER_APP_DIR" };
3982
4269
  function qoderDbPaths(tool, platform = process.platform, home = homedir5(), env = process.env) {
3983
4270
  let root;
3984
- if (platform === "darwin") root = join17(home, "Library", "Application Support");
3985
- else if (platform === "win32") root = env.APPDATA || join17(home, "AppData", "Roaming");
3986
- else root = env.XDG_CONFIG_HOME || join17(home, ".config");
4271
+ if (platform === "darwin") root = join18(home, "Library", "Application Support");
4272
+ else if (platform === "win32") root = env.APPDATA || join18(home, "AppData", "Roaming");
4273
+ else root = env.XDG_CONFIG_HOME || join18(home, ".config");
3987
4274
  const one = tool ? QODER_DATA_DIRS[tool] : void 0;
3988
4275
  const tools = one ? [tool] : ["qoder_cn", "qoder"];
3989
- return tools.map((t) => join17(env[QODER_APP_DIR_ENV[t] ?? ""] || join17(root, QODER_DATA_DIRS[t] ?? ""), "main.sqlite"));
4276
+ return tools.map((t) => join18(env[QODER_APP_DIR_ENV[t] ?? ""] || join18(root, QODER_DATA_DIRS[t] ?? ""), "main.sqlite"));
3990
4277
  }
3991
4278
 
3992
4279
  // src/daemon/locate.ts
3993
- import { execFile as execFile3, execFileSync as execFileSync8 } from "child_process";
3994
- import { accessSync, closeSync as closeSync4, constants, existsSync as existsSync16, lstatSync, openSync as openSync4, readFileSync as readFileSync19, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync7 } from "fs";
4280
+ import { execFile as execFile4, execFileSync as execFileSync9 } from "child_process";
4281
+ import { accessSync, closeSync as closeSync4, constants, existsSync as existsSync16, lstatSync, openSync as openSync4, readFileSync as readFileSync20, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync7 } from "fs";
3995
4282
  import { homedir as homedir6 } from "os";
3996
- import { delimiter as delimiter2, dirname as dirname11, join as join18, win32 as win322 } from "path";
4283
+ import { delimiter as delimiter2, dirname as dirname11, join as join19, win32 as win323 } from "path";
3997
4284
 
3998
4285
  // src/core/agentEnv.ts
3999
4286
  var BUN_HIJACK_ENV = ["BUN_BE_BUN", "BUN_OPTIONS"];
@@ -4042,13 +4329,13 @@ var defaultLocateDeps = () => ({
4042
4329
  localAppData: process.env.LOCALAPPDATA ?? "",
4043
4330
  readText: (p) => {
4044
4331
  try {
4045
- return readFileSync19(p, "utf8");
4332
+ return readFileSync20(p, "utf8");
4046
4333
  } catch {
4047
4334
  return null;
4048
4335
  }
4049
4336
  },
4050
4337
  // 🔴 daemon 自己也不能找到垫片:远程任务要的是真程序(窗口接管 spec 2026-09-30 §3.1)
4051
- skipDirs: [join18(deskbuddyHome(), "bin")],
4338
+ skipDirs: [join19(deskbuddyHome(), "bin")],
4052
4339
  winAppHints: (product, exe) => winInstallDirs(product, exe),
4053
4340
  winAppExeHints: () => winWorkbuddyExeHints(),
4054
4341
  isPe: (p) => {
@@ -4133,7 +4420,7 @@ var defaultProbe = createVersionProbe({
4133
4420
  },
4134
4421
  runSync: (loc) => {
4135
4422
  try {
4136
- const out = execFileSync8(loc.file, [...loc.prefixArgs, "--version"], {
4423
+ const out = execFileSync9(loc.file, [...loc.prefixArgs, "--version"], {
4137
4424
  encoding: "utf8",
4138
4425
  stdio: ["ignore", "pipe", "pipe"],
4139
4426
  windowsHide: true,
@@ -4147,7 +4434,7 @@ var defaultProbe = createVersionProbe({
4147
4434
  },
4148
4435
  runAsync: (loc) => new Promise((resolve6) => {
4149
4436
  try {
4150
- execFile3(
4437
+ execFile4(
4151
4438
  loc.file,
4152
4439
  [...loc.prefixArgs, "--version"],
4153
4440
  { encoding: "utf8", windowsHide: true, timeout: PROBE_TIMEOUT_MS, env: probeEnv(loc) },
@@ -4173,9 +4460,9 @@ function installDirsFromProcs(procs, exe) {
4173
4460
  const out = [];
4174
4461
  for (const p of procs ?? []) {
4175
4462
  const first = winSplitArgs(p.cmdline)[0] ?? "";
4176
- if (win322.basename(first).toLowerCase() !== exe.toLowerCase()) continue;
4177
- const dir2 = win322.dirname(first);
4178
- if (win322.isAbsolute(dir2) && !out.some((d) => d.toLowerCase() === dir2.toLowerCase())) out.push(dir2);
4463
+ if (win323.basename(first).toLowerCase() !== exe.toLowerCase()) continue;
4464
+ const dir2 = win323.dirname(first);
4465
+ if (win323.isAbsolute(dir2) && !out.some((d) => d.toLowerCase() === dir2.toLowerCase())) out.push(dir2);
4179
4466
  }
4180
4467
  return out;
4181
4468
  }
@@ -4183,8 +4470,8 @@ function parseUninstallDirs(out) {
4183
4470
  const dirs = [];
4184
4471
  for (const raw of out.split(/\r?\n/)) {
4185
4472
  let v = raw.trim().replace(/,\s*-?\d+$/, "").replace(/^"|"$/g, "").trim();
4186
- if (!v || !win322.isAbsolute(v)) continue;
4187
- if (/\.exe$/i.test(v)) v = win322.dirname(v);
4473
+ if (!v || !win323.isAbsolute(v)) continue;
4474
+ if (/\.exe$/i.test(v)) v = win323.dirname(v);
4188
4475
  v = v.replace(/[\\/]+$/, "");
4189
4476
  if (!dirs.some((d) => d.toLowerCase() === v.toLowerCase())) dirs.push(v);
4190
4477
  }
@@ -4196,7 +4483,7 @@ function winInstallDirs(product, exe) {
4196
4483
  try {
4197
4484
  const name = product.replace(/'/g, "''");
4198
4485
  const script = `[Console]::OutputEncoding=[Text.Encoding]::UTF8;Get-ItemProperty 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*','HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*','HKLM:\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*' -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like '${name}*' } | ForEach-Object { $_.InstallLocation; $_.DisplayIcon }`;
4199
- const out = execFileSync8("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
4486
+ const out = execFileSync9("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
4200
4487
  encoding: "utf8",
4201
4488
  stdio: ["ignore", "pipe", "ignore"],
4202
4489
  windowsHide: true,
@@ -4211,7 +4498,7 @@ function parseExeHints(out) {
4211
4498
  const res = [];
4212
4499
  for (const raw of out.split(/\r?\n/)) {
4213
4500
  const v = raw.trim().replace(/,\s*-?\d+$/, "").replace(/^"|"$/g, "").trim().replace(/[\\/]+$/, "");
4214
- if (!v || !win322.isAbsolute(v)) continue;
4501
+ if (!v || !win323.isAbsolute(v)) continue;
4215
4502
  if (!res.some((x) => x.toLowerCase() === v.toLowerCase())) res.push(v);
4216
4503
  }
4217
4504
  return res;
@@ -4221,7 +4508,7 @@ function winWorkbuddyExeHints() {
4221
4508
  const fromProcs = installDirsFromProcs(winProcs(), "WorkBuddy.exe");
4222
4509
  let fromPs = [];
4223
4510
  try {
4224
- const out = execFileSync8("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", WIN_WORKBUDDY_EXE_PS], {
4511
+ const out = execFileSync9("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", WIN_WORKBUDDY_EXE_PS], {
4225
4512
  encoding: "utf8",
4226
4513
  stdio: ["ignore", "pipe", "ignore"],
4227
4514
  windowsHide: true,
@@ -4235,7 +4522,7 @@ function winWorkbuddyExeHints() {
4235
4522
  function locateWorkbuddyAppExe(d = defaultLocateDeps()) {
4236
4523
  if (!isWin(d)) {
4237
4524
  for (const dir2 of appDirs(d.home)) {
4238
- const p = join18(dir2, "WorkBuddy.app");
4525
+ const p = join19(dir2, "WorkBuddy.app");
4239
4526
  if (d.exists(p)) return p;
4240
4527
  }
4241
4528
  return null;
@@ -4244,15 +4531,15 @@ function locateWorkbuddyAppExe(d = defaultLocateDeps()) {
4244
4531
  }
4245
4532
  function pickWorkbuddyExe(cands, d) {
4246
4533
  for (const c of cands) {
4247
- const exe = /\.exe$/i.test(c) ? c : win322.join(c, "WorkBuddy.exe");
4248
- if (win322.basename(exe).toLowerCase() === "workbuddy.exe" && d.exists(exe)) return exe;
4534
+ const exe = /\.exe$/i.test(c) ? c : win323.join(c, "WorkBuddy.exe");
4535
+ if (win323.basename(exe).toLowerCase() === "workbuddy.exe" && d.exists(exe)) return exe;
4249
4536
  }
4250
4537
  return null;
4251
4538
  }
4252
4539
  function winWorkbuddyExeHintsAsync() {
4253
4540
  return new Promise((resolve6) => {
4254
4541
  try {
4255
- execFile3(
4542
+ execFile4(
4256
4543
  "powershell.exe",
4257
4544
  ["-NoProfile", "-NonInteractive", "-Command", WIN_WORKBUDDY_EXE_PS],
4258
4545
  { encoding: "utf8", windowsHide: true, timeout: 15e3 },
@@ -4272,20 +4559,20 @@ var WIN_EXTS = [".exe", ".cmd", ".bat"];
4272
4559
  function extraBinDirs(home, nodePath = "", win) {
4273
4560
  if (win) {
4274
4561
  return [
4275
- join18(home, ".local", "bin"),
4276
- ...win.appData ? [join18(win.appData, "npm")] : [],
4277
- join18(home, ".bun", "bin"),
4278
- ...win.localAppData ? [join18(win.localAppData, "Volta", "bin")] : [],
4279
- join18(home, "scoop", "shims"),
4562
+ join19(home, ".local", "bin"),
4563
+ ...win.appData ? [join19(win.appData, "npm")] : [],
4564
+ join19(home, ".bun", "bin"),
4565
+ ...win.localAppData ? [join19(win.localAppData, "Volta", "bin")] : [],
4566
+ join19(home, "scoop", "shims"),
4280
4567
  ...nodePath ? [dirname11(nodePath)] : []
4281
4568
  ];
4282
4569
  }
4283
4570
  return [
4284
- join18(home, ".local", "bin"),
4285
- join18(home, ".claude", "local"),
4286
- join18(home, ".npm-global", "bin"),
4287
- join18(home, ".bun", "bin"),
4288
- join18(home, ".volta", "bin"),
4571
+ join19(home, ".local", "bin"),
4572
+ join19(home, ".claude", "local"),
4573
+ join19(home, ".npm-global", "bin"),
4574
+ join19(home, ".bun", "bin"),
4575
+ join19(home, ".volta", "bin"),
4289
4576
  "/opt/homebrew/bin",
4290
4577
  "/usr/local/bin",
4291
4578
  ...nodePath ? [dirname11(nodePath)] : []
@@ -4299,7 +4586,7 @@ function whichAllIn(name, d) {
4299
4586
  const out = [];
4300
4587
  for (const dir2 of binDirs(d)) {
4301
4588
  for (const ext of exts) {
4302
- const p = join18(dir2, name + ext);
4589
+ const p = join19(dir2, name + ext);
4303
4590
  if (d.isExecutable(p)) out.push(p);
4304
4591
  }
4305
4592
  }
@@ -4323,7 +4610,7 @@ function binDirs(d) {
4323
4610
  function parseNpmCmdShim(shimPath, text) {
4324
4611
  const m = text.match(/"%~?dp0%?\\?([^"%]+)"\s+%\*/i);
4325
4612
  if (!m) return null;
4326
- return join18(dirname11(shimPath), m[1].replace(/^\\/, ""));
4613
+ return join19(dirname11(shimPath), m[1].replace(/^\\/, ""));
4327
4614
  }
4328
4615
  var JS_RUNTIME_EXE = /^(?:node|bun|bunx|deno)(?:\.exe)?$/i;
4329
4616
  function resolveWinLaunch(file3, d) {
@@ -4334,7 +4621,7 @@ function resolveWinLaunch(file3, d) {
4334
4621
  const target = text ? parseNpmCmdShim(file3, text) : null;
4335
4622
  if (!target || !d.exists(target)) return null;
4336
4623
  if (/\.(?:cmd|bat)$/i.test(target)) return null;
4337
- if (JS_RUNTIME_EXE.test(win322.basename(target.replace(/\//g, "\\")))) return null;
4624
+ if (JS_RUNTIME_EXE.test(win323.basename(target.replace(/\//g, "\\")))) return null;
4338
4625
  return resolveWinLaunch(target, d);
4339
4626
  }
4340
4627
  if (/\.(?:c|m)?js$/.test(lower)) return { file: d.nodePath, prefixArgs: [file3] };
@@ -4343,13 +4630,13 @@ function resolveWinLaunch(file3, d) {
4343
4630
  return null;
4344
4631
  }
4345
4632
  function appDirs(home) {
4346
- return ["/Applications", join18(home, "Applications")];
4633
+ return ["/Applications", join19(home, "Applications")];
4347
4634
  }
4348
4635
  function winAppDirs(d, product) {
4349
4636
  return [
4350
- ...d.localAppData ? [join18(d.localAppData, "Programs", product)] : [],
4351
- join18("C:\\Program Files", product),
4352
- join18("C:\\Program Files (x86)", product)
4637
+ ...d.localAppData ? [join19(d.localAppData, "Programs", product)] : [],
4638
+ join19("C:\\Program Files", product),
4639
+ join19("C:\\Program Files (x86)", product)
4353
4640
  ];
4354
4641
  }
4355
4642
  var WORKBUDDY_CLI_IN_WIN_APP = "resources/app.asar.unpacked/cli/bin/codebuddy";
@@ -4357,8 +4644,8 @@ var QODER_CN_WORKER_IN_WIN_APP = "resources/app.asar.unpacked/node_modules/@qode
4357
4644
  var QODER_WORKER_IN_WIN_APP = "resources/app.asar.unpacked/node_modules/@qoder-ai/qoder-agent-sdk/dist/_worker/qoder-worker-runtime.obf.mjs";
4358
4645
  function winClaudeExeCandidates(d) {
4359
4646
  return [
4360
- ...d.home ? [join18(d.home, ".local", "bin", "claude.exe")] : [],
4361
- ...d.appData ? [join18(d.appData, "npm", "node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe")] : []
4647
+ ...d.home ? [join19(d.home, ".local", "bin", "claude.exe")] : [],
4648
+ ...d.appData ? [join19(d.appData, "npm", "node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe")] : []
4362
4649
  ];
4363
4650
  }
4364
4651
  function winClaudeLaunches(d) {
@@ -4404,20 +4691,20 @@ function locateWin(tool, d) {
4404
4691
  return locateWorkbuddy(d)?.loc ?? null;
4405
4692
  case "qoder_cn": {
4406
4693
  for (const dir2 of winAppDirs(d, "Qoder CN")) {
4407
- const p = join18(dir2, QODER_CN_WORKER_IN_WIN_APP);
4408
- if (d.exists(p)) return qoderWorker(d, p, join18(dir2, "Qoder CN.exe"));
4694
+ const p = join19(dir2, QODER_CN_WORKER_IN_WIN_APP);
4695
+ if (d.exists(p)) return qoderWorker(d, p, join19(dir2, "Qoder CN.exe"));
4409
4696
  }
4410
4697
  return plain("qoderclicn");
4411
4698
  }
4412
4699
  case "qoder": {
4413
4700
  for (const dir2 of winAppDirs(d, "Qoder")) {
4414
- const p = join18(dir2, QODER_WORKER_IN_WIN_APP);
4415
- if (d.exists(p)) return qoderWorker(d, p, join18(dir2, "Qoder.exe"));
4701
+ const p = join19(dir2, QODER_WORKER_IN_WIN_APP);
4702
+ if (d.exists(p)) return qoderWorker(d, p, join19(dir2, "Qoder.exe"));
4416
4703
  }
4417
4704
  return plain("qodercli");
4418
4705
  }
4419
4706
  case "opencode": {
4420
- const p = join18(d.home, ".opencode", "bin", "opencode.exe");
4707
+ const p = join19(d.home, ".opencode", "bin", "opencode.exe");
4421
4708
  if (d.exists(p)) return { file: p, prefixArgs: [] };
4422
4709
  return plain("opencode");
4423
4710
  }
@@ -4441,8 +4728,8 @@ function workbuddyHasTui(loc, exists = existsSync16, realpath = realpathSync2) {
4441
4728
  const cands = [...loc.prefixArgs, loc.file].map(real);
4442
4729
  const script = cands.find((a) => BIN.test(a));
4443
4730
  if (!script) return true;
4444
- const dist = join18(dirname11(dirname11(script)), "dist");
4445
- return exists(join18(dist, "codebuddy.js"));
4731
+ const dist = join19(dirname11(dirname11(script)), "dist");
4732
+ return exists(join19(dist, "codebuddy.js"));
4446
4733
  }
4447
4734
  function locateWorkbuddyTui(d = defaultLocateDeps(), exists, realpath) {
4448
4735
  const cands = [locateWorkbuddyStandalone(d), locateWorkbuddyApp(d)].filter((c) => c !== null);
@@ -4483,7 +4770,7 @@ function locateWorkbuddyStandalone(d = defaultLocateDeps()) {
4483
4770
  function locateWorkbuddyApp(d = defaultLocateDeps()) {
4484
4771
  if (!isWin(d)) {
4485
4772
  for (const dir2 of appDirs(d.home)) {
4486
- const p = join18(dir2, WORKBUDDY_CLI_IN_APP);
4773
+ const p = join19(dir2, WORKBUDDY_CLI_IN_APP);
4487
4774
  if (d.isExecutable(p)) return { file: p, prefixArgs: [] };
4488
4775
  }
4489
4776
  return null;
@@ -4491,7 +4778,7 @@ function locateWorkbuddyApp(d = defaultLocateDeps()) {
4491
4778
  const inApp = (dirs) => {
4492
4779
  for (const dir2 of dirs) {
4493
4780
  for (const ext of [".exe", ".cmd", ""]) {
4494
- const p = join18(dir2, WORKBUDDY_CLI_IN_WIN_APP + ext);
4781
+ const p = join19(dir2, WORKBUDDY_CLI_IN_WIN_APP + ext);
4495
4782
  if (d.exists(p)) {
4496
4783
  const r = resolveWinLaunch(p, d);
4497
4784
  if (r) return r;
@@ -4526,20 +4813,20 @@ function locate(tool, d = defaultLocateDeps()) {
4526
4813
  return locateWorkbuddy(d)?.loc ?? null;
4527
4814
  case "qoder_cn": {
4528
4815
  for (const dir2 of appDirs(d.home)) {
4529
- const p = join18(dir2, QODER_CN_WORKER_IN_APP);
4530
- if (d.exists(p)) return qoderWorker(d, p, join18(dir2, "Qoder CN.app", "Contents", "MacOS", "Qoder CN"));
4816
+ const p = join19(dir2, QODER_CN_WORKER_IN_APP);
4817
+ if (d.exists(p)) return qoderWorker(d, p, join19(dir2, "Qoder CN.app", "Contents", "MacOS", "Qoder CN"));
4531
4818
  }
4532
4819
  return plain("qoderclicn");
4533
4820
  }
4534
4821
  case "qoder": {
4535
4822
  for (const dir2 of appDirs(d.home)) {
4536
- const p = join18(dir2, QODER_WORKER_IN_APP);
4537
- if (d.exists(p)) return qoderWorker(d, p, join18(dir2, "Qoder.app", "Contents", "MacOS", "Qoder"));
4823
+ const p = join19(dir2, QODER_WORKER_IN_APP);
4824
+ if (d.exists(p)) return qoderWorker(d, p, join19(dir2, "Qoder.app", "Contents", "MacOS", "Qoder"));
4538
4825
  }
4539
4826
  return plain("qodercli");
4540
4827
  }
4541
4828
  case "opencode": {
4542
- const p = join18(d.home, ".opencode", "bin", "opencode");
4829
+ const p = join19(d.home, ".opencode", "bin", "opencode");
4543
4830
  if (d.isExecutable(p)) return { file: p, prefixArgs: [] };
4544
4831
  return plain("opencode");
4545
4832
  }
@@ -4560,7 +4847,7 @@ function findWt(d = defaultLocateDeps()) {
4560
4847
  if (!isWin(d)) return null;
4561
4848
  const hit = whichIn("wt", d);
4562
4849
  if (hit) return hit;
4563
- const alias = d.localAppData ? join18(d.localAppData, "Microsoft", "WindowsApps", "wt.exe") : "";
4850
+ const alias = d.localAppData ? join19(d.localAppData, "Microsoft", "WindowsApps", "wt.exe") : "";
4564
4851
  return alias && (d.exists(alias) || (d.lexists?.(alias) ?? false)) ? alias : null;
4565
4852
  }
4566
4853
 
@@ -4627,12 +4914,12 @@ function findWbTranscript(configDir, sessionId) {
4627
4914
  if (!SESSION_UUID_RE.test(sessionId)) return null;
4628
4915
  let dirs;
4629
4916
  try {
4630
- dirs = readdirSync8(join19(configDir, "projects"));
4917
+ dirs = readdirSync8(join20(configDir, "projects"));
4631
4918
  } catch {
4632
4919
  return null;
4633
4920
  }
4634
4921
  for (const d of dirs) {
4635
- const p = join19(configDir, "projects", d, `${sessionId}.jsonl`);
4922
+ const p = join20(configDir, "projects", d, `${sessionId}.jsonl`);
4636
4923
  if (existsSync17(p)) return p;
4637
4924
  }
4638
4925
  return null;
@@ -4718,8 +5005,8 @@ function wbElectronCandidates(appCliPath) {
4718
5005
  const m = /^(.*?)[\\/]resources[\\/]app\.asar\.unpacked[\\/]/i.exec(appCliPath);
4719
5006
  if (!m) return [];
4720
5007
  const root = m[1];
4721
- if (/\.app[\\/]Contents$/.test(root)) return [join19(root, "MacOS", "Electron"), join19(root, "MacOS", "WorkBuddy")];
4722
- return [join19(root, "WorkBuddy.exe")];
5008
+ if (/\.app[\\/]Contents$/.test(root)) return [join20(root, "MacOS", "Electron"), join20(root, "MacOS", "WorkBuddy")];
5009
+ return [join20(root, "WorkBuddy.exe")];
4723
5010
  }
4724
5011
  function defaultWbElectron(d = defaultLocateDeps()) {
4725
5012
  if ((d.platform ?? process.platform) === "win32") return null;
@@ -4738,14 +5025,14 @@ function defaultAppRunning(platform = process.platform) {
4738
5025
  return new Promise((resolve6) => {
4739
5026
  try {
4740
5027
  if (platform === "darwin") {
4741
- execFile4("pgrep", ["-f", "WorkBuddy.app/Contents/MacOS/"], { timeout: 5e3 }, (err) => {
5028
+ execFile5("pgrep", ["-f", "WorkBuddy.app/Contents/MacOS/"], { timeout: 5e3 }, (err) => {
4742
5029
  const code = err?.code;
4743
5030
  resolve6(!err ? true : code === 1 ? false : true);
4744
5031
  });
4745
5032
  return;
4746
5033
  }
4747
5034
  if (platform === "win32") {
4748
- execFile4(
5035
+ execFile5(
4749
5036
  "tasklist",
4750
5037
  ["/FI", "IMAGENAME eq WorkBuddy.exe", "/FO", "CSV", "/NH"],
4751
5038
  { timeout: 1e4, windowsHide: true, encoding: "utf8" },
@@ -4762,11 +5049,11 @@ function defaultAppRunning(platform = process.platform) {
4762
5049
  var PENDING_MAX = 20;
4763
5050
  var PENDING_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
4764
5051
  function pendingPath() {
4765
- return join19(deskbuddyHome(), "workbuddy-pending.json");
5052
+ return join20(deskbuddyHome(), "workbuddy-pending.json");
4766
5053
  }
4767
5054
  function loadPendingFile() {
4768
5055
  try {
4769
- const v = JSON.parse(readFileSync20(pendingPath(), "utf8"));
5056
+ const v = JSON.parse(readFileSync21(pendingPath(), "utf8"));
4770
5057
  return Array.isArray(v) ? v.filter((j) => j && typeof j.sessionId === "string" && typeof j.cwd === "string") : [];
4771
5058
  } catch {
4772
5059
  return [];
@@ -4778,10 +5065,10 @@ function savePendingFile(jobs) {
4778
5065
  rmSync12(pendingPath(), { force: true });
4779
5066
  return;
4780
5067
  }
4781
- mkdirSync18(deskbuddyHome(), { recursive: true });
5068
+ mkdirSync19(deskbuddyHome(), { recursive: true });
4782
5069
  const tmp = pendingPath() + ".tmp";
4783
- writeFileSync18(tmp, JSON.stringify(jobs), { mode: 384 });
4784
- renameSync12(tmp, pendingPath());
5070
+ writeFileSync19(tmp, JSON.stringify(jobs), { mode: 384 });
5071
+ renameSync13(tmp, pendingPath());
4785
5072
  } catch {
4786
5073
  }
4787
5074
  }
@@ -4792,7 +5079,7 @@ var defaultWbAppDbDeps = () => ({
4792
5079
  electron: () => defaultWbElectron(),
4793
5080
  runElectron: (bin, script, input) => new Promise((resolve6, reject) => {
4794
5081
  const env = { ...process.env, ELECTRON_RUN_AS_NODE: "1" };
4795
- const c = execFile4(
5082
+ const c = execFile5(
4796
5083
  bin,
4797
5084
  ["-e", script],
4798
5085
  { env, timeout: 15e3, windowsHide: true, maxBuffer: 1024 * 1024 },
@@ -5018,7 +5305,7 @@ var WsCdpClient = class {
5018
5305
  };
5019
5306
 
5020
5307
  // src/daemon/workbuddyApp/keeper.ts
5021
- import { posix as posix2, win32 as win323 } from "path";
5308
+ import { posix as posix2, win32 as win324 } from "path";
5022
5309
  var DEFAULT_CDP_PORT = 39217;
5023
5310
  var ENV_NAME = "WORKBUDDY_REMOTE_DEBUGGING_PORT";
5024
5311
  var RESTART_GAP_MS = 30 * 60 * 1e3;
@@ -5030,7 +5317,7 @@ var VERIFY_MIN_MS = 30 * 1e3;
5030
5317
  var VERIFY_MAX_MS = 60 * 1e3;
5031
5318
  var VERIFY_STEP_MS = 5 * 1e3;
5032
5319
  var defaultExec = (file3, args, timeoutMs = 1e4) => new Promise((done) => {
5033
- execFile5(file3, args, { timeout: timeoutMs, windowsHide: true, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 }, (err, stdout2) => {
5320
+ execFile6(file3, args, { timeout: timeoutMs, windowsHide: true, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 }, (err, stdout2) => {
5034
5321
  const code = err ? typeof err.code === "number" ? err.code : -1 : 0;
5035
5322
  done({ code, stdout: String(stdout2 ?? "") });
5036
5323
  });
@@ -5080,21 +5367,21 @@ function cleanLaunchEnv(src = process.env, shim = shimDir()) {
5080
5367
  }
5081
5368
  var REMEMBER_EXE_MS = 30 * 60 * 1e3;
5082
5369
  var AWAY_IDLE_MS = 5 * 60 * 1e3;
5083
- var keeperThrottleFile = () => join20(deskbuddyHome(), "wbapp", "keeper.json");
5370
+ var keeperThrottleFile = () => join21(deskbuddyHome(), "wbapp", "keeper.json");
5084
5371
  var filePersist = {
5085
5372
  load: () => {
5086
5373
  try {
5087
- return JSON.parse(readFileSync21(keeperThrottleFile(), "utf8"));
5374
+ return JSON.parse(readFileSync22(keeperThrottleFile(), "utf8"));
5088
5375
  } catch {
5089
5376
  return null;
5090
5377
  }
5091
5378
  },
5092
5379
  save: (s) => {
5093
5380
  try {
5094
- mkdirSync19(join20(deskbuddyHome(), "wbapp"), { recursive: true });
5381
+ mkdirSync20(join21(deskbuddyHome(), "wbapp"), { recursive: true });
5095
5382
  const f = keeperThrottleFile();
5096
- writeFileSync19(f + ".tmp", JSON.stringify(s));
5097
- renameSync13(f + ".tmp", f);
5383
+ writeFileSync20(f + ".tmp", JSON.stringify(s));
5384
+ renameSync14(f + ".tmp", f);
5098
5385
  } catch {
5099
5386
  }
5100
5387
  }
@@ -5126,7 +5413,7 @@ function defaultWorkbuddyAppPath() {
5126
5413
  }
5127
5414
  function isValidAppPath(p, platform = process.platform) {
5128
5415
  if (typeof p !== "string" || !p) return false;
5129
- if (platform === "win32") return win323.isAbsolute(p) && /^[a-z]:[\\/]/i.test(p) && win323.basename(p).toLowerCase() === "workbuddy.exe";
5416
+ if (platform === "win32") return win324.isAbsolute(p) && /^[a-z]:[\\/]/i.test(p) && win324.basename(p).toLowerCase() === "workbuddy.exe";
5130
5417
  return posix2.isAbsolute(p) && posix2.basename(p) === "WorkBuddy.app";
5131
5418
  }
5132
5419
  var HUNG_RESTART_MS = 20 * 60 * 1e3;
@@ -5278,7 +5565,7 @@ function workbuddyBusy(now = Date.now(), dir2 = stateDir(), alive = isAlive) {
5278
5565
  for (const f of readdirSync9(dir2)) {
5279
5566
  if (!f.endsWith(".json")) continue;
5280
5567
  try {
5281
- const s = JSON.parse(readFileSync21(join20(dir2, f), "utf8"));
5568
+ const s = JSON.parse(readFileSync22(join21(dir2, f), "utf8"));
5282
5569
  if (s.tool !== "workbuddy" || s.state !== "watch" && s.state !== "ask_approval") continue;
5283
5570
  if (typeof s.pid === "number" && s.pid > 0) {
5284
5571
  if (alive(s.pid, s.pidName)) return true;
@@ -6535,11 +6822,11 @@ var keyCache = null;
6535
6822
  function defaultDiscover() {
6536
6823
  if (process.platform === "win32" || typeof process.getuid !== "function") return null;
6537
6824
  try {
6538
- const ps = execFileSync9("ps", ["-A", "-ww", "-o", "pid=,uid=,args="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
6825
+ const ps = execFileSync10("ps", ["-A", "-ww", "-o", "pid=,uid=,args="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
6539
6826
  const hit = parseDumateServe(ps, process.getuid());
6540
6827
  if (!hit) return null;
6541
6828
  if (keyCache && keyCache.pid === hit.pid && keyCache.port === hit.port) return keyCache;
6542
- const env = execFileSync9("ps", ["eww", "-p", String(hit.pid), "-o", "command="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
6829
+ const env = execFileSync10("ps", ["eww", "-p", String(hit.pid), "-o", "command="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
6543
6830
  const key = parseInappKey(env);
6544
6831
  keyCache = key ? { ...hit, key } : null;
6545
6832
  return keyCache;
@@ -6649,7 +6936,7 @@ function scanSessionDirs(root, now, maxAgeMs = ACTIVE_DIR_MS) {
6649
6936
  const out = [];
6650
6937
  const list = (p) => {
6651
6938
  try {
6652
- return readdirSync10(p, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => join21(p, d.name));
6939
+ return readdirSync10(p, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => join22(p, d.name));
6653
6940
  } catch {
6654
6941
  return [];
6655
6942
  }
@@ -7280,7 +7567,7 @@ var DumateWatch = class {
7280
7567
  const now = this.#now();
7281
7568
  if (now - this.#scanAt >= SCAN_DIRS_MS) {
7282
7569
  this.#scanAt = now;
7283
- for (const d of (this.#d.sessionDirs ?? (() => scanSessionDirs(join21(qianfanHome(), "workspace", "sessions"), now)))()) {
7570
+ for (const d of (this.#d.sessionDirs ?? (() => scanSessionDirs(join22(qianfanHome(), "workspace", "sessions"), now)))()) {
7284
7571
  if (!this.#dirs.has(dirKey(d))) this.#touchDir(d, now);
7285
7572
  }
7286
7573
  }
@@ -7392,9 +7679,9 @@ function runHook(node, input, agentPid, tool = "dumate") {
7392
7679
  }
7393
7680
 
7394
7681
  // src/daemon/qoderApp/keeper.ts
7395
- import { existsSync as existsSync19, mkdirSync as mkdirSync20, readdirSync as readdirSync11, readFileSync as readFileSync22, renameSync as renameSync14, writeFileSync as writeFileSync20 } from "fs";
7682
+ import { existsSync as existsSync19, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as readFileSync23, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
7396
7683
  import { homedir as homedir7 } from "os";
7397
- import { join as join22, win32 as win324 } from "path";
7684
+ import { join as join23, win32 as win325 } from "path";
7398
7685
  var WAKE_LAUNCH_GAP_MS2 = 60 * 1e3;
7399
7686
  var RESTART_GAP_MS2 = 30 * 60 * 1e3;
7400
7687
  var RESTART_DAILY_MAX2 = 3;
@@ -7406,7 +7693,7 @@ function winBrandMainProc(procs, exe) {
7406
7693
  for (const p of procs) {
7407
7694
  const argv = winSplitArgs(p.cmdline);
7408
7695
  const first = argv[0] ?? "";
7409
- if (win324.basename(first).toLowerCase() !== want) continue;
7696
+ if (win325.basename(first).toLowerCase() !== want) continue;
7410
7697
  const rest = argv.slice(1);
7411
7698
  if (rest.some((a) => a.startsWith("--type=") || !a.startsWith("-") || /\.(c|m)?js$/i.test(a))) continue;
7412
7699
  return { pid: p.pid, exe: first };
@@ -7422,7 +7709,7 @@ function winBrandMains(procs, exe) {
7422
7709
  return out;
7423
7710
  }
7424
7711
  function isWinAppExe(p, exe) {
7425
- return typeof p === "string" && /^[a-z]:[\\/]/i.test(p) && win324.basename(p).toLowerCase() === exe.toLowerCase();
7712
+ return typeof p === "string" && /^[a-z]:[\\/]/i.test(p) && win325.basename(p).toLowerCase() === exe.toLowerCase();
7426
7713
  }
7427
7714
  var WIN_SESSION_PS = `$me = (Get-Process -Id $PID).SessionId; $ex = @(Get-Process -Name explorer -ErrorAction SilentlyContinue | ForEach-Object { $_.SessionId }) -join ','; Write-Output ("{0}|{1}" -f $me, $ex)`;
7428
7715
  function parseWinSession(out) {
@@ -7457,7 +7744,7 @@ function toolBusy(tool, now = Date.now(), dir2 = stateDir(), alive = isAlive) {
7457
7744
  for (const f of readdirSync11(dir2)) {
7458
7745
  if (!f.endsWith(".json")) continue;
7459
7746
  try {
7460
- const s = JSON.parse(readFileSync22(join22(dir2, f), "utf8"));
7747
+ const s = JSON.parse(readFileSync23(join23(dir2, f), "utf8"));
7461
7748
  if (s.tool !== tool || s.state !== "watch" && s.state !== "ask_approval") continue;
7462
7749
  if (typeof s.pid === "number" && s.pid > 0) {
7463
7750
  if (alive(s.pid, s.pidName)) return true;
@@ -7470,7 +7757,7 @@ function toolBusy(tool, now = Date.now(), dir2 = stateDir(), alive = isAlive) {
7470
7757
  return false;
7471
7758
  }
7472
7759
  function defaultThrottleFile() {
7473
- return join22(deskbuddyHome(), "qoderapp", "keeper.json");
7760
+ return join23(deskbuddyHome(), "qoderapp", "keeper.json");
7474
7761
  }
7475
7762
  var QoderCdpKeeper = class {
7476
7763
  #d;
@@ -7560,7 +7847,7 @@ var QoderCdpKeeper = class {
7560
7847
  /** 节流状态(按品牌一份,落盘;读不出当没有) */
7561
7848
  #loadThrottle() {
7562
7849
  try {
7563
- const all = JSON.parse(readFileSync22(this.#file(), "utf8"));
7850
+ const all = JSON.parse(readFileSync23(this.#file(), "utf8"));
7564
7851
  const t = all?.[this.#d.brand.tool] ?? {};
7565
7852
  const out = { lastLaunch: Number(t.lastLaunch) || 0, lastRestart: Number(t.lastRestart) || 0, day: typeof t.day === "string" ? t.day : "", restarts: Number(t.restarts) || 0 };
7566
7853
  if (this.#d.brand.win && isWinAppExe(t.appExe, this.#d.brand.win.exe)) out.appExe = t.appExe;
@@ -7574,14 +7861,14 @@ var QoderCdpKeeper = class {
7574
7861
  try {
7575
7862
  let all = {};
7576
7863
  try {
7577
- all = JSON.parse(readFileSync22(f, "utf8"));
7864
+ all = JSON.parse(readFileSync23(f, "utf8"));
7578
7865
  } catch {
7579
7866
  all = {};
7580
7867
  }
7581
7868
  all[this.#d.brand.tool] = t;
7582
- mkdirSync20(join22(f, ".."), { recursive: true });
7583
- writeFileSync20(f + ".tmp", JSON.stringify(all));
7584
- renameSync14(f + ".tmp", f);
7869
+ mkdirSync21(join23(f, ".."), { recursive: true });
7870
+ writeFileSync21(f + ".tmp", JSON.stringify(all));
7871
+ renameSync15(f + ".tmp", f);
7585
7872
  } catch {
7586
7873
  }
7587
7874
  }
@@ -7661,7 +7948,7 @@ var QoderCdpKeeper = class {
7661
7948
  }
7662
7949
  if (this.#platform() !== "darwin") return null;
7663
7950
  const name = this.#d.brand.macApp.split("/").pop() ?? "";
7664
- for (const p of [this.#d.brand.macApp, join22(homedir7(), "Applications", name)]) if (existsSync19(p)) return p;
7951
+ for (const p of [this.#d.brand.macApp, join23(homedir7(), "Applications", name)]) if (existsSync19(p)) return p;
7665
7952
  return null;
7666
7953
  }
7667
7954
  /** 一轮:健康检查 → 活着核对属主。🔴 平时不重启 App;只有端口无响应满 HUNG_RESTART_MS 时按节流与在场规则重启 */
@@ -7928,17 +8215,17 @@ var DUMATE_BRAND = {
7928
8215
  installPaths: () => {
7929
8216
  const out = [];
7930
8217
  const la = process.env.LOCALAPPDATA;
7931
- if (la) out.push(join23(la, "Programs", "DuMate", "DuMate.exe"), join23(la, "Programs", "qianfan-desktop-app", "DuMate.exe"));
7932
- for (const pf of [process.env.ProgramFiles, process.env["ProgramFiles(x86)"]]) if (pf) out.push(join23(pf, "DuMate", "DuMate.exe"));
8218
+ if (la) out.push(join24(la, "Programs", "DuMate", "DuMate.exe"), join24(la, "Programs", "qianfan-desktop-app", "DuMate.exe"));
8219
+ for (const pf of [process.env.ProgramFiles, process.env["ProgramFiles(x86)"]]) if (pf) out.push(join24(pf, "DuMate", "DuMate.exe"));
7933
8220
  return out;
7934
8221
  }
7935
8222
  }
7936
8223
  };
7937
8224
  var DM_DOWN_ROUNDS = 2;
7938
8225
  var DM_ACTIVE_MS = 10 * 60 * 1e3;
7939
- function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsRoot = join23(qianfanHome(), "workspace", "sessions")) {
8226
+ function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsRoot = join24(qianfanHome(), "workspace", "sessions")) {
7940
8227
  let latest = -1;
7941
- const xdg = join23(dataHome, "qianfan_desk_xdg");
8228
+ const xdg = join24(dataHome, "qianfan_desk_xdg");
7942
8229
  let users = [];
7943
8230
  try {
7944
8231
  users = readdirSync12(xdg);
@@ -7947,14 +8234,14 @@ function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsR
7947
8234
  }
7948
8235
  let found = false;
7949
8236
  for (const u of users) {
7950
- const dir2 = join23(xdg, u, "data", "opencode");
8237
+ const dir2 = join24(xdg, u, "data", "opencode");
7951
8238
  try {
7952
- latest = Math.max(latest, statSync10(join23(dir2, "opencode.db")).mtimeMs);
8239
+ latest = Math.max(latest, statSync10(join24(dir2, "opencode.db")).mtimeMs);
7953
8240
  found = true;
7954
8241
  } catch {
7955
8242
  }
7956
8243
  try {
7957
- const w = statSync10(join23(dir2, "opencode.db-wal"));
8244
+ const w = statSync10(join24(dir2, "opencode.db-wal"));
7958
8245
  if (w.size > 0) latest = Math.max(latest, w.mtimeMs);
7959
8246
  } catch {
7960
8247
  }
@@ -7965,7 +8252,7 @@ function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsR
7965
8252
  return "idle";
7966
8253
  }
7967
8254
  function dmKeeperThrottleFile() {
7968
- return join23(deskbuddyHome(), "dmapp", "keeper.json");
8255
+ return join24(deskbuddyHome(), "dmapp", "keeper.json");
7969
8256
  }
7970
8257
  var DumateKeeper = class {
7971
8258
  #d;
@@ -8051,302 +8338,117 @@ var DumateKeeper = class {
8051
8338
  };
8052
8339
 
8053
8340
  // src/daemon/dumateApp/shortcuts.ts
8054
- var LNK_LIST_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
8055
- $s = New-Object -ComObject WScript.Shell
8056
- $dirs = @(@([Environment]::GetFolderPath('Programs'), $true), @([Environment]::GetFolderPath('CommonPrograms'), $true), @([Environment]::GetFolderPath('Desktop'), $false), @([Environment]::GetFolderPath('CommonDesktopDirectory'), $false), @((Join-Path $env:APPDATA 'Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar'), $false))
8057
- $out = @()
8058
- foreach ($d in $dirs) {
8059
- if (-not $d[0] -or -not (Test-Path -LiteralPath $d[0])) { continue }
8060
- foreach ($f in (Get-ChildItem -LiteralPath $d[0] -Filter *.lnk -Recurse:$d[1] -ErrorAction SilentlyContinue)) {
8061
- try { $l = $s.CreateShortcut($f.FullName); $out += [pscustomobject]@{ path = $f.FullName; target = [string]$l.TargetPath; args = [string]$l.Arguments } } catch {}
8062
- }
8063
- }
8064
- ConvertTo-Json -InputObject @($out) -Compress`;
8065
- var LNK_WRITE_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
8066
- $ops = $env:DB_LNK_OPS | ConvertFrom-Json
8067
- $s = New-Object -ComObject WScript.Shell
8068
- $out = @()
8069
- foreach ($o in @($ops)) {
8070
- $ok = $false
8071
- try {
8072
- $l = $s.CreateShortcut([string]$o.path)
8073
- if ([IO.Path]::GetFileName([string]$l.TargetPath) -ieq 'DuMate.exe') { $l.Arguments = [string]$o.args; $l.Save(); $ok = $true }
8074
- } catch {}
8075
- $out += [pscustomobject]@{ path = [string]$o.path; ok = $ok }
8076
- }
8077
- ConvertTo-Json -InputObject @($out) -Compress`;
8078
- function portFlag(port) {
8079
- return `--remote-debugging-port=${port}`;
8080
- }
8081
- function hasPortFlag(args) {
8082
- return /(^|\s)--remote-debugging-port(=|\s|$)/.test(args);
8083
- }
8084
- function isDumateLnk(l) {
8085
- return win325.basename(l.target || "").toLowerCase() === "dumate.exe";
8086
- }
8087
- var keyOf = (p) => p.toLowerCase();
8088
- function planPatch(list, records, port) {
8089
- const out = { ...records };
8090
- const writes = [];
8091
- for (const l of list) {
8092
- if (!isDumateLnk(l) || hasPortFlag(l.args)) continue;
8093
- const orig = l.args;
8094
- const patched = orig.trim() ? `${orig.trim()} ${portFlag(port)}` : portFlag(port);
8095
- writes.push({ path: l.path, args: patched });
8096
- out[keyOf(l.path)] = { path: l.path, orig, patched };
8097
- }
8098
- return { writes, records: out };
8099
- }
8100
- function planRestore(list, records, port) {
8101
- const byKey = new Map(list.map((l) => [keyOf(l.path), l]));
8102
- const flag = portFlag(port);
8103
- const writes = [];
8104
- for (const r of Object.values(records)) {
8105
- const cur = byKey.get(keyOf(r.path));
8106
- if (!cur || !isDumateLnk(cur)) continue;
8107
- if (cur.args === r.patched) writes.push({ path: cur.path, args: r.orig });
8108
- else if (cur.args.split(/\s+/).includes(flag)) writes.push({ path: cur.path, args: cur.args.split(/\s+/).filter((x) => x && x !== flag).join(" ") });
8109
- }
8110
- return writes;
8111
- }
8112
- function shortcutsFile() {
8113
- return join24(deskbuddyHome(), "dmapp", "shortcuts.json");
8114
- }
8115
- function loadRecords(file3 = shortcutsFile()) {
8341
+ function dmPort() {
8116
8342
  try {
8117
- const v = JSON.parse(readFileSync23(file3, "utf8"));
8118
- if (!v || typeof v !== "object") return {};
8119
- const out = {};
8120
- for (const [k, r] of Object.entries(v)) {
8121
- if (r && typeof r.path === "string" && typeof r.orig === "string" && typeof r.patched === "string") out[k] = { path: r.path, orig: r.orig, patched: r.patched };
8122
- }
8123
- return out;
8343
+ return loadConfig().dumateCdpPort ?? DM_DEFAULT_CDP_PORT;
8124
8344
  } catch {
8125
- return {};
8345
+ return DM_DEFAULT_CDP_PORT;
8126
8346
  }
8127
8347
  }
8128
- function saveRecords(r, file3 = shortcutsFile()) {
8348
+ function shortcutsWanted() {
8129
8349
  try {
8130
- mkdirSync21(join24(file3, ".."), { recursive: true });
8131
- writeFileSync21(file3 + ".tmp", JSON.stringify(r, null, 2));
8132
- renameSync15(file3 + ".tmp", file3);
8350
+ const c = loadConfig();
8351
+ return c.enabledTools.includes("dumate") && c.dumateShortcuts !== false;
8133
8352
  } catch {
8353
+ return false;
8134
8354
  }
8135
8355
  }
8136
- function parseJsonArray(out) {
8137
- if (out === null) return null;
8138
- try {
8139
- const v = JSON.parse(out.trim() || "[]");
8140
- return Array.isArray(v) ? v : null;
8141
- } catch {
8142
- return null;
8143
- }
8356
+ var DUMATE_SHORTCUT_APP = {
8357
+ label: "\u767E\u5EA6\u642D\u5B50",
8358
+ appName: "DuMate",
8359
+ exe: "DuMate.exe",
8360
+ dir: "dmapp",
8361
+ stem: "shortcuts",
8362
+ port: dmPort,
8363
+ wanted: shortcutsWanted,
8364
+ off: () => loadConfig().dumateShortcuts === false,
8365
+ skipEnv: "DESKBUDDY_SKIP_DM_LNK"
8366
+ };
8367
+ function ensureDumateShortcuts(d, ps = defaultPs) {
8368
+ return ensureAppShortcuts(DUMATE_SHORTCUT_APP, d, ps);
8144
8369
  }
8145
- function parseList(out) {
8146
- const arr = parseJsonArray(out);
8147
- if (!arr) return null;
8148
- return arr.filter((x) => !!x && typeof x.path === "string" && typeof x.target === "string").map((x) => ({ path: x.path, target: x.target, args: typeof x.args === "string" ? x.args : "" }));
8370
+ function ensureDumateShortcutsSync(d, ps = defaultPsSync) {
8371
+ ensureAppShortcutsSync(DUMATE_SHORTCUT_APP, d, ps);
8149
8372
  }
8150
- var psArgs = (script) => ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script];
8151
- var defaultPs = (script, env) => new Promise((done) => {
8152
- execFile6(
8153
- "powershell.exe",
8154
- psArgs(script),
8155
- { timeout: 2e4, windowsHide: true, encoding: "utf8", maxBuffer: 8 * 1024 * 1024, env: { ...process.env, ...env ?? {} } },
8156
- (err, stdout2) => done(err ? null : String(stdout2 ?? ""))
8157
- );
8158
- });
8159
- var defaultPsSync = (script, env) => {
8160
- try {
8161
- return execFileSync10("powershell.exe", psArgs(script), { timeout: 2e4, windowsHide: true, encoding: "utf8", maxBuffer: 8 * 1024 * 1024, env: { ...process.env, ...env ?? {} }, stdio: ["ignore", "pipe", "ignore"] });
8162
- } catch {
8163
- return null;
8373
+ function restoreDumateShortcutsSync(d, ps = defaultPsSync) {
8374
+ restoreAppShortcutsSync(DUMATE_SHORTCUT_APP, d, ps);
8375
+ }
8376
+
8377
+ // src/daemon/qoderApp/brand.ts
8378
+ var QODER_BRANDS = {
8379
+ qoder_cn: {
8380
+ tool: "qoder_cn",
8381
+ label: "Qoder CN",
8382
+ macApp: "/Applications/Qoder CN.app",
8383
+ macExe: "/Applications/Qoder CN.app/Contents/MacOS/Qoder CN",
8384
+ appName: "Qoder CN",
8385
+ bundleId: "com.qodercn.app",
8386
+ ua: /\bQoderCNApp\//,
8387
+ comm: /\/Qoder CN\.app\//,
8388
+ defaultPort: 39227
8389
+ },
8390
+ qoder: {
8391
+ tool: "qoder",
8392
+ label: "Qoder",
8393
+ macApp: "/Applications/Qoder.app",
8394
+ macExe: "/Applications/Qoder.app/Contents/MacOS/Qoder",
8395
+ appName: "Qoder",
8396
+ bundleId: "com.qoder.app",
8397
+ ua: /\bQoderApp\//,
8398
+ comm: /\/Qoder\.app\//,
8399
+ defaultPort: 39228
8164
8400
  }
8165
8401
  };
8166
- var FAIL_RETRY_MS = 24 * 60 * 60 * 1e3;
8167
- function active(d) {
8168
- if ((d.platform ?? process.platform) !== "win32") return false;
8169
- return !(d.skip ? d.skip() : process.env.DESKBUDDY_SKIP_DM_LNK === "1");
8402
+ function isQoderDesktopPid(pidName) {
8403
+ const n = String(pidName ?? "").replace(/\\/g, "/");
8404
+ return /\/Qoder( CN)?\.app\/Contents\/MacOS\/Qoder( CN)?$/i.test(n) || /(^|\/)Qoder( CN)?\.exe$/i.test(n);
8170
8405
  }
8171
- function portOf(d) {
8172
- if (d.port) return d.port();
8406
+
8407
+ // src/daemon/qoderApp/shortcuts.ts
8408
+ var QODER_SHORTCUT_EVERY_MS = 10 * 60 * 1e3;
8409
+ function portOf2(tool) {
8173
8410
  try {
8174
- return loadConfig().dumateCdpPort ?? DM_DEFAULT_CDP_PORT;
8411
+ const c = loadConfig();
8412
+ return (tool === "qoder_cn" ? c.qoderCnCdpPort : c.qoderCdpPort) ?? QODER_BRANDS[tool].defaultPort;
8175
8413
  } catch {
8176
- return DM_DEFAULT_CDP_PORT;
8414
+ return QODER_BRANDS[tool].defaultPort;
8177
8415
  }
8178
8416
  }
8179
- var nowOf = (d) => d.now ? d.now() : Date.now();
8180
- var failFileOf = (d) => d.failFile ?? join24(deskbuddyHome(), "dmapp", "shortcuts-fail.json");
8181
- var lockFileOf = (d) => d.lockFile ?? join24(deskbuddyHome(), "dmapp", "shortcuts.lock");
8182
- function shortcutsWanted() {
8417
+ function qoderShortcutsWanted(tool) {
8183
8418
  try {
8184
8419
  const c = loadConfig();
8185
- return c.enabledTools.includes("dumate") && c.dumateShortcuts !== false;
8420
+ return c.enabledTools.includes(tool) && c.qoderShortcuts !== false;
8186
8421
  } catch {
8187
8422
  return false;
8188
8423
  }
8189
8424
  }
8190
- function loadFails(d) {
8191
- try {
8192
- const v = JSON.parse(readFileSync23(failFileOf(d), "utf8"));
8193
- const out = {};
8194
- for (const [k, t] of Object.entries(v ?? {})) if (typeof t === "number") out[k] = t;
8195
- return out;
8196
- } catch {
8197
- return {};
8198
- }
8199
- }
8200
- function saveFails(d, f) {
8201
- const file3 = failFileOf(d);
8202
- try {
8203
- mkdirSync21(join24(file3, ".."), { recursive: true });
8204
- writeFileSync21(file3 + ".tmp", JSON.stringify(f));
8205
- renameSync15(file3 + ".tmp", file3);
8206
- } catch {
8207
- }
8208
- }
8209
- function lock(d) {
8210
- return acquireLock({ path: lockFileOf(d), pid: process.pid, now: () => nowOf(d), alive: pidAlive2 });
8211
- }
8212
- function sleepSync2(ms) {
8213
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
8214
- }
8215
- function lockSync(d, waitMs = 3e4) {
8216
- for (let waited = 0; ; waited += 500) {
8217
- const r = lock(d);
8218
- if (r || waited >= waitMs) return r;
8219
- sleepSync2(500);
8220
- }
8221
- }
8222
- function applyResults(d, writes, results, records, prev) {
8223
- const okSet = new Set((results ?? []).filter((r) => r && r.ok === true && typeof r.path === "string").map((r) => keyOf(r.path)));
8224
- const out = { ...records };
8225
- const fails = loadFails(d);
8226
- const now = nowOf(d);
8227
- for (const w of writes) {
8228
- const k = keyOf(w.path);
8229
- if (okSet.has(k)) {
8230
- d.log(`\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u5DF2\u5E26\u4E0A\u8C03\u8BD5\u7AEF\u53E3\uFF1A${w.path}`);
8231
- delete fails[k];
8232
- continue;
8233
- }
8234
- if (!fails[k] || now - fails[k] >= FAIL_RETRY_MS) d.log(`\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u6539\u4E0D\u4E86\uFF08\u53EF\u80FD\u8981\u7BA1\u7406\u5458\u6743\u9650\u6216\u88AB\u5360\u7528\uFF09\uFF0C\u8FD9\u4E2A\u5165\u53E3\u6253\u5F00\u7684 DuMate \u4E0D\u5E26\u8C03\u8BD5\u7AEF\u53E3\uFF08\u4E00\u5929\u540E\u518D\u8BD5\uFF09\uFF1A${w.path}`);
8235
- fails[k] = now;
8236
- if (prev[k]) out[k] = prev[k];
8237
- else delete out[k];
8238
- }
8239
- saveFails(d, fails);
8240
- return out;
8241
- }
8242
- function restoreWith(d, list, records, write3) {
8243
- const writes = planRestore(list, records, portOf(d));
8244
- const finish = (results) => {
8245
- const ok = new Set((results ?? []).filter((r2) => r2 && r2.ok === true && typeof r2.path === "string").map((r2) => keyOf(r2.path)));
8246
- const keep = {};
8247
- for (const w of writes) {
8248
- if (ok.has(keyOf(w.path))) d.log(`\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u5DF2\u8FD8\u539F\uFF1A${w.path}`);
8249
- else {
8250
- d.log(`\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u8FD8\u539F\u5931\u8D25\uFF1A${w.path}`);
8251
- const r2 = records[keyOf(w.path)];
8252
- if (r2) keep[keyOf(w.path)] = r2;
8253
- }
8254
- }
8255
- return keep;
8425
+ function qoderShortcutApp(tool) {
8426
+ const b = QODER_BRANDS[tool];
8427
+ return {
8428
+ label: b.label,
8429
+ appName: b.label,
8430
+ exe: `${b.appName}.exe`,
8431
+ dir: "qoderapp",
8432
+ stem: `shortcuts-${tool}`,
8433
+ port: () => portOf2(tool),
8434
+ wanted: () => qoderShortcutsWanted(tool),
8435
+ off: () => loadConfig().qoderShortcuts === false,
8436
+ skipEnv: "DESKBUDDY_SKIP_QODER_LNK"
8256
8437
  };
8257
- if (writes.length === 0) return {};
8258
- const r = write3(writes);
8259
- return r instanceof Promise ? r.then(finish) : finish(r);
8260
8438
  }
8261
- async function ensureDumateShortcuts(d, ps = defaultPs) {
8262
- if (!active(d)) return;
8263
- const wanted = d.enabled ?? shortcutsWanted;
8264
- if (!wanted()) return;
8265
- const release2 = lock(d);
8266
- if (!release2) return;
8267
- try {
8268
- const list = parseList(await ps(LNK_LIST_PS));
8269
- if (!list) return;
8270
- const prev = loadRecords(d.file);
8271
- const fails = loadFails(d);
8272
- const now = nowOf(d);
8273
- const plan = planPatch(list, prev, portOf(d));
8274
- const writes = plan.writes.filter((w) => {
8275
- const t = fails[keyOf(w.path)];
8276
- return !t || now - t >= FAIL_RETRY_MS;
8277
- });
8278
- if (writes.length === 0) return;
8279
- const skipped = new Set(plan.writes.filter((w) => !writes.includes(w)).map((w) => keyOf(w.path)));
8280
- const records = { ...plan.records };
8281
- for (const k of skipped) {
8282
- if (prev[k]) records[k] = prev[k];
8283
- else delete records[k];
8284
- }
8285
- const results = parseJsonArray(await ps(LNK_WRITE_PS, { DB_LNK_OPS: JSON.stringify(writes) }));
8286
- let next = applyResults(d, writes, results, records, prev);
8287
- if (!wanted()) {
8288
- const list2 = parseList(await ps(LNK_LIST_PS));
8289
- if (list2) next = await restoreWith(d, list2, next, async (ops) => parseJsonArray(await ps(LNK_WRITE_PS, { DB_LNK_OPS: JSON.stringify(ops) })));
8290
- }
8291
- saveRecords(next, d.file);
8292
- } finally {
8293
- release2();
8294
- }
8439
+ function ensureQoderShortcuts(tool, d, ps = defaultPs) {
8440
+ return ensureAppShortcuts(qoderShortcutApp(tool), d, ps);
8295
8441
  }
8296
- function ensureDumateShortcutsSync(d, ps = defaultPsSync) {
8297
- if (!active(d)) return;
8298
- let off = false;
8299
- try {
8300
- off = loadConfig().dumateShortcuts === false;
8301
- } catch {
8302
- off = false;
8303
- }
8304
- if (off) return restoreDumateShortcutsSync(d, ps);
8305
- const release2 = lockSync(d);
8306
- if (!release2) {
8307
- d.log("\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u6B63\u88AB\u53E6\u4E00\u4E2A DeskBuddy \u8FDB\u7A0B\u4FEE\u6539\uFF0C\u8FD9\u6B21\u6CA1\u6539\uFF08\u5B88\u62A4\u8FDB\u7A0B\u4F1A\u518D\u8865\uFF09");
8308
- return;
8309
- }
8310
- try {
8311
- const list = parseList(ps(LNK_LIST_PS));
8312
- if (!list) {
8313
- d.log("\u8BFB\u4E0D\u4E86\u5F00\u59CB\u83DC\u5355 / \u684C\u9762\u7684\u5FEB\u6377\u65B9\u5F0F\uFF0C\u767E\u5EA6\u642D\u5B50\u7684\u5FEB\u6377\u65B9\u5F0F\u6CA1\u6539\uFF08\u5B88\u62A4\u8FDB\u7A0B\u4F1A\u518D\u8BD5\uFF09");
8314
- return;
8315
- }
8316
- const prev = loadRecords(d.file);
8317
- const { writes, records } = planPatch(list, prev, portOf(d));
8318
- if (writes.length === 0) return;
8319
- const results = parseJsonArray(ps(LNK_WRITE_PS, { DB_LNK_OPS: JSON.stringify(writes) }));
8320
- saveRecords(applyResults(d, writes, results, records, prev), d.file);
8321
- } finally {
8322
- release2();
8323
- }
8442
+ function ensureQoderShortcutsSync(tool, d, ps = defaultPsSync) {
8443
+ ensureAppShortcutsSync(qoderShortcutApp(tool), d, ps);
8324
8444
  }
8325
- function restoreDumateShortcutsSync(d, ps = defaultPsSync) {
8326
- if (!active(d)) return;
8327
- const records = loadRecords(d.file);
8328
- if (Object.keys(records).length === 0) return;
8329
- const release2 = lockSync(d);
8330
- if (!release2) {
8331
- d.log("\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u6B63\u88AB\u53E6\u4E00\u4E2A DeskBuddy \u8FDB\u7A0B\u4FEE\u6539\uFF0C\u8FD9\u6B21\u6CA1\u8FD8\u539F\uFF08\u8BB0\u5F55\u4FDD\u7559\uFF0C\u4E0B\u6B21 disable \u518D\u8BD5\uFF09");
8332
- return;
8333
- }
8334
- try {
8335
- const list = parseList(ps(LNK_LIST_PS));
8336
- if (!list) {
8337
- d.log("\u8BFB\u4E0D\u4E86\u5FEB\u6377\u65B9\u5F0F\uFF0C\u767E\u5EA6\u642D\u5B50\u5FEB\u6377\u65B9\u5F0F\u6CA1\u8FD8\u539F\uFF08\u8BB0\u5F55\u4FDD\u7559\uFF0C\u4E0B\u6B21 disable \u518D\u8BD5\uFF09");
8338
- return;
8339
- }
8340
- const keep = restoreWith(d, list, loadRecords(d.file), (ops) => parseJsonArray(ps(LNK_WRITE_PS, { DB_LNK_OPS: JSON.stringify(ops) })));
8341
- saveRecords(keep, d.file);
8342
- } finally {
8343
- release2();
8344
- }
8445
+ function restoreQoderShortcutsSync(tool, d, ps = defaultPsSync) {
8446
+ restoreAppShortcutsSync(qoderShortcutApp(tool), d, ps);
8345
8447
  }
8346
8448
 
8347
8449
  // src/adapters/traeHook.ts
8348
8450
  import { chmodSync as chmodSync5, existsSync as existsSync20, mkdirSync as mkdirSync22, readFileSync as readFileSync24, realpathSync as realpathSync5, renameSync as renameSync16, rmSync as rmSync13, statSync as statSync11, writeFileSync as writeFileSync22 } from "fs";
8349
- import { dirname as dirname13, join as join25 } from "path";
8451
+ import { dirname as dirname13, join as join26 } from "path";
8350
8452
  var TRAE_EVENTS = ["UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop", "Notification"];
8351
8453
  var TRAE_NOTICE_TYPES = ["permission_prompt", "ask_user_question", "document_review", "browser_interaction"];
8352
8454
  var TRAE_NOTICE_MATCHER = `^(${TRAE_NOTICE_TYPES.join("|")})$`;
@@ -8434,7 +8536,7 @@ function strip(f, scripts) {
8434
8536
  }
8435
8537
  function installTraeHook(path, hookPath, events = TRAE_EVENTS, platform = process.platform) {
8436
8538
  const f = readHooksFile(path);
8437
- const gatePath = join25(dirname13(hookPath), "gate.cjs");
8539
+ const gatePath = join26(dirname13(hookPath), "gate.cjs");
8438
8540
  const before = JSON.stringify(f);
8439
8541
  strip(f, [hookPath, gatePath]);
8440
8542
  if (f.version === void 0) f.version = 1;
@@ -8453,7 +8555,7 @@ function installTraeHook(path, hookPath, events = TRAE_EVENTS, platform = proces
8453
8555
  function uninstallTraeHook(path, hookPath) {
8454
8556
  if (!existsSync20(path)) return;
8455
8557
  const f = readHooksFile(path);
8456
- if (strip(f, [hookPath, join25(dirname13(hookPath), "gate.cjs")])) writeHooksFile(path, f);
8558
+ if (strip(f, [hookPath, join26(dirname13(hookPath), "gate.cjs")])) writeHooksFile(path, f);
8457
8559
  }
8458
8560
  function isTraeHookInstalled(path, hookPath) {
8459
8561
  try {
@@ -8471,11 +8573,11 @@ import { existsSync as existsSync22, readFileSync as readFileSync26 } from "fs";
8471
8573
 
8472
8574
  // src/adapters/cbChannel.ts
8473
8575
  import { chmodSync as chmodSync6, existsSync as existsSync21, lstatSync as lstatSync2, mkdirSync as mkdirSync23, readFileSync as readFileSync25, realpathSync as realpathSync6, renameSync as renameSync17, statSync as statSync12, writeFileSync as writeFileSync23 } from "fs";
8474
- import { dirname as dirname14, join as join26 } from "path";
8576
+ import { dirname as dirname14, join as join27 } from "path";
8475
8577
  var CB_MCP_NAME = "deskbuddy";
8476
8578
  var CB_CHANNEL_SCRIPT = "cbchannel.cjs";
8477
8579
  function cbChannelScript(hookPath) {
8478
- return join26(dirname14(hookPath), CB_CHANNEL_SCRIPT);
8580
+ return join27(dirname14(hookPath), CB_CHANNEL_SCRIPT);
8479
8581
  }
8480
8582
  function read(path) {
8481
8583
  if (!existsSync21(path)) return {};
@@ -8561,6 +8663,7 @@ var CC_CONFIG_PATHS = {
8561
8663
  // 千问办公只装状态上报:不装 gate.cjs、不装 rewake(选择题 / 授权由 daemon 的 qwenworkBridge 经 App 内置 MCP 回填)
8562
8664
  qwenwork: qwenworkSettingsPath
8563
8665
  };
8666
+ var qoderLnkLog = (m) => console.log(` ${m}`);
8564
8667
  var WINDOW_GATE_TOOLS = /* @__PURE__ */ new Set(["claude_code", "qoder_cn", "qoder"]);
8565
8668
  function codebuddyMcpPath() {
8566
8669
  return pathJoin(codebuddyConfigDir(), ".mcp.json");
@@ -8574,9 +8677,13 @@ function installCodebuddyTerminalApprovals(gatePath) {
8574
8677
  var ADAPTERS = {
8575
8678
  "cc-hook": {
8576
8679
  configPath: (tool) => CC_CONFIG_PATHS[tool]?.() ?? null,
8577
- install: (p, hook, events, tool) => installCcHook(p, hook, events, tool),
8680
+ install: (p, hook, events, tool) => {
8681
+ installCcHook(p, hook, events, tool);
8682
+ if ((tool === "qoder_cn" || tool === "qoder") && pathResolve(p) === pathResolve(CC_CONFIG_PATHS[tool]())) ensureQoderShortcutsSync(tool, { log: qoderLnkLog });
8683
+ },
8578
8684
  uninstall: (p, hook) => {
8579
8685
  uninstallCcHook(p, hook);
8686
+ for (const tool of ["qoder_cn", "qoder"]) if (pathResolve(p) === pathResolve(CC_CONFIG_PATHS[tool]())) restoreQoderShortcutsSync(tool, { log: qoderLnkLog });
8580
8687
  if (pathResolve(pathDirname(p)) === pathResolve(codebuddyConfigDir())) uninstallCbChannel(codebuddyMcpPath());
8581
8688
  },
8582
8689
  // Windows 上装出去的是正斜杠形式;JSON 里的反斜杠还会被转义成两个,原样搜不到
@@ -8710,7 +8817,7 @@ function subscribedEvents(registry, tool, fallback) {
8710
8817
  // src/wrap/pty.ts
8711
8818
  import { chmodSync as chmodSync7, existsSync as existsSync23, statSync as statSync13 } from "fs";
8712
8819
  import { createRequire as createRequire4 } from "module";
8713
- import { dirname as dirname15, join as join27 } from "path";
8820
+ import { dirname as dirname15, join as join28 } from "path";
8714
8821
  import { fileURLToPath as fileURLToPath4 } from "url";
8715
8822
  var req = createRequire4(import.meta.url);
8716
8823
  var VENDORED_PTY_PLATFORMS = ["darwin-arm64", "darwin-x64", "win32-arm64", "win32-x64"];
@@ -8720,8 +8827,8 @@ function hasVendoredPty(platform = process.platform, arch = process.arch) {
8720
8827
  function vendoredPtyDir(from = dirname15(fileURLToPath4(import.meta.url))) {
8721
8828
  let dir2 = from;
8722
8829
  for (let i = 0; i < 4; i++) {
8723
- const cand = join27(dir2, "vendor", "node-pty");
8724
- if (existsSync23(join27(cand, "package.json"))) return cand;
8830
+ const cand = join28(dir2, "vendor", "node-pty");
8831
+ if (existsSync23(join28(cand, "package.json"))) return cand;
8725
8832
  const up = dirname15(dir2);
8726
8833
  if (up === dir2) break;
8727
8834
  dir2 = up;
@@ -8731,7 +8838,7 @@ function vendoredPtyDir(from = dirname15(fileURLToPath4(import.meta.url))) {
8731
8838
  function fixSpawnHelper(ptyDir) {
8732
8839
  if (process.platform !== "darwin") return;
8733
8840
  try {
8734
- const helper = join27(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
8841
+ const helper = join28(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
8735
8842
  if (existsSync23(helper) && (statSync13(helper).mode & 73) === 0) chmodSync7(helper, 493);
8736
8843
  } catch {
8737
8844
  }
@@ -8836,7 +8943,7 @@ function accentLine(term, tabRow = /←.*[☐☒].*Submit.*→/) {
8836
8943
  }
8837
8944
 
8838
8945
  // src/commands/migrateQoder.ts
8839
- import { dirname as dirname17, join as join28 } from "path";
8946
+ import { dirname as dirname17, join as join29 } from "path";
8840
8947
 
8841
8948
  // src/core/detect.ts
8842
8949
  import { existsSync as existsSync24 } from "fs";
@@ -8940,7 +9047,7 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
8940
9047
  try {
8941
9048
  const cfg = loadConfig();
8942
9049
  const hookPath = installedHookPath();
8943
- const scripts = [hookPath, join28(dirname17(hookPath), "gate.cjs")];
9050
+ const scripts = [hookPath, join29(dirname17(hookPath), "gate.cjs")];
8944
9051
  if (!retagCcHook(qoderCnSettingsPath(), scripts, "qoder", "qoder_cn")) return false;
8945
9052
  const hadQoder = cfg.enabledTools.includes("qoder");
8946
9053
  let intl = false;
@@ -8971,24 +9078,24 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
8971
9078
  import { execFile as execFile9, execFileSync as execFileSync13 } from "child_process";
8972
9079
  import { chmodSync as chmodSync9, existsSync as existsSync25, mkdirSync as mkdirSync25, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "fs";
8973
9080
  import { homedir as homedir9 } from "os";
8974
- import { join as join32 } from "path";
9081
+ import { join as join33 } from "path";
8975
9082
 
8976
9083
  // src/daemon/executor.ts
8977
9084
  import { execFile as execFile7, execFileSync as execFileSync11 } from "child_process";
8978
9085
  import { homedir as homedir8 } from "os";
8979
- import { join as join30 } from "path";
9086
+ import { join as join31 } from "path";
8980
9087
 
8981
9088
  // src/core/codebuddyDirs.ts
8982
- import { join as join29, win32 as win326, posix as posix3 } from "path";
9089
+ import { join as join30, win32 as win326, posix as posix3 } from "path";
8983
9090
  function same(a, b, platform) {
8984
9091
  const pa = platform === "win32" ? win326.resolve(a).toLowerCase() : posix3.resolve(a);
8985
9092
  const pb = platform === "win32" ? win326.resolve(b).toLowerCase() : posix3.resolve(b);
8986
9093
  return pa === pb;
8987
9094
  }
8988
9095
  function workbuddyRunConfigDir(stateDir2, home, platform = process.platform) {
8989
- const wb = join29(home, ".workbuddy");
9096
+ const wb = join30(home, ".workbuddy");
8990
9097
  if (typeof stateDir2 !== "string" || !stateDir2) return wb;
8991
- const cb = join29(home, ".codebuddy");
9098
+ const cb = join30(home, ".codebuddy");
8992
9099
  if (same(stateDir2, cb, platform)) return cb;
8993
9100
  return wb;
8994
9101
  }
@@ -9080,7 +9187,7 @@ function buildSpawnPlan(cmd, cwd, gate, home = homedir8(), configDir, platform =
9080
9187
  file: file3,
9081
9188
  args: workbuddyPlan(cmd, gate),
9082
9189
  cwd,
9083
- env: { CODEBUDDY_CONFIG_DIR: cmd.sessionId ? workbuddyRunConfigDir(configDir, home, platform) : join30(home, ".workbuddy") }
9190
+ env: { CODEBUDDY_CONFIG_DIR: cmd.sessionId ? workbuddyRunConfigDir(configDir, home, platform) : join31(home, ".workbuddy") }
9084
9191
  };
9085
9192
  case "qoder_cn":
9086
9193
  case "qoder":
@@ -9350,7 +9457,7 @@ function killTree(child) {
9350
9457
  import { execFile as execFile8, execFileSync as execFileSync12, spawn as spawn4 } from "child_process";
9351
9458
  import { chmodSync as chmodSync8, mkdirSync as mkdirSync24, rmSync as rmSync14, writeFileSync as writeFileSync24 } from "fs";
9352
9459
  import { userInfo } from "os";
9353
- import { join as join31 } from "path";
9460
+ import { join as join32 } from "path";
9354
9461
  function safePath(p) {
9355
9462
  return /^(?:[A-Za-z]:[\\/]|\/)/.test(p) && !/[\r\n\0"'`$%;\u2018-\u201b]/.test(p);
9356
9463
  }
@@ -9450,7 +9557,7 @@ async function openTerminal(t, d) {
9450
9557
  checkTarget(t);
9451
9558
  if (d.platform === "darwin") {
9452
9559
  mkdirSync24(launchDir(t.home), { recursive: true, mode: 448 });
9453
- const file3 = join31(launchDir(t.home), `${t.runId}.command`);
9560
+ const file3 = join32(launchDir(t.home), `${t.runId}.command`);
9454
9561
  writeFileSync24(file3, macCommandScript(t), { encoding: "utf8", mode: 448 });
9455
9562
  chmodSync8(file3, 448);
9456
9563
  await d.run("open", ["-a", "Terminal", file3]);
@@ -9470,7 +9577,7 @@ async function openTerminal(t, d) {
9470
9577
  function removeCommandFile(home, runId) {
9471
9578
  if (!RUN_ID_RE.test(runId)) return;
9472
9579
  try {
9473
- rmSync14(join31(launchDir(home), `${runId}.command`), { force: true });
9580
+ rmSync14(join32(launchDir(home), `${runId}.command`), { force: true });
9474
9581
  } catch {
9475
9582
  }
9476
9583
  }
@@ -9552,8 +9659,8 @@ var WORKBUDDY_PROBE_ARGS = ["-p", PROBE_TEXT, "--output-format", "json", "--no-s
9552
9659
  var WORKBUDDY_AUTH_FILE = "Tencent-Cloud.coding-copilot.info";
9553
9660
  function workbuddyAuthFile(home, platform, localAppData = "") {
9554
9661
  const tail = ["CodeBuddyExtension", "Data", "Public", "auth", WORKBUDDY_AUTH_FILE];
9555
- if (platform === "darwin") return join32(home, "Library", "Application Support", ...tail);
9556
- if (platform === "win32") return localAppData ? join32(localAppData, ...tail) : null;
9662
+ if (platform === "darwin") return join33(home, "Library", "Application Support", ...tail);
9663
+ if (platform === "win32") return localAppData ? join33(localAppData, ...tail) : null;
9557
9664
  return null;
9558
9665
  }
9559
9666
  var WORKBUDDY_VIA_APP_NOTE = "WorkBuddy \u5C06\u901A\u8FC7\u684C\u9762 App \u8FD0\u884C\uFF0C\u5728 App \u91CC\u767B\u5F55\u5373\u53EF";
@@ -9567,7 +9674,7 @@ async function checkWorkbuddy(d) {
9567
9674
  const auth = d.workbuddyAuthFile?.() ?? null;
9568
9675
  if (auth && d.exists?.(auth)) return { tool, state: "logged_in", note: "\u72EC\u7ACB\u7248\u51ED\u636E\u6587\u4EF6\u5728" };
9569
9676
  }
9570
- const env = envFor(d, loc, { CODEBUDDY_CONFIG_DIR: join32(d.home, ".workbuddy"), DESKBUDDY_NO_WAKE: "1", [PROBE_ENV]: "1" });
9677
+ const env = envFor(d, loc, { CODEBUDDY_CONFIG_DIR: join33(d.home, ".workbuddy"), DESKBUDDY_NO_WAKE: "1", [PROBE_ENV]: "1" });
9571
9678
  const r = await d.run(loc.file, [...loc.prefixArgs, ...WORKBUDDY_PROBE_ARGS], env, WORKBUDDY_PROBE_TIMEOUT_MS);
9572
9679
  const bad = failedRun(r);
9573
9680
  if (bad) return { tool, state: "unknown", note: bad };
@@ -9652,7 +9759,7 @@ var defaultCheckDeps = () => ({
9652
9759
  home: homedir9(),
9653
9760
  codexConfig: () => {
9654
9761
  try {
9655
- return readFileSync27(join32(codexHome(), "config.toml"), "utf8");
9762
+ return readFileSync27(join33(codexHome(), "config.toml"), "utf8");
9656
9763
  } catch {
9657
9764
  return null;
9658
9765
  }
@@ -9766,7 +9873,7 @@ function winLoginScript(cmd) {
9766
9873
  return lines.join("\r\n") + "\r\n";
9767
9874
  }
9768
9875
  function loginScriptPath(home, tool, platform) {
9769
- return join32(launchDir(home), `login-${tool}.${platform === "win32" ? "ps1" : "command"}`);
9876
+ return join33(launchDir(home), `login-${tool}.${platform === "win32" ? "ps1" : "command"}`);
9770
9877
  }
9771
9878
  function winLoginWtArgs(script) {
9772
9879
  if (!safePath(script)) throw new Error("\u811A\u672C\u8DEF\u5F84\u91CC\u6709\u4E0D\u80FD\u8FDB\u547D\u4EE4\u884C\u7684\u5B57\u7B26");
@@ -9803,14 +9910,14 @@ var defaultLoginOpenDeps = () => ({
9803
9910
  home: deskbuddyHome(),
9804
9911
  pathDirs: () => childPath().split(":"),
9805
9912
  write: (file3, content) => {
9806
- mkdirSync25(join32(file3, ".."), { recursive: true, mode: 448 });
9913
+ mkdirSync25(join33(file3, ".."), { recursive: true, mode: 448 });
9807
9914
  writeFileSync25(file3, content, { mode: 448 });
9808
9915
  chmodSync9(file3, 448);
9809
9916
  }
9810
9917
  });
9811
9918
  async function installCodebuddyHooks(log) {
9812
9919
  try {
9813
- const { installTools: installTools2 } = await import("./enable-OAEIZPXE.js");
9920
+ const { installTools: installTools2 } = await import("./enable-KQYXVSQN.js");
9814
9921
  installTools2(["workbuddy"], () => {
9815
9922
  }, null, { auto: true });
9816
9923
  } catch (e) {
@@ -9996,7 +10103,7 @@ async function autoEnableLoginLog(tools, check, log) {
9996
10103
  // src/daemon/workbuddySetup.ts
9997
10104
  import { execFile as execFile10, spawn as spawn5 } from "child_process";
9998
10105
  import { existsSync as existsSync26 } from "fs";
9999
- import { dirname as dirname18, join as join33 } from "path";
10106
+ import { dirname as dirname18, join as join34 } from "path";
10000
10107
  var DIALOG_TITLE = "DeskBuddy";
10001
10108
  var BTN_INSTALL = "\u5B89\u88C5";
10002
10109
  var BTN_LATER = "\u6682\u4E0D";
@@ -10135,9 +10242,9 @@ function npmPlan(d) {
10135
10242
  for (const f of whichAllIn("npm", d)) {
10136
10243
  if (!/\.cmd$/i.test(f)) continue;
10137
10244
  const dir2 = dirname18(f);
10138
- const cli = join33(dir2, "node_modules", "npm", "bin", "npm-cli.js");
10245
+ const cli = join34(dir2, "node_modules", "npm", "bin", "npm-cli.js");
10139
10246
  if (!d.exists(cli)) continue;
10140
- const node = join33(dir2, "node.exe");
10247
+ const node = join34(dir2, "node.exe");
10141
10248
  return { file: d.exists(node) ? node : d.nodePath, args: [cli, ...NPM_INSTALL_ARGS] };
10142
10249
  }
10143
10250
  return null;
@@ -10254,7 +10361,7 @@ async function runOffer(source, d, opts = {}) {
10254
10361
  }
10255
10362
  }
10256
10363
  function lockPath() {
10257
- return join33(deskbuddyHome(), "workbuddy-setup.lock");
10364
+ return join34(deskbuddyHome(), "workbuddy-setup.lock");
10258
10365
  }
10259
10366
  var defaultLockDeps = () => ({ path: lockPath(), pid: process.pid, now: () => Date.now(), alive: pidAlive2 });
10260
10367
  var WorkbuddyOffer = class {
@@ -10324,7 +10431,7 @@ function defaultOfferDeps(log) {
10324
10431
  }),
10325
10432
  openLogin: () => defaultOpenLogin(platform),
10326
10433
  installHooks: async () => {
10327
- const { installTools: installTools2 } = await import("./enable-OAEIZPXE.js");
10434
+ const { installTools: installTools2 } = await import("./enable-KQYXVSQN.js");
10328
10435
  installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
10329
10436
  },
10330
10437
  log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
@@ -10493,14 +10600,14 @@ function installTools(tools, out, shim = defaultShimEnvForInstall(), opts = {})
10493
10600
  installed.push(tool);
10494
10601
  out(`\u2705 ${tool}\uFF1Ahook \u5DF2\u88C5\u8FDB ${configPath2}\uFF08${events.length} \u4E2A\u4E8B\u4EF6\uFF09`);
10495
10602
  try {
10496
- if (adapter.installWindowGate?.(configPath2, join34(dirname19(hookPath), "gate.cjs"), tool)) {
10603
+ if (adapter.installWindowGate?.(configPath2, join35(dirname19(hookPath), "gate.cjs"), tool)) {
10497
10604
  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`);
10498
10605
  }
10499
10606
  } catch (e) {
10500
10607
  out(`\u26A0\uFE0F ${tool}\uFF1A\u8BBE\u5907\u786E\u8BA4\u6388\u6743\u6CA1\u88C5\u4E0A\uFF1A${e.message}`);
10501
10608
  }
10502
10609
  try {
10503
- if (adapter.installRewake?.(configPath2, join34(dirname19(hookPath), "wake.cjs"), tool)) {
10610
+ if (adapter.installRewake?.(configPath2, join35(dirname19(hookPath), "wake.cjs"), tool)) {
10504
10611
  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`);
10505
10612
  }
10506
10613
  } catch (e) {
@@ -10625,6 +10732,9 @@ export {
10625
10732
  scrubAgentEnv,
10626
10733
  scrubForCommand,
10627
10734
  defaultLocateDeps,
10735
+ PROBE_TIMEOUT_MS,
10736
+ PROBE_SHORT_TTL_MS,
10737
+ classifyAsyncError,
10628
10738
  warmClaudeProbe,
10629
10739
  whichIn,
10630
10740
  whichAllIn,
@@ -10764,6 +10874,10 @@ export {
10764
10874
  DUMATE_BRAND,
10765
10875
  DumateKeeper,
10766
10876
  ensureDumateShortcuts,
10877
+ QODER_BRANDS,
10878
+ isQoderDesktopPid,
10879
+ QODER_SHORTCUT_EVERY_MS,
10880
+ ensureQoderShortcuts,
10767
10881
  adapterFor,
10768
10882
  migrateLegacyQoder,
10769
10883
  EXEC_TIMEOUT_MS,