deskbuddy 0.2.0-beta.31 → 0.2.0-beta.33
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-WMCE7UNE.js → chunk-RHIQGM66.js} +296 -80
- package/dist/cli.js +2187 -709
- package/dist/deskbuddy-dsh.mjs +218 -4
- package/dist/{enable-EDDFXBHM.js → enable-NGQ3J3NW.js} +1 -1
- package/dist/gate.cjs +40 -3
- package/dist/hook.cjs +14 -2
- package/dist/opencode.mjs +341 -6
- package/hook/deskbuddy-dsh.d.mts +13 -0
- package/hook/deskbuddy-dsh.mjs +218 -4
- package/hook/gate.cjs +40 -3
- package/hook/hook-debug.log +42 -0
- package/hook/hook.cjs +14 -2
- package/hook/opencode.d.mts +19 -1
- package/hook/opencode.mjs +341 -6
- package/package.json +1 -1
|
@@ -67,6 +67,9 @@ function qoderCnSettingsPath() {
|
|
|
67
67
|
function qwenworkHome() {
|
|
68
68
|
return process.env.DESKBUDDY_QWENWORK_DIR || join(homedir(), ".QwenWorkCN");
|
|
69
69
|
}
|
|
70
|
+
function qwenworkDataHome() {
|
|
71
|
+
return process.env.DESKBUDDY_QWENWORK_CN_HOME || join(homedir(), ".qwenworkcn");
|
|
72
|
+
}
|
|
70
73
|
function qwenworkSettingsPath() {
|
|
71
74
|
return join(qwenworkHome(), "settings.json");
|
|
72
75
|
}
|
|
@@ -145,6 +148,7 @@ function loadConfig() {
|
|
|
145
148
|
approvalPolicy: parsed.approvalPolicy === "all" ? "all" : parsed.approvalPolicy === "commands" ? "commands" : void 0,
|
|
146
149
|
codexAppServer: typeof parsed.codexAppServer === "string" ? parsed.codexAppServer : void 0,
|
|
147
150
|
autoUpdate: typeof parsed.autoUpdate === "boolean" ? parsed.autoUpdate : void 0,
|
|
151
|
+
transcript: parsed.transcript === false ? false : void 0,
|
|
148
152
|
disabledTools: Array.isArray(parsed.disabledTools) ? parsed.disabledTools.filter((t) => typeof t === "string") : void 0,
|
|
149
153
|
workbuddySetup: parseWorkbuddySetup(parsed.workbuddySetup),
|
|
150
154
|
workbuddyAppApproval: typeof parsed.workbuddyAppApproval === "boolean" ? parsed.workbuddyAppApproval : void 0,
|
|
@@ -1019,6 +1023,8 @@ var SERVICES = {
|
|
|
1019
1023
|
var DIRS_SERVICE = "com.shifeng.api.service.api.v2.deskbuddy.deskbuddyclientdirsreportapi";
|
|
1020
1024
|
var INSTALL_REDEEM_SERVICE = "com.shifeng.api.service.api.v2.deskbuddy.deskbuddyinstallredeemapi";
|
|
1021
1025
|
var CMD_RESULT_SERVICE = "com.shifeng.api.service.api.v2.deskbuddy.deskbuddycommandresultapi";
|
|
1026
|
+
var TRANSCRIPT_SERVICE = "com.shifeng.api.service.api.v2.deskbuddy.deskbuddytranscriptappendapi";
|
|
1027
|
+
var CODE_NOT_SUPPORT = "5001";
|
|
1022
1028
|
var COMMAND_OUTPUT_MAX = 8e3;
|
|
1023
1029
|
var APPROVAL_SERVICES = {
|
|
1024
1030
|
create: "com.shifeng.api.service.api.v2.deskbuddy.deskbuddyapprovalcreateapi",
|
|
@@ -1164,7 +1170,8 @@ var api = {
|
|
|
1164
1170
|
dirsReport: (payload) => call(DIRS_SERVICE, payload),
|
|
1165
1171
|
installRedeem: (installCode, clientId, hostName) => call(INSTALL_REDEEM_SERVICE, { installCode, clientId, hostName, ...machineInfo() }),
|
|
1166
1172
|
// 2 秒超时、失败不重试(spec §4.1):回报丢了只是设备少一句提示,任务状态仍由会话快照负责
|
|
1167
|
-
commandResult: (payload, timeoutMs = 2e3) => call(CMD_RESULT_SERVICE, payload, timeoutMs)
|
|
1173
|
+
commandResult: (payload, timeoutMs = 2e3) => call(CMD_RESULT_SERVICE, payload, timeoutMs),
|
|
1174
|
+
transcriptAppend: (payload, timeoutMs = 15e3) => call(TRANSCRIPT_SERVICE, payload, timeoutMs)
|
|
1168
1175
|
};
|
|
1169
1176
|
|
|
1170
1177
|
// src/core/registry.ts
|
|
@@ -1523,6 +1530,19 @@ function installCcWindowGate(settingsPath, gatePath, tool = "claude_code", platf
|
|
|
1523
1530
|
});
|
|
1524
1531
|
writeSettings(settingsPath, settings);
|
|
1525
1532
|
}
|
|
1533
|
+
var PRETOOL_QUESTION_TIMEOUT_S = 660;
|
|
1534
|
+
var PRETOOL_QUESTION_MATCHER = "^AskUserQuestion$";
|
|
1535
|
+
function installCcPreToolQuestion(settingsPath, gatePath, tool, platform = process.platform) {
|
|
1536
|
+
const settings = readSettings(settingsPath);
|
|
1537
|
+
settings.hooks ??= {};
|
|
1538
|
+
const groups = settings.hooks.PreToolUse ??= [];
|
|
1539
|
+
if (groups.some((g) => g.hooks?.some((h) => mentions(h.command, gatePath) && h.command.includes("--pretool-question")))) return;
|
|
1540
|
+
groups.push({
|
|
1541
|
+
matcher: PRETOOL_QUESTION_MATCHER,
|
|
1542
|
+
hooks: [{ type: "command", command: `node ${scriptArg(gatePath, platform, shQuote2)} --pretool-question --tool ${tool}`, timeout: PRETOOL_QUESTION_TIMEOUT_S }]
|
|
1543
|
+
});
|
|
1544
|
+
writeSettings(settingsPath, settings);
|
|
1545
|
+
}
|
|
1526
1546
|
var REWAKE_TIMEOUT_S = 20 * 24 * 60 * 60;
|
|
1527
1547
|
var REWAKE_MESSAGE = "\u4EE5\u4E0B\u662F\u4E00\u6761 DeskBuddy \u8BBE\u5907\u6307\u4EE4\uFF08\u6309\u4F1A\u8BDD\u5F00\u5934 DeskBuddy \u8BF4\u660E\u91CC\u7684\u53E3\u4EE4\u6838\u5BF9\uFF0C\u53E3\u4EE4\u4E00\u81F4\u624D\u7167\u5E38\u6267\u884C\uFF0C\u5B8C\u6210\u540E\u7B80\u8981\u56DE\u590D\u7ED3\u679C\uFF09\uFF1A";
|
|
1528
1548
|
var REWAKE_SUMMARY = "DeskBuddy \u8BBE\u5907\u6307\u4EE4";
|
|
@@ -1875,7 +1895,7 @@ import { join as join26 } from "path";
|
|
|
1875
1895
|
|
|
1876
1896
|
// src/daemon/appShortcuts.ts
|
|
1877
1897
|
import { execFile as execFile2, execFileSync as execFileSync4 } from "child_process";
|
|
1878
|
-
import { mkdirSync as mkdirSync11, readFileSync as
|
|
1898
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync13, renameSync as renameSync8, writeFileSync as writeFileSync11 } from "fs";
|
|
1879
1899
|
import { join as join10, win32 as win322 } from "path";
|
|
1880
1900
|
|
|
1881
1901
|
// src/core/fileLock.ts
|
|
@@ -1938,7 +1958,25 @@ function pidAlive2(pid) {
|
|
|
1938
1958
|
}
|
|
1939
1959
|
|
|
1940
1960
|
// src/daemon/winPaths.ts
|
|
1961
|
+
import { readFileSync as readFileSync12, statSync as statSync4 } from "fs";
|
|
1941
1962
|
import { win32 } from "path";
|
|
1963
|
+
function decodeText(b) {
|
|
1964
|
+
if (b.length >= 2 && b[0] === 255 && b[1] === 254) return b.subarray(2).toString("utf16le");
|
|
1965
|
+
if (b.length >= 2 && b[0] === 254 && b[1] === 255) {
|
|
1966
|
+
const be = Buffer.from(b.subarray(2, 2 + (b.length - 2 & ~1)));
|
|
1967
|
+
return be.swap16().toString("utf16le");
|
|
1968
|
+
}
|
|
1969
|
+
if (b.length >= 3 && b[0] === 239 && b[1] === 187 && b[2] === 191) return b.subarray(3).toString("utf8");
|
|
1970
|
+
return b.toString("utf8");
|
|
1971
|
+
}
|
|
1972
|
+
function readSmallText(p) {
|
|
1973
|
+
try {
|
|
1974
|
+
if (statSync4(p).size > 64 * 1024) return null;
|
|
1975
|
+
return decodeText(readFileSync12(p));
|
|
1976
|
+
} catch {
|
|
1977
|
+
return null;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1942
1980
|
function isValidWinPath(p) {
|
|
1943
1981
|
if (typeof p !== "string" || p.length < 4 || p.length > 1024) return false;
|
|
1944
1982
|
if (!/^[a-z]:\\/i.test(p)) return false;
|
|
@@ -2055,12 +2093,7 @@ function launcherTargets(list, writes, exe) {
|
|
|
2055
2093
|
return [...out];
|
|
2056
2094
|
}
|
|
2057
2095
|
function readSmall(p) {
|
|
2058
|
-
|
|
2059
|
-
if (statSync4(p).size > 64 * 1024) return null;
|
|
2060
|
-
return readFileSync12(p, "utf8");
|
|
2061
|
-
} catch {
|
|
2062
|
-
return null;
|
|
2063
|
-
}
|
|
2096
|
+
return readSmallText(p);
|
|
2064
2097
|
}
|
|
2065
2098
|
var keyOf = (p) => p.toLowerCase();
|
|
2066
2099
|
function planPatchFor(exe, list, records, port) {
|
|
@@ -2092,7 +2125,7 @@ function recordsFile(app) {
|
|
|
2092
2125
|
}
|
|
2093
2126
|
function loadRecords(file3) {
|
|
2094
2127
|
try {
|
|
2095
|
-
const v = JSON.parse(
|
|
2128
|
+
const v = JSON.parse(readFileSync13(file3, "utf8"));
|
|
2096
2129
|
if (!v || typeof v !== "object") return {};
|
|
2097
2130
|
const out = {};
|
|
2098
2131
|
for (const [k, r] of Object.entries(v)) {
|
|
@@ -2161,7 +2194,7 @@ var writeEnv = (app, ops, list) => ({
|
|
|
2161
2194
|
var matcherOf = (app, d, restore = false) => lnkMatcher(app, d.readText, restore);
|
|
2162
2195
|
function loadFails(app, d) {
|
|
2163
2196
|
try {
|
|
2164
|
-
const v = JSON.parse(
|
|
2197
|
+
const v = JSON.parse(readFileSync13(failFileOf(app, d), "utf8"));
|
|
2165
2198
|
const out = {};
|
|
2166
2199
|
for (const [k, t] of Object.entries(v ?? {})) if (typeof t === "number") out[k] = t;
|
|
2167
2200
|
return out;
|
|
@@ -2317,12 +2350,12 @@ function restoreAppShortcutsSync(app, d, ps = defaultPsSync) {
|
|
|
2317
2350
|
}
|
|
2318
2351
|
|
|
2319
2352
|
// src/daemon/dumateApp/keeper.ts
|
|
2320
|
-
import { readdirSync as readdirSync13, statSync as
|
|
2353
|
+
import { readdirSync as readdirSync13, statSync as statSync11 } from "fs";
|
|
2321
2354
|
import { join as join25 } from "path";
|
|
2322
2355
|
|
|
2323
2356
|
// src/daemon/dumateWatch.ts
|
|
2324
2357
|
import { execFileSync as execFileSync10, spawn as spawn3 } from "child_process";
|
|
2325
|
-
import { readdirSync as readdirSync11, realpathSync as realpathSync4, statSync as
|
|
2358
|
+
import { readdirSync as readdirSync11, realpathSync as realpathSync4, statSync as statSync10 } from "fs";
|
|
2326
2359
|
import { request as httpRequest } from "http";
|
|
2327
2360
|
import { join as join23 } from "path";
|
|
2328
2361
|
|
|
@@ -3039,7 +3072,7 @@ function traeNoticeSummary(toolName, toolInput, described, notice) {
|
|
|
3039
3072
|
|
|
3040
3073
|
// src/daemon/workbuddyApp/keeper.ts
|
|
3041
3074
|
import { execFile as execFile6, spawn as spawn2 } from "child_process";
|
|
3042
|
-
import { existsSync as existsSync19, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as
|
|
3075
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
|
|
3043
3076
|
import { delimiter as delimiter3, join as join22, resolve as resolve4 } from "path";
|
|
3044
3077
|
|
|
3045
3078
|
// src/core/process.ts
|
|
@@ -3102,7 +3135,7 @@ function isAlive(pid, expectName, kill = process.kill.bind(process)) {
|
|
|
3102
3135
|
}
|
|
3103
3136
|
|
|
3104
3137
|
// src/core/state.ts
|
|
3105
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync15, readdirSync as readdirSync5, readFileSync as
|
|
3138
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync15, readdirSync as readdirSync5, readFileSync as readFileSync16, renameSync as renameSync10, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
|
|
3106
3139
|
import { join as join14 } from "path";
|
|
3107
3140
|
|
|
3108
3141
|
// src/core/codexServer.ts
|
|
@@ -3153,7 +3186,7 @@ function programOf(args) {
|
|
|
3153
3186
|
}
|
|
3154
3187
|
|
|
3155
3188
|
// src/core/ended.ts
|
|
3156
|
-
import { closeSync, mkdirSync as mkdirSync12, openSync, readdirSync as readdirSync2, readFileSync as
|
|
3189
|
+
import { closeSync, mkdirSync as mkdirSync12, openSync, readdirSync as readdirSync2, readFileSync as readFileSync14, readSync, realpathSync, renameSync as renameSync9, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync12 } from "fs";
|
|
3157
3190
|
import { join as join11 } from "path";
|
|
3158
3191
|
var ENDED_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3159
3192
|
var SID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
@@ -3185,7 +3218,7 @@ function writeEnded(s, now = Date.now()) {
|
|
|
3185
3218
|
function readEnded(sessionId, now = Date.now()) {
|
|
3186
3219
|
if (!SID_RE.test(sessionId)) return null;
|
|
3187
3220
|
try {
|
|
3188
|
-
const r = JSON.parse(
|
|
3221
|
+
const r = JSON.parse(readFileSync14(join11(endedDir(), `${sessionId}.json`), "utf8"));
|
|
3189
3222
|
if (!r || r.sessionId !== sessionId || typeof r.endedAt !== "number" || now - r.endedAt > ENDED_TTL_MS) return null;
|
|
3190
3223
|
return r;
|
|
3191
3224
|
} catch {
|
|
@@ -3276,7 +3309,7 @@ function isDirSync(p) {
|
|
|
3276
3309
|
}
|
|
3277
3310
|
|
|
3278
3311
|
// src/core/qoderAppSessions.ts
|
|
3279
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as
|
|
3312
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "fs";
|
|
3280
3313
|
import { join as join12 } from "path";
|
|
3281
3314
|
var QODER_APP_SESSION_TOOLS = ["qoder_cn", "qoder"];
|
|
3282
3315
|
var KEEPER_FILE = "keeper";
|
|
@@ -3320,7 +3353,7 @@ function listQoderAppSessions(tool) {
|
|
|
3320
3353
|
for (const f of names) {
|
|
3321
3354
|
let t = "";
|
|
3322
3355
|
try {
|
|
3323
|
-
t = String(JSON.parse(
|
|
3356
|
+
t = String(JSON.parse(readFileSync15(join12(dir(), f), "utf8")).tool ?? "");
|
|
3324
3357
|
} catch {
|
|
3325
3358
|
t = "";
|
|
3326
3359
|
}
|
|
@@ -3334,7 +3367,7 @@ function qoderAppMarkedAt(sessionId) {
|
|
|
3334
3367
|
const f = file(sessionId);
|
|
3335
3368
|
if (!f) return 0;
|
|
3336
3369
|
try {
|
|
3337
|
-
const at = JSON.parse(
|
|
3370
|
+
const at = JSON.parse(readFileSync15(f, "utf8")).at;
|
|
3338
3371
|
return typeof at === "number" ? at : 0;
|
|
3339
3372
|
} catch {
|
|
3340
3373
|
return 0;
|
|
@@ -3407,7 +3440,7 @@ function statePath(sessionId) {
|
|
|
3407
3440
|
}
|
|
3408
3441
|
function readState(sessionId) {
|
|
3409
3442
|
try {
|
|
3410
|
-
return JSON.parse(
|
|
3443
|
+
return JSON.parse(readFileSync16(statePath(sessionId), "utf8"));
|
|
3411
3444
|
} catch {
|
|
3412
3445
|
return null;
|
|
3413
3446
|
}
|
|
@@ -3472,7 +3505,7 @@ var STALE_STATES = /* @__PURE__ */ new Set(["watch", "ask_approval"]);
|
|
|
3472
3505
|
var STALE_NO_PID_LOG = "\u65E0\u8FDB\u7A0B\u53F7\u4E14 2 \u5C0F\u65F6\u65E0\u4E8B\u4EF6\uFF0C\u6309\u5DF2\u7ED3\u675F\u5904\u7406";
|
|
3473
3506
|
function pendingApprovalSessions() {
|
|
3474
3507
|
try {
|
|
3475
|
-
const recs = JSON.parse(
|
|
3508
|
+
const recs = JSON.parse(readFileSync16(join14(deskbuddyHome(), "approvals.json"), "utf8"));
|
|
3476
3509
|
return new Set(Array.isArray(recs) ? recs.filter((r) => r && r.status === "pending" && typeof r.sessionId === "string").map((r) => r.sessionId) : []);
|
|
3477
3510
|
} catch {
|
|
3478
3511
|
return /* @__PURE__ */ new Set();
|
|
@@ -3499,7 +3532,7 @@ function readAliveStates(tool, opts = {}) {
|
|
|
3499
3532
|
if (!file3.endsWith(".json")) continue;
|
|
3500
3533
|
let s;
|
|
3501
3534
|
try {
|
|
3502
|
-
s = JSON.parse(
|
|
3535
|
+
s = JSON.parse(readFileSync16(join14(stateDir(), file3), "utf8"));
|
|
3503
3536
|
} catch {
|
|
3504
3537
|
rmSync8(join14(stateDir(), file3), { force: true });
|
|
3505
3538
|
continue;
|
|
@@ -3551,7 +3584,7 @@ var ALIAS_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
3551
3584
|
function resolveAlias(sessionId, now = Date.now()) {
|
|
3552
3585
|
let map = {};
|
|
3553
3586
|
try {
|
|
3554
|
-
map = JSON.parse(
|
|
3587
|
+
map = JSON.parse(readFileSync16(join14(deskbuddyHome(), "alias.json"), "utf8")) || {};
|
|
3555
3588
|
} catch {
|
|
3556
3589
|
return sessionId;
|
|
3557
3590
|
}
|
|
@@ -3566,7 +3599,7 @@ function resolveAlias(sessionId, now = Date.now()) {
|
|
|
3566
3599
|
|
|
3567
3600
|
// src/wrap/shim.ts
|
|
3568
3601
|
import { execFile as execFile3, execFileSync as execFileSync7 } from "child_process";
|
|
3569
|
-
import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync16, readdirSync as readdirSync6, readFileSync as
|
|
3602
|
+
import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync16, readdirSync as readdirSync6, readFileSync as readFileSync17, rmdirSync, rmSync as rmSync9, writeFileSync as writeFileSync16 } from "fs";
|
|
3570
3603
|
import { homedir as homedir3 } from "os";
|
|
3571
3604
|
import { delimiter, join as join15, resolve as resolve3 } from "path";
|
|
3572
3605
|
var SHIM_FALLBACK_EXIT = 213;
|
|
@@ -3722,7 +3755,7 @@ function removeRcBlock(content) {
|
|
|
3722
3755
|
return content.slice(0, start) + content.slice(end);
|
|
3723
3756
|
}
|
|
3724
3757
|
function readRc(p) {
|
|
3725
|
-
return
|
|
3758
|
+
return readFileSync17(p).toString("latin1");
|
|
3726
3759
|
}
|
|
3727
3760
|
function writeRc(p, latin1) {
|
|
3728
3761
|
writeFileSync16(p, Buffer.from(latin1, "latin1"));
|
|
@@ -3977,7 +4010,7 @@ function ourShims(binDir) {
|
|
|
3977
4010
|
}
|
|
3978
4011
|
return names.filter((n) => {
|
|
3979
4012
|
try {
|
|
3980
|
-
return
|
|
4013
|
+
return readFileSync17(join15(binDir, n), "utf8").includes(SHIM_MARKER);
|
|
3981
4014
|
} catch {
|
|
3982
4015
|
return false;
|
|
3983
4016
|
}
|
|
@@ -3989,7 +4022,7 @@ function uninstallShim(tool, e) {
|
|
|
3989
4022
|
let removed = false;
|
|
3990
4023
|
const file3 = shimFile(e.binDir, command, e.platform);
|
|
3991
4024
|
try {
|
|
3992
|
-
if (existsSync14(file3) &&
|
|
4025
|
+
if (existsSync14(file3) && readFileSync17(file3, "utf8").includes(SHIM_MARKER)) {
|
|
3993
4026
|
rmSync9(file3, { force: true });
|
|
3994
4027
|
removed = true;
|
|
3995
4028
|
}
|
|
@@ -4033,7 +4066,7 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
|
|
|
4033
4066
|
const file3 = shimFile(binDir, command, platform);
|
|
4034
4067
|
let installed = false;
|
|
4035
4068
|
try {
|
|
4036
|
-
installed =
|
|
4069
|
+
installed = readFileSync17(file3, "utf8").includes(SHIM_MARKER);
|
|
4037
4070
|
} catch {
|
|
4038
4071
|
installed = false;
|
|
4039
4072
|
}
|
|
@@ -4045,18 +4078,18 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
|
|
|
4045
4078
|
|
|
4046
4079
|
// src/daemon/workbuddyAppDb.ts
|
|
4047
4080
|
import { execFile as execFile5 } from "child_process";
|
|
4048
|
-
import { closeSync as closeSync5, existsSync as existsSync18, mkdirSync as mkdirSync20, openSync as openSync5, readdirSync as readdirSync9, readFileSync as
|
|
4081
|
+
import { closeSync as closeSync5, existsSync as existsSync18, mkdirSync as mkdirSync20, openSync as openSync5, readdirSync as readdirSync9, readFileSync as readFileSync23, readSync as readSync5, renameSync as renameSync14, rmSync as rmSync12, statSync as statSync9, writeFileSync as writeFileSync20 } from "fs";
|
|
4049
4082
|
import { createRequire as createRequire3 } from "module";
|
|
4050
4083
|
import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as join21 } from "path";
|
|
4051
4084
|
|
|
4052
4085
|
// src/core/launch.ts
|
|
4053
|
-
import { mkdirSync as mkdirSync18, readFileSync as
|
|
4086
|
+
import { mkdirSync as mkdirSync18, readFileSync as readFileSync19, renameSync as renameSync12, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
|
|
4054
4087
|
import { join as join17 } from "path";
|
|
4055
4088
|
|
|
4056
4089
|
// src/core/wake.ts
|
|
4057
4090
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
4058
4091
|
import { createHash as createHash2, createHmac, timingSafeEqual } from "crypto";
|
|
4059
|
-
import { chmodSync as chmodSync4, closeSync as closeSync2, mkdirSync as mkdirSync17, openSync as openSync2, readdirSync as readdirSync7, readFileSync as
|
|
4092
|
+
import { chmodSync as chmodSync4, closeSync as closeSync2, mkdirSync as mkdirSync17, openSync as openSync2, readdirSync as readdirSync7, readFileSync as readFileSync18, readSync as readSync2, renameSync as renameSync11, rmSync as rmSync10, statSync as statSync6, writeFileSync as writeFileSync17 } from "fs";
|
|
4060
4093
|
import { tmpdir } from "os";
|
|
4061
4094
|
import { join as join16 } from "path";
|
|
4062
4095
|
function wakeDir(home = deskbuddyHome()) {
|
|
@@ -4125,7 +4158,7 @@ function isWakeMarked(sessionId, alive = pidExists) {
|
|
|
4125
4158
|
const safe = safeSid(sessionId);
|
|
4126
4159
|
if (!safe) return false;
|
|
4127
4160
|
try {
|
|
4128
|
-
const m = JSON.parse(
|
|
4161
|
+
const m = JSON.parse(readFileSync18(join16(marksDir(), `${safe}.json`), "utf8"));
|
|
4129
4162
|
const daemonPid = Number(m?.daemonPid) || 0;
|
|
4130
4163
|
if (!daemonPid || !alive(daemonPid)) return false;
|
|
4131
4164
|
const pid = Number(m?.agentPid) || 0;
|
|
@@ -4195,10 +4228,11 @@ function macEqual(a, b) {
|
|
|
4195
4228
|
var WAKE_MARK_RE = /\[DeskBuddy#([0-9A-Za-z_-]{1,64})(?::[0-9a-f]{32})?\]/;
|
|
4196
4229
|
var INTERRUPT_RE = /^\[Request interrupted by user/;
|
|
4197
4230
|
var TRANSCRIPT_TAIL2 = 256 * 1024;
|
|
4231
|
+
var TEXT_PART_TYPES = /* @__PURE__ */ new Set(["text", "input_text", "output_text"]);
|
|
4198
4232
|
function userText(content) {
|
|
4199
4233
|
if (typeof content === "string") return content;
|
|
4200
4234
|
if (!Array.isArray(content)) return "";
|
|
4201
|
-
return content.filter((x) => x && x.type
|
|
4235
|
+
return content.filter((x) => x && TEXT_PART_TYPES.has(x.type)).map((x) => String(x.text ?? "")).join("\n");
|
|
4202
4236
|
}
|
|
4203
4237
|
function analyzeTranscript(file3) {
|
|
4204
4238
|
if (!file3) return null;
|
|
@@ -4223,7 +4257,9 @@ function analyzeTranscript(file3) {
|
|
|
4223
4257
|
} catch {
|
|
4224
4258
|
continue;
|
|
4225
4259
|
}
|
|
4226
|
-
if (!o
|
|
4260
|
+
if (!o) continue;
|
|
4261
|
+
if (o.type === "message" && (o.role === "user" || o.role === "assistant")) o = { type: o.role, message: { content: o.content } };
|
|
4262
|
+
if (!o.message) continue;
|
|
4227
4263
|
if (o.type === "assistant") {
|
|
4228
4264
|
const t = userText(o.message.content).trim();
|
|
4229
4265
|
if (t) {
|
|
@@ -4289,7 +4325,7 @@ function claimLaunch(runId) {
|
|
|
4289
4325
|
return null;
|
|
4290
4326
|
}
|
|
4291
4327
|
try {
|
|
4292
|
-
const p = JSON.parse(
|
|
4328
|
+
const p = JSON.parse(readFileSync19(claimed, "utf8"));
|
|
4293
4329
|
if (!p || typeof p.cwd !== "string" || typeof p.resume !== "string") return null;
|
|
4294
4330
|
if (p.tool === void 0) p.tool = "claude_code";
|
|
4295
4331
|
return validPlan(p) ? p : null;
|
|
@@ -4304,7 +4340,7 @@ function claimLaunch(runId) {
|
|
|
4304
4340
|
}
|
|
4305
4341
|
function launchPending(runId) {
|
|
4306
4342
|
try {
|
|
4307
|
-
|
|
4343
|
+
readFileSync19(planFile(runId));
|
|
4308
4344
|
return true;
|
|
4309
4345
|
} catch {
|
|
4310
4346
|
return false;
|
|
@@ -4312,7 +4348,7 @@ function launchPending(runId) {
|
|
|
4312
4348
|
}
|
|
4313
4349
|
|
|
4314
4350
|
// src/core/title.ts
|
|
4315
|
-
import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as
|
|
4351
|
+
import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync20, readSync as readSync3, statSync as statSync7 } from "fs";
|
|
4316
4352
|
import { createRequire as createRequire2 } from "module";
|
|
4317
4353
|
import { homedir as homedir5 } from "os";
|
|
4318
4354
|
import { basename as basename3, dirname as dirname10, isAbsolute, join as join18 } from "path";
|
|
@@ -4374,7 +4410,7 @@ function qoderDbPaths(tool, platform = process.platform, home = homedir5(), env
|
|
|
4374
4410
|
|
|
4375
4411
|
// src/daemon/locate.ts
|
|
4376
4412
|
import { execFile as execFile4, execFileSync as execFileSync9 } from "child_process";
|
|
4377
|
-
import { accessSync, closeSync as closeSync4, constants, existsSync as existsSync17, lstatSync, openSync as openSync4, readFileSync as
|
|
4413
|
+
import { accessSync, closeSync as closeSync4, constants, existsSync as existsSync17, lstatSync, openSync as openSync4, readFileSync as readFileSync22, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync8 } from "fs";
|
|
4378
4414
|
import { homedir as homedir6 } from "os";
|
|
4379
4415
|
import { delimiter as delimiter2, dirname as dirname11, join as join20, win32 as win325 } from "path";
|
|
4380
4416
|
|
|
@@ -4394,7 +4430,7 @@ function scrubForCommand(cmd, env = process.env) {
|
|
|
4394
4430
|
}
|
|
4395
4431
|
|
|
4396
4432
|
// src/daemon/winAppLocator.ts
|
|
4397
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync19, readdirSync as readdirSync8, readFileSync as
|
|
4433
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync19, readdirSync as readdirSync8, readFileSync as readFileSync21, renameSync as renameSync13, writeFileSync as writeFileSync19 } from "fs";
|
|
4398
4434
|
import { join as join19, win32 as win324 } from "path";
|
|
4399
4435
|
var SOURCE_TEXT = {
|
|
4400
4436
|
process: "\u6B63\u5728\u8FD0\u884C\u7684\u8FDB\u7A0B",
|
|
@@ -4427,14 +4463,7 @@ var WIN_APP_SPECS = {
|
|
|
4427
4463
|
};
|
|
4428
4464
|
var defaultLocFs = {
|
|
4429
4465
|
exists: (p) => existsSync16(p),
|
|
4430
|
-
readText: (p) =>
|
|
4431
|
-
try {
|
|
4432
|
-
if (statSync8(p).size > 64 * 1024) return null;
|
|
4433
|
-
return readFileSync20(p, "utf8");
|
|
4434
|
-
} catch {
|
|
4435
|
-
return null;
|
|
4436
|
-
}
|
|
4437
|
-
},
|
|
4466
|
+
readText: (p) => readSmallText(p),
|
|
4438
4467
|
subdirs: (p) => {
|
|
4439
4468
|
try {
|
|
4440
4469
|
return readdirSync8(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -4530,7 +4559,7 @@ var LOCATE_EVERY_MS = 10 * 60 * 1e3;
|
|
|
4530
4559
|
var cacheFile = () => join19(deskbuddyHome(), WIN_APPS_FILE);
|
|
4531
4560
|
function loadCache(file3 = cacheFile()) {
|
|
4532
4561
|
try {
|
|
4533
|
-
const v = JSON.parse(
|
|
4562
|
+
const v = JSON.parse(readFileSync21(file3, "utf8"));
|
|
4534
4563
|
const out = {};
|
|
4535
4564
|
for (const [k, e] of Object.entries(v ?? {})) {
|
|
4536
4565
|
const x = e;
|
|
@@ -4685,7 +4714,7 @@ var defaultLocateDeps = () => ({
|
|
|
4685
4714
|
nodePath: process.execPath,
|
|
4686
4715
|
isExecutable: (p) => {
|
|
4687
4716
|
try {
|
|
4688
|
-
if (!
|
|
4717
|
+
if (!statSync8(p).isFile()) return false;
|
|
4689
4718
|
accessSync(p, constants.X_OK);
|
|
4690
4719
|
return true;
|
|
4691
4720
|
} catch {
|
|
@@ -4706,7 +4735,7 @@ var defaultLocateDeps = () => ({
|
|
|
4706
4735
|
localAppData: process.env.LOCALAPPDATA ?? "",
|
|
4707
4736
|
readText: (p) => {
|
|
4708
4737
|
try {
|
|
4709
|
-
return
|
|
4738
|
+
return readFileSync22(p, "utf8");
|
|
4710
4739
|
} catch {
|
|
4711
4740
|
return null;
|
|
4712
4741
|
}
|
|
@@ -4790,7 +4819,7 @@ function classifyAsyncError(e, stdout2, stderr) {
|
|
|
4790
4819
|
var defaultProbe = createVersionProbe({
|
|
4791
4820
|
stat: (p) => {
|
|
4792
4821
|
try {
|
|
4793
|
-
const st =
|
|
4822
|
+
const st = statSync8(p);
|
|
4794
4823
|
return { size: st.size, mtimeMs: st.mtimeMs };
|
|
4795
4824
|
} catch {
|
|
4796
4825
|
return null;
|
|
@@ -5303,7 +5332,7 @@ var SLICE = 64 * 1024;
|
|
|
5303
5332
|
function readSlice(p, from) {
|
|
5304
5333
|
const fd = openSync5(p, "r");
|
|
5305
5334
|
try {
|
|
5306
|
-
const size =
|
|
5335
|
+
const size = statSync9(p).size;
|
|
5307
5336
|
const len = Math.min(size, SLICE);
|
|
5308
5337
|
const buf = Buffer.alloc(len);
|
|
5309
5338
|
readSync5(fd, buf, 0, len, from === "head" ? 0 : size - len);
|
|
@@ -5347,7 +5376,7 @@ function userText2(o) {
|
|
|
5347
5376
|
function wbTranscriptInfo(p) {
|
|
5348
5377
|
const head = jsonLines(readSlice(p, "head"));
|
|
5349
5378
|
const tail = jsonLines(readSlice(p, "tail"));
|
|
5350
|
-
const mtime = Math.floor(
|
|
5379
|
+
const mtime = Math.floor(statSync9(p).mtimeMs);
|
|
5351
5380
|
const hs = head.map((o) => tsOf(o.timestamp)).filter((n) => n !== null);
|
|
5352
5381
|
const ts = tail.map((o) => tsOf(o.timestamp)).filter((n) => n !== null);
|
|
5353
5382
|
const createdAt = hs.length ? Math.min(...hs) : mtime;
|
|
@@ -5428,7 +5457,7 @@ function pendingPath() {
|
|
|
5428
5457
|
}
|
|
5429
5458
|
function loadPendingFile() {
|
|
5430
5459
|
try {
|
|
5431
|
-
const v = JSON.parse(
|
|
5460
|
+
const v = JSON.parse(readFileSync23(pendingPath(), "utf8"));
|
|
5432
5461
|
return Array.isArray(v) ? v.filter((j) => j && typeof j.sessionId === "string" && typeof j.cwd === "string") : [];
|
|
5433
5462
|
} catch {
|
|
5434
5463
|
return [];
|
|
@@ -5746,7 +5775,7 @@ var keeperThrottleFile = () => join22(deskbuddyHome(), "wbapp", "keeper.json");
|
|
|
5746
5775
|
var filePersist = {
|
|
5747
5776
|
load: () => {
|
|
5748
5777
|
try {
|
|
5749
|
-
return JSON.parse(
|
|
5778
|
+
return JSON.parse(readFileSync24(keeperThrottleFile(), "utf8"));
|
|
5750
5779
|
} catch {
|
|
5751
5780
|
return null;
|
|
5752
5781
|
}
|
|
@@ -5940,7 +5969,7 @@ function workbuddyBusy(now = Date.now(), dir2 = stateDir(), alive = isAlive) {
|
|
|
5940
5969
|
for (const f of readdirSync10(dir2)) {
|
|
5941
5970
|
if (!f.endsWith(".json")) continue;
|
|
5942
5971
|
try {
|
|
5943
|
-
const s = JSON.parse(
|
|
5972
|
+
const s = JSON.parse(readFileSync24(join22(dir2, f), "utf8"));
|
|
5944
5973
|
if (s.tool !== "workbuddy" || s.state !== "watch" && s.state !== "ask_approval") continue;
|
|
5945
5974
|
if (typeof s.pid === "number" && s.pid > 0) {
|
|
5946
5975
|
if (alive(s.pid, s.pidName)) return true;
|
|
@@ -7105,6 +7134,149 @@ var QoderAppTasks = class {
|
|
|
7105
7134
|
}
|
|
7106
7135
|
};
|
|
7107
7136
|
|
|
7137
|
+
// src/core/summaryTools.ts
|
|
7138
|
+
var SUMMARY_TOOLS = ["claude_code", "codex", "qoder", "qoder_cn", "opencode", "workbuddy", "qwenwork", "dumate", "deepseek_harness"];
|
|
7139
|
+
var SUMMARY_CAPS = SUMMARY_TOOLS.map((t) => `summary:${t}`);
|
|
7140
|
+
|
|
7141
|
+
// src/daemon/summary.ts
|
|
7142
|
+
var SUMMARY_TOOLS2 = SUMMARY_TOOLS;
|
|
7143
|
+
var SUMMARY_NO_OUTPUT = "no_output";
|
|
7144
|
+
var SUMMARY_TIMEOUT = "timeout";
|
|
7145
|
+
function isSummary(cmd) {
|
|
7146
|
+
return cmd.kind === "summary";
|
|
7147
|
+
}
|
|
7148
|
+
function summaryMark(instructionId) {
|
|
7149
|
+
return `[DeskBuddy#${instructionId}]`;
|
|
7150
|
+
}
|
|
7151
|
+
function withSummaryMark(text, instructionId) {
|
|
7152
|
+
if (text.includes(`[DeskBuddy#${instructionId}]`) || text.includes(`[DeskBuddy#${instructionId}:`)) return text;
|
|
7153
|
+
return `${text}
|
|
7154
|
+
${summaryMark(instructionId)}`;
|
|
7155
|
+
}
|
|
7156
|
+
function clipOutput(text) {
|
|
7157
|
+
return text.length > COMMAND_OUTPUT_MAX ? text.slice(0, COMMAND_OUTPUT_MAX) : text;
|
|
7158
|
+
}
|
|
7159
|
+
var BUSY = /* @__PURE__ */ new Set(["watch", "ask_approval"]);
|
|
7160
|
+
var PTY_SETTLE_MS = 1500;
|
|
7161
|
+
var SUMMARY_WAIT_MS = 4 * 60 * 1e3;
|
|
7162
|
+
var PTY_SUMMARY_WAIT_MS = SUMMARY_WAIT_MS;
|
|
7163
|
+
function ptyVerdict(job, st, tail, now) {
|
|
7164
|
+
if (now - job.startedAt > PTY_SUMMARY_WAIT_MS) return { kind: "fail", reason: SUMMARY_TIMEOUT };
|
|
7165
|
+
if (!st) return { kind: "fail", reason: "session_gone" };
|
|
7166
|
+
if (!tail || tail.id !== job.instructionId) return { kind: "wait" };
|
|
7167
|
+
if (tail.humanAfter || tail.interrupted) return { kind: "fail", reason: "exec_failed" };
|
|
7168
|
+
if (!tail.answered) return { kind: "wait" };
|
|
7169
|
+
if (BUSY.has(st.state) || now - st.updatedAt < PTY_SETTLE_MS) return { kind: "wait" };
|
|
7170
|
+
const text = (tail.reply ?? "").trim();
|
|
7171
|
+
return text ? { kind: "done", text } : { kind: "fail", reason: SUMMARY_NO_OUTPUT };
|
|
7172
|
+
}
|
|
7173
|
+
function hasSummaryMark(text, instructionId) {
|
|
7174
|
+
return text.includes(`[DeskBuddy#${instructionId}]`) || text.includes(`[DeskBuddy#${instructionId}:`);
|
|
7175
|
+
}
|
|
7176
|
+
function messagesVerdict(list, instructionId, idle) {
|
|
7177
|
+
if (!Array.isArray(list)) return { kind: "wait" };
|
|
7178
|
+
const msgs = list;
|
|
7179
|
+
const textOf = (m) => Array.isArray(m.parts) ? m.parts.filter((p) => p && p.type === "text" && typeof p.text === "string" && p.synthetic !== true).map((p) => p.text).join("\n").trim() : "";
|
|
7180
|
+
let at = -1;
|
|
7181
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
7182
|
+
const m = msgs[i];
|
|
7183
|
+
if (m && m.info?.role === "user" && hasSummaryMark(textOf(m), instructionId)) {
|
|
7184
|
+
at = i;
|
|
7185
|
+
break;
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
if (at < 0) return { kind: "wait" };
|
|
7189
|
+
const after = msgs.slice(at + 1).filter((m) => m && m.info);
|
|
7190
|
+
if (after.some((m) => m.info?.role === "user")) return { kind: "fail", reason: "exec_failed" };
|
|
7191
|
+
const markId = typeof msgs[at].info?.id === "string" ? msgs[at].info?.id : "";
|
|
7192
|
+
const replies = after.filter((m) => m.info?.role === "assistant" && (!markId || typeof m.info.parentID !== "string" || m.info.parentID === markId));
|
|
7193
|
+
if (!idle || replies.length === 0) return { kind: "wait" };
|
|
7194
|
+
const last = replies[replies.length - 1];
|
|
7195
|
+
if (!last.info?.time || last.info.time.completed == null) return { kind: "wait" };
|
|
7196
|
+
for (let i = replies.length - 1; i >= 0; i--) {
|
|
7197
|
+
const t = textOf(replies[i]);
|
|
7198
|
+
if (t) return { kind: "done", text: t };
|
|
7199
|
+
}
|
|
7200
|
+
return { kind: "fail", reason: SUMMARY_NO_OUTPUT };
|
|
7201
|
+
}
|
|
7202
|
+
function replyVerdict(r) {
|
|
7203
|
+
if (!r || typeof r !== "object") return { kind: "wait" };
|
|
7204
|
+
const v = r;
|
|
7205
|
+
if (v.ok === true) {
|
|
7206
|
+
const t = typeof v.text === "string" ? v.text.trim() : "";
|
|
7207
|
+
return t ? { kind: "done", text: t } : { kind: "fail", reason: SUMMARY_NO_OUTPUT };
|
|
7208
|
+
}
|
|
7209
|
+
const reason = typeof v.reason === "string" && /^[a-z_]{1,32}$/.test(v.reason) ? v.reason : "exec_failed";
|
|
7210
|
+
return { kind: "fail", reason };
|
|
7211
|
+
}
|
|
7212
|
+
var PtySummaryWatch = class {
|
|
7213
|
+
#d;
|
|
7214
|
+
#jobs = /* @__PURE__ */ new Map();
|
|
7215
|
+
constructor(deps) {
|
|
7216
|
+
this.#d = deps;
|
|
7217
|
+
}
|
|
7218
|
+
get size() {
|
|
7219
|
+
return this.#jobs.size;
|
|
7220
|
+
}
|
|
7221
|
+
has(instructionId) {
|
|
7222
|
+
return this.#jobs.has(instructionId);
|
|
7223
|
+
}
|
|
7224
|
+
/** 交出去(started / queued)时登记;handedAt = 交出去的时刻(缺省现在)。同一条重复登记保留最早的时刻 */
|
|
7225
|
+
begin(cmd, sessionId, handedAt, check) {
|
|
7226
|
+
const prev = this.#jobs.get(cmd.instructionId);
|
|
7227
|
+
this.#jobs.set(cmd.instructionId, { cmd, sessionId, startedAt: prev?.startedAt ?? handedAt ?? this.#d.now(), check: check ?? prev?.check });
|
|
7228
|
+
}
|
|
7229
|
+
drop(instructionId) {
|
|
7230
|
+
this.#jobs.delete(instructionId);
|
|
7231
|
+
}
|
|
7232
|
+
#settle(id, job, v) {
|
|
7233
|
+
if (v.kind === "wait" || this.#jobs.get(id) !== job) return;
|
|
7234
|
+
this.#jobs.delete(id);
|
|
7235
|
+
if (v.kind === "done") this.#d.done(job.cmd, job.sessionId, v.text);
|
|
7236
|
+
else this.#d.fail(job.cmd, job.sessionId, v.reason);
|
|
7237
|
+
}
|
|
7238
|
+
tick() {
|
|
7239
|
+
const now = this.#d.now();
|
|
7240
|
+
for (const [id, job] of [...this.#jobs]) {
|
|
7241
|
+
if (job.check) {
|
|
7242
|
+
if (now - job.startedAt > PTY_SUMMARY_WAIT_MS) {
|
|
7243
|
+
this.#settle(id, job, { kind: "fail", reason: SUMMARY_TIMEOUT });
|
|
7244
|
+
continue;
|
|
7245
|
+
}
|
|
7246
|
+
if (job.checking) continue;
|
|
7247
|
+
let r;
|
|
7248
|
+
try {
|
|
7249
|
+
r = job.check({ instructionId: id, sessionId: job.sessionId, startedAt: job.startedAt }, now);
|
|
7250
|
+
} catch {
|
|
7251
|
+
continue;
|
|
7252
|
+
}
|
|
7253
|
+
if (r && typeof r.then === "function") {
|
|
7254
|
+
job.checking = true;
|
|
7255
|
+
void r.then(
|
|
7256
|
+
(v) => {
|
|
7257
|
+
job.checking = false;
|
|
7258
|
+
this.#settle(id, job, v);
|
|
7259
|
+
},
|
|
7260
|
+
() => {
|
|
7261
|
+
job.checking = false;
|
|
7262
|
+
}
|
|
7263
|
+
);
|
|
7264
|
+
} else this.#settle(id, job, r);
|
|
7265
|
+
continue;
|
|
7266
|
+
}
|
|
7267
|
+
let st = null;
|
|
7268
|
+
let tail = null;
|
|
7269
|
+
try {
|
|
7270
|
+
st = this.#d.readState(job.sessionId);
|
|
7271
|
+
const path = st ? this.#d.transcriptOf(st) : null;
|
|
7272
|
+
tail = path ? this.#d.analyze(path) : null;
|
|
7273
|
+
} catch {
|
|
7274
|
+
}
|
|
7275
|
+
this.#settle(id, job, ptyVerdict({ instructionId: id, startedAt: job.startedAt }, st, tail, now));
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
};
|
|
7279
|
+
|
|
7108
7280
|
// src/daemon/dumateWatch.ts
|
|
7109
7281
|
var APP_NOT_RUNNING = "app_not_running";
|
|
7110
7282
|
function unavailableMessage(reason) {
|
|
@@ -7158,6 +7330,7 @@ function isRefused(e) {
|
|
|
7158
7330
|
return code(e) === "ECONNREFUSED" || code(e?.cause) === "ECONNREFUSED";
|
|
7159
7331
|
}
|
|
7160
7332
|
var REPLY_HISTORY_LIMIT = 10;
|
|
7333
|
+
var SUMMARY_HISTORY_LIMIT = 100;
|
|
7161
7334
|
function pickOfInfo(info) {
|
|
7162
7335
|
const i = info && typeof info === "object" ? info : null;
|
|
7163
7336
|
if (!i || i.role !== "user") return null;
|
|
@@ -7331,7 +7504,7 @@ function scanSessionDirs(root, now, maxAgeMs = ACTIVE_DIR_MS) {
|
|
|
7331
7504
|
for (const day of list(u).sort().reverse().slice(0, 2))
|
|
7332
7505
|
for (const dir2 of list(day)) {
|
|
7333
7506
|
try {
|
|
7334
|
-
const at =
|
|
7507
|
+
const at = statSync10(dir2).mtimeMs;
|
|
7335
7508
|
if (now - at <= maxAgeMs) out.push({ dir: dir2, at });
|
|
7336
7509
|
} catch {
|
|
7337
7510
|
}
|
|
@@ -7530,6 +7703,36 @@ var DumateWatch = class {
|
|
|
7530
7703
|
if (r.status >= 400 && r.status < 500) return { status: "failed", reason: "window_failed", message: `\u5EFA\u4E86\u4F1A\u8BDD\u4F46\u7B2C\u4E00\u53E5\u88AB\u62D2\uFF08HTTP ${r.status}\uFF09`, sessionId: sid };
|
|
7531
7704
|
return { status: "failed", reason: "window_failed", message: r.status === 0 ? "\u5EFA\u4E86\u4F1A\u8BDD\u4F46\u53D1\u7B2C\u4E00\u53E5\u65F6\u8FDE\u63A5\u65AD\u5F00\u6216\u8D85\u65F6" : `\u5EFA\u4E86\u4F1A\u8BDD\u4F46\u767E\u5EA6\u642D\u5B50\u51FA\u9519\uFF08HTTP ${r.status}\uFF09`, sessionId: sid };
|
|
7532
7705
|
}
|
|
7706
|
+
/**
|
|
7707
|
+
* 任务总结的读回(spec 2026-10-11 summary-all-tools):GET /session/:id/message + /session/status,按标记认本轮(messagesVerdict)。
|
|
7708
|
+
* 连不上 / 读不出 → 等(总超时由调用方判);不唤起 App
|
|
7709
|
+
*/
|
|
7710
|
+
/**
|
|
7711
|
+
* 会话完整对话(spec 2026-10-11 transcript-sync §3):GET /session/:id/message 全量(消息只追加,序号稳定)。
|
|
7712
|
+
* 连不上 / 读不出 → null(游标不动,下次可读再补);不唤起 App
|
|
7713
|
+
*/
|
|
7714
|
+
async transcriptMessages(sessionId) {
|
|
7715
|
+
const t = this.#target ?? this.#discover(false);
|
|
7716
|
+
if (!t) return null;
|
|
7717
|
+
const dir2 = this.#sessionDir.get(sessionId) ?? "";
|
|
7718
|
+
const r = await this.#http(t)(t, { method: "GET", path: `/session/${encodeURIComponent(sessionId)}/message`, ...dir2 ? { directory: dir2 } : {} });
|
|
7719
|
+
return r.status === 200 && Array.isArray(r.body) ? r.body : null;
|
|
7720
|
+
}
|
|
7721
|
+
async summaryCheck(sessionId, instructionId) {
|
|
7722
|
+
const wait = { kind: "wait" };
|
|
7723
|
+
const t = this.#target ?? this.#discover(false);
|
|
7724
|
+
if (!t) return wait;
|
|
7725
|
+
const http = this.#http(t);
|
|
7726
|
+
const dir2 = this.#sessionDir.get(sessionId) ?? "";
|
|
7727
|
+
const sid = encodeURIComponent(sessionId);
|
|
7728
|
+
const msgs = await http(t, { method: "GET", path: `/session/${sid}/message?limit=${SUMMARY_HISTORY_LIMIT}`, ...dir2 ? { directory: dir2 } : {} });
|
|
7729
|
+
if (msgs.status === 404) return { kind: "fail", reason: "session_gone" };
|
|
7730
|
+
if (msgs.status !== 200) return wait;
|
|
7731
|
+
const st = await http(t, { method: "GET", path: "/session/status", ...dir2 ? { directory: dir2 } : {} });
|
|
7732
|
+
if (st.status !== 200 || !st.body || typeof st.body !== "object") return wait;
|
|
7733
|
+
const type = st.body[sessionId]?.type;
|
|
7734
|
+
return messagesVerdict(msgs.body, instructionId, type !== "busy" && type !== "preparing" && type !== "retry");
|
|
7735
|
+
}
|
|
7533
7736
|
/**
|
|
7534
7737
|
* 设备回复:往百度搭子里这个会话发一轮(spec 2026-10-08 dumate-qwenwork-reply §3.1)。界面订着同一个 serve 的事件流,实时显示(10-08 实测)。
|
|
7535
7738
|
* 请求体与界面自己发消息一致:带这个会话最后一条用户消息的 agent / model(没有就 build + /config 的 model)。
|
|
@@ -8065,7 +8268,7 @@ function runHook(node, input, agentPid, tool = "dumate") {
|
|
|
8065
8268
|
}
|
|
8066
8269
|
|
|
8067
8270
|
// src/daemon/qoderApp/keeper.ts
|
|
8068
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync22, readdirSync as readdirSync12, readFileSync as
|
|
8271
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync22, readdirSync as readdirSync12, readFileSync as readFileSync25, renameSync as renameSync16, writeFileSync as writeFileSync22 } from "fs";
|
|
8069
8272
|
import { homedir as homedir7 } from "os";
|
|
8070
8273
|
import { join as join24, win32 as win327 } from "path";
|
|
8071
8274
|
var WAKE_LAUNCH_GAP_MS2 = 60 * 1e3;
|
|
@@ -8130,7 +8333,7 @@ function toolBusy(tool, now = Date.now(), dir2 = stateDir(), alive = isAlive) {
|
|
|
8130
8333
|
for (const f of readdirSync12(dir2)) {
|
|
8131
8334
|
if (!f.endsWith(".json")) continue;
|
|
8132
8335
|
try {
|
|
8133
|
-
const s = JSON.parse(
|
|
8336
|
+
const s = JSON.parse(readFileSync25(join24(dir2, f), "utf8"));
|
|
8134
8337
|
if (s.tool !== tool || s.state !== "watch" && s.state !== "ask_approval") continue;
|
|
8135
8338
|
if (typeof s.pid === "number" && s.pid > 0) {
|
|
8136
8339
|
if (alive(s.pid, s.pidName)) return true;
|
|
@@ -8233,7 +8436,7 @@ var QoderCdpKeeper = class {
|
|
|
8233
8436
|
/** 节流状态(按品牌一份,落盘;读不出当没有) */
|
|
8234
8437
|
#loadThrottle() {
|
|
8235
8438
|
try {
|
|
8236
|
-
const all = JSON.parse(
|
|
8439
|
+
const all = JSON.parse(readFileSync25(this.#file(), "utf8"));
|
|
8237
8440
|
const t = all?.[this.#d.brand.tool] ?? {};
|
|
8238
8441
|
const out = { lastLaunch: Number(t.lastLaunch) || 0, lastRestart: Number(t.lastRestart) || 0, day: typeof t.day === "string" ? t.day : "", restarts: Number(t.restarts) || 0 };
|
|
8239
8442
|
if (this.#d.brand.win && isWinAppExe(t.appExe, this.#d.brand.win.exe)) out.appExe = t.appExe;
|
|
@@ -8247,7 +8450,7 @@ var QoderCdpKeeper = class {
|
|
|
8247
8450
|
try {
|
|
8248
8451
|
let all = {};
|
|
8249
8452
|
try {
|
|
8250
|
-
all = JSON.parse(
|
|
8453
|
+
all = JSON.parse(readFileSync25(f, "utf8"));
|
|
8251
8454
|
} catch {
|
|
8252
8455
|
all = {};
|
|
8253
8456
|
}
|
|
@@ -8623,12 +8826,12 @@ function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsR
|
|
|
8623
8826
|
for (const u of users) {
|
|
8624
8827
|
const dir2 = join25(xdg, u, "data", "opencode");
|
|
8625
8828
|
try {
|
|
8626
|
-
latest = Math.max(latest,
|
|
8829
|
+
latest = Math.max(latest, statSync11(join25(dir2, "opencode.db")).mtimeMs);
|
|
8627
8830
|
found = true;
|
|
8628
8831
|
} catch {
|
|
8629
8832
|
}
|
|
8630
8833
|
try {
|
|
8631
|
-
const w =
|
|
8834
|
+
const w = statSync11(join25(dir2, "opencode.db-wal"));
|
|
8632
8835
|
if (w.size > 0) latest = Math.max(latest, w.mtimeMs);
|
|
8633
8836
|
} catch {
|
|
8634
8837
|
}
|
|
@@ -8836,7 +9039,7 @@ function restoreQoderShortcutsSync(tool, d, ps = defaultPsSync) {
|
|
|
8836
9039
|
}
|
|
8837
9040
|
|
|
8838
9041
|
// src/adapters/traeHook.ts
|
|
8839
|
-
import { chmodSync as chmodSync5, existsSync as existsSync21, mkdirSync as mkdirSync23, readFileSync as
|
|
9042
|
+
import { chmodSync as chmodSync5, existsSync as existsSync21, mkdirSync as mkdirSync23, readFileSync as readFileSync26, realpathSync as realpathSync5, renameSync as renameSync17, rmSync as rmSync13, statSync as statSync12, writeFileSync as writeFileSync23 } from "fs";
|
|
8840
9043
|
import { dirname as dirname13, join as join27 } from "path";
|
|
8841
9044
|
var TRAE_EVENTS = ["UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop", "Notification"];
|
|
8842
9045
|
var TRAE_NOTICE_TYPES = ["permission_prompt", "ask_user_question", "document_review", "browser_interaction"];
|
|
@@ -8844,7 +9047,7 @@ var TRAE_NOTICE_MATCHER = `^(${TRAE_NOTICE_TYPES.join("|")})$`;
|
|
|
8844
9047
|
var TRAE_NOTICE_TIMEOUT_S = 7 * 24 * 60 * 60;
|
|
8845
9048
|
function readHooksFile(path) {
|
|
8846
9049
|
if (!existsSync21(path)) return {};
|
|
8847
|
-
const raw =
|
|
9050
|
+
const raw = readFileSync26(path, "utf8");
|
|
8848
9051
|
if (raw.trim() === "") return {};
|
|
8849
9052
|
let parsed;
|
|
8850
9053
|
try {
|
|
@@ -8870,7 +9073,7 @@ function writeHooksFile(linkPath, f) {
|
|
|
8870
9073
|
const path = writeTarget(linkPath);
|
|
8871
9074
|
let mode;
|
|
8872
9075
|
try {
|
|
8873
|
-
mode =
|
|
9076
|
+
mode = statSync12(path).mode & 511;
|
|
8874
9077
|
} catch {
|
|
8875
9078
|
mode = void 0;
|
|
8876
9079
|
}
|
|
@@ -8958,10 +9161,10 @@ function isTraeHookInstalled(path, hookPath) {
|
|
|
8958
9161
|
var TRAE_NOTICE = " TRAE\uFF1A\u8BF7\u5728 TRAE \u7684 \u8BBE\u7F6E > Hooks \u91CC\u786E\u8BA4\u300C\u5168\u5C40\u300DHooks \u5DF2\u542F\u7528\u3001\u8FD0\u884C\u65B9\u5F0F\u9009\u300C\u672C\u5730\u81EA\u52A8\u8FD0\u884C\u300D\uFF08\u6C99\u7BB1\u91CC hook \u8FDE\u4E0D\u4E0A\u5B88\u62A4\u8FDB\u7A0B\uFF09\uFF1B\u7535\u8111\u4E0A\u5F39\u6388\u6743\u6846\u65F6\u8BBE\u5907\u4E0A\u4F1A\u51FA\u73B0\u63D0\u793A\u5361\uFF0C\u9700\u56DE\u5230\u7535\u8111\u4E0A\u5904\u7406";
|
|
8959
9162
|
|
|
8960
9163
|
// src/commands/tools.ts
|
|
8961
|
-
import { existsSync as existsSync23, readFileSync as
|
|
9164
|
+
import { existsSync as existsSync23, readFileSync as readFileSync28 } from "fs";
|
|
8962
9165
|
|
|
8963
9166
|
// src/adapters/cbChannel.ts
|
|
8964
|
-
import { chmodSync as chmodSync6, existsSync as existsSync22, lstatSync as lstatSync2, mkdirSync as mkdirSync24, readFileSync as
|
|
9167
|
+
import { chmodSync as chmodSync6, existsSync as existsSync22, lstatSync as lstatSync2, mkdirSync as mkdirSync24, readFileSync as readFileSync27, realpathSync as realpathSync6, renameSync as renameSync18, statSync as statSync13, writeFileSync as writeFileSync24 } from "fs";
|
|
8965
9168
|
import { dirname as dirname14, join as join28 } from "path";
|
|
8966
9169
|
var CB_MCP_NAME = "deskbuddy";
|
|
8967
9170
|
var CB_CHANNEL_SCRIPT = "cbchannel.cjs";
|
|
@@ -8970,7 +9173,7 @@ function cbChannelScript(hookPath) {
|
|
|
8970
9173
|
}
|
|
8971
9174
|
function read(path) {
|
|
8972
9175
|
if (!existsSync22(path)) return {};
|
|
8973
|
-
const raw =
|
|
9176
|
+
const raw = readFileSync27(path, "utf8");
|
|
8974
9177
|
if (raw.trim() === "") return {};
|
|
8975
9178
|
let v;
|
|
8976
9179
|
try {
|
|
@@ -8991,7 +9194,7 @@ function write2(file3, v) {
|
|
|
8991
9194
|
mkdirSync24(dirname14(path), { recursive: true });
|
|
8992
9195
|
let mode;
|
|
8993
9196
|
try {
|
|
8994
|
-
mode =
|
|
9197
|
+
mode = statSync13(path).mode & 511;
|
|
8995
9198
|
} catch {
|
|
8996
9199
|
mode = void 0;
|
|
8997
9200
|
}
|
|
@@ -9039,7 +9242,7 @@ function codebuddyWanted(d = { standalone: () => standaloneProbe() }) {
|
|
|
9039
9242
|
function fileContains(path, needle) {
|
|
9040
9243
|
try {
|
|
9041
9244
|
if (!existsSync23(path)) return false;
|
|
9042
|
-
return
|
|
9245
|
+
return readFileSync28(path, "utf8").includes(needle);
|
|
9043
9246
|
} catch {
|
|
9044
9247
|
return false;
|
|
9045
9248
|
}
|
|
@@ -9086,6 +9289,7 @@ var ADAPTERS = {
|
|
|
9086
9289
|
if (tool === "workbuddy") return installCodebuddyTerminalApprovals(gate);
|
|
9087
9290
|
if (!WINDOW_GATE_TOOLS.has(tool)) return false;
|
|
9088
9291
|
installCcWindowGate(p, gate, tool);
|
|
9292
|
+
if (tool === "qoder_cn" || tool === "qoder") installCcPreToolQuestion(p, gate, tool);
|
|
9089
9293
|
return true;
|
|
9090
9294
|
},
|
|
9091
9295
|
// asyncRewake 只有 Claude Code 认(2.1.280 实测);别家当成同步 hook 会一直等
|
|
@@ -9140,7 +9344,7 @@ ADAPTERS["dumate-http"] = {
|
|
|
9140
9344
|
uninstall: () => restoreDumateShortcutsSync({ log: dmLnkLog }),
|
|
9141
9345
|
isInstalled: (p) => {
|
|
9142
9346
|
try {
|
|
9143
|
-
const enabled = JSON.parse(
|
|
9347
|
+
const enabled = JSON.parse(readFileSync28(p, "utf8")).enabledTools;
|
|
9144
9348
|
return Array.isArray(enabled) && enabled.includes("dumate");
|
|
9145
9349
|
} catch {
|
|
9146
9350
|
return false;
|
|
@@ -9173,7 +9377,7 @@ ADAPTERS["coze-cdp"] = {
|
|
|
9173
9377
|
},
|
|
9174
9378
|
isInstalled: (p) => {
|
|
9175
9379
|
try {
|
|
9176
|
-
const enabled = JSON.parse(
|
|
9380
|
+
const enabled = JSON.parse(readFileSync28(p, "utf8")).enabledTools;
|
|
9177
9381
|
return Array.isArray(enabled) && enabled.includes("coze");
|
|
9178
9382
|
} catch {
|
|
9179
9383
|
return false;
|
|
@@ -9204,7 +9408,7 @@ function subscribedEvents(registry, tool, fallback) {
|
|
|
9204
9408
|
}
|
|
9205
9409
|
|
|
9206
9410
|
// src/wrap/pty.ts
|
|
9207
|
-
import { chmodSync as chmodSync7, existsSync as existsSync24, statSync as
|
|
9411
|
+
import { chmodSync as chmodSync7, existsSync as existsSync24, statSync as statSync14 } from "fs";
|
|
9208
9412
|
import { createRequire as createRequire4 } from "module";
|
|
9209
9413
|
import { dirname as dirname15, join as join29 } from "path";
|
|
9210
9414
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -9228,7 +9432,7 @@ function fixSpawnHelper(ptyDir) {
|
|
|
9228
9432
|
if (process.platform !== "darwin") return;
|
|
9229
9433
|
try {
|
|
9230
9434
|
const helper = join29(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
|
|
9231
|
-
if (existsSync24(helper) && (
|
|
9435
|
+
if (existsSync24(helper) && (statSync14(helper).mode & 73) === 0) chmodSync7(helper, 493);
|
|
9232
9436
|
} catch {
|
|
9233
9437
|
}
|
|
9234
9438
|
}
|
|
@@ -9465,7 +9669,7 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
|
|
|
9465
9669
|
|
|
9466
9670
|
// src/daemon/loginGuide.ts
|
|
9467
9671
|
import { execFile as execFile9, execFileSync as execFileSync13 } from "child_process";
|
|
9468
|
-
import { chmodSync as chmodSync9, existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as
|
|
9672
|
+
import { chmodSync as chmodSync9, existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync29, writeFileSync as writeFileSync26 } from "fs";
|
|
9469
9673
|
import { homedir as homedir9 } from "os";
|
|
9470
9674
|
import { join as join34 } from "path";
|
|
9471
9675
|
|
|
@@ -10148,7 +10352,7 @@ var defaultCheckDeps = () => ({
|
|
|
10148
10352
|
home: homedir9(),
|
|
10149
10353
|
codexConfig: () => {
|
|
10150
10354
|
try {
|
|
10151
|
-
return
|
|
10355
|
+
return readFileSync29(join34(codexHome(), "config.toml"), "utf8");
|
|
10152
10356
|
} catch {
|
|
10153
10357
|
return null;
|
|
10154
10358
|
}
|
|
@@ -10306,7 +10510,7 @@ var defaultLoginOpenDeps = () => ({
|
|
|
10306
10510
|
});
|
|
10307
10511
|
async function installCodebuddyHooks(log) {
|
|
10308
10512
|
try {
|
|
10309
|
-
const { installTools: installTools2 } = await import("./enable-
|
|
10513
|
+
const { installTools: installTools2 } = await import("./enable-NGQ3J3NW.js");
|
|
10310
10514
|
installTools2(["workbuddy"], () => {
|
|
10311
10515
|
}, null, { auto: true });
|
|
10312
10516
|
} catch (e) {
|
|
@@ -10820,7 +11024,7 @@ function defaultOfferDeps(log) {
|
|
|
10820
11024
|
}),
|
|
10821
11025
|
openLogin: () => defaultOpenLogin(platform),
|
|
10822
11026
|
installHooks: async () => {
|
|
10823
|
-
const { installTools: installTools2 } = await import("./enable-
|
|
11027
|
+
const { installTools: installTools2 } = await import("./enable-NGQ3J3NW.js");
|
|
10824
11028
|
installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
|
|
10825
11029
|
},
|
|
10826
11030
|
log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
|
|
@@ -11071,8 +11275,10 @@ export {
|
|
|
11071
11275
|
codebuddyConfigDir,
|
|
11072
11276
|
qoderCnSettingsPath,
|
|
11073
11277
|
qwenworkHome,
|
|
11278
|
+
qwenworkDataHome,
|
|
11074
11279
|
qoderSettingsPath,
|
|
11075
11280
|
opencodePluginPath,
|
|
11281
|
+
codexHome,
|
|
11076
11282
|
installedHookPath,
|
|
11077
11283
|
loadConfig,
|
|
11078
11284
|
saveConfig,
|
|
@@ -11084,7 +11290,7 @@ export {
|
|
|
11084
11290
|
packageVersion,
|
|
11085
11291
|
installedHookVersion,
|
|
11086
11292
|
syncHookFile,
|
|
11087
|
-
|
|
11293
|
+
CODE_NOT_SUPPORT,
|
|
11088
11294
|
APP_ID,
|
|
11089
11295
|
APP_SECRET,
|
|
11090
11296
|
sign,
|
|
@@ -11259,6 +11465,16 @@ export {
|
|
|
11259
11465
|
APP_IN_USE_REASON,
|
|
11260
11466
|
QODER_APP_POLL_MS,
|
|
11261
11467
|
QoderAppTasks,
|
|
11468
|
+
SUMMARY_CAPS,
|
|
11469
|
+
SUMMARY_TOOLS2 as SUMMARY_TOOLS,
|
|
11470
|
+
SUMMARY_NO_OUTPUT,
|
|
11471
|
+
isSummary,
|
|
11472
|
+
withSummaryMark,
|
|
11473
|
+
clipOutput,
|
|
11474
|
+
SUMMARY_WAIT_MS,
|
|
11475
|
+
ptyVerdict,
|
|
11476
|
+
replyVerdict,
|
|
11477
|
+
PtySummaryWatch,
|
|
11262
11478
|
APP_NOT_RUNNING,
|
|
11263
11479
|
DumateWatch,
|
|
11264
11480
|
runHook,
|