deskbuddy 0.2.0-beta.30 → 0.2.0-beta.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/commands/enable.ts
|
|
4
|
-
import { dirname as dirname19, join as
|
|
4
|
+
import { dirname as dirname19, join as join36 } from "path";
|
|
5
5
|
|
|
6
6
|
// src/core/config.ts
|
|
7
7
|
import { randomUUID } from "crypto";
|
|
@@ -1871,12 +1871,12 @@ function isDshPluginInstalled(patchPath) {
|
|
|
1871
1871
|
var DSH_NOTICE = " \u5DF2\u5F00\u7740\u7684 DeepSeek Harness\uFF08dsh web / \u684C\u9762\u7AEF\uFF09\u91CD\u542F\u540E\u751F\u6548";
|
|
1872
1872
|
|
|
1873
1873
|
// src/daemon/dumateApp/shortcuts.ts
|
|
1874
|
-
import { join as
|
|
1874
|
+
import { join as join26 } from "path";
|
|
1875
1875
|
|
|
1876
1876
|
// src/daemon/appShortcuts.ts
|
|
1877
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";
|
|
1878
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync12, renameSync as renameSync8, statSync as statSync4, writeFileSync as writeFileSync11 } from "fs";
|
|
1879
|
+
import { join as join10, win32 as win322 } from "path";
|
|
1880
1880
|
|
|
1881
1881
|
// src/core/fileLock.ts
|
|
1882
1882
|
import { existsSync as existsSync10, mkdirSync as mkdirSync10, readFileSync as readFileSync11, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
@@ -1937,7 +1937,55 @@ function pidAlive2(pid) {
|
|
|
1937
1937
|
}
|
|
1938
1938
|
}
|
|
1939
1939
|
|
|
1940
|
+
// src/daemon/winPaths.ts
|
|
1941
|
+
import { win32 } from "path";
|
|
1942
|
+
function isValidWinPath(p) {
|
|
1943
|
+
if (typeof p !== "string" || p.length < 4 || p.length > 1024) return false;
|
|
1944
|
+
if (!/^[a-z]:\\/i.test(p)) return false;
|
|
1945
|
+
if (/[\u0000-\u001f*?"<>|%]/.test(p)) return false;
|
|
1946
|
+
return !p.split("\\").includes("..");
|
|
1947
|
+
}
|
|
1948
|
+
function normalizeHint(raw) {
|
|
1949
|
+
if (typeof raw !== "string") return null;
|
|
1950
|
+
let v = raw.trim();
|
|
1951
|
+
if (!v) return null;
|
|
1952
|
+
if (v.startsWith('"')) {
|
|
1953
|
+
const end = v.indexOf('"', 1);
|
|
1954
|
+
if (end < 0) return null;
|
|
1955
|
+
v = v.slice(1, end);
|
|
1956
|
+
} else {
|
|
1957
|
+
v = v.replace(/,\s*-?\d+$/, "");
|
|
1958
|
+
const m = /^(.*?\.exe)(\s|$)/i.exec(v);
|
|
1959
|
+
if (m) v = m[1];
|
|
1960
|
+
}
|
|
1961
|
+
v = v.replace(/\//g, "\\").replace(/\\+$/, "").trim();
|
|
1962
|
+
return isValidWinPath(v) ? v : null;
|
|
1963
|
+
}
|
|
1964
|
+
function launcherTarget(text, exe) {
|
|
1965
|
+
const kv = /* @__PURE__ */ new Map();
|
|
1966
|
+
for (const line of text.split(/\r?\n/)) {
|
|
1967
|
+
const i = line.indexOf("=");
|
|
1968
|
+
if (i > 0) kv.set(line.slice(0, i).trim(), line.slice(i + 1).trim());
|
|
1969
|
+
}
|
|
1970
|
+
const dir2 = (kv.get("installDir") ?? "").replace(/\//g, "\\").replace(/\\+$/, "");
|
|
1971
|
+
const app = (kv.get("appExecutable") ?? "").replace(/\//g, "\\");
|
|
1972
|
+
const seg = app.split("\\");
|
|
1973
|
+
const shapeOk = seg.length === 1 || seg.length === 3 && seg[0].toLowerCase() === ".qoder-versions" && /^[0-9a-z][0-9a-z._-]*$/i.test(seg[1]);
|
|
1974
|
+
if (!shapeOk || seg[seg.length - 1].toLowerCase() !== exe.toLowerCase() || !isValidWinPath(dir2)) return null;
|
|
1975
|
+
const p = win32.join(dir2, app);
|
|
1976
|
+
return isValidWinPath(p) ? p : null;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1940
1979
|
// src/daemon/appShortcuts.ts
|
|
1980
|
+
function exeNameOf(app) {
|
|
1981
|
+
let p = null;
|
|
1982
|
+
try {
|
|
1983
|
+
p = app.locatedExe?.() ?? null;
|
|
1984
|
+
} catch {
|
|
1985
|
+
p = null;
|
|
1986
|
+
}
|
|
1987
|
+
return p ? win322.basename(p) : app.exe;
|
|
1988
|
+
}
|
|
1941
1989
|
var LNK_LIST_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
|
|
1942
1990
|
$s = New-Object -ComObject WScript.Shell
|
|
1943
1991
|
$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))
|
|
@@ -1951,13 +1999,16 @@ foreach ($d in $dirs) {
|
|
|
1951
1999
|
ConvertTo-Json -InputObject @($out) -Compress`;
|
|
1952
2000
|
var LNK_WRITE_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
|
|
1953
2001
|
$ops = $env:DB_LNK_OPS | ConvertFrom-Json
|
|
2002
|
+
# 允许的 Launcher 目标(完整路径,小写);PowerShell 5.1 的 ConvertFrom-Json 数组要展开
|
|
2003
|
+
$launchers = @($env:DB_LNK_LAUNCHERS | ConvertFrom-Json | ForEach-Object { $_ } | ForEach-Object { ([string]$_).ToLowerInvariant() })
|
|
1954
2004
|
$s = New-Object -ComObject WScript.Shell
|
|
1955
2005
|
$out = @()
|
|
1956
2006
|
foreach ($o in @($ops)) {
|
|
1957
2007
|
$ok = $false
|
|
1958
2008
|
try {
|
|
1959
2009
|
$l = $s.CreateShortcut([string]$o.path)
|
|
1960
|
-
|
|
2010
|
+
$t = [string]$l.TargetPath
|
|
2011
|
+
if (([IO.Path]::GetFileName($t) -ieq [string]$env:DB_LNK_EXE) -or ($launchers -contains $t.ToLowerInvariant())) { $l.Arguments = [string]$o.args; $l.Save(); $ok = $true }
|
|
1961
2012
|
} catch {}
|
|
1962
2013
|
$out += [pscustomobject]@{ path = [string]$o.path; ok = $ok }
|
|
1963
2014
|
}
|
|
@@ -1969,7 +2020,47 @@ function hasPortFlag(args) {
|
|
|
1969
2020
|
return /(^|\s)--remote-debugging-port(=|\s|$)/.test(args);
|
|
1970
2021
|
}
|
|
1971
2022
|
function isAppLnk(l, exe) {
|
|
1972
|
-
|
|
2023
|
+
if (typeof exe === "function") return exe(l);
|
|
2024
|
+
return win322.basename(l.target || "").toLowerCase() === exe.toLowerCase();
|
|
2025
|
+
}
|
|
2026
|
+
function lnkMatcher(app, readText = readSmall, restore = false) {
|
|
2027
|
+
const exe = exeNameOf(app);
|
|
2028
|
+
let located = null;
|
|
2029
|
+
try {
|
|
2030
|
+
located = app.locatedExe?.() ?? null;
|
|
2031
|
+
} catch {
|
|
2032
|
+
located = null;
|
|
2033
|
+
}
|
|
2034
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
2035
|
+
return (l) => {
|
|
2036
|
+
const target = l.target || "";
|
|
2037
|
+
if (win322.basename(target).toLowerCase() === exe.toLowerCase()) return true;
|
|
2038
|
+
if (!located && !restore || !isValidWinPath(target) || !/\.exe$/i.test(target)) return false;
|
|
2039
|
+
const k = target.toLowerCase();
|
|
2040
|
+
if (!cache2.has(k)) {
|
|
2041
|
+
const ini = readText(win322.join(win322.dirname(target), "install.ini"));
|
|
2042
|
+
const to = ini ? launcherTarget(ini, exe) : null;
|
|
2043
|
+
cache2.set(k, !!to && (restore || !!located && to.toLowerCase() === located.toLowerCase()));
|
|
2044
|
+
}
|
|
2045
|
+
return cache2.get(k) === true;
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
function launcherTargets(list, writes, exe) {
|
|
2049
|
+
const byPath = new Map(list.map((l) => [l.path.toLowerCase(), l.target]));
|
|
2050
|
+
const out = /* @__PURE__ */ new Set();
|
|
2051
|
+
for (const w of writes) {
|
|
2052
|
+
const t = byPath.get(w.path.toLowerCase());
|
|
2053
|
+
if (t && win322.basename(t).toLowerCase() !== exe.toLowerCase()) out.add(t.toLowerCase());
|
|
2054
|
+
}
|
|
2055
|
+
return [...out];
|
|
2056
|
+
}
|
|
2057
|
+
function readSmall(p) {
|
|
2058
|
+
try {
|
|
2059
|
+
if (statSync4(p).size > 64 * 1024) return null;
|
|
2060
|
+
return readFileSync12(p, "utf8");
|
|
2061
|
+
} catch {
|
|
2062
|
+
return null;
|
|
2063
|
+
}
|
|
1973
2064
|
}
|
|
1974
2065
|
var keyOf = (p) => p.toLowerCase();
|
|
1975
2066
|
function planPatchFor(exe, list, records, port) {
|
|
@@ -2030,9 +2121,9 @@ function parseJsonArray(out) {
|
|
|
2030
2121
|
}
|
|
2031
2122
|
}
|
|
2032
2123
|
function parseList(out) {
|
|
2033
|
-
const
|
|
2034
|
-
if (!
|
|
2035
|
-
return
|
|
2124
|
+
const arr2 = parseJsonArray(out);
|
|
2125
|
+
if (!arr2) return null;
|
|
2126
|
+
return arr2.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
2127
|
}
|
|
2037
2128
|
var psArgs = (script) => ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script];
|
|
2038
2129
|
var defaultPs = (script, env) => new Promise((done) => {
|
|
@@ -2062,7 +2153,12 @@ var nowOf = (d) => d.now ? d.now() : Date.now();
|
|
|
2062
2153
|
var fileOf = (app, d) => d.file ?? recordsFile(app);
|
|
2063
2154
|
var failFileOf = (app, d) => d.failFile ?? join10(deskbuddyHome(), app.dir, `${app.stem}-fail.json`);
|
|
2064
2155
|
var lockFileOf = (app, d) => d.lockFile ?? join10(deskbuddyHome(), app.dir, `${app.stem}.lock`);
|
|
2065
|
-
var writeEnv = (app, ops) => ({
|
|
2156
|
+
var writeEnv = (app, ops, list) => ({
|
|
2157
|
+
DB_LNK_OPS: JSON.stringify(ops),
|
|
2158
|
+
DB_LNK_EXE: exeNameOf(app),
|
|
2159
|
+
DB_LNK_LAUNCHERS: JSON.stringify(launcherTargets(list, ops, exeNameOf(app)))
|
|
2160
|
+
});
|
|
2161
|
+
var matcherOf = (app, d, restore = false) => lnkMatcher(app, d.readText, restore);
|
|
2066
2162
|
function loadFails(app, d) {
|
|
2067
2163
|
try {
|
|
2068
2164
|
const v = JSON.parse(readFileSync12(failFileOf(app, d), "utf8"));
|
|
@@ -2116,7 +2212,7 @@ function applyResults(app, d, writes, results, records, prev) {
|
|
|
2116
2212
|
return out;
|
|
2117
2213
|
}
|
|
2118
2214
|
function restoreWith(app, d, list, records, write3) {
|
|
2119
|
-
const writes = planRestoreFor(app
|
|
2215
|
+
const writes = planRestoreFor(matcherOf(app, d, true), list, records, portOf(app, d));
|
|
2120
2216
|
const finish = (results) => {
|
|
2121
2217
|
const ok = new Set((results ?? []).filter((r2) => r2 && r2.ok === true && typeof r2.path === "string").map((r2) => keyOf(r2.path)));
|
|
2122
2218
|
const keep = {};
|
|
@@ -2146,7 +2242,7 @@ async function ensureAppShortcuts(app, d, ps = defaultPs) {
|
|
|
2146
2242
|
const prev = loadRecords(fileOf(app, d));
|
|
2147
2243
|
const fails = loadFails(app, d);
|
|
2148
2244
|
const now = nowOf(d);
|
|
2149
|
-
const plan = planPatchFor(app
|
|
2245
|
+
const plan = planPatchFor(matcherOf(app, d), list, prev, portOf(app, d));
|
|
2150
2246
|
const writes = plan.writes.filter((w) => {
|
|
2151
2247
|
const t = fails[keyOf(w.path)];
|
|
2152
2248
|
return !t || now - t >= FAIL_RETRY_MS;
|
|
@@ -2158,11 +2254,11 @@ async function ensureAppShortcuts(app, d, ps = defaultPs) {
|
|
|
2158
2254
|
if (prev[k]) records[k] = prev[k];
|
|
2159
2255
|
else delete records[k];
|
|
2160
2256
|
}
|
|
2161
|
-
const results = parseJsonArray(await ps(LNK_WRITE_PS, writeEnv(app, writes)));
|
|
2257
|
+
const results = parseJsonArray(await ps(LNK_WRITE_PS, writeEnv(app, writes, list)));
|
|
2162
2258
|
let next = applyResults(app, d, writes, results, records, prev);
|
|
2163
2259
|
if (!wanted()) {
|
|
2164
2260
|
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))));
|
|
2261
|
+
if (list2) next = await restoreWith(app, d, list2, next, async (ops) => parseJsonArray(await ps(LNK_WRITE_PS, writeEnv(app, ops, list2))));
|
|
2166
2262
|
}
|
|
2167
2263
|
saveRecords(next, fileOf(app, d));
|
|
2168
2264
|
} finally {
|
|
@@ -2190,9 +2286,9 @@ function ensureAppShortcutsSync(app, d, ps = defaultPsSync) {
|
|
|
2190
2286
|
return;
|
|
2191
2287
|
}
|
|
2192
2288
|
const prev = loadRecords(fileOf(app, d));
|
|
2193
|
-
const { writes, records } = planPatchFor(app
|
|
2289
|
+
const { writes, records } = planPatchFor(matcherOf(app, d), list, prev, portOf(app, d));
|
|
2194
2290
|
if (writes.length === 0) return;
|
|
2195
|
-
const results = parseJsonArray(ps(LNK_WRITE_PS, writeEnv(app, writes)));
|
|
2291
|
+
const results = parseJsonArray(ps(LNK_WRITE_PS, writeEnv(app, writes, list)));
|
|
2196
2292
|
saveRecords(applyResults(app, d, writes, results, records, prev), fileOf(app, d));
|
|
2197
2293
|
} finally {
|
|
2198
2294
|
release2();
|
|
@@ -2213,7 +2309,7 @@ function restoreAppShortcutsSync(app, d, ps = defaultPsSync) {
|
|
|
2213
2309
|
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
2310
|
return;
|
|
2215
2311
|
}
|
|
2216
|
-
const keep = restoreWith(app, d, list, loadRecords(fileOf(app, d)), (ops) => parseJsonArray(ps(LNK_WRITE_PS, writeEnv(app, ops))));
|
|
2312
|
+
const keep = restoreWith(app, d, list, loadRecords(fileOf(app, d)), (ops) => parseJsonArray(ps(LNK_WRITE_PS, writeEnv(app, ops, list))));
|
|
2217
2313
|
saveRecords(keep, fileOf(app, d));
|
|
2218
2314
|
} finally {
|
|
2219
2315
|
release2();
|
|
@@ -2221,14 +2317,14 @@ function restoreAppShortcutsSync(app, d, ps = defaultPsSync) {
|
|
|
2221
2317
|
}
|
|
2222
2318
|
|
|
2223
2319
|
// src/daemon/dumateApp/keeper.ts
|
|
2224
|
-
import { readdirSync as
|
|
2225
|
-
import { join as
|
|
2320
|
+
import { readdirSync as readdirSync13, statSync as statSync12 } from "fs";
|
|
2321
|
+
import { join as join25 } from "path";
|
|
2226
2322
|
|
|
2227
2323
|
// src/daemon/dumateWatch.ts
|
|
2228
2324
|
import { execFileSync as execFileSync10, spawn as spawn3 } from "child_process";
|
|
2229
|
-
import { readdirSync as
|
|
2325
|
+
import { readdirSync as readdirSync11, realpathSync as realpathSync4, statSync as statSync11 } from "fs";
|
|
2230
2326
|
import { request as httpRequest } from "http";
|
|
2231
|
-
import { join as
|
|
2327
|
+
import { join as join23 } from "path";
|
|
2232
2328
|
|
|
2233
2329
|
// hook/ocTranslate.mjs
|
|
2234
2330
|
function toCcTool(tool, args) {
|
|
@@ -2943,8 +3039,8 @@ function traeNoticeSummary(toolName, toolInput, described, notice) {
|
|
|
2943
3039
|
|
|
2944
3040
|
// src/daemon/workbuddyApp/keeper.ts
|
|
2945
3041
|
import { execFile as execFile6, spawn as spawn2 } from "child_process";
|
|
2946
|
-
import { existsSync as
|
|
2947
|
-
import { delimiter as delimiter3, join as
|
|
3042
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as readFileSync23, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
|
|
3043
|
+
import { delimiter as delimiter3, join as join22, resolve as resolve4 } from "path";
|
|
2948
3044
|
|
|
2949
3045
|
// src/core/process.ts
|
|
2950
3046
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
@@ -3057,7 +3153,7 @@ function programOf(args) {
|
|
|
3057
3153
|
}
|
|
3058
3154
|
|
|
3059
3155
|
// src/core/ended.ts
|
|
3060
|
-
import { closeSync, mkdirSync as mkdirSync12, openSync, readdirSync as readdirSync2, readFileSync as readFileSync13, readSync, realpathSync, renameSync as renameSync9, rmSync as rmSync5, statSync as
|
|
3156
|
+
import { closeSync, mkdirSync as mkdirSync12, openSync, readdirSync as readdirSync2, readFileSync as readFileSync13, readSync, realpathSync, renameSync as renameSync9, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync12 } from "fs";
|
|
3061
3157
|
import { join as join11 } from "path";
|
|
3062
3158
|
var ENDED_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3063
3159
|
var SID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
@@ -3079,7 +3175,7 @@ function writeEnded(s, now = Date.now()) {
|
|
|
3079
3175
|
for (const n of readdirSync2(dir2)) {
|
|
3080
3176
|
const f = join11(dir2, n);
|
|
3081
3177
|
try {
|
|
3082
|
-
if (now -
|
|
3178
|
+
if (now - statSync5(f).mtimeMs > ENDED_TTL_MS) rmSync5(f, { force: true });
|
|
3083
3179
|
} catch {
|
|
3084
3180
|
}
|
|
3085
3181
|
}
|
|
@@ -3104,7 +3200,7 @@ function projectDirName(cwd) {
|
|
|
3104
3200
|
function readChunk(file3, fromEnd, max) {
|
|
3105
3201
|
let fd;
|
|
3106
3202
|
try {
|
|
3107
|
-
const size =
|
|
3203
|
+
const size = statSync5(file3).size;
|
|
3108
3204
|
const len = Math.min(size, max);
|
|
3109
3205
|
const buf = Buffer.alloc(len);
|
|
3110
3206
|
fd = openSync(file3, "r");
|
|
@@ -3137,7 +3233,7 @@ function claudeTranscriptCwd(sessionId, home = claudeHome()) {
|
|
|
3137
3233
|
for (const d of dirs) {
|
|
3138
3234
|
const file3 = join11(home, "projects", d, `${sessionId}.jsonl`);
|
|
3139
3235
|
try {
|
|
3140
|
-
|
|
3236
|
+
statSync5(file3);
|
|
3141
3237
|
} catch {
|
|
3142
3238
|
continue;
|
|
3143
3239
|
}
|
|
@@ -3173,7 +3269,7 @@ function resolveEndedCwd(sessionId, tool, d) {
|
|
|
3173
3269
|
}
|
|
3174
3270
|
function isDirSync(p) {
|
|
3175
3271
|
try {
|
|
3176
|
-
return
|
|
3272
|
+
return statSync5(p).isDirectory();
|
|
3177
3273
|
} catch {
|
|
3178
3274
|
return false;
|
|
3179
3275
|
}
|
|
@@ -3949,9 +4045,9 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
|
|
|
3949
4045
|
|
|
3950
4046
|
// src/daemon/workbuddyAppDb.ts
|
|
3951
4047
|
import { execFile as execFile5 } from "child_process";
|
|
3952
|
-
import { closeSync as closeSync5, existsSync as
|
|
4048
|
+
import { closeSync as closeSync5, existsSync as existsSync18, mkdirSync as mkdirSync20, openSync as openSync5, readdirSync as readdirSync9, readFileSync as readFileSync22, readSync as readSync5, renameSync as renameSync14, rmSync as rmSync12, statSync as statSync10, writeFileSync as writeFileSync20 } from "fs";
|
|
3953
4049
|
import { createRequire as createRequire3 } from "module";
|
|
3954
|
-
import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as
|
|
4050
|
+
import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as join21 } from "path";
|
|
3955
4051
|
|
|
3956
4052
|
// src/core/launch.ts
|
|
3957
4053
|
import { mkdirSync as mkdirSync18, readFileSync as readFileSync18, renameSync as renameSync12, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
|
|
@@ -3960,7 +4056,7 @@ import { join as join17 } from "path";
|
|
|
3960
4056
|
// src/core/wake.ts
|
|
3961
4057
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
3962
4058
|
import { createHash as createHash2, createHmac, timingSafeEqual } from "crypto";
|
|
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
|
|
4059
|
+
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 statSync6, writeFileSync as writeFileSync17 } from "fs";
|
|
3964
4060
|
import { tmpdir } from "os";
|
|
3965
4061
|
import { join as join16 } from "path";
|
|
3966
4062
|
function wakeDir(home = deskbuddyHome()) {
|
|
@@ -4108,7 +4204,7 @@ function analyzeTranscript(file3) {
|
|
|
4108
4204
|
if (!file3) return null;
|
|
4109
4205
|
let fd;
|
|
4110
4206
|
try {
|
|
4111
|
-
const size =
|
|
4207
|
+
const size = statSync6(file3).size;
|
|
4112
4208
|
const len = Math.min(size, TRANSCRIPT_TAIL2);
|
|
4113
4209
|
const buf = Buffer.alloc(len);
|
|
4114
4210
|
fd = openSync2(file3, "r");
|
|
@@ -4216,16 +4312,16 @@ function launchPending(runId) {
|
|
|
4216
4312
|
}
|
|
4217
4313
|
|
|
4218
4314
|
// src/core/title.ts
|
|
4219
|
-
import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync19, readSync as readSync3, statSync as
|
|
4315
|
+
import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync19, readSync as readSync3, statSync as statSync7 } from "fs";
|
|
4220
4316
|
import { createRequire as createRequire2 } from "module";
|
|
4221
4317
|
import { homedir as homedir5 } from "os";
|
|
4222
4318
|
import { basename as basename3, dirname as dirname10, isAbsolute, join as join18 } from "path";
|
|
4223
4319
|
|
|
4224
4320
|
// src/core/dirFilter.ts
|
|
4225
4321
|
import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
|
|
4226
|
-
import { posix, win32 as
|
|
4322
|
+
import { posix, win32 as win323 } from "path";
|
|
4227
4323
|
function norm(p, win) {
|
|
4228
|
-
if (win) return
|
|
4324
|
+
if (win) return win323.resolve(p).replace(/[\\/]+$/, "").toLowerCase();
|
|
4229
4325
|
return posix.resolve(p).replace(/\/+$/, "");
|
|
4230
4326
|
}
|
|
4231
4327
|
function isUnder(p, base, win) {
|
|
@@ -4234,7 +4330,7 @@ function isUnder(p, base, win) {
|
|
|
4234
4330
|
function isAutoWorkspace(p, opts = {}) {
|
|
4235
4331
|
if (!p) return false;
|
|
4236
4332
|
const win = (opts.platform ?? process.platform) === "win32";
|
|
4237
|
-
const P = win ?
|
|
4333
|
+
const P = win ? win323 : posix;
|
|
4238
4334
|
const home = norm(opts.home ?? homedir4(), win);
|
|
4239
4335
|
const full = norm(p, win);
|
|
4240
4336
|
const name = P.basename(full);
|
|
@@ -4245,7 +4341,7 @@ function isAutoWorkspace(p, opts = {}) {
|
|
|
4245
4341
|
function isReportableDir(p, opts = {}) {
|
|
4246
4342
|
if (!p) return false;
|
|
4247
4343
|
const win = (opts.platform ?? process.platform) === "win32";
|
|
4248
|
-
const P = win ?
|
|
4344
|
+
const P = win ? win323 : posix;
|
|
4249
4345
|
const full = norm(p, win);
|
|
4250
4346
|
if (full === norm(P.parse(P.resolve(p)).root, win)) return false;
|
|
4251
4347
|
if (full === norm(opts.home ?? homedir4(), win)) return false;
|
|
@@ -4278,9 +4374,9 @@ function qoderDbPaths(tool, platform = process.platform, home = homedir5(), env
|
|
|
4278
4374
|
|
|
4279
4375
|
// src/daemon/locate.ts
|
|
4280
4376
|
import { execFile as execFile4, execFileSync as execFileSync9 } from "child_process";
|
|
4281
|
-
import { accessSync, closeSync as closeSync4, constants, existsSync as
|
|
4377
|
+
import { accessSync, closeSync as closeSync4, constants, existsSync as existsSync17, lstatSync, openSync as openSync4, readFileSync as readFileSync21, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync9 } from "fs";
|
|
4282
4378
|
import { homedir as homedir6 } from "os";
|
|
4283
|
-
import { delimiter as delimiter2, dirname as dirname11, join as
|
|
4379
|
+
import { delimiter as delimiter2, dirname as dirname11, join as join20, win32 as win325 } from "path";
|
|
4284
4380
|
|
|
4285
4381
|
// src/core/agentEnv.ts
|
|
4286
4382
|
var BUN_HIJACK_ENV = ["BUN_BE_BUN", "BUN_OPTIONS"];
|
|
@@ -4297,6 +4393,287 @@ function scrubForCommand(cmd, env = process.env) {
|
|
|
4297
4393
|
return true;
|
|
4298
4394
|
}
|
|
4299
4395
|
|
|
4396
|
+
// src/daemon/winAppLocator.ts
|
|
4397
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync19, readdirSync as readdirSync8, readFileSync as readFileSync20, renameSync as renameSync13, statSync as statSync8, writeFileSync as writeFileSync19 } from "fs";
|
|
4398
|
+
import { join as join19, win32 as win324 } from "path";
|
|
4399
|
+
var SOURCE_TEXT = {
|
|
4400
|
+
process: "\u6B63\u5728\u8FD0\u884C\u7684\u8FDB\u7A0B",
|
|
4401
|
+
remembered: "\u4E4B\u524D\u8BB0\u4E0B\u7684\u4F4D\u7F6E",
|
|
4402
|
+
uninstall: "\u6CE8\u518C\u8868\u5378\u8F7D\u9879",
|
|
4403
|
+
shortcut: "\u5FEB\u6377\u65B9\u5F0F",
|
|
4404
|
+
appPaths: "App Paths",
|
|
4405
|
+
protocol: "URL \u534F\u8BAE",
|
|
4406
|
+
default: "\u9ED8\u8BA4\u76EE\u5F55",
|
|
4407
|
+
path: "PATH"
|
|
4408
|
+
};
|
|
4409
|
+
var QODER_CN_WORKER_REL = "resources/app.asar.unpacked/node_modules/@qoder-ai/qoder-cn-agent-sdk/dist/_worker/qoder-worker-runtime.obf.mjs";
|
|
4410
|
+
var QODER_WORKER_REL = "resources/app.asar.unpacked/node_modules/@qoder-ai/qoder-agent-sdk/dist/_worker/qoder-worker-runtime.obf.mjs";
|
|
4411
|
+
function stdDirs(env, ...names) {
|
|
4412
|
+
const out = [];
|
|
4413
|
+
for (const n of names) {
|
|
4414
|
+
if (env.localAppData) out.push(win324.join(env.localAppData, "Programs", n));
|
|
4415
|
+
out.push(win324.join(env.programFiles || "C:\\Program Files", n));
|
|
4416
|
+
out.push(win324.join(env.programFilesX86 || "C:\\Program Files (x86)", n));
|
|
4417
|
+
}
|
|
4418
|
+
return out;
|
|
4419
|
+
}
|
|
4420
|
+
var WIN_APP_SPECS = {
|
|
4421
|
+
qoder_cn: { id: "qoder_cn", label: "Qoder CN", exe: "Qoder CN.exe", names: /^Qoder CN(\s|$)/i, protocols: ["qoder-cn"], required: [QODER_CN_WORKER_REL], defaultDirs: (e) => stdDirs(e, "Qoder CN") },
|
|
4422
|
+
qoder: { id: "qoder", label: "Qoder", exe: "Qoder.exe", names: /^Qoder(?! CN)(\s|$)/i, protocols: ["qoder"], required: [QODER_WORKER_REL], defaultDirs: (e) => stdDirs(e, "Qoder") },
|
|
4423
|
+
// 与原 locateWorkbuddyAppExe 一致:DisplayName 含 WorkBuddy、只要 WorkBuddy.exe 在
|
|
4424
|
+
workbuddy: { id: "workbuddy", label: "WorkBuddy", exe: "WorkBuddy.exe", names: /WorkBuddy/i, protocols: ["workbuddy"], required: [], defaultDirs: (e) => stdDirs(e, "WorkBuddy") },
|
|
4425
|
+
qwenwork: { id: "qwenwork", label: "\u5343\u95EE\u529E\u516C", exe: "QwenWorkCN.exe", names: /千问办公|QwenWork/i, protocols: ["qwenwork-cn"], required: [], defaultDirs: (e) => stdDirs(e, "QwenWorkCN") },
|
|
4426
|
+
dumate: { id: "dumate", label: "\u767E\u5EA6\u642D\u5B50", exe: "DuMate.exe", names: /^DuMate(\s|$)/i, protocols: ["dumate"], required: [], defaultDirs: (e) => stdDirs(e, "DuMate", "qianfan-desktop-app") }
|
|
4427
|
+
};
|
|
4428
|
+
var defaultLocFs = {
|
|
4429
|
+
exists: (p) => existsSync16(p),
|
|
4430
|
+
readText: (p) => {
|
|
4431
|
+
try {
|
|
4432
|
+
if (statSync8(p).size > 64 * 1024) return null;
|
|
4433
|
+
return readFileSync20(p, "utf8");
|
|
4434
|
+
} catch {
|
|
4435
|
+
return null;
|
|
4436
|
+
}
|
|
4437
|
+
},
|
|
4438
|
+
subdirs: (p) => {
|
|
4439
|
+
try {
|
|
4440
|
+
return readdirSync8(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
4441
|
+
} catch {
|
|
4442
|
+
return [];
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
};
|
|
4446
|
+
function validExe(p, spec, fs) {
|
|
4447
|
+
if (!isValidWinPath(p) || win324.basename(p).toLowerCase() !== spec.exe.toLowerCase() || !fs.exists(p)) return false;
|
|
4448
|
+
const dir2 = win324.dirname(p);
|
|
4449
|
+
return spec.required.every((r) => fs.exists(win324.join(dir2, ...r.split("/"))));
|
|
4450
|
+
}
|
|
4451
|
+
function expandHint(hint, spec, fs, deep = true) {
|
|
4452
|
+
const out = [];
|
|
4453
|
+
const add = (p) => {
|
|
4454
|
+
if (p && isValidWinPath(p) && !out.some((x) => x.toLowerCase() === p.toLowerCase())) out.push(p);
|
|
4455
|
+
};
|
|
4456
|
+
const base = win324.basename(hint);
|
|
4457
|
+
if (base.toLowerCase() === spec.exe.toLowerCase()) add(hint);
|
|
4458
|
+
const dir2 = /\.[a-z0-9]{2,4}$/i.test(base) ? win324.dirname(hint) : hint;
|
|
4459
|
+
add(win324.join(dir2, spec.exe));
|
|
4460
|
+
const ini = fs.readText(win324.join(dir2, "install.ini"));
|
|
4461
|
+
if (ini) add(launcherTarget(ini, spec.exe));
|
|
4462
|
+
if (deep) for (const sub of fs.subdirs(dir2).filter((s) => /^[0-9a-z][0-9a-z._-]*$/i.test(s)).sort().reverse().slice(0, 20)) add(win324.join(dir2, sub, spec.exe));
|
|
4463
|
+
return out;
|
|
4464
|
+
}
|
|
4465
|
+
var WIN_LOCATE_PS = String.raw`[Console]::OutputEncoding=[Text.Encoding]::UTF8
|
|
4466
|
+
# PowerShell 5.1 的 ConvertFrom-Json 把数组当一个对象输出,经 ForEach-Object 展开成元素(SF-Test 实测,否则 -contains 全不中)
|
|
4467
|
+
$exes = @($env:DB_LOC_EXES | ConvertFrom-Json | ForEach-Object { $_ } | ForEach-Object { [string]$_ }); $protos = @($env:DB_LOC_PROTOS | ConvertFrom-Json | ForEach-Object { $_ } | ForEach-Object { [string]$_ })
|
|
4468
|
+
$o = [ordered]@{ procs = @(); uninstall = @(); appPaths = @(); protocols = @() }
|
|
4469
|
+
try { $o.procs = @(Get-CimInstance Win32_Process -ErrorAction Stop | Where-Object { $exes -contains $_.Name } | ForEach-Object { [pscustomobject]@{ name = [string]$_.Name; path = [string]$_.ExecutablePath } }) } catch {}
|
|
4470
|
+
$o.uninstall = @(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 } | ForEach-Object { [pscustomobject]@{ name = [string]$_.DisplayName; il = [string]$_.InstallLocation; icon = [string]$_.DisplayIcon; un = [string]$_.UninstallString } })
|
|
4471
|
+
foreach ($e in $exes) { foreach ($h in @('HKCU:','HKLM:')) { $p = Get-ItemProperty -LiteralPath "$h\Software\Microsoft\Windows\CurrentVersion\App Paths\$e" -ErrorAction SilentlyContinue; if ($p) { $o.appPaths += [pscustomobject]@{ exe = $e; def = [string]$p.'(default)'; path = [string]$p.Path } } } }
|
|
4472
|
+
foreach ($n in $protos) { foreach ($h in @('HKCU:\Software\Classes','HKLM:\Software\Classes')) { $c = (Get-ItemProperty -LiteralPath "$h\$n\shell\open\command" -ErrorAction SilentlyContinue).'(default)'; if ($c) { $o.protocols += [pscustomobject]@{ name = $n; cmd = [string]$c } } } }
|
|
4473
|
+
ConvertTo-Json -InputObject $o -Compress -Depth 4`;
|
|
4474
|
+
var str = (v) => typeof v === "string" ? v : "";
|
|
4475
|
+
var arr = (v) => (Array.isArray(v) ? v : v && typeof v === "object" ? [v] : []).filter((x) => x && typeof x === "object");
|
|
4476
|
+
function parseFacts(out) {
|
|
4477
|
+
if (out === null) return null;
|
|
4478
|
+
try {
|
|
4479
|
+
const v = JSON.parse(out.trim());
|
|
4480
|
+
if (!v || typeof v !== "object") return null;
|
|
4481
|
+
return {
|
|
4482
|
+
procs: arr(v.procs).map((x) => ({ name: str(x.name), path: str(x.path) })),
|
|
4483
|
+
uninstall: arr(v.uninstall).map((x) => ({ name: str(x.name), il: str(x.il), icon: str(x.icon), un: str(x.un) })),
|
|
4484
|
+
appPaths: arr(v.appPaths).map((x) => ({ exe: str(x.exe), def: str(x.def), path: str(x.path) })),
|
|
4485
|
+
protocols: arr(v.protocols).map((x) => ({ name: str(x.name), cmd: str(x.cmd) }))
|
|
4486
|
+
};
|
|
4487
|
+
} catch {
|
|
4488
|
+
return null;
|
|
4489
|
+
}
|
|
4490
|
+
}
|
|
4491
|
+
function parseLnks(out) {
|
|
4492
|
+
if (out === null) return null;
|
|
4493
|
+
try {
|
|
4494
|
+
const v = JSON.parse(out.trim() || "[]");
|
|
4495
|
+
return arr(v).map((x) => ({ path: str(x.path), target: str(x.target) })).filter((x) => x.path && x.target);
|
|
4496
|
+
} catch {
|
|
4497
|
+
return null;
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
function locateFromFacts(spec, facts, lnks, remembered, env, fs) {
|
|
4501
|
+
const exeLow = spec.exe.toLowerCase();
|
|
4502
|
+
const groups = [
|
|
4503
|
+
{ source: "process", hints: (facts?.procs ?? []).filter((p) => p.name.toLowerCase() === exeLow).map((p) => p.path), failed: facts === null },
|
|
4504
|
+
{ source: "remembered", hints: remembered ? [remembered] : [] },
|
|
4505
|
+
{ source: "uninstall", hints: (facts?.uninstall ?? []).filter((u) => spec.names.test(u.name.trim())).flatMap((u) => [u.il, u.icon, u.un]), failed: facts === null },
|
|
4506
|
+
{
|
|
4507
|
+
source: "shortcut",
|
|
4508
|
+
hints: (lnks ?? []).filter((l) => win324.basename(l.target).toLowerCase() === exeLow || spec.names.test(win324.basename(l.path).replace(/\.lnk$/i, ""))).map((l) => l.target),
|
|
4509
|
+
failed: lnks === null
|
|
4510
|
+
},
|
|
4511
|
+
{ source: "appPaths", hints: (facts?.appPaths ?? []).filter((a) => a.exe.toLowerCase() === exeLow).flatMap((a) => [a.def, a.path]), failed: facts === null },
|
|
4512
|
+
{ source: "protocol", hints: (facts?.protocols ?? []).filter((p) => spec.protocols.includes(p.name.toLowerCase())).map((p) => p.cmd), failed: facts === null },
|
|
4513
|
+
{ source: "default", hints: spec.defaultDirs(env) },
|
|
4514
|
+
{ source: "path", hints: (env.path ?? "").split(";").filter((x) => x.trim()).map((x) => x.trim()) }
|
|
4515
|
+
];
|
|
4516
|
+
const notes = [];
|
|
4517
|
+
for (const g of groups) {
|
|
4518
|
+
const hints = g.hints.map(normalizeHint).filter((h) => h !== null);
|
|
4519
|
+
for (const h of hints) for (const c of expandHint(h, spec, fs, g.source !== "path")) if (validExe(c, spec, fs)) return { found: { exe: c, source: g.source }, tried: "" };
|
|
4520
|
+
if (g.source === "remembered" && hints.length === 0) continue;
|
|
4521
|
+
const what = g.failed ? "\u67E5\u8BE2\u5931\u8D25\u6216\u8D85\u65F6" : hints.length === 0 ? "\u6CA1\u6709\u7EBF\u7D22" : `${hints.length} \u6761\u7EBF\u7D22\u90FD\u4E0D\u5408\u683C\uFF08\u5982 ${hints[0]}\uFF09`;
|
|
4522
|
+
notes.push(`${SOURCE_TEXT[g.source]}\uFF1A${what}`);
|
|
4523
|
+
}
|
|
4524
|
+
return { found: null, tried: notes.join("\uFF1B") };
|
|
4525
|
+
}
|
|
4526
|
+
var WIN_APPS_FILE = "winapps.json";
|
|
4527
|
+
var LOCATE_FAIL_LOG_MS = 6 * 60 * 60 * 1e3;
|
|
4528
|
+
var LOCATE_MIN_GAP_MS = 60 * 1e3;
|
|
4529
|
+
var LOCATE_EVERY_MS = 10 * 60 * 1e3;
|
|
4530
|
+
var cacheFile = () => join19(deskbuddyHome(), WIN_APPS_FILE);
|
|
4531
|
+
function loadCache(file3 = cacheFile()) {
|
|
4532
|
+
try {
|
|
4533
|
+
const v = JSON.parse(readFileSync20(file3, "utf8"));
|
|
4534
|
+
const out = {};
|
|
4535
|
+
for (const [k, e] of Object.entries(v ?? {})) {
|
|
4536
|
+
const x = e;
|
|
4537
|
+
if (x && isValidWinPath(x.exe) && typeof x.source === "string" && x.source in SOURCE_TEXT) out[k] = { exe: x.exe, source: x.source, at: typeof x.at === "number" ? x.at : 0 };
|
|
4538
|
+
}
|
|
4539
|
+
return out;
|
|
4540
|
+
} catch {
|
|
4541
|
+
return {};
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
function saveCache(c, file3) {
|
|
4545
|
+
try {
|
|
4546
|
+
mkdirSync19(join19(file3, ".."), { recursive: true });
|
|
4547
|
+
writeFileSync19(file3 + ".tmp", JSON.stringify(c, null, 2));
|
|
4548
|
+
renameSync13(file3 + ".tmp", file3);
|
|
4549
|
+
} catch {
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
function cachedWinAppExe(id, fs = defaultLocFs, file3 = cacheFile()) {
|
|
4553
|
+
const spec = WIN_APP_SPECS[id];
|
|
4554
|
+
const e = spec ? loadCache(file3)[id] : void 0;
|
|
4555
|
+
return spec && e && validExe(e.exe, spec, fs) ? e.exe : null;
|
|
4556
|
+
}
|
|
4557
|
+
var WinAppLocator = class {
|
|
4558
|
+
#d;
|
|
4559
|
+
/** 正在进行的查询(只覆盖 ids 里的工具) */
|
|
4560
|
+
#inflight = null;
|
|
4561
|
+
/** 每个工具上次查完的时间(最小间隔按工具分别记) */
|
|
4562
|
+
#lastRunAt = /* @__PURE__ */ new Map();
|
|
4563
|
+
#logFn;
|
|
4564
|
+
#lastResult = {};
|
|
4565
|
+
#failLogged = /* @__PURE__ */ new Map();
|
|
4566
|
+
constructor(d = {}) {
|
|
4567
|
+
this.#d = d;
|
|
4568
|
+
this.#logFn = d.log;
|
|
4569
|
+
}
|
|
4570
|
+
/** 补上日志函数(先被不带日志的调用方建出来时,daemon 后给的 log 也要生效);已有的不覆盖 */
|
|
4571
|
+
setLog(log) {
|
|
4572
|
+
if (log && !this.#logFn) this.#logFn = log;
|
|
4573
|
+
}
|
|
4574
|
+
get hasLog() {
|
|
4575
|
+
return !!this.#logFn;
|
|
4576
|
+
}
|
|
4577
|
+
#now() {
|
|
4578
|
+
return this.#d.now ? this.#d.now() : Date.now();
|
|
4579
|
+
}
|
|
4580
|
+
#active() {
|
|
4581
|
+
if ((this.#d.platform ?? process.platform) !== "win32") return false;
|
|
4582
|
+
return !(this.#d.skip ? this.#d.skip() : process.env.DESKBUDDY_SKIP_WIN_LOCATE === "1");
|
|
4583
|
+
}
|
|
4584
|
+
#env() {
|
|
4585
|
+
return this.#d.env ?? { localAppData: process.env.LOCALAPPDATA, programFiles: process.env.ProgramFiles, programFilesX86: process.env["ProgramFiles(x86)"], path: process.env.PATH };
|
|
4586
|
+
}
|
|
4587
|
+
/**
|
|
4588
|
+
* 查一遍(一次 PowerShell 查进程 / 注册表 + 一次枚举快捷方式,异步带超时),结果写缓存。
|
|
4589
|
+
* 正在进行的查询已覆盖这些工具 → 共用它;没覆盖 → 等它结束再查自己这批(不并发起两次 PowerShell)
|
|
4590
|
+
*/
|
|
4591
|
+
refresh(ids = Object.keys(WIN_APP_SPECS)) {
|
|
4592
|
+
if (!this.#active()) return Promise.resolve({});
|
|
4593
|
+
const want = ids.filter((i) => WIN_APP_SPECS[i]);
|
|
4594
|
+
const cur = this.#inflight;
|
|
4595
|
+
if (cur && want.every((i) => cur.ids.has(i))) return cur.p;
|
|
4596
|
+
const p = (cur ? cur.p.then(() => void 0, () => void 0) : Promise.resolve()).then(() => this.#run(want));
|
|
4597
|
+
const entry = { ids: new Set(want), p };
|
|
4598
|
+
this.#inflight = entry;
|
|
4599
|
+
void p.finally(() => {
|
|
4600
|
+
if (this.#inflight === entry) this.#inflight = null;
|
|
4601
|
+
}).catch(() => void 0);
|
|
4602
|
+
return p;
|
|
4603
|
+
}
|
|
4604
|
+
/** 某一个工具的主程序:只查这一个工具;它近 60 秒内查过就直接用缓存(正在查它就等查完)。非 Windows / 测试兜底返回缓存 */
|
|
4605
|
+
async locate(id) {
|
|
4606
|
+
const fs = this.#d.fs ?? defaultLocFs;
|
|
4607
|
+
const file3 = this.#d.file ?? cacheFile();
|
|
4608
|
+
if (this.#active() && WIN_APP_SPECS[id]) {
|
|
4609
|
+
const cur = this.#inflight;
|
|
4610
|
+
if (cur && cur.ids.has(id)) await cur.p.catch(() => void 0);
|
|
4611
|
+
else if (this.#now() - (this.#lastRunAt.get(id) ?? -Infinity) >= LOCATE_MIN_GAP_MS) await this.refresh([id]).catch(() => void 0);
|
|
4612
|
+
}
|
|
4613
|
+
return cachedWinAppExe(id, fs, file3);
|
|
4614
|
+
}
|
|
4615
|
+
async #run(ids) {
|
|
4616
|
+
const ps = this.#d.ps ?? defaultPs;
|
|
4617
|
+
const fs = this.#d.fs ?? defaultLocFs;
|
|
4618
|
+
const file3 = this.#d.file ?? cacheFile();
|
|
4619
|
+
const specs = ids.map((i) => WIN_APP_SPECS[i]);
|
|
4620
|
+
const facts = parseFacts(
|
|
4621
|
+
await ps(WIN_LOCATE_PS, { DB_LOC_EXES: JSON.stringify(specs.map((s) => s.exe)), DB_LOC_PROTOS: JSON.stringify(specs.flatMap((s) => s.protocols)) }).catch(() => null)
|
|
4622
|
+
);
|
|
4623
|
+
const lnks = parseLnks(await ps(LNK_LIST_PS).catch(() => null));
|
|
4624
|
+
const cache2 = loadCache(file3);
|
|
4625
|
+
const out = {};
|
|
4626
|
+
let dirty = false;
|
|
4627
|
+
for (const spec of specs) {
|
|
4628
|
+
const prev = cache2[spec.id];
|
|
4629
|
+
const r = locateFromFacts(spec, facts, lnks, prev?.exe ?? null, this.#env(), fs);
|
|
4630
|
+
out[spec.id] = r.found;
|
|
4631
|
+
if (r.found) {
|
|
4632
|
+
this.#failLogged.delete(spec.id);
|
|
4633
|
+
const changed = !prev || prev.exe.toLowerCase() !== r.found.exe.toLowerCase();
|
|
4634
|
+
if (changed) this.#log(`${spec.label} \u684C\u9762\u7248\u4F4D\u7F6E\uFF1A${r.found.exe}\uFF08\u4ECE${SOURCE_TEXT[r.found.source]}\u627E\u5230\uFF09`);
|
|
4635
|
+
if (changed || r.found.source !== "remembered") {
|
|
4636
|
+
cache2[spec.id] = { exe: r.found.exe, source: r.found.source, at: this.#now() };
|
|
4637
|
+
dirty = true;
|
|
4638
|
+
}
|
|
4639
|
+
} else {
|
|
4640
|
+
if (prev) {
|
|
4641
|
+
delete cache2[spec.id];
|
|
4642
|
+
dirty = true;
|
|
4643
|
+
}
|
|
4644
|
+
this.#noteMissing(spec, r.tried);
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
if (dirty) saveCache(cache2, file3);
|
|
4648
|
+
for (const id of ids) this.#lastRunAt.set(id, this.#now());
|
|
4649
|
+
this.#lastResult = out;
|
|
4650
|
+
return out;
|
|
4651
|
+
}
|
|
4652
|
+
/** 同一原因 LOCATE_FAIL_LOG_MS 内只记一次(不刷屏) */
|
|
4653
|
+
#noteMissing(spec, tried) {
|
|
4654
|
+
const key = `${spec.id}\0${tried}`;
|
|
4655
|
+
const at = this.#failLogged.get(key);
|
|
4656
|
+
const now = this.#now();
|
|
4657
|
+
if (at !== void 0 && now - at < LOCATE_FAIL_LOG_MS) return;
|
|
4658
|
+
for (const k of this.#failLogged.keys()) if (k.startsWith(`${spec.id}\0`)) this.#failLogged.delete(k);
|
|
4659
|
+
this.#failLogged.set(key, now);
|
|
4660
|
+
this.#log(`\u672C\u673A\u627E\u4E0D\u5230 ${spec.label} \u684C\u9762\u7248\uFF08${tried}\uFF09`);
|
|
4661
|
+
}
|
|
4662
|
+
#log(msg) {
|
|
4663
|
+
this.#logFn?.(msg);
|
|
4664
|
+
}
|
|
4665
|
+
/** 测试用:上一轮结果 */
|
|
4666
|
+
get lastResult() {
|
|
4667
|
+
return this.#lastResult;
|
|
4668
|
+
}
|
|
4669
|
+
};
|
|
4670
|
+
var shared = null;
|
|
4671
|
+
function winAppLocator(log) {
|
|
4672
|
+
if (!shared) shared = new WinAppLocator({ log });
|
|
4673
|
+
else shared.setLog(log);
|
|
4674
|
+
return shared;
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4300
4677
|
// src/daemon/locate.ts
|
|
4301
4678
|
function qoderWorker(d, worker, appBin) {
|
|
4302
4679
|
if (d.isExecutable(appBin)) return { file: appBin, prefixArgs: [worker], env: { ELECTRON_RUN_AS_NODE: "1" } };
|
|
@@ -4308,14 +4685,14 @@ var defaultLocateDeps = () => ({
|
|
|
4308
4685
|
nodePath: process.execPath,
|
|
4309
4686
|
isExecutable: (p) => {
|
|
4310
4687
|
try {
|
|
4311
|
-
if (!
|
|
4688
|
+
if (!statSync9(p).isFile()) return false;
|
|
4312
4689
|
accessSync(p, constants.X_OK);
|
|
4313
4690
|
return true;
|
|
4314
4691
|
} catch {
|
|
4315
4692
|
return false;
|
|
4316
4693
|
}
|
|
4317
4694
|
},
|
|
4318
|
-
exists: (p) =>
|
|
4695
|
+
exists: (p) => existsSync17(p),
|
|
4319
4696
|
lexists: (p) => {
|
|
4320
4697
|
try {
|
|
4321
4698
|
lstatSync(p);
|
|
@@ -4329,15 +4706,16 @@ var defaultLocateDeps = () => ({
|
|
|
4329
4706
|
localAppData: process.env.LOCALAPPDATA ?? "",
|
|
4330
4707
|
readText: (p) => {
|
|
4331
4708
|
try {
|
|
4332
|
-
return
|
|
4709
|
+
return readFileSync21(p, "utf8");
|
|
4333
4710
|
} catch {
|
|
4334
4711
|
return null;
|
|
4335
4712
|
}
|
|
4336
4713
|
},
|
|
4337
4714
|
// 🔴 daemon 自己也不能找到垫片:远程任务要的是真程序(窗口接管 spec 2026-09-30 §3.1)
|
|
4338
|
-
skipDirs: [
|
|
4715
|
+
skipDirs: [join20(deskbuddyHome(), "bin")],
|
|
4339
4716
|
winAppHints: (product, exe) => winInstallDirs(product, exe),
|
|
4340
4717
|
winAppExeHints: () => winWorkbuddyExeHints(),
|
|
4718
|
+
winAppExe: (id) => cachedWinAppExe(id),
|
|
4341
4719
|
isPe: (p) => {
|
|
4342
4720
|
let fd = null;
|
|
4343
4721
|
try {
|
|
@@ -4412,7 +4790,7 @@ function classifyAsyncError(e, stdout2, stderr) {
|
|
|
4412
4790
|
var defaultProbe = createVersionProbe({
|
|
4413
4791
|
stat: (p) => {
|
|
4414
4792
|
try {
|
|
4415
|
-
const st =
|
|
4793
|
+
const st = statSync9(p);
|
|
4416
4794
|
return { size: st.size, mtimeMs: st.mtimeMs };
|
|
4417
4795
|
} catch {
|
|
4418
4796
|
return null;
|
|
@@ -4460,9 +4838,9 @@ function installDirsFromProcs(procs, exe) {
|
|
|
4460
4838
|
const out = [];
|
|
4461
4839
|
for (const p of procs ?? []) {
|
|
4462
4840
|
const first = winSplitArgs(p.cmdline)[0] ?? "";
|
|
4463
|
-
if (
|
|
4464
|
-
const dir2 =
|
|
4465
|
-
if (
|
|
4841
|
+
if (win325.basename(first).toLowerCase() !== exe.toLowerCase()) continue;
|
|
4842
|
+
const dir2 = win325.dirname(first);
|
|
4843
|
+
if (win325.isAbsolute(dir2) && !out.some((d) => d.toLowerCase() === dir2.toLowerCase())) out.push(dir2);
|
|
4466
4844
|
}
|
|
4467
4845
|
return out;
|
|
4468
4846
|
}
|
|
@@ -4470,8 +4848,8 @@ function parseUninstallDirs(out) {
|
|
|
4470
4848
|
const dirs = [];
|
|
4471
4849
|
for (const raw of out.split(/\r?\n/)) {
|
|
4472
4850
|
let v = raw.trim().replace(/,\s*-?\d+$/, "").replace(/^"|"$/g, "").trim();
|
|
4473
|
-
if (!v || !
|
|
4474
|
-
if (/\.exe$/i.test(v)) v =
|
|
4851
|
+
if (!v || !win325.isAbsolute(v)) continue;
|
|
4852
|
+
if (/\.exe$/i.test(v)) v = win325.dirname(v);
|
|
4475
4853
|
v = v.replace(/[\\/]+$/, "");
|
|
4476
4854
|
if (!dirs.some((d) => d.toLowerCase() === v.toLowerCase())) dirs.push(v);
|
|
4477
4855
|
}
|
|
@@ -4498,7 +4876,7 @@ function parseExeHints(out) {
|
|
|
4498
4876
|
const res = [];
|
|
4499
4877
|
for (const raw of out.split(/\r?\n/)) {
|
|
4500
4878
|
const v = raw.trim().replace(/,\s*-?\d+$/, "").replace(/^"|"$/g, "").trim().replace(/[\\/]+$/, "");
|
|
4501
|
-
if (!v || !
|
|
4879
|
+
if (!v || !win325.isAbsolute(v)) continue;
|
|
4502
4880
|
if (!res.some((x) => x.toLowerCase() === v.toLowerCase())) res.push(v);
|
|
4503
4881
|
}
|
|
4504
4882
|
return res;
|
|
@@ -4522,57 +4900,54 @@ function winWorkbuddyExeHints() {
|
|
|
4522
4900
|
function locateWorkbuddyAppExe(d = defaultLocateDeps()) {
|
|
4523
4901
|
if (!isWin(d)) {
|
|
4524
4902
|
for (const dir2 of appDirs(d.home)) {
|
|
4525
|
-
const p =
|
|
4903
|
+
const p = join20(dir2, "WorkBuddy.app");
|
|
4526
4904
|
if (d.exists(p)) return p;
|
|
4527
4905
|
}
|
|
4528
4906
|
return null;
|
|
4529
4907
|
}
|
|
4530
|
-
return pickWorkbuddyExe(winAppDirs(d, "WorkBuddy"), d) ?? pickWorkbuddyExe(d.winAppExeHints?.() ?? [], d);
|
|
4908
|
+
return pickWorkbuddyExe(locatedExe(d, "workbuddy"), d) ?? pickWorkbuddyExe(winAppDirs(d, "WorkBuddy"), d) ?? pickWorkbuddyExe(d.winAppExeHints?.() ?? [], d);
|
|
4909
|
+
}
|
|
4910
|
+
function locatedExe(d, id) {
|
|
4911
|
+
const p = d.winAppExe?.(id);
|
|
4912
|
+
return p ? [p] : [];
|
|
4913
|
+
}
|
|
4914
|
+
function locatedDirs(d, id) {
|
|
4915
|
+
return locatedExe(d, id).map((p) => win325.dirname(p));
|
|
4531
4916
|
}
|
|
4532
4917
|
function pickWorkbuddyExe(cands, d) {
|
|
4533
4918
|
for (const c of cands) {
|
|
4534
|
-
const exe = /\.exe$/i.test(c) ? c :
|
|
4535
|
-
if (
|
|
4919
|
+
const exe = /\.exe$/i.test(c) ? c : win325.join(c, "WorkBuddy.exe");
|
|
4920
|
+
if (win325.basename(exe).toLowerCase() === "workbuddy.exe" && d.exists(exe)) return exe;
|
|
4536
4921
|
}
|
|
4537
4922
|
return null;
|
|
4538
4923
|
}
|
|
4539
|
-
function
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
execFile4(
|
|
4543
|
-
"powershell.exe",
|
|
4544
|
-
["-NoProfile", "-NonInteractive", "-Command", WIN_WORKBUDDY_EXE_PS],
|
|
4545
|
-
{ encoding: "utf8", windowsHide: true, timeout: 15e3 },
|
|
4546
|
-
(err, stdout2) => resolve6(err && !stdout2 ? [] : parseExeHints(String(stdout2 ?? "")))
|
|
4547
|
-
);
|
|
4548
|
-
} catch {
|
|
4549
|
-
resolve6([]);
|
|
4550
|
-
}
|
|
4551
|
-
});
|
|
4924
|
+
async function winWorkbuddyLocatorHints() {
|
|
4925
|
+
const p = await winAppLocator().locate("workbuddy");
|
|
4926
|
+
return p ? [p] : [];
|
|
4552
4927
|
}
|
|
4553
|
-
async function locateWorkbuddyAppExeAsync(d = defaultLocateDeps(), hints =
|
|
4928
|
+
async function locateWorkbuddyAppExeAsync(d = defaultLocateDeps(), hints = winWorkbuddyLocatorHints) {
|
|
4554
4929
|
if (!isWin(d)) return locateWorkbuddyAppExe(d);
|
|
4555
|
-
return pickWorkbuddyExe(winAppDirs(d, "WorkBuddy"), d) ?? pickWorkbuddyExe(await hints(), d);
|
|
4930
|
+
return pickWorkbuddyExe(locatedExe(d, "workbuddy"), d) ?? pickWorkbuddyExe(winAppDirs(d, "WorkBuddy"), d) ?? pickWorkbuddyExe(await hints(), d);
|
|
4556
4931
|
}
|
|
4557
4932
|
var isWin = (d) => (d.platform ?? process.platform) === "win32";
|
|
4558
4933
|
var WIN_EXTS = [".exe", ".cmd", ".bat"];
|
|
4559
4934
|
function extraBinDirs(home, nodePath = "", win) {
|
|
4560
4935
|
if (win) {
|
|
4561
4936
|
return [
|
|
4562
|
-
|
|
4563
|
-
...win.appData ? [
|
|
4564
|
-
|
|
4565
|
-
...win.localAppData ? [
|
|
4566
|
-
|
|
4937
|
+
join20(home, ".local", "bin"),
|
|
4938
|
+
...win.appData ? [join20(win.appData, "npm")] : [],
|
|
4939
|
+
join20(home, ".bun", "bin"),
|
|
4940
|
+
...win.localAppData ? [join20(win.localAppData, "Volta", "bin")] : [],
|
|
4941
|
+
join20(home, "scoop", "shims"),
|
|
4567
4942
|
...nodePath ? [dirname11(nodePath)] : []
|
|
4568
4943
|
];
|
|
4569
4944
|
}
|
|
4570
4945
|
return [
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4946
|
+
join20(home, ".local", "bin"),
|
|
4947
|
+
join20(home, ".claude", "local"),
|
|
4948
|
+
join20(home, ".npm-global", "bin"),
|
|
4949
|
+
join20(home, ".bun", "bin"),
|
|
4950
|
+
join20(home, ".volta", "bin"),
|
|
4576
4951
|
"/opt/homebrew/bin",
|
|
4577
4952
|
"/usr/local/bin",
|
|
4578
4953
|
...nodePath ? [dirname11(nodePath)] : []
|
|
@@ -4586,7 +4961,7 @@ function whichAllIn(name, d) {
|
|
|
4586
4961
|
const out = [];
|
|
4587
4962
|
for (const dir2 of binDirs(d)) {
|
|
4588
4963
|
for (const ext of exts) {
|
|
4589
|
-
const p =
|
|
4964
|
+
const p = join20(dir2, name + ext);
|
|
4590
4965
|
if (d.isExecutable(p)) out.push(p);
|
|
4591
4966
|
}
|
|
4592
4967
|
}
|
|
@@ -4610,7 +4985,7 @@ function binDirs(d) {
|
|
|
4610
4985
|
function parseNpmCmdShim(shimPath, text) {
|
|
4611
4986
|
const m = text.match(/"%~?dp0%?\\?([^"%]+)"\s+%\*/i);
|
|
4612
4987
|
if (!m) return null;
|
|
4613
|
-
return
|
|
4988
|
+
return join20(dirname11(shimPath), m[1].replace(/^\\/, ""));
|
|
4614
4989
|
}
|
|
4615
4990
|
var JS_RUNTIME_EXE = /^(?:node|bun|bunx|deno)(?:\.exe)?$/i;
|
|
4616
4991
|
function resolveWinLaunch(file3, d) {
|
|
@@ -4621,7 +4996,7 @@ function resolveWinLaunch(file3, d) {
|
|
|
4621
4996
|
const target = text ? parseNpmCmdShim(file3, text) : null;
|
|
4622
4997
|
if (!target || !d.exists(target)) return null;
|
|
4623
4998
|
if (/\.(?:cmd|bat)$/i.test(target)) return null;
|
|
4624
|
-
if (JS_RUNTIME_EXE.test(
|
|
4999
|
+
if (JS_RUNTIME_EXE.test(win325.basename(target.replace(/\//g, "\\")))) return null;
|
|
4625
5000
|
return resolveWinLaunch(target, d);
|
|
4626
5001
|
}
|
|
4627
5002
|
if (/\.(?:c|m)?js$/.test(lower)) return { file: d.nodePath, prefixArgs: [file3] };
|
|
@@ -4630,22 +5005,22 @@ function resolveWinLaunch(file3, d) {
|
|
|
4630
5005
|
return null;
|
|
4631
5006
|
}
|
|
4632
5007
|
function appDirs(home) {
|
|
4633
|
-
return ["/Applications",
|
|
5008
|
+
return ["/Applications", join20(home, "Applications")];
|
|
4634
5009
|
}
|
|
4635
5010
|
function winAppDirs(d, product) {
|
|
4636
5011
|
return [
|
|
4637
|
-
...d.localAppData ? [
|
|
4638
|
-
|
|
4639
|
-
|
|
5012
|
+
...d.localAppData ? [join20(d.localAppData, "Programs", product)] : [],
|
|
5013
|
+
join20("C:\\Program Files", product),
|
|
5014
|
+
join20("C:\\Program Files (x86)", product)
|
|
4640
5015
|
];
|
|
4641
5016
|
}
|
|
4642
5017
|
var WORKBUDDY_CLI_IN_WIN_APP = "resources/app.asar.unpacked/cli/bin/codebuddy";
|
|
4643
|
-
var QODER_CN_WORKER_IN_WIN_APP =
|
|
4644
|
-
var QODER_WORKER_IN_WIN_APP =
|
|
5018
|
+
var QODER_CN_WORKER_IN_WIN_APP = QODER_CN_WORKER_REL;
|
|
5019
|
+
var QODER_WORKER_IN_WIN_APP = QODER_WORKER_REL;
|
|
4645
5020
|
function winClaudeExeCandidates(d) {
|
|
4646
5021
|
return [
|
|
4647
|
-
...d.home ? [
|
|
4648
|
-
...d.appData ? [
|
|
5022
|
+
...d.home ? [join20(d.home, ".local", "bin", "claude.exe")] : [],
|
|
5023
|
+
...d.appData ? [join20(d.appData, "npm", "node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe")] : []
|
|
4649
5024
|
];
|
|
4650
5025
|
}
|
|
4651
5026
|
function winClaudeLaunches(d) {
|
|
@@ -4690,21 +5065,21 @@ function locateWin(tool, d) {
|
|
|
4690
5065
|
case "workbuddy":
|
|
4691
5066
|
return locateWorkbuddy(d)?.loc ?? null;
|
|
4692
5067
|
case "qoder_cn": {
|
|
4693
|
-
for (const dir2 of winAppDirs(d, "Qoder CN")) {
|
|
4694
|
-
const p =
|
|
4695
|
-
if (d.exists(p)) return qoderWorker(d, p,
|
|
5068
|
+
for (const dir2 of [...locatedDirs(d, "qoder_cn"), ...winAppDirs(d, "Qoder CN")]) {
|
|
5069
|
+
const p = join20(dir2, QODER_CN_WORKER_IN_WIN_APP);
|
|
5070
|
+
if (d.exists(p)) return qoderWorker(d, p, join20(dir2, "Qoder CN.exe"));
|
|
4696
5071
|
}
|
|
4697
5072
|
return plain("qoderclicn");
|
|
4698
5073
|
}
|
|
4699
5074
|
case "qoder": {
|
|
4700
|
-
for (const dir2 of winAppDirs(d, "Qoder")) {
|
|
4701
|
-
const p =
|
|
4702
|
-
if (d.exists(p)) return qoderWorker(d, p,
|
|
5075
|
+
for (const dir2 of [...locatedDirs(d, "qoder"), ...winAppDirs(d, "Qoder")]) {
|
|
5076
|
+
const p = join20(dir2, QODER_WORKER_IN_WIN_APP);
|
|
5077
|
+
if (d.exists(p)) return qoderWorker(d, p, join20(dir2, "Qoder.exe"));
|
|
4703
5078
|
}
|
|
4704
5079
|
return plain("qodercli");
|
|
4705
5080
|
}
|
|
4706
5081
|
case "opencode": {
|
|
4707
|
-
const p =
|
|
5082
|
+
const p = join20(d.home, ".opencode", "bin", "opencode.exe");
|
|
4708
5083
|
if (d.exists(p)) return { file: p, prefixArgs: [] };
|
|
4709
5084
|
return plain("opencode");
|
|
4710
5085
|
}
|
|
@@ -4716,7 +5091,7 @@ function locateWin(tool, d) {
|
|
|
4716
5091
|
return null;
|
|
4717
5092
|
}
|
|
4718
5093
|
}
|
|
4719
|
-
function workbuddyHasTui(loc, exists =
|
|
5094
|
+
function workbuddyHasTui(loc, exists = existsSync17, realpath = realpathSync2) {
|
|
4720
5095
|
const real = (p) => {
|
|
4721
5096
|
try {
|
|
4722
5097
|
return realpath(p);
|
|
@@ -4728,8 +5103,8 @@ function workbuddyHasTui(loc, exists = existsSync16, realpath = realpathSync2) {
|
|
|
4728
5103
|
const cands = [...loc.prefixArgs, loc.file].map(real);
|
|
4729
5104
|
const script = cands.find((a) => BIN.test(a));
|
|
4730
5105
|
if (!script) return true;
|
|
4731
|
-
const dist =
|
|
4732
|
-
return exists(
|
|
5106
|
+
const dist = join20(dirname11(dirname11(script)), "dist");
|
|
5107
|
+
return exists(join20(dist, "codebuddy.js"));
|
|
4733
5108
|
}
|
|
4734
5109
|
function locateWorkbuddyTui(d = defaultLocateDeps(), exists, realpath) {
|
|
4735
5110
|
const cands = [locateWorkbuddyStandalone(d), locateWorkbuddyApp(d)].filter((c) => c !== null);
|
|
@@ -4770,7 +5145,7 @@ function locateWorkbuddyStandalone(d = defaultLocateDeps()) {
|
|
|
4770
5145
|
function locateWorkbuddyApp(d = defaultLocateDeps()) {
|
|
4771
5146
|
if (!isWin(d)) {
|
|
4772
5147
|
for (const dir2 of appDirs(d.home)) {
|
|
4773
|
-
const p =
|
|
5148
|
+
const p = join20(dir2, WORKBUDDY_CLI_IN_APP);
|
|
4774
5149
|
if (d.isExecutable(p)) return { file: p, prefixArgs: [] };
|
|
4775
5150
|
}
|
|
4776
5151
|
return null;
|
|
@@ -4778,7 +5153,7 @@ function locateWorkbuddyApp(d = defaultLocateDeps()) {
|
|
|
4778
5153
|
const inApp = (dirs) => {
|
|
4779
5154
|
for (const dir2 of dirs) {
|
|
4780
5155
|
for (const ext of [".exe", ".cmd", ""]) {
|
|
4781
|
-
const p =
|
|
5156
|
+
const p = join20(dir2, WORKBUDDY_CLI_IN_WIN_APP + ext);
|
|
4782
5157
|
if (d.exists(p)) {
|
|
4783
5158
|
const r = resolveWinLaunch(p, d);
|
|
4784
5159
|
if (r) return r;
|
|
@@ -4787,7 +5162,7 @@ function locateWorkbuddyApp(d = defaultLocateDeps()) {
|
|
|
4787
5162
|
}
|
|
4788
5163
|
return null;
|
|
4789
5164
|
};
|
|
4790
|
-
return inApp(winAppDirs(d, "WorkBuddy")) ?? inApp(d.winAppHints?.("WorkBuddy", "WorkBuddy.exe") ?? []);
|
|
5165
|
+
return inApp([...locatedDirs(d, "workbuddy"), ...winAppDirs(d, "WorkBuddy")]) ?? inApp(d.winAppHints?.("WorkBuddy", "WorkBuddy.exe") ?? []);
|
|
4791
5166
|
}
|
|
4792
5167
|
function locateWorkbuddy(d = defaultLocateDeps()) {
|
|
4793
5168
|
const s = locateWorkbuddyStandalone(d);
|
|
@@ -4813,20 +5188,20 @@ function locate(tool, d = defaultLocateDeps()) {
|
|
|
4813
5188
|
return locateWorkbuddy(d)?.loc ?? null;
|
|
4814
5189
|
case "qoder_cn": {
|
|
4815
5190
|
for (const dir2 of appDirs(d.home)) {
|
|
4816
|
-
const p =
|
|
4817
|
-
if (d.exists(p)) return qoderWorker(d, p,
|
|
5191
|
+
const p = join20(dir2, QODER_CN_WORKER_IN_APP);
|
|
5192
|
+
if (d.exists(p)) return qoderWorker(d, p, join20(dir2, "Qoder CN.app", "Contents", "MacOS", "Qoder CN"));
|
|
4818
5193
|
}
|
|
4819
5194
|
return plain("qoderclicn");
|
|
4820
5195
|
}
|
|
4821
5196
|
case "qoder": {
|
|
4822
5197
|
for (const dir2 of appDirs(d.home)) {
|
|
4823
|
-
const p =
|
|
4824
|
-
if (d.exists(p)) return qoderWorker(d, p,
|
|
5198
|
+
const p = join20(dir2, QODER_WORKER_IN_APP);
|
|
5199
|
+
if (d.exists(p)) return qoderWorker(d, p, join20(dir2, "Qoder.app", "Contents", "MacOS", "Qoder"));
|
|
4825
5200
|
}
|
|
4826
5201
|
return plain("qodercli");
|
|
4827
5202
|
}
|
|
4828
5203
|
case "opencode": {
|
|
4829
|
-
const p =
|
|
5204
|
+
const p = join20(d.home, ".opencode", "bin", "opencode");
|
|
4830
5205
|
if (d.isExecutable(p)) return { file: p, prefixArgs: [] };
|
|
4831
5206
|
return plain("opencode");
|
|
4832
5207
|
}
|
|
@@ -4847,7 +5222,7 @@ function findWt(d = defaultLocateDeps()) {
|
|
|
4847
5222
|
if (!isWin(d)) return null;
|
|
4848
5223
|
const hit = whichIn("wt", d);
|
|
4849
5224
|
if (hit) return hit;
|
|
4850
|
-
const alias = d.localAppData ?
|
|
5225
|
+
const alias = d.localAppData ? join20(d.localAppData, "Microsoft", "WindowsApps", "wt.exe") : "";
|
|
4851
5226
|
return alias && (d.exists(alias) || (d.lexists?.(alias) ?? false)) ? alias : null;
|
|
4852
5227
|
}
|
|
4853
5228
|
|
|
@@ -4914,13 +5289,13 @@ function findWbTranscript(configDir, sessionId) {
|
|
|
4914
5289
|
if (!SESSION_UUID_RE.test(sessionId)) return null;
|
|
4915
5290
|
let dirs;
|
|
4916
5291
|
try {
|
|
4917
|
-
dirs =
|
|
5292
|
+
dirs = readdirSync9(join21(configDir, "projects"));
|
|
4918
5293
|
} catch {
|
|
4919
5294
|
return null;
|
|
4920
5295
|
}
|
|
4921
5296
|
for (const d of dirs) {
|
|
4922
|
-
const p =
|
|
4923
|
-
if (
|
|
5297
|
+
const p = join21(configDir, "projects", d, `${sessionId}.jsonl`);
|
|
5298
|
+
if (existsSync18(p)) return p;
|
|
4924
5299
|
}
|
|
4925
5300
|
return null;
|
|
4926
5301
|
}
|
|
@@ -4928,7 +5303,7 @@ var SLICE = 64 * 1024;
|
|
|
4928
5303
|
function readSlice(p, from) {
|
|
4929
5304
|
const fd = openSync5(p, "r");
|
|
4930
5305
|
try {
|
|
4931
|
-
const size =
|
|
5306
|
+
const size = statSync10(p).size;
|
|
4932
5307
|
const len = Math.min(size, SLICE);
|
|
4933
5308
|
const buf = Buffer.alloc(len);
|
|
4934
5309
|
readSync5(fd, buf, 0, len, from === "head" ? 0 : size - len);
|
|
@@ -4972,7 +5347,7 @@ function userText2(o) {
|
|
|
4972
5347
|
function wbTranscriptInfo(p) {
|
|
4973
5348
|
const head = jsonLines(readSlice(p, "head"));
|
|
4974
5349
|
const tail = jsonLines(readSlice(p, "tail"));
|
|
4975
|
-
const mtime = Math.floor(
|
|
5350
|
+
const mtime = Math.floor(statSync10(p).mtimeMs);
|
|
4976
5351
|
const hs = head.map((o) => tsOf(o.timestamp)).filter((n) => n !== null);
|
|
4977
5352
|
const ts = tail.map((o) => tsOf(o.timestamp)).filter((n) => n !== null);
|
|
4978
5353
|
const createdAt = hs.length ? Math.min(...hs) : mtime;
|
|
@@ -5005,8 +5380,8 @@ function wbElectronCandidates(appCliPath) {
|
|
|
5005
5380
|
const m = /^(.*?)[\\/]resources[\\/]app\.asar\.unpacked[\\/]/i.exec(appCliPath);
|
|
5006
5381
|
if (!m) return [];
|
|
5007
5382
|
const root = m[1];
|
|
5008
|
-
if (/\.app[\\/]Contents$/.test(root)) return [
|
|
5009
|
-
return [
|
|
5383
|
+
if (/\.app[\\/]Contents$/.test(root)) return [join21(root, "MacOS", "Electron"), join21(root, "MacOS", "WorkBuddy")];
|
|
5384
|
+
return [join21(root, "WorkBuddy.exe")];
|
|
5010
5385
|
}
|
|
5011
5386
|
function defaultWbElectron(d = defaultLocateDeps()) {
|
|
5012
5387
|
if ((d.platform ?? process.platform) === "win32") return null;
|
|
@@ -5049,11 +5424,11 @@ function defaultAppRunning(platform = process.platform) {
|
|
|
5049
5424
|
var PENDING_MAX = 20;
|
|
5050
5425
|
var PENDING_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
5051
5426
|
function pendingPath() {
|
|
5052
|
-
return
|
|
5427
|
+
return join21(deskbuddyHome(), "workbuddy-pending.json");
|
|
5053
5428
|
}
|
|
5054
5429
|
function loadPendingFile() {
|
|
5055
5430
|
try {
|
|
5056
|
-
const v = JSON.parse(
|
|
5431
|
+
const v = JSON.parse(readFileSync22(pendingPath(), "utf8"));
|
|
5057
5432
|
return Array.isArray(v) ? v.filter((j) => j && typeof j.sessionId === "string" && typeof j.cwd === "string") : [];
|
|
5058
5433
|
} catch {
|
|
5059
5434
|
return [];
|
|
@@ -5065,10 +5440,10 @@ function savePendingFile(jobs) {
|
|
|
5065
5440
|
rmSync12(pendingPath(), { force: true });
|
|
5066
5441
|
return;
|
|
5067
5442
|
}
|
|
5068
|
-
|
|
5443
|
+
mkdirSync20(deskbuddyHome(), { recursive: true });
|
|
5069
5444
|
const tmp = pendingPath() + ".tmp";
|
|
5070
|
-
|
|
5071
|
-
|
|
5445
|
+
writeFileSync20(tmp, JSON.stringify(jobs), { mode: 384 });
|
|
5446
|
+
renameSync14(tmp, pendingPath());
|
|
5072
5447
|
} catch {
|
|
5073
5448
|
}
|
|
5074
5449
|
}
|
|
@@ -5173,7 +5548,7 @@ async function registerNow(job, d) {
|
|
|
5173
5548
|
if (!SESSION_UUID_RE.test(job.sessionId)) return "skip bad_session";
|
|
5174
5549
|
if (!job.cwd || !isAbsolute2(job.cwd)) return "skip bad_cwd";
|
|
5175
5550
|
const db = d.dbPath();
|
|
5176
|
-
if (!db || !
|
|
5551
|
+
if (!db || !existsSync18(db)) return "skip no_db";
|
|
5177
5552
|
const tp = findWbTranscript(d.configDir(), job.sessionId);
|
|
5178
5553
|
if (!tp) return "skip no_transcript";
|
|
5179
5554
|
const info = wbTranscriptInfo(tp);
|
|
@@ -5305,7 +5680,7 @@ var WsCdpClient = class {
|
|
|
5305
5680
|
};
|
|
5306
5681
|
|
|
5307
5682
|
// src/daemon/workbuddyApp/keeper.ts
|
|
5308
|
-
import { posix as posix2, win32 as
|
|
5683
|
+
import { posix as posix2, win32 as win326 } from "path";
|
|
5309
5684
|
var DEFAULT_CDP_PORT = 39217;
|
|
5310
5685
|
var ENV_NAME = "WORKBUDDY_REMOTE_DEBUGGING_PORT";
|
|
5311
5686
|
var RESTART_GAP_MS = 30 * 60 * 1e3;
|
|
@@ -5367,21 +5742,21 @@ function cleanLaunchEnv(src = process.env, shim = shimDir()) {
|
|
|
5367
5742
|
}
|
|
5368
5743
|
var REMEMBER_EXE_MS = 30 * 60 * 1e3;
|
|
5369
5744
|
var AWAY_IDLE_MS = 5 * 60 * 1e3;
|
|
5370
|
-
var keeperThrottleFile = () =>
|
|
5745
|
+
var keeperThrottleFile = () => join22(deskbuddyHome(), "wbapp", "keeper.json");
|
|
5371
5746
|
var filePersist = {
|
|
5372
5747
|
load: () => {
|
|
5373
5748
|
try {
|
|
5374
|
-
return JSON.parse(
|
|
5749
|
+
return JSON.parse(readFileSync23(keeperThrottleFile(), "utf8"));
|
|
5375
5750
|
} catch {
|
|
5376
5751
|
return null;
|
|
5377
5752
|
}
|
|
5378
5753
|
},
|
|
5379
5754
|
save: (s) => {
|
|
5380
5755
|
try {
|
|
5381
|
-
|
|
5756
|
+
mkdirSync21(join22(deskbuddyHome(), "wbapp"), { recursive: true });
|
|
5382
5757
|
const f = keeperThrottleFile();
|
|
5383
|
-
|
|
5384
|
-
|
|
5758
|
+
writeFileSync21(f + ".tmp", JSON.stringify(s));
|
|
5759
|
+
renameSync15(f + ".tmp", f);
|
|
5385
5760
|
} catch {
|
|
5386
5761
|
}
|
|
5387
5762
|
}
|
|
@@ -5413,7 +5788,7 @@ function defaultWorkbuddyAppPath() {
|
|
|
5413
5788
|
}
|
|
5414
5789
|
function isValidAppPath(p, platform = process.platform) {
|
|
5415
5790
|
if (typeof p !== "string" || !p) return false;
|
|
5416
|
-
if (platform === "win32") return
|
|
5791
|
+
if (platform === "win32") return win326.isAbsolute(p) && /^[a-z]:[\\/]/i.test(p) && win326.basename(p).toLowerCase() === "workbuddy.exe";
|
|
5417
5792
|
return posix2.isAbsolute(p) && posix2.basename(p) === "WorkBuddy.app";
|
|
5418
5793
|
}
|
|
5419
5794
|
var HUNG_RESTART_MS = 20 * 60 * 1e3;
|
|
@@ -5561,11 +5936,11 @@ function winMainProc(procs) {
|
|
|
5561
5936
|
return null;
|
|
5562
5937
|
}
|
|
5563
5938
|
function workbuddyBusy(now = Date.now(), dir2 = stateDir(), alive = isAlive) {
|
|
5564
|
-
if (!
|
|
5565
|
-
for (const f of
|
|
5939
|
+
if (!existsSync19(dir2)) return false;
|
|
5940
|
+
for (const f of readdirSync10(dir2)) {
|
|
5566
5941
|
if (!f.endsWith(".json")) continue;
|
|
5567
5942
|
try {
|
|
5568
|
-
const s = JSON.parse(
|
|
5943
|
+
const s = JSON.parse(readFileSync23(join22(dir2, f), "utf8"));
|
|
5569
5944
|
if (s.tool !== "workbuddy" || s.state !== "watch" && s.state !== "ask_approval") continue;
|
|
5570
5945
|
if (typeof s.pid === "number" && s.pid > 0) {
|
|
5571
5946
|
if (alive(s.pid, s.pidName)) return true;
|
|
@@ -5883,7 +6258,7 @@ var CdpKeeper = class {
|
|
|
5883
6258
|
this.#loadThrottle();
|
|
5884
6259
|
let path = null;
|
|
5885
6260
|
try {
|
|
5886
|
-
const exists = this.#d.exists ??
|
|
6261
|
+
const exists = this.#d.exists ?? existsSync19;
|
|
5887
6262
|
if (this.#appExe && isValidAppPath(this.#appExe, this.#platform()) && exists(this.#appExe)) path = this.#appExe;
|
|
5888
6263
|
else {
|
|
5889
6264
|
const found = await (this.#d.appPath ? this.#d.appPath() : defaultWorkbuddyAppPath());
|
|
@@ -6099,12 +6474,12 @@ var TYPE_TEXT = "text";
|
|
|
6099
6474
|
var TYPE_SUMMARY = "summary";
|
|
6100
6475
|
var MAX_TEXT_LENGTH = 2e3;
|
|
6101
6476
|
var MAX_ID_LENGTH = 64;
|
|
6102
|
-
function
|
|
6477
|
+
function str2(v) {
|
|
6103
6478
|
return typeof v === "string" ? v : "";
|
|
6104
6479
|
}
|
|
6105
6480
|
function parseMillis(v) {
|
|
6106
6481
|
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
6107
|
-
const s =
|
|
6482
|
+
const s = str2(v).trim();
|
|
6108
6483
|
if (!/^\d{1,16}$/.test(s)) return 0;
|
|
6109
6484
|
const n = Number(s);
|
|
6110
6485
|
return Number.isSafeInteger(n) ? n : 0;
|
|
@@ -6117,21 +6492,21 @@ function sanitizeText(raw) {
|
|
|
6117
6492
|
}
|
|
6118
6493
|
function parseCommand(frame) {
|
|
6119
6494
|
const f = frame;
|
|
6120
|
-
if (!f ||
|
|
6495
|
+
if (!f || str2(f.service) !== SERVICE_COMMAND) return null;
|
|
6121
6496
|
const d = f.data;
|
|
6122
6497
|
if (!d || typeof d !== "object") return null;
|
|
6123
|
-
const instructionId =
|
|
6498
|
+
const instructionId = str2(d.instructionId);
|
|
6124
6499
|
if (!isValidId(instructionId)) return null;
|
|
6125
|
-
const type =
|
|
6500
|
+
const type = str2(d.type);
|
|
6126
6501
|
if (type !== TYPE_TEXT && type !== TYPE_SUMMARY) return null;
|
|
6127
|
-
const tool =
|
|
6502
|
+
const tool = str2(d.tool);
|
|
6128
6503
|
if (!isValidId(tool)) return null;
|
|
6129
|
-
const sessionId =
|
|
6504
|
+
const sessionId = str2(d.sessionId);
|
|
6130
6505
|
if (sessionId && !isValidId(sessionId)) return null;
|
|
6131
6506
|
if (type === TYPE_SUMMARY && !sessionId) return null;
|
|
6132
|
-
const text = sanitizeText(
|
|
6507
|
+
const text = sanitizeText(str2(d.text));
|
|
6133
6508
|
if (!text || text.length > MAX_TEXT_LENGTH) return null;
|
|
6134
|
-
const rawDir =
|
|
6509
|
+
const rawDir = str2(d.dirRef);
|
|
6135
6510
|
const dirRef = !sessionId && /^[0-9a-f]{16}$/.test(rawDir) ? rawDir : "";
|
|
6136
6511
|
const cmd = { instructionId, type, sessionId, tool, text, expireAt: parseMillis(d.expireAt), dirRef };
|
|
6137
6512
|
if (type === TYPE_SUMMARY) cmd.kind = "summary";
|
|
@@ -6151,14 +6526,14 @@ function cleanFeedback(v) {
|
|
|
6151
6526
|
}
|
|
6152
6527
|
function parseApprovalFrame(frame) {
|
|
6153
6528
|
const f = frame;
|
|
6154
|
-
if (!f ||
|
|
6529
|
+
if (!f || str2(f.service) !== SERVICE_COMMAND) return null;
|
|
6155
6530
|
const d = f.data;
|
|
6156
|
-
if (!d || typeof d !== "object" ||
|
|
6157
|
-
const instructionId =
|
|
6531
|
+
if (!d || typeof d !== "object" || str2(d.type) !== TYPE_APPROVAL) return null;
|
|
6532
|
+
const instructionId = str2(d.instructionId);
|
|
6158
6533
|
if (!isValidId(instructionId)) return null;
|
|
6159
|
-
const approvalId =
|
|
6534
|
+
const approvalId = str2(d.approvalId);
|
|
6160
6535
|
if (!isValidId(approvalId)) return null;
|
|
6161
|
-
const decision =
|
|
6536
|
+
const decision = str2(d.decision);
|
|
6162
6537
|
if (decision !== "allow" && decision !== "deny" && decision !== "allow_always") return null;
|
|
6163
6538
|
return {
|
|
6164
6539
|
instructionId,
|
|
@@ -6178,6 +6553,11 @@ function optionFields(d) {
|
|
|
6178
6553
|
function cleanDeviceName(v) {
|
|
6179
6554
|
return typeof v === "string" ? v.replace(/[\u0000-\u001f\u007f]/g, "").trim().slice(0, 32) : "";
|
|
6180
6555
|
}
|
|
6556
|
+
var APP_WAIT_MARGIN_MS = 20 * 1e3;
|
|
6557
|
+
function appWaitBudget(expireAt, now, max) {
|
|
6558
|
+
if (!(expireAt > 0)) return max;
|
|
6559
|
+
return Math.min(max, expireAt - now - APP_WAIT_MARGIN_MS);
|
|
6560
|
+
}
|
|
6181
6561
|
function isExpired(cmd, now = Date.now()) {
|
|
6182
6562
|
return cmd.expireAt > 0 && now > cmd.expireAt;
|
|
6183
6563
|
}
|
|
@@ -6408,6 +6788,12 @@ var QoderAppTasks = class {
|
|
|
6408
6788
|
async #ensureReady(cmd, sid, q, report, mayWake) {
|
|
6409
6789
|
if (this.available()) return true;
|
|
6410
6790
|
if (!mayWake || !this.#d.wake || !this.canWake()) return false;
|
|
6791
|
+
const raw = appWaitBudget(cmd.expireAt, this.#d.now(), QODER_APP_WAKE_WAIT_MS);
|
|
6792
|
+
const budget = Math.max(0, raw);
|
|
6793
|
+
if (raw <= 0 && !sid) {
|
|
6794
|
+
this.#d.log(`\u6307\u4EE4 ${cmd.instructionId} \u79BB\u8FC7\u671F\u4E0D\u5230 ${APP_WAIT_MARGIN_MS / 1e3} \u79D2\uFF0C\u4E0D\u7B49 ${this.#d.label} App\uFF0C\u76F4\u63A5\u56DE\u843D`);
|
|
6795
|
+
return false;
|
|
6796
|
+
}
|
|
6411
6797
|
let w;
|
|
6412
6798
|
q.wakeAt = this.#d.now();
|
|
6413
6799
|
try {
|
|
@@ -6425,13 +6811,13 @@ var QoderAppTasks = class {
|
|
|
6425
6811
|
this.#d.log(`\u6307\u4EE4 ${cmd.instructionId} \u7B49 ${this.#d.label} App ${w === "launched" ? "\u6253\u5F00" : w === "restarted" ? "\u5E26\u7AEF\u53E3\u91CD\u542F" : "\u8FDE\u4E0A"}`);
|
|
6426
6812
|
report("queued", sid);
|
|
6427
6813
|
}
|
|
6428
|
-
const end =
|
|
6814
|
+
const end = q.wakeAt + budget;
|
|
6429
6815
|
while (this.#d.now() < end) {
|
|
6430
6816
|
this.#d.kick?.();
|
|
6431
|
-
await this.#sleep(this.#d.pollMs ?? QODER_APP_POLL_MS);
|
|
6817
|
+
await this.#sleep(Math.max(1, Math.min(this.#d.pollMs ?? QODER_APP_POLL_MS, end - this.#d.now())));
|
|
6432
6818
|
if (this.available()) return true;
|
|
6433
6819
|
}
|
|
6434
|
-
this.#d.log(`\u6307\u4EE4 ${cmd.instructionId} ${this.#d.label} App ${
|
|
6820
|
+
this.#d.log(`\u6307\u4EE4 ${cmd.instructionId} ${this.#d.label} App ${Math.round(budget / 1e3)} \u79D2\u5185\u6CA1\u8FDE\u4E0A${budget < QODER_APP_WAKE_WAIT_MS ? "\uFF08\u518D\u7B49\u6307\u4EE4\u5C31\u8FC7\u671F\u4E86\uFF09" : ""}`);
|
|
6435
6821
|
return false;
|
|
6436
6822
|
}
|
|
6437
6823
|
/** 只给测试和诊断用 */
|
|
@@ -6918,17 +7304,17 @@ var hasArg = (cc) => Object.values(cc.tool_input).some((v) => typeof v === "stri
|
|
|
6918
7304
|
function dumateAskCc(p, call2) {
|
|
6919
7305
|
if (call2 && hasArg(call2.cc)) return call2.cc;
|
|
6920
7306
|
const md = p.metadata && typeof p.metadata === "object" ? p.metadata : {};
|
|
6921
|
-
const
|
|
6922
|
-
const file3 =
|
|
6923
|
-
const dir2 =
|
|
7307
|
+
const str3 = (v) => typeof v === "string" ? v : "";
|
|
7308
|
+
const file3 = str3(md.filepath) || str3(md.filePath) || str3(md.hostPath);
|
|
7309
|
+
const dir2 = str3(md.parentDir) || str3(md.hostParentDir);
|
|
6924
7310
|
const patterns = Array.isArray(p.patterns) ? p.patterns.filter((x) => typeof x === "string").join(" ") : "";
|
|
6925
7311
|
if (call2 && call2.tool) {
|
|
6926
|
-
const cc = toCcTool(call2.tool, { filePath: file3, command:
|
|
7312
|
+
const cc = toCcTool(call2.tool, { filePath: file3, command: str3(md.command), path: dir2 || patterns, pattern: str3(md.pattern), url: str3(md.url) });
|
|
6927
7313
|
if (hasArg(cc)) return cc;
|
|
6928
7314
|
}
|
|
6929
7315
|
if (p.permission === "external_directory") {
|
|
6930
7316
|
const display = p.display && typeof p.display === "object" ? p.display : {};
|
|
6931
|
-
return { tool_name:
|
|
7317
|
+
return { tool_name: str3(display.title) || "\u8BBF\u95EE\u5DE5\u4F5C\u533A\u5916\u76EE\u5F55", tool_input: { path: file3 || dir2 || patterns } };
|
|
6932
7318
|
}
|
|
6933
7319
|
return askToCc(p);
|
|
6934
7320
|
}
|
|
@@ -6936,7 +7322,7 @@ function scanSessionDirs(root, now, maxAgeMs = ACTIVE_DIR_MS) {
|
|
|
6936
7322
|
const out = [];
|
|
6937
7323
|
const list = (p) => {
|
|
6938
7324
|
try {
|
|
6939
|
-
return
|
|
7325
|
+
return readdirSync11(p, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => join23(p, d.name));
|
|
6940
7326
|
} catch {
|
|
6941
7327
|
return [];
|
|
6942
7328
|
}
|
|
@@ -6945,7 +7331,7 @@ function scanSessionDirs(root, now, maxAgeMs = ACTIVE_DIR_MS) {
|
|
|
6945
7331
|
for (const day of list(u).sort().reverse().slice(0, 2))
|
|
6946
7332
|
for (const dir2 of list(day)) {
|
|
6947
7333
|
try {
|
|
6948
|
-
const at =
|
|
7334
|
+
const at = statSync11(dir2).mtimeMs;
|
|
6949
7335
|
if (now - at <= maxAgeMs) out.push({ dir: dir2, at });
|
|
6950
7336
|
} catch {
|
|
6951
7337
|
}
|
|
@@ -7088,14 +7474,14 @@ var DumateWatch = class {
|
|
|
7088
7474
|
return this.#d.alt.subscribe;
|
|
7089
7475
|
}
|
|
7090
7476
|
/** 设备新建 / 回复用的目标:可用就用;不可用按规则唤起并等连上(ensure);还是不行返回原因码 */
|
|
7091
|
-
async #ensureTarget() {
|
|
7477
|
+
async #ensureTarget(expireAt = 0) {
|
|
7092
7478
|
const pick = () => this.#discover(false);
|
|
7093
7479
|
let t = this.#target ?? pick();
|
|
7094
7480
|
if (t) return t;
|
|
7095
7481
|
let why = APP_NOT_RUNNING;
|
|
7096
7482
|
if (this.#d.ensure) {
|
|
7097
7483
|
try {
|
|
7098
|
-
why = await this.#d.ensure();
|
|
7484
|
+
why = await this.#d.ensure(expireAt);
|
|
7099
7485
|
} catch {
|
|
7100
7486
|
why = APP_NOT_RUNNING;
|
|
7101
7487
|
}
|
|
@@ -7110,12 +7496,12 @@ var DumateWatch = class {
|
|
|
7110
7496
|
* model / agent 取法同回复:没有历史,直接 GET /config 的 model + agent='build'。
|
|
7111
7497
|
* 幂等:同一 instructionId 在本进程里只建一次(跨重启靠 daemon 的 seen 去重);/session 不收客户端指定 id,所以不做确定性 id
|
|
7112
7498
|
*/
|
|
7113
|
-
async startTask(cwd, text, instructionId) {
|
|
7499
|
+
async startTask(cwd, text, instructionId, expireAt = 0) {
|
|
7114
7500
|
const notSent = (reason, message) => ({ status: "not_sent", reason, message });
|
|
7115
7501
|
if (this.#d.enabled && !this.#d.enabled()) return notSent("tool_unsupported", "\u767E\u5EA6\u642D\u5B50\u6CA1\u6709\u63A5\u5165");
|
|
7116
7502
|
const existing = instructionId ? this.#newTasks.get(instructionId) : void 0;
|
|
7117
7503
|
if (existing) return { status: "started", sessionId: existing };
|
|
7118
|
-
const got = await this.#ensureTarget();
|
|
7504
|
+
const got = await this.#ensureTarget(expireAt);
|
|
7119
7505
|
if (typeof got === "string") return notSent(got, unavailableMessage(got));
|
|
7120
7506
|
const t = got;
|
|
7121
7507
|
const http = this.#http(t);
|
|
@@ -7149,10 +7535,10 @@ var DumateWatch = class {
|
|
|
7149
7535
|
* 请求体与界面自己发消息一致:带这个会话最后一条用户消息的 agent / model(没有就 build + /config 的 model)。
|
|
7150
7536
|
* 先查 /session/status 判忙闲(busy / preparing / retry → queued),再 POST prompt_async(带会话目录)
|
|
7151
7537
|
*/
|
|
7152
|
-
async deliverReply(sessionId, text) {
|
|
7538
|
+
async deliverReply(sessionId, text, expireAt = 0) {
|
|
7153
7539
|
const notSent = (reason, message) => ({ status: "not_sent", reason, message });
|
|
7154
7540
|
if (this.#d.enabled && !this.#d.enabled()) return notSent("tool_unsupported", "\u767E\u5EA6\u642D\u5B50\u6CA1\u6709\u63A5\u5165");
|
|
7155
|
-
const got = await this.#ensureTarget();
|
|
7541
|
+
const got = await this.#ensureTarget(expireAt);
|
|
7156
7542
|
if (typeof got === "string") return notSent(got, unavailableMessage(got));
|
|
7157
7543
|
const t = got;
|
|
7158
7544
|
const http = this.#http(t);
|
|
@@ -7567,7 +7953,7 @@ var DumateWatch = class {
|
|
|
7567
7953
|
const now = this.#now();
|
|
7568
7954
|
if (now - this.#scanAt >= SCAN_DIRS_MS) {
|
|
7569
7955
|
this.#scanAt = now;
|
|
7570
|
-
for (const d of (this.#d.sessionDirs ?? (() => scanSessionDirs(
|
|
7956
|
+
for (const d of (this.#d.sessionDirs ?? (() => scanSessionDirs(join23(qianfanHome(), "workspace", "sessions"), now)))()) {
|
|
7571
7957
|
if (!this.#dirs.has(dirKey(d))) this.#touchDir(d, now);
|
|
7572
7958
|
}
|
|
7573
7959
|
}
|
|
@@ -7679,9 +8065,9 @@ function runHook(node, input, agentPid, tool = "dumate") {
|
|
|
7679
8065
|
}
|
|
7680
8066
|
|
|
7681
8067
|
// src/daemon/qoderApp/keeper.ts
|
|
7682
|
-
import { existsSync as
|
|
8068
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync22, readdirSync as readdirSync12, readFileSync as readFileSync24, renameSync as renameSync16, writeFileSync as writeFileSync22 } from "fs";
|
|
7683
8069
|
import { homedir as homedir7 } from "os";
|
|
7684
|
-
import { join as
|
|
8070
|
+
import { join as join24, win32 as win327 } from "path";
|
|
7685
8071
|
var WAKE_LAUNCH_GAP_MS2 = 60 * 1e3;
|
|
7686
8072
|
var RESTART_GAP_MS2 = 30 * 60 * 1e3;
|
|
7687
8073
|
var RESTART_DAILY_MAX2 = 3;
|
|
@@ -7693,7 +8079,7 @@ function winBrandMainProc(procs, exe) {
|
|
|
7693
8079
|
for (const p of procs) {
|
|
7694
8080
|
const argv = winSplitArgs(p.cmdline);
|
|
7695
8081
|
const first = argv[0] ?? "";
|
|
7696
|
-
if (
|
|
8082
|
+
if (win327.basename(first).toLowerCase() !== want) continue;
|
|
7697
8083
|
const rest = argv.slice(1);
|
|
7698
8084
|
if (rest.some((a) => a.startsWith("--type=") || !a.startsWith("-") || /\.(c|m)?js$/i.test(a))) continue;
|
|
7699
8085
|
return { pid: p.pid, exe: first };
|
|
@@ -7709,7 +8095,7 @@ function winBrandMains(procs, exe) {
|
|
|
7709
8095
|
return out;
|
|
7710
8096
|
}
|
|
7711
8097
|
function isWinAppExe(p, exe) {
|
|
7712
|
-
return typeof p === "string" && /^[a-z]:[\\/]/i.test(p) &&
|
|
8098
|
+
return typeof p === "string" && /^[a-z]:[\\/]/i.test(p) && win327.basename(p).toLowerCase() === exe.toLowerCase();
|
|
7713
8099
|
}
|
|
7714
8100
|
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)`;
|
|
7715
8101
|
function parseWinSession(out) {
|
|
@@ -7740,11 +8126,11 @@ function parseLsappBundle(out) {
|
|
|
7740
8126
|
return m ? m[1] : null;
|
|
7741
8127
|
}
|
|
7742
8128
|
function toolBusy(tool, now = Date.now(), dir2 = stateDir(), alive = isAlive) {
|
|
7743
|
-
if (!
|
|
7744
|
-
for (const f of
|
|
8129
|
+
if (!existsSync20(dir2)) return false;
|
|
8130
|
+
for (const f of readdirSync12(dir2)) {
|
|
7745
8131
|
if (!f.endsWith(".json")) continue;
|
|
7746
8132
|
try {
|
|
7747
|
-
const s = JSON.parse(
|
|
8133
|
+
const s = JSON.parse(readFileSync24(join24(dir2, f), "utf8"));
|
|
7748
8134
|
if (s.tool !== tool || s.state !== "watch" && s.state !== "ask_approval") continue;
|
|
7749
8135
|
if (typeof s.pid === "number" && s.pid > 0) {
|
|
7750
8136
|
if (alive(s.pid, s.pidName)) return true;
|
|
@@ -7757,7 +8143,7 @@ function toolBusy(tool, now = Date.now(), dir2 = stateDir(), alive = isAlive) {
|
|
|
7757
8143
|
return false;
|
|
7758
8144
|
}
|
|
7759
8145
|
function defaultThrottleFile() {
|
|
7760
|
-
return
|
|
8146
|
+
return join24(deskbuddyHome(), "qoderapp", "keeper.json");
|
|
7761
8147
|
}
|
|
7762
8148
|
var QoderCdpKeeper = class {
|
|
7763
8149
|
#d;
|
|
@@ -7847,7 +8233,7 @@ var QoderCdpKeeper = class {
|
|
|
7847
8233
|
/** 节流状态(按品牌一份,落盘;读不出当没有) */
|
|
7848
8234
|
#loadThrottle() {
|
|
7849
8235
|
try {
|
|
7850
|
-
const all = JSON.parse(
|
|
8236
|
+
const all = JSON.parse(readFileSync24(this.#file(), "utf8"));
|
|
7851
8237
|
const t = all?.[this.#d.brand.tool] ?? {};
|
|
7852
8238
|
const out = { lastLaunch: Number(t.lastLaunch) || 0, lastRestart: Number(t.lastRestart) || 0, day: typeof t.day === "string" ? t.day : "", restarts: Number(t.restarts) || 0 };
|
|
7853
8239
|
if (this.#d.brand.win && isWinAppExe(t.appExe, this.#d.brand.win.exe)) out.appExe = t.appExe;
|
|
@@ -7861,14 +8247,14 @@ var QoderCdpKeeper = class {
|
|
|
7861
8247
|
try {
|
|
7862
8248
|
let all = {};
|
|
7863
8249
|
try {
|
|
7864
|
-
all = JSON.parse(
|
|
8250
|
+
all = JSON.parse(readFileSync24(f, "utf8"));
|
|
7865
8251
|
} catch {
|
|
7866
8252
|
all = {};
|
|
7867
8253
|
}
|
|
7868
8254
|
all[this.#d.brand.tool] = t;
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
8255
|
+
mkdirSync22(join24(f, ".."), { recursive: true });
|
|
8256
|
+
writeFileSync22(f + ".tmp", JSON.stringify(all));
|
|
8257
|
+
renameSync16(f + ".tmp", f);
|
|
7872
8258
|
} catch {
|
|
7873
8259
|
}
|
|
7874
8260
|
}
|
|
@@ -7941,14 +8327,15 @@ var QoderCdpKeeper = class {
|
|
|
7941
8327
|
if (this.#d.appPath) return this.#d.appPath();
|
|
7942
8328
|
if (this.#isWin()) {
|
|
7943
8329
|
const win = this.#d.brand.win;
|
|
7944
|
-
const exists = this.#d.exists ??
|
|
8330
|
+
const exists = this.#d.exists ?? existsSync20;
|
|
7945
8331
|
const t = this.#loadThrottle();
|
|
7946
|
-
|
|
8332
|
+
const located = this.#d.locatedExe ? this.#d.locatedExe() : cachedWinAppExe(this.#d.brand.tool);
|
|
8333
|
+
for (const p of [t.appExe, located, ...win.installPaths?.() ?? []]) if (isWinAppExe(p, win.exe) && exists(p)) return p;
|
|
7947
8334
|
return null;
|
|
7948
8335
|
}
|
|
7949
8336
|
if (this.#platform() !== "darwin") return null;
|
|
7950
8337
|
const name = this.#d.brand.macApp.split("/").pop() ?? "";
|
|
7951
|
-
for (const p of [this.#d.brand.macApp,
|
|
8338
|
+
for (const p of [this.#d.brand.macApp, join24(homedir7(), "Applications", name)]) if (existsSync20(p)) return p;
|
|
7952
8339
|
return null;
|
|
7953
8340
|
}
|
|
7954
8341
|
/** 一轮:健康检查 → 活着核对属主。🔴 平时不重启 App;只有端口无响应满 HUNG_RESTART_MS 时按节流与在场规则重启 */
|
|
@@ -8215,33 +8602,33 @@ var DUMATE_BRAND = {
|
|
|
8215
8602
|
installPaths: () => {
|
|
8216
8603
|
const out = [];
|
|
8217
8604
|
const la = process.env.LOCALAPPDATA;
|
|
8218
|
-
if (la) out.push(
|
|
8219
|
-
for (const pf of [process.env.ProgramFiles, process.env["ProgramFiles(x86)"]]) if (pf) out.push(
|
|
8605
|
+
if (la) out.push(join25(la, "Programs", "DuMate", "DuMate.exe"), join25(la, "Programs", "qianfan-desktop-app", "DuMate.exe"));
|
|
8606
|
+
for (const pf of [process.env.ProgramFiles, process.env["ProgramFiles(x86)"]]) if (pf) out.push(join25(pf, "DuMate", "DuMate.exe"));
|
|
8220
8607
|
return out;
|
|
8221
8608
|
}
|
|
8222
8609
|
}
|
|
8223
8610
|
};
|
|
8224
8611
|
var DM_DOWN_ROUNDS = 2;
|
|
8225
8612
|
var DM_ACTIVE_MS = 10 * 60 * 1e3;
|
|
8226
|
-
function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsRoot =
|
|
8613
|
+
function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsRoot = join25(qianfanHome(), "workspace", "sessions")) {
|
|
8227
8614
|
let latest = -1;
|
|
8228
|
-
const xdg =
|
|
8615
|
+
const xdg = join25(dataHome, "qianfan_desk_xdg");
|
|
8229
8616
|
let users = [];
|
|
8230
8617
|
try {
|
|
8231
|
-
users =
|
|
8618
|
+
users = readdirSync13(xdg);
|
|
8232
8619
|
} catch {
|
|
8233
8620
|
users = [];
|
|
8234
8621
|
}
|
|
8235
8622
|
let found = false;
|
|
8236
8623
|
for (const u of users) {
|
|
8237
|
-
const dir2 =
|
|
8624
|
+
const dir2 = join25(xdg, u, "data", "opencode");
|
|
8238
8625
|
try {
|
|
8239
|
-
latest = Math.max(latest,
|
|
8626
|
+
latest = Math.max(latest, statSync12(join25(dir2, "opencode.db")).mtimeMs);
|
|
8240
8627
|
found = true;
|
|
8241
8628
|
} catch {
|
|
8242
8629
|
}
|
|
8243
8630
|
try {
|
|
8244
|
-
const w =
|
|
8631
|
+
const w = statSync12(join25(dir2, "opencode.db-wal"));
|
|
8245
8632
|
if (w.size > 0) latest = Math.max(latest, w.mtimeMs);
|
|
8246
8633
|
} catch {
|
|
8247
8634
|
}
|
|
@@ -8252,7 +8639,7 @@ function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsR
|
|
|
8252
8639
|
return "idle";
|
|
8253
8640
|
}
|
|
8254
8641
|
function dmKeeperThrottleFile() {
|
|
8255
|
-
return
|
|
8642
|
+
return join25(deskbuddyHome(), "dmapp", "keeper.json");
|
|
8256
8643
|
}
|
|
8257
8644
|
var DumateKeeper = class {
|
|
8258
8645
|
#d;
|
|
@@ -8362,7 +8749,8 @@ var DUMATE_SHORTCUT_APP = {
|
|
|
8362
8749
|
port: dmPort,
|
|
8363
8750
|
wanted: shortcutsWanted,
|
|
8364
8751
|
off: () => loadConfig().dumateShortcuts === false,
|
|
8365
|
-
skipEnv: "DESKBUDDY_SKIP_DM_LNK"
|
|
8752
|
+
skipEnv: "DESKBUDDY_SKIP_DM_LNK",
|
|
8753
|
+
locatedExe: () => cachedWinAppExe("dumate")
|
|
8366
8754
|
};
|
|
8367
8755
|
function ensureDumateShortcuts(d, ps = defaultPs) {
|
|
8368
8756
|
return ensureAppShortcuts(DUMATE_SHORTCUT_APP, d, ps);
|
|
@@ -8433,7 +8821,8 @@ function qoderShortcutApp(tool) {
|
|
|
8433
8821
|
port: () => portOf2(tool),
|
|
8434
8822
|
wanted: () => qoderShortcutsWanted(tool),
|
|
8435
8823
|
off: () => loadConfig().qoderShortcuts === false,
|
|
8436
|
-
skipEnv: "DESKBUDDY_SKIP_QODER_LNK"
|
|
8824
|
+
skipEnv: "DESKBUDDY_SKIP_QODER_LNK",
|
|
8825
|
+
locatedExe: () => cachedWinAppExe(tool)
|
|
8437
8826
|
};
|
|
8438
8827
|
}
|
|
8439
8828
|
function ensureQoderShortcuts(tool, d, ps = defaultPs) {
|
|
@@ -8447,15 +8836,15 @@ function restoreQoderShortcutsSync(tool, d, ps = defaultPsSync) {
|
|
|
8447
8836
|
}
|
|
8448
8837
|
|
|
8449
8838
|
// src/adapters/traeHook.ts
|
|
8450
|
-
import { chmodSync as chmodSync5, existsSync as
|
|
8451
|
-
import { dirname as dirname13, join as
|
|
8839
|
+
import { chmodSync as chmodSync5, existsSync as existsSync21, mkdirSync as mkdirSync23, readFileSync as readFileSync25, realpathSync as realpathSync5, renameSync as renameSync17, rmSync as rmSync13, statSync as statSync13, writeFileSync as writeFileSync23 } from "fs";
|
|
8840
|
+
import { dirname as dirname13, join as join27 } from "path";
|
|
8452
8841
|
var TRAE_EVENTS = ["UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop", "Notification"];
|
|
8453
8842
|
var TRAE_NOTICE_TYPES = ["permission_prompt", "ask_user_question", "document_review", "browser_interaction"];
|
|
8454
8843
|
var TRAE_NOTICE_MATCHER = `^(${TRAE_NOTICE_TYPES.join("|")})$`;
|
|
8455
8844
|
var TRAE_NOTICE_TIMEOUT_S = 7 * 24 * 60 * 60;
|
|
8456
8845
|
function readHooksFile(path) {
|
|
8457
|
-
if (!
|
|
8458
|
-
const raw =
|
|
8846
|
+
if (!existsSync21(path)) return {};
|
|
8847
|
+
const raw = readFileSync25(path, "utf8");
|
|
8459
8848
|
if (raw.trim() === "") return {};
|
|
8460
8849
|
let parsed;
|
|
8461
8850
|
try {
|
|
@@ -8477,19 +8866,19 @@ function writeTarget(path) {
|
|
|
8477
8866
|
}
|
|
8478
8867
|
}
|
|
8479
8868
|
function writeHooksFile(linkPath, f) {
|
|
8480
|
-
|
|
8869
|
+
mkdirSync23(dirname13(linkPath), { recursive: true });
|
|
8481
8870
|
const path = writeTarget(linkPath);
|
|
8482
8871
|
let mode;
|
|
8483
8872
|
try {
|
|
8484
|
-
mode =
|
|
8873
|
+
mode = statSync13(path).mode & 511;
|
|
8485
8874
|
} catch {
|
|
8486
8875
|
mode = void 0;
|
|
8487
8876
|
}
|
|
8488
8877
|
const tmp = path + ".deskbuddy.tmp";
|
|
8489
8878
|
try {
|
|
8490
|
-
|
|
8879
|
+
writeFileSync23(tmp, JSON.stringify(f, null, 2) + "\n", "utf8");
|
|
8491
8880
|
if (mode !== void 0) chmodSync5(tmp, mode);
|
|
8492
|
-
|
|
8881
|
+
renameSync17(tmp, path);
|
|
8493
8882
|
} catch (e) {
|
|
8494
8883
|
try {
|
|
8495
8884
|
rmSync13(tmp, { force: true });
|
|
@@ -8536,7 +8925,7 @@ function strip(f, scripts) {
|
|
|
8536
8925
|
}
|
|
8537
8926
|
function installTraeHook(path, hookPath, events = TRAE_EVENTS, platform = process.platform) {
|
|
8538
8927
|
const f = readHooksFile(path);
|
|
8539
|
-
const gatePath =
|
|
8928
|
+
const gatePath = join27(dirname13(hookPath), "gate.cjs");
|
|
8540
8929
|
const before = JSON.stringify(f);
|
|
8541
8930
|
strip(f, [hookPath, gatePath]);
|
|
8542
8931
|
if (f.version === void 0) f.version = 1;
|
|
@@ -8553,13 +8942,13 @@ function installTraeHook(path, hookPath, events = TRAE_EVENTS, platform = proces
|
|
|
8553
8942
|
if (JSON.stringify(f) !== before) writeHooksFile(path, f);
|
|
8554
8943
|
}
|
|
8555
8944
|
function uninstallTraeHook(path, hookPath) {
|
|
8556
|
-
if (!
|
|
8945
|
+
if (!existsSync21(path)) return;
|
|
8557
8946
|
const f = readHooksFile(path);
|
|
8558
|
-
if (strip(f, [hookPath,
|
|
8947
|
+
if (strip(f, [hookPath, join27(dirname13(hookPath), "gate.cjs")])) writeHooksFile(path, f);
|
|
8559
8948
|
}
|
|
8560
8949
|
function isTraeHookInstalled(path, hookPath) {
|
|
8561
8950
|
try {
|
|
8562
|
-
if (!
|
|
8951
|
+
if (!existsSync21(path)) return false;
|
|
8563
8952
|
const f = readHooksFile(path);
|
|
8564
8953
|
return Object.values(f.hooks ?? {}).some((groups) => (groups ?? []).some((g) => (g?.hooks ?? []).some((h) => mentions2(h?.command, hookPath))));
|
|
8565
8954
|
} catch {
|
|
@@ -8569,19 +8958,19 @@ function isTraeHookInstalled(path, hookPath) {
|
|
|
8569
8958
|
var TRAE_NOTICE = " TRAE\uFF1A\u8BF7\u5728 TRAE \u7684 \u8BBE\u7F6E > Hooks \u91CC\u786E\u8BA4\u300C\u5168\u5C40\u300DHooks \u5DF2\u542F\u7528\u3001\u8FD0\u884C\u65B9\u5F0F\u9009\u300C\u672C\u5730\u81EA\u52A8\u8FD0\u884C\u300D\uFF08\u6C99\u7BB1\u91CC hook \u8FDE\u4E0D\u4E0A\u5B88\u62A4\u8FDB\u7A0B\uFF09\uFF1B\u7535\u8111\u4E0A\u5F39\u6388\u6743\u6846\u65F6\u8BBE\u5907\u4E0A\u4F1A\u51FA\u73B0\u63D0\u793A\u5361\uFF0C\u9700\u56DE\u5230\u7535\u8111\u4E0A\u5904\u7406";
|
|
8570
8959
|
|
|
8571
8960
|
// src/commands/tools.ts
|
|
8572
|
-
import { existsSync as
|
|
8961
|
+
import { existsSync as existsSync23, readFileSync as readFileSync27 } from "fs";
|
|
8573
8962
|
|
|
8574
8963
|
// src/adapters/cbChannel.ts
|
|
8575
|
-
import { chmodSync as chmodSync6, existsSync as
|
|
8576
|
-
import { dirname as dirname14, join as
|
|
8964
|
+
import { chmodSync as chmodSync6, existsSync as existsSync22, lstatSync as lstatSync2, mkdirSync as mkdirSync24, readFileSync as readFileSync26, realpathSync as realpathSync6, renameSync as renameSync18, statSync as statSync14, writeFileSync as writeFileSync24 } from "fs";
|
|
8965
|
+
import { dirname as dirname14, join as join28 } from "path";
|
|
8577
8966
|
var CB_MCP_NAME = "deskbuddy";
|
|
8578
8967
|
var CB_CHANNEL_SCRIPT = "cbchannel.cjs";
|
|
8579
8968
|
function cbChannelScript(hookPath) {
|
|
8580
|
-
return
|
|
8969
|
+
return join28(dirname14(hookPath), CB_CHANNEL_SCRIPT);
|
|
8581
8970
|
}
|
|
8582
8971
|
function read(path) {
|
|
8583
|
-
if (!
|
|
8584
|
-
const raw =
|
|
8972
|
+
if (!existsSync22(path)) return {};
|
|
8973
|
+
const raw = readFileSync26(path, "utf8");
|
|
8585
8974
|
if (raw.trim() === "") return {};
|
|
8586
8975
|
let v;
|
|
8587
8976
|
try {
|
|
@@ -8599,17 +8988,17 @@ function write2(file3, v) {
|
|
|
8599
8988
|
} catch {
|
|
8600
8989
|
path = file3;
|
|
8601
8990
|
}
|
|
8602
|
-
|
|
8991
|
+
mkdirSync24(dirname14(path), { recursive: true });
|
|
8603
8992
|
let mode;
|
|
8604
8993
|
try {
|
|
8605
|
-
mode =
|
|
8994
|
+
mode = statSync14(path).mode & 511;
|
|
8606
8995
|
} catch {
|
|
8607
8996
|
mode = void 0;
|
|
8608
8997
|
}
|
|
8609
8998
|
const tmp = path + ".deskbuddy.tmp";
|
|
8610
|
-
|
|
8999
|
+
writeFileSync24(tmp, JSON.stringify(v, null, 2), "utf8");
|
|
8611
9000
|
if (mode !== void 0) chmodSync6(tmp, mode);
|
|
8612
|
-
|
|
9001
|
+
renameSync18(tmp, path);
|
|
8613
9002
|
}
|
|
8614
9003
|
function ours(entry) {
|
|
8615
9004
|
if (!entry || typeof entry !== "object") return false;
|
|
@@ -8628,7 +9017,7 @@ function installCbChannel(mcpPath, scriptPath, nodePath = CB_NODE) {
|
|
|
8628
9017
|
write2(mcpPath, f);
|
|
8629
9018
|
}
|
|
8630
9019
|
function uninstallCbChannel(mcpPath) {
|
|
8631
|
-
if (!
|
|
9020
|
+
if (!existsSync22(mcpPath)) return;
|
|
8632
9021
|
const f = read(mcpPath);
|
|
8633
9022
|
const servers = f.mcpServers;
|
|
8634
9023
|
if (!servers || typeof servers !== "object" || Array.isArray(servers) || !ours(servers[CB_MCP_NAME])) return;
|
|
@@ -8649,8 +9038,8 @@ function codebuddyWanted(d = { standalone: () => standaloneProbe() }) {
|
|
|
8649
9038
|
}
|
|
8650
9039
|
function fileContains(path, needle) {
|
|
8651
9040
|
try {
|
|
8652
|
-
if (!
|
|
8653
|
-
return
|
|
9041
|
+
if (!existsSync23(path)) return false;
|
|
9042
|
+
return readFileSync27(path, "utf8").includes(needle);
|
|
8654
9043
|
} catch {
|
|
8655
9044
|
return false;
|
|
8656
9045
|
}
|
|
@@ -8751,7 +9140,7 @@ ADAPTERS["dumate-http"] = {
|
|
|
8751
9140
|
uninstall: () => restoreDumateShortcutsSync({ log: dmLnkLog }),
|
|
8752
9141
|
isInstalled: (p) => {
|
|
8753
9142
|
try {
|
|
8754
|
-
const enabled = JSON.parse(
|
|
9143
|
+
const enabled = JSON.parse(readFileSync27(p, "utf8")).enabledTools;
|
|
8755
9144
|
return Array.isArray(enabled) && enabled.includes("dumate");
|
|
8756
9145
|
} catch {
|
|
8757
9146
|
return false;
|
|
@@ -8772,7 +9161,7 @@ ADAPTERS["trae-hooks"] = {
|
|
|
8772
9161
|
extraConfigPaths: (tool, purpose) => {
|
|
8773
9162
|
if (tool !== "trae") return [];
|
|
8774
9163
|
const primary = pathResolve(traeHooksPath());
|
|
8775
|
-
return traeHooksPaths().filter((p) => pathResolve(p) !== primary && (purpose === "uninstall" ||
|
|
9164
|
+
return traeHooksPaths().filter((p) => pathResolve(p) !== primary && (purpose === "uninstall" || existsSync23(pathDirname(p))));
|
|
8776
9165
|
}
|
|
8777
9166
|
};
|
|
8778
9167
|
var COZE_NOTICE = " \u6263\u5B50\u4E0D\u9700\u8981\u6539\u5B83\u7684\u4EFB\u4F55\u914D\u7F6E\uFF1A\u5B88\u62A4\u8FDB\u7A0B\u5728\u8DD1\u65F6\u4F1A\u8BA9\u6263\u5B50\u5E26\u8C03\u8BD5\u7AEF\u53E3\u542F\u52A8\uFF08\u4F60\u4E0D\u5728\u7535\u8111\u524D\u4E14\u6263\u5B50\u7A7A\u95F2\u65F6\u624D\u4F1A\u91CD\u5F00\u5B83\uFF09\uFF0C\u72B6\u6001\u548C\u5F85\u786E\u8BA4\u90FD\u4F1A\u63A8\u5230\u8BBE\u5907";
|
|
@@ -8784,7 +9173,7 @@ ADAPTERS["coze-cdp"] = {
|
|
|
8784
9173
|
},
|
|
8785
9174
|
isInstalled: (p) => {
|
|
8786
9175
|
try {
|
|
8787
|
-
const enabled = JSON.parse(
|
|
9176
|
+
const enabled = JSON.parse(readFileSync27(p, "utf8")).enabledTools;
|
|
8788
9177
|
return Array.isArray(enabled) && enabled.includes("coze");
|
|
8789
9178
|
} catch {
|
|
8790
9179
|
return false;
|
|
@@ -8815,9 +9204,9 @@ function subscribedEvents(registry, tool, fallback) {
|
|
|
8815
9204
|
}
|
|
8816
9205
|
|
|
8817
9206
|
// src/wrap/pty.ts
|
|
8818
|
-
import { chmodSync as chmodSync7, existsSync as
|
|
9207
|
+
import { chmodSync as chmodSync7, existsSync as existsSync24, statSync as statSync15 } from "fs";
|
|
8819
9208
|
import { createRequire as createRequire4 } from "module";
|
|
8820
|
-
import { dirname as dirname15, join as
|
|
9209
|
+
import { dirname as dirname15, join as join29 } from "path";
|
|
8821
9210
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8822
9211
|
var req = createRequire4(import.meta.url);
|
|
8823
9212
|
var VENDORED_PTY_PLATFORMS = ["darwin-arm64", "darwin-x64", "win32-arm64", "win32-x64"];
|
|
@@ -8827,8 +9216,8 @@ function hasVendoredPty(platform = process.platform, arch = process.arch) {
|
|
|
8827
9216
|
function vendoredPtyDir(from = dirname15(fileURLToPath4(import.meta.url))) {
|
|
8828
9217
|
let dir2 = from;
|
|
8829
9218
|
for (let i = 0; i < 4; i++) {
|
|
8830
|
-
const cand =
|
|
8831
|
-
if (
|
|
9219
|
+
const cand = join29(dir2, "vendor", "node-pty");
|
|
9220
|
+
if (existsSync24(join29(cand, "package.json"))) return cand;
|
|
8832
9221
|
const up = dirname15(dir2);
|
|
8833
9222
|
if (up === dir2) break;
|
|
8834
9223
|
dir2 = up;
|
|
@@ -8838,8 +9227,8 @@ function vendoredPtyDir(from = dirname15(fileURLToPath4(import.meta.url))) {
|
|
|
8838
9227
|
function fixSpawnHelper(ptyDir) {
|
|
8839
9228
|
if (process.platform !== "darwin") return;
|
|
8840
9229
|
try {
|
|
8841
|
-
const helper =
|
|
8842
|
-
if (
|
|
9230
|
+
const helper = join29(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
|
|
9231
|
+
if (existsSync24(helper) && (statSync15(helper).mode & 73) === 0) chmodSync7(helper, 493);
|
|
8843
9232
|
} catch {
|
|
8844
9233
|
}
|
|
8845
9234
|
}
|
|
@@ -8943,10 +9332,10 @@ function accentLine(term, tabRow = /←.*[☐☒].*Submit.*→/) {
|
|
|
8943
9332
|
}
|
|
8944
9333
|
|
|
8945
9334
|
// src/commands/migrateQoder.ts
|
|
8946
|
-
import { dirname as dirname17, join as
|
|
9335
|
+
import { dirname as dirname17, join as join30 } from "path";
|
|
8947
9336
|
|
|
8948
9337
|
// src/core/detect.ts
|
|
8949
|
-
import { existsSync as
|
|
9338
|
+
import { existsSync as existsSync25 } from "fs";
|
|
8950
9339
|
import { dirname as dirname16 } from "path";
|
|
8951
9340
|
|
|
8952
9341
|
// src/daemon/cozeApp/brand.ts
|
|
@@ -9026,7 +9415,7 @@ function toolDetectDirs(tool) {
|
|
|
9026
9415
|
}
|
|
9027
9416
|
var defaultDetectDeps = () => ({
|
|
9028
9417
|
located: (tool) => locate(tool) != null,
|
|
9029
|
-
exists:
|
|
9418
|
+
exists: existsSync25,
|
|
9030
9419
|
env: process.env
|
|
9031
9420
|
});
|
|
9032
9421
|
function callerTool(env) {
|
|
@@ -9047,7 +9436,7 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
|
|
|
9047
9436
|
try {
|
|
9048
9437
|
const cfg = loadConfig();
|
|
9049
9438
|
const hookPath = installedHookPath();
|
|
9050
|
-
const scripts = [hookPath,
|
|
9439
|
+
const scripts = [hookPath, join30(dirname17(hookPath), "gate.cjs")];
|
|
9051
9440
|
if (!retagCcHook(qoderCnSettingsPath(), scripts, "qoder", "qoder_cn")) return false;
|
|
9052
9441
|
const hadQoder = cfg.enabledTools.includes("qoder");
|
|
9053
9442
|
let intl = false;
|
|
@@ -9076,26 +9465,26 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
|
|
|
9076
9465
|
|
|
9077
9466
|
// src/daemon/loginGuide.ts
|
|
9078
9467
|
import { execFile as execFile9, execFileSync as execFileSync13 } from "child_process";
|
|
9079
|
-
import { chmodSync as chmodSync9, existsSync as
|
|
9468
|
+
import { chmodSync as chmodSync9, existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync28, writeFileSync as writeFileSync26 } from "fs";
|
|
9080
9469
|
import { homedir as homedir9 } from "os";
|
|
9081
|
-
import { join as
|
|
9470
|
+
import { join as join34 } from "path";
|
|
9082
9471
|
|
|
9083
9472
|
// src/daemon/executor.ts
|
|
9084
9473
|
import { execFile as execFile7, execFileSync as execFileSync11 } from "child_process";
|
|
9085
9474
|
import { homedir as homedir8 } from "os";
|
|
9086
|
-
import { join as
|
|
9475
|
+
import { join as join32 } from "path";
|
|
9087
9476
|
|
|
9088
9477
|
// src/core/codebuddyDirs.ts
|
|
9089
|
-
import { join as
|
|
9478
|
+
import { join as join31, win32 as win328, posix as posix3 } from "path";
|
|
9090
9479
|
function same(a, b, platform) {
|
|
9091
|
-
const pa = platform === "win32" ?
|
|
9092
|
-
const pb = platform === "win32" ?
|
|
9480
|
+
const pa = platform === "win32" ? win328.resolve(a).toLowerCase() : posix3.resolve(a);
|
|
9481
|
+
const pb = platform === "win32" ? win328.resolve(b).toLowerCase() : posix3.resolve(b);
|
|
9093
9482
|
return pa === pb;
|
|
9094
9483
|
}
|
|
9095
9484
|
function workbuddyRunConfigDir(stateDir2, home, platform = process.platform) {
|
|
9096
|
-
const wb =
|
|
9485
|
+
const wb = join31(home, ".workbuddy");
|
|
9097
9486
|
if (typeof stateDir2 !== "string" || !stateDir2) return wb;
|
|
9098
|
-
const cb =
|
|
9487
|
+
const cb = join31(home, ".codebuddy");
|
|
9099
9488
|
if (same(stateDir2, cb, platform)) return cb;
|
|
9100
9489
|
return wb;
|
|
9101
9490
|
}
|
|
@@ -9187,7 +9576,7 @@ function buildSpawnPlan(cmd, cwd, gate, home = homedir8(), configDir, platform =
|
|
|
9187
9576
|
file: file3,
|
|
9188
9577
|
args: workbuddyPlan(cmd, gate),
|
|
9189
9578
|
cwd,
|
|
9190
|
-
env: { CODEBUDDY_CONFIG_DIR: cmd.sessionId ? workbuddyRunConfigDir(configDir, home, platform) :
|
|
9579
|
+
env: { CODEBUDDY_CONFIG_DIR: cmd.sessionId ? workbuddyRunConfigDir(configDir, home, platform) : join32(home, ".workbuddy") }
|
|
9191
9580
|
};
|
|
9192
9581
|
case "qoder_cn":
|
|
9193
9582
|
case "qoder":
|
|
@@ -9455,9 +9844,9 @@ function killTree(child) {
|
|
|
9455
9844
|
|
|
9456
9845
|
// src/daemon/openWindow.ts
|
|
9457
9846
|
import { execFile as execFile8, execFileSync as execFileSync12, spawn as spawn4 } from "child_process";
|
|
9458
|
-
import { chmodSync as chmodSync8, mkdirSync as
|
|
9847
|
+
import { chmodSync as chmodSync8, mkdirSync as mkdirSync25, rmSync as rmSync14, writeFileSync as writeFileSync25 } from "fs";
|
|
9459
9848
|
import { userInfo } from "os";
|
|
9460
|
-
import { join as
|
|
9849
|
+
import { join as join33 } from "path";
|
|
9461
9850
|
function safePath(p) {
|
|
9462
9851
|
return /^(?:[A-Za-z]:[\\/]|\/)/.test(p) && !/[\r\n\0"'`$%;\u2018-\u201b]/.test(p);
|
|
9463
9852
|
}
|
|
@@ -9556,9 +9945,9 @@ var defaultOpenerDeps = (findWt2) => ({
|
|
|
9556
9945
|
async function openTerminal(t, d) {
|
|
9557
9946
|
checkTarget(t);
|
|
9558
9947
|
if (d.platform === "darwin") {
|
|
9559
|
-
|
|
9560
|
-
const file3 =
|
|
9561
|
-
|
|
9948
|
+
mkdirSync25(launchDir(t.home), { recursive: true, mode: 448 });
|
|
9949
|
+
const file3 = join33(launchDir(t.home), `${t.runId}.command`);
|
|
9950
|
+
writeFileSync25(file3, macCommandScript(t), { encoding: "utf8", mode: 448 });
|
|
9562
9951
|
chmodSync8(file3, 448);
|
|
9563
9952
|
await d.run("open", ["-a", "Terminal", file3]);
|
|
9564
9953
|
return "terminal";
|
|
@@ -9577,7 +9966,7 @@ async function openTerminal(t, d) {
|
|
|
9577
9966
|
function removeCommandFile(home, runId) {
|
|
9578
9967
|
if (!RUN_ID_RE.test(runId)) return;
|
|
9579
9968
|
try {
|
|
9580
|
-
rmSync14(
|
|
9969
|
+
rmSync14(join33(launchDir(home), `${runId}.command`), { force: true });
|
|
9581
9970
|
} catch {
|
|
9582
9971
|
}
|
|
9583
9972
|
}
|
|
@@ -9659,8 +10048,8 @@ var WORKBUDDY_PROBE_ARGS = ["-p", PROBE_TEXT, "--output-format", "json", "--no-s
|
|
|
9659
10048
|
var WORKBUDDY_AUTH_FILE = "Tencent-Cloud.coding-copilot.info";
|
|
9660
10049
|
function workbuddyAuthFile(home, platform, localAppData = "") {
|
|
9661
10050
|
const tail = ["CodeBuddyExtension", "Data", "Public", "auth", WORKBUDDY_AUTH_FILE];
|
|
9662
|
-
if (platform === "darwin") return
|
|
9663
|
-
if (platform === "win32") return localAppData ?
|
|
10051
|
+
if (platform === "darwin") return join34(home, "Library", "Application Support", ...tail);
|
|
10052
|
+
if (platform === "win32") return localAppData ? join34(localAppData, ...tail) : null;
|
|
9664
10053
|
return null;
|
|
9665
10054
|
}
|
|
9666
10055
|
var WORKBUDDY_VIA_APP_NOTE = "WorkBuddy \u5C06\u901A\u8FC7\u684C\u9762 App \u8FD0\u884C\uFF0C\u5728 App \u91CC\u767B\u5F55\u5373\u53EF";
|
|
@@ -9674,7 +10063,7 @@ async function checkWorkbuddy(d) {
|
|
|
9674
10063
|
const auth = d.workbuddyAuthFile?.() ?? null;
|
|
9675
10064
|
if (auth && d.exists?.(auth)) return { tool, state: "logged_in", note: "\u72EC\u7ACB\u7248\u51ED\u636E\u6587\u4EF6\u5728" };
|
|
9676
10065
|
}
|
|
9677
|
-
const env = envFor(d, loc, { CODEBUDDY_CONFIG_DIR:
|
|
10066
|
+
const env = envFor(d, loc, { CODEBUDDY_CONFIG_DIR: join34(d.home, ".workbuddy"), DESKBUDDY_NO_WAKE: "1", [PROBE_ENV]: "1" });
|
|
9678
10067
|
const r = await d.run(loc.file, [...loc.prefixArgs, ...WORKBUDDY_PROBE_ARGS], env, WORKBUDDY_PROBE_TIMEOUT_MS);
|
|
9679
10068
|
const bad = failedRun(r);
|
|
9680
10069
|
if (bad) return { tool, state: "unknown", note: bad };
|
|
@@ -9759,7 +10148,7 @@ var defaultCheckDeps = () => ({
|
|
|
9759
10148
|
home: homedir9(),
|
|
9760
10149
|
codexConfig: () => {
|
|
9761
10150
|
try {
|
|
9762
|
-
return
|
|
10151
|
+
return readFileSync28(join34(codexHome(), "config.toml"), "utf8");
|
|
9763
10152
|
} catch {
|
|
9764
10153
|
return null;
|
|
9765
10154
|
}
|
|
@@ -9769,9 +10158,9 @@ var defaultCheckDeps = () => ({
|
|
|
9769
10158
|
// 与设备任务唤起 App 同一个 locate(locateWorkbuddyAppExe:注册表卸载项 / App Paths / 开始菜单快捷方式…);App 自带 CLI 找得到也算
|
|
9770
10159
|
workbuddyAppInstalled: () => locateWorkbuddyAppExe() !== null || locateWorkbuddyApp() !== null,
|
|
9771
10160
|
workbuddyAuthFile: () => workbuddyAuthFile(homedir9(), process.platform, process.env.LOCALAPPDATA ?? ""),
|
|
9772
|
-
exists: (p) =>
|
|
10161
|
+
exists: (p) => existsSync26(p)
|
|
9773
10162
|
});
|
|
9774
|
-
function daemonCheckDeps(base = defaultLocateDeps(), exeHintsAsync =
|
|
10163
|
+
function daemonCheckDeps(base = defaultLocateDeps(), exeHintsAsync = winWorkbuddyLocatorHints) {
|
|
9775
10164
|
const noPs = { ...base, winAppHints: void 0, winAppExeHints: void 0 };
|
|
9776
10165
|
return {
|
|
9777
10166
|
...defaultCheckDeps(),
|
|
@@ -9873,7 +10262,7 @@ function winLoginScript(cmd) {
|
|
|
9873
10262
|
return lines.join("\r\n") + "\r\n";
|
|
9874
10263
|
}
|
|
9875
10264
|
function loginScriptPath(home, tool, platform) {
|
|
9876
|
-
return
|
|
10265
|
+
return join34(launchDir(home), `login-${tool}.${platform === "win32" ? "ps1" : "command"}`);
|
|
9877
10266
|
}
|
|
9878
10267
|
function winLoginWtArgs(script) {
|
|
9879
10268
|
if (!safePath(script)) throw new Error("\u811A\u672C\u8DEF\u5F84\u91CC\u6709\u4E0D\u80FD\u8FDB\u547D\u4EE4\u884C\u7684\u5B57\u7B26");
|
|
@@ -9910,14 +10299,14 @@ var defaultLoginOpenDeps = () => ({
|
|
|
9910
10299
|
home: deskbuddyHome(),
|
|
9911
10300
|
pathDirs: () => childPath().split(":"),
|
|
9912
10301
|
write: (file3, content) => {
|
|
9913
|
-
|
|
9914
|
-
|
|
10302
|
+
mkdirSync26(join34(file3, ".."), { recursive: true, mode: 448 });
|
|
10303
|
+
writeFileSync26(file3, content, { mode: 448 });
|
|
9915
10304
|
chmodSync9(file3, 448);
|
|
9916
10305
|
}
|
|
9917
10306
|
});
|
|
9918
10307
|
async function installCodebuddyHooks(log) {
|
|
9919
10308
|
try {
|
|
9920
|
-
const { installTools: installTools2 } = await import("./enable-
|
|
10309
|
+
const { installTools: installTools2 } = await import("./enable-EDDFXBHM.js");
|
|
9921
10310
|
installTools2(["workbuddy"], () => {
|
|
9922
10311
|
}, null, { auto: true });
|
|
9923
10312
|
} catch (e) {
|
|
@@ -10102,8 +10491,8 @@ async function autoEnableLoginLog(tools, check, log) {
|
|
|
10102
10491
|
|
|
10103
10492
|
// src/daemon/workbuddySetup.ts
|
|
10104
10493
|
import { execFile as execFile10, spawn as spawn5 } from "child_process";
|
|
10105
|
-
import { existsSync as
|
|
10106
|
-
import { dirname as dirname18, join as
|
|
10494
|
+
import { existsSync as existsSync27 } from "fs";
|
|
10495
|
+
import { dirname as dirname18, join as join35 } from "path";
|
|
10107
10496
|
var DIALOG_TITLE = "DeskBuddy";
|
|
10108
10497
|
var BTN_INSTALL = "\u5B89\u88C5";
|
|
10109
10498
|
var BTN_LATER = "\u6682\u4E0D";
|
|
@@ -10242,9 +10631,9 @@ function npmPlan(d) {
|
|
|
10242
10631
|
for (const f of whichAllIn("npm", d)) {
|
|
10243
10632
|
if (!/\.cmd$/i.test(f)) continue;
|
|
10244
10633
|
const dir2 = dirname18(f);
|
|
10245
|
-
const cli =
|
|
10634
|
+
const cli = join35(dir2, "node_modules", "npm", "bin", "npm-cli.js");
|
|
10246
10635
|
if (!d.exists(cli)) continue;
|
|
10247
|
-
const node =
|
|
10636
|
+
const node = join35(dir2, "node.exe");
|
|
10248
10637
|
return { file: d.exists(node) ? node : d.nodePath, args: [cli, ...NPM_INSTALL_ARGS] };
|
|
10249
10638
|
}
|
|
10250
10639
|
return null;
|
|
@@ -10361,7 +10750,7 @@ async function runOffer(source, d, opts = {}) {
|
|
|
10361
10750
|
}
|
|
10362
10751
|
}
|
|
10363
10752
|
function lockPath() {
|
|
10364
|
-
return
|
|
10753
|
+
return join35(deskbuddyHome(), "workbuddy-setup.lock");
|
|
10365
10754
|
}
|
|
10366
10755
|
var defaultLockDeps = () => ({ path: lockPath(), pid: process.pid, now: () => Date.now(), alive: pidAlive2 });
|
|
10367
10756
|
var WorkbuddyOffer = class {
|
|
@@ -10431,7 +10820,7 @@ function defaultOfferDeps(log) {
|
|
|
10431
10820
|
}),
|
|
10432
10821
|
openLogin: () => defaultOpenLogin(platform),
|
|
10433
10822
|
installHooks: async () => {
|
|
10434
|
-
const { installTools: installTools2 } = await import("./enable-
|
|
10823
|
+
const { installTools: installTools2 } = await import("./enable-EDDFXBHM.js");
|
|
10435
10824
|
installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
|
|
10436
10825
|
},
|
|
10437
10826
|
log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
|
|
@@ -10520,7 +10909,7 @@ function defaultPromptStartDeps(env = process.env) {
|
|
|
10520
10909
|
gui: () => guiAvailable(defaultGuiDeps()),
|
|
10521
10910
|
spawnChild: (source) => {
|
|
10522
10911
|
const cli = process.argv[1];
|
|
10523
|
-
if (!cli || !
|
|
10912
|
+
if (!cli || !existsSync27(cli)) throw new Error("\u627E\u4E0D\u5230 deskbuddy \u81EA\u5DF1\u7684\u5165\u53E3\u6587\u4EF6");
|
|
10524
10913
|
const c = spawn5(process.execPath, [cli, "workbuddy-setup", "--from", source], {
|
|
10525
10914
|
detached: true,
|
|
10526
10915
|
stdio: "ignore",
|
|
@@ -10600,14 +10989,14 @@ function installTools(tools, out, shim = defaultShimEnvForInstall(), opts = {})
|
|
|
10600
10989
|
installed.push(tool);
|
|
10601
10990
|
out(`\u2705 ${tool}\uFF1Ahook \u5DF2\u88C5\u8FDB ${configPath2}\uFF08${events.length} \u4E2A\u4E8B\u4EF6\uFF09`);
|
|
10602
10991
|
try {
|
|
10603
|
-
if (adapter.installWindowGate?.(configPath2,
|
|
10992
|
+
if (adapter.installWindowGate?.(configPath2, join36(dirname19(hookPath), "gate.cjs"), tool)) {
|
|
10604
10993
|
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`);
|
|
10605
10994
|
}
|
|
10606
10995
|
} catch (e) {
|
|
10607
10996
|
out(`\u26A0\uFE0F ${tool}\uFF1A\u8BBE\u5907\u786E\u8BA4\u6388\u6743\u6CA1\u88C5\u4E0A\uFF1A${e.message}`);
|
|
10608
10997
|
}
|
|
10609
10998
|
try {
|
|
10610
|
-
if (adapter.installRewake?.(configPath2,
|
|
10999
|
+
if (adapter.installRewake?.(configPath2, join36(dirname19(hookPath), "wake.cjs"), tool)) {
|
|
10611
11000
|
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`);
|
|
10612
11001
|
}
|
|
10613
11002
|
} catch (e) {
|
|
@@ -10731,6 +11120,9 @@ export {
|
|
|
10731
11120
|
accentLine,
|
|
10732
11121
|
scrubAgentEnv,
|
|
10733
11122
|
scrubForCommand,
|
|
11123
|
+
WIN_APP_SPECS,
|
|
11124
|
+
LOCATE_EVERY_MS,
|
|
11125
|
+
winAppLocator,
|
|
10734
11126
|
defaultLocateDeps,
|
|
10735
11127
|
PROBE_TIMEOUT_MS,
|
|
10736
11128
|
PROBE_SHORT_TTL_MS,
|
|
@@ -10859,6 +11251,8 @@ export {
|
|
|
10859
11251
|
cleanFeedback,
|
|
10860
11252
|
parseApprovalFrame,
|
|
10861
11253
|
cleanDeviceName,
|
|
11254
|
+
APP_WAIT_MARGIN_MS,
|
|
11255
|
+
appWaitBudget,
|
|
10862
11256
|
isExpired,
|
|
10863
11257
|
NOT_REGISTERED_RE_SRC,
|
|
10864
11258
|
PROBE,
|