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