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.
@@ -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 readFileSync12, renameSync as renameSync8, statSync as statSync4, writeFileSync as writeFileSync11 } from "fs";
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
- try {
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(readFileSync12(file3, "utf8"));
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(readFileSync12(failFileOf(app, d), "utf8"));
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 statSync12 } from "fs";
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 statSync11 } from "fs";
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 readFileSync23, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
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 readFileSync15, renameSync as renameSync10, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
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 readFileSync13, readSync, realpathSync, renameSync as renameSync9, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync12 } from "fs";
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(readFileSync13(join11(endedDir(), `${sessionId}.json`), "utf8"));
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 readFileSync14, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "fs";
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(readFileSync14(join12(dir(), f), "utf8")).tool ?? "");
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(readFileSync14(f, "utf8")).at;
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(readFileSync15(statePath(sessionId), "utf8"));
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(readFileSync15(join14(deskbuddyHome(), "approvals.json"), "utf8"));
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(readFileSync15(join14(stateDir(), file3), "utf8"));
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(readFileSync15(join14(deskbuddyHome(), "alias.json"), "utf8")) || {};
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 readFileSync16, rmdirSync, rmSync as rmSync9, writeFileSync as writeFileSync16 } from "fs";
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 readFileSync16(p).toString("latin1");
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 readFileSync16(join15(binDir, n), "utf8").includes(SHIM_MARKER);
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) && readFileSync16(file3, "utf8").includes(SHIM_MARKER)) {
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 = readFileSync16(file3, "utf8").includes(SHIM_MARKER);
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 readFileSync22, readSync as readSync5, renameSync as renameSync14, rmSync as rmSync12, statSync as statSync10, writeFileSync as writeFileSync20 } from "fs";
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 readFileSync18, renameSync as renameSync12, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
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 readFileSync17, readSync as readSync2, renameSync as renameSync11, rmSync as rmSync10, statSync as statSync6, writeFileSync as writeFileSync17 } from "fs";
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(readFileSync17(join16(marksDir(), `${safe}.json`), "utf8"));
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 === "text").map((x) => String(x.text ?? "")).join("\n");
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 || !o.message) continue;
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(readFileSync18(claimed, "utf8"));
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
- readFileSync18(planFile(runId));
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 readFileSync19, readSync as readSync3, statSync as statSync7 } from "fs";
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 readFileSync21, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync9 } from "fs";
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 readFileSync20, renameSync as renameSync13, statSync as statSync8, writeFileSync as writeFileSync19 } from "fs";
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(readFileSync20(file3, "utf8"));
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 (!statSync9(p).isFile()) return false;
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 readFileSync21(p, "utf8");
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 = statSync9(p);
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 = statSync10(p).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(statSync10(p).mtimeMs);
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(readFileSync22(pendingPath(), "utf8"));
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(readFileSync23(keeperThrottleFile(), "utf8"));
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(readFileSync23(join22(dir2, f), "utf8"));
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 = statSync11(dir2).mtimeMs;
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 readFileSync24, renameSync as renameSync16, writeFileSync as writeFileSync22 } from "fs";
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(readFileSync24(join24(dir2, f), "utf8"));
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(readFileSync24(this.#file(), "utf8"));
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(readFileSync24(f, "utf8"));
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, statSync12(join25(dir2, "opencode.db")).mtimeMs);
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 = statSync12(join25(dir2, "opencode.db-wal"));
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 readFileSync25, realpathSync as realpathSync5, renameSync as renameSync17, rmSync as rmSync13, statSync as statSync13, writeFileSync as writeFileSync23 } from "fs";
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 = readFileSync25(path, "utf8");
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 = statSync13(path).mode & 511;
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 readFileSync27 } from "fs";
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 readFileSync26, realpathSync as realpathSync6, renameSync as renameSync18, statSync as statSync14, writeFileSync as writeFileSync24 } from "fs";
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 = readFileSync26(path, "utf8");
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 = statSync14(path).mode & 511;
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 readFileSync27(path, "utf8").includes(needle);
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(readFileSync27(p, "utf8")).enabledTools;
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(readFileSync27(p, "utf8")).enabledTools;
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 statSync15 } from "fs";
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) && (statSync15(helper).mode & 73) === 0) chmodSync7(helper, 493);
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 readFileSync28, writeFileSync as writeFileSync26 } from "fs";
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 readFileSync28(join34(codexHome(), "config.toml"), "utf8");
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-EDDFXBHM.js");
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-EDDFXBHM.js");
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
- COMMAND_OUTPUT_MAX,
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,