deskbuddy 0.2.0-beta.31 → 0.2.0-beta.32

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
  }
@@ -1523,6 +1526,19 @@ function installCcWindowGate(settingsPath, gatePath, tool = "claude_code", platf
1523
1526
  });
1524
1527
  writeSettings(settingsPath, settings);
1525
1528
  }
1529
+ var PRETOOL_QUESTION_TIMEOUT_S = 660;
1530
+ var PRETOOL_QUESTION_MATCHER = "^AskUserQuestion$";
1531
+ function installCcPreToolQuestion(settingsPath, gatePath, tool, platform = process.platform) {
1532
+ const settings = readSettings(settingsPath);
1533
+ settings.hooks ??= {};
1534
+ const groups = settings.hooks.PreToolUse ??= [];
1535
+ if (groups.some((g) => g.hooks?.some((h) => mentions(h.command, gatePath) && h.command.includes("--pretool-question")))) return;
1536
+ groups.push({
1537
+ matcher: PRETOOL_QUESTION_MATCHER,
1538
+ hooks: [{ type: "command", command: `node ${scriptArg(gatePath, platform, shQuote2)} --pretool-question --tool ${tool}`, timeout: PRETOOL_QUESTION_TIMEOUT_S }]
1539
+ });
1540
+ writeSettings(settingsPath, settings);
1541
+ }
1526
1542
  var REWAKE_TIMEOUT_S = 20 * 24 * 60 * 60;
1527
1543
  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
1544
  var REWAKE_SUMMARY = "DeskBuddy \u8BBE\u5907\u6307\u4EE4";
@@ -1875,7 +1891,7 @@ import { join as join26 } from "path";
1875
1891
 
1876
1892
  // src/daemon/appShortcuts.ts
1877
1893
  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";
1894
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync13, renameSync as renameSync8, writeFileSync as writeFileSync11 } from "fs";
1879
1895
  import { join as join10, win32 as win322 } from "path";
1880
1896
 
1881
1897
  // src/core/fileLock.ts
@@ -1938,7 +1954,25 @@ function pidAlive2(pid) {
1938
1954
  }
1939
1955
 
1940
1956
  // src/daemon/winPaths.ts
1957
+ import { readFileSync as readFileSync12, statSync as statSync4 } from "fs";
1941
1958
  import { win32 } from "path";
1959
+ function decodeText(b) {
1960
+ if (b.length >= 2 && b[0] === 255 && b[1] === 254) return b.subarray(2).toString("utf16le");
1961
+ if (b.length >= 2 && b[0] === 254 && b[1] === 255) {
1962
+ const be = Buffer.from(b.subarray(2, 2 + (b.length - 2 & ~1)));
1963
+ return be.swap16().toString("utf16le");
1964
+ }
1965
+ if (b.length >= 3 && b[0] === 239 && b[1] === 187 && b[2] === 191) return b.subarray(3).toString("utf8");
1966
+ return b.toString("utf8");
1967
+ }
1968
+ function readSmallText(p) {
1969
+ try {
1970
+ if (statSync4(p).size > 64 * 1024) return null;
1971
+ return decodeText(readFileSync12(p));
1972
+ } catch {
1973
+ return null;
1974
+ }
1975
+ }
1942
1976
  function isValidWinPath(p) {
1943
1977
  if (typeof p !== "string" || p.length < 4 || p.length > 1024) return false;
1944
1978
  if (!/^[a-z]:\\/i.test(p)) return false;
@@ -2055,12 +2089,7 @@ function launcherTargets(list, writes, exe) {
2055
2089
  return [...out];
2056
2090
  }
2057
2091
  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
- }
2092
+ return readSmallText(p);
2064
2093
  }
2065
2094
  var keyOf = (p) => p.toLowerCase();
2066
2095
  function planPatchFor(exe, list, records, port) {
@@ -2092,7 +2121,7 @@ function recordsFile(app) {
2092
2121
  }
2093
2122
  function loadRecords(file3) {
2094
2123
  try {
2095
- const v = JSON.parse(readFileSync12(file3, "utf8"));
2124
+ const v = JSON.parse(readFileSync13(file3, "utf8"));
2096
2125
  if (!v || typeof v !== "object") return {};
2097
2126
  const out = {};
2098
2127
  for (const [k, r] of Object.entries(v)) {
@@ -2161,7 +2190,7 @@ var writeEnv = (app, ops, list) => ({
2161
2190
  var matcherOf = (app, d, restore = false) => lnkMatcher(app, d.readText, restore);
2162
2191
  function loadFails(app, d) {
2163
2192
  try {
2164
- const v = JSON.parse(readFileSync12(failFileOf(app, d), "utf8"));
2193
+ const v = JSON.parse(readFileSync13(failFileOf(app, d), "utf8"));
2165
2194
  const out = {};
2166
2195
  for (const [k, t] of Object.entries(v ?? {})) if (typeof t === "number") out[k] = t;
2167
2196
  return out;
@@ -2317,12 +2346,12 @@ function restoreAppShortcutsSync(app, d, ps = defaultPsSync) {
2317
2346
  }
2318
2347
 
2319
2348
  // src/daemon/dumateApp/keeper.ts
2320
- import { readdirSync as readdirSync13, statSync as statSync12 } from "fs";
2349
+ import { readdirSync as readdirSync13, statSync as statSync11 } from "fs";
2321
2350
  import { join as join25 } from "path";
2322
2351
 
2323
2352
  // src/daemon/dumateWatch.ts
2324
2353
  import { execFileSync as execFileSync10, spawn as spawn3 } from "child_process";
2325
- import { readdirSync as readdirSync11, realpathSync as realpathSync4, statSync as statSync11 } from "fs";
2354
+ import { readdirSync as readdirSync11, realpathSync as realpathSync4, statSync as statSync10 } from "fs";
2326
2355
  import { request as httpRequest } from "http";
2327
2356
  import { join as join23 } from "path";
2328
2357
 
@@ -3039,7 +3068,7 @@ function traeNoticeSummary(toolName, toolInput, described, notice) {
3039
3068
 
3040
3069
  // src/daemon/workbuddyApp/keeper.ts
3041
3070
  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";
3071
+ import { existsSync as existsSync19, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
3043
3072
  import { delimiter as delimiter3, join as join22, resolve as resolve4 } from "path";
3044
3073
 
3045
3074
  // src/core/process.ts
@@ -3102,7 +3131,7 @@ function isAlive(pid, expectName, kill = process.kill.bind(process)) {
3102
3131
  }
3103
3132
 
3104
3133
  // 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";
3134
+ 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
3135
  import { join as join14 } from "path";
3107
3136
 
3108
3137
  // src/core/codexServer.ts
@@ -3153,7 +3182,7 @@ function programOf(args) {
3153
3182
  }
3154
3183
 
3155
3184
  // 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";
3185
+ 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
3186
  import { join as join11 } from "path";
3158
3187
  var ENDED_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
3159
3188
  var SID_RE = /^[A-Za-z0-9_-]{1,64}$/;
@@ -3185,7 +3214,7 @@ function writeEnded(s, now = Date.now()) {
3185
3214
  function readEnded(sessionId, now = Date.now()) {
3186
3215
  if (!SID_RE.test(sessionId)) return null;
3187
3216
  try {
3188
- const r = JSON.parse(readFileSync13(join11(endedDir(), `${sessionId}.json`), "utf8"));
3217
+ const r = JSON.parse(readFileSync14(join11(endedDir(), `${sessionId}.json`), "utf8"));
3189
3218
  if (!r || r.sessionId !== sessionId || typeof r.endedAt !== "number" || now - r.endedAt > ENDED_TTL_MS) return null;
3190
3219
  return r;
3191
3220
  } catch {
@@ -3276,7 +3305,7 @@ function isDirSync(p) {
3276
3305
  }
3277
3306
 
3278
3307
  // 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";
3308
+ import { existsSync as existsSync11, mkdirSync as mkdirSync13, readdirSync as readdirSync3, readFileSync as readFileSync15, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "fs";
3280
3309
  import { join as join12 } from "path";
3281
3310
  var QODER_APP_SESSION_TOOLS = ["qoder_cn", "qoder"];
3282
3311
  var KEEPER_FILE = "keeper";
@@ -3320,7 +3349,7 @@ function listQoderAppSessions(tool) {
3320
3349
  for (const f of names) {
3321
3350
  let t = "";
3322
3351
  try {
3323
- t = String(JSON.parse(readFileSync14(join12(dir(), f), "utf8")).tool ?? "");
3352
+ t = String(JSON.parse(readFileSync15(join12(dir(), f), "utf8")).tool ?? "");
3324
3353
  } catch {
3325
3354
  t = "";
3326
3355
  }
@@ -3334,7 +3363,7 @@ function qoderAppMarkedAt(sessionId) {
3334
3363
  const f = file(sessionId);
3335
3364
  if (!f) return 0;
3336
3365
  try {
3337
- const at = JSON.parse(readFileSync14(f, "utf8")).at;
3366
+ const at = JSON.parse(readFileSync15(f, "utf8")).at;
3338
3367
  return typeof at === "number" ? at : 0;
3339
3368
  } catch {
3340
3369
  return 0;
@@ -3407,7 +3436,7 @@ function statePath(sessionId) {
3407
3436
  }
3408
3437
  function readState(sessionId) {
3409
3438
  try {
3410
- return JSON.parse(readFileSync15(statePath(sessionId), "utf8"));
3439
+ return JSON.parse(readFileSync16(statePath(sessionId), "utf8"));
3411
3440
  } catch {
3412
3441
  return null;
3413
3442
  }
@@ -3472,7 +3501,7 @@ var STALE_STATES = /* @__PURE__ */ new Set(["watch", "ask_approval"]);
3472
3501
  var STALE_NO_PID_LOG = "\u65E0\u8FDB\u7A0B\u53F7\u4E14 2 \u5C0F\u65F6\u65E0\u4E8B\u4EF6\uFF0C\u6309\u5DF2\u7ED3\u675F\u5904\u7406";
3473
3502
  function pendingApprovalSessions() {
3474
3503
  try {
3475
- const recs = JSON.parse(readFileSync15(join14(deskbuddyHome(), "approvals.json"), "utf8"));
3504
+ const recs = JSON.parse(readFileSync16(join14(deskbuddyHome(), "approvals.json"), "utf8"));
3476
3505
  return new Set(Array.isArray(recs) ? recs.filter((r) => r && r.status === "pending" && typeof r.sessionId === "string").map((r) => r.sessionId) : []);
3477
3506
  } catch {
3478
3507
  return /* @__PURE__ */ new Set();
@@ -3499,7 +3528,7 @@ function readAliveStates(tool, opts = {}) {
3499
3528
  if (!file3.endsWith(".json")) continue;
3500
3529
  let s;
3501
3530
  try {
3502
- s = JSON.parse(readFileSync15(join14(stateDir(), file3), "utf8"));
3531
+ s = JSON.parse(readFileSync16(join14(stateDir(), file3), "utf8"));
3503
3532
  } catch {
3504
3533
  rmSync8(join14(stateDir(), file3), { force: true });
3505
3534
  continue;
@@ -3551,7 +3580,7 @@ var ALIAS_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
3551
3580
  function resolveAlias(sessionId, now = Date.now()) {
3552
3581
  let map = {};
3553
3582
  try {
3554
- map = JSON.parse(readFileSync15(join14(deskbuddyHome(), "alias.json"), "utf8")) || {};
3583
+ map = JSON.parse(readFileSync16(join14(deskbuddyHome(), "alias.json"), "utf8")) || {};
3555
3584
  } catch {
3556
3585
  return sessionId;
3557
3586
  }
@@ -3566,7 +3595,7 @@ function resolveAlias(sessionId, now = Date.now()) {
3566
3595
 
3567
3596
  // src/wrap/shim.ts
3568
3597
  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";
3598
+ 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
3599
  import { homedir as homedir3 } from "os";
3571
3600
  import { delimiter, join as join15, resolve as resolve3 } from "path";
3572
3601
  var SHIM_FALLBACK_EXIT = 213;
@@ -3722,7 +3751,7 @@ function removeRcBlock(content) {
3722
3751
  return content.slice(0, start) + content.slice(end);
3723
3752
  }
3724
3753
  function readRc(p) {
3725
- return readFileSync16(p).toString("latin1");
3754
+ return readFileSync17(p).toString("latin1");
3726
3755
  }
3727
3756
  function writeRc(p, latin1) {
3728
3757
  writeFileSync16(p, Buffer.from(latin1, "latin1"));
@@ -3977,7 +4006,7 @@ function ourShims(binDir) {
3977
4006
  }
3978
4007
  return names.filter((n) => {
3979
4008
  try {
3980
- return readFileSync16(join15(binDir, n), "utf8").includes(SHIM_MARKER);
4009
+ return readFileSync17(join15(binDir, n), "utf8").includes(SHIM_MARKER);
3981
4010
  } catch {
3982
4011
  return false;
3983
4012
  }
@@ -3989,7 +4018,7 @@ function uninstallShim(tool, e) {
3989
4018
  let removed = false;
3990
4019
  const file3 = shimFile(e.binDir, command, e.platform);
3991
4020
  try {
3992
- if (existsSync14(file3) && readFileSync16(file3, "utf8").includes(SHIM_MARKER)) {
4021
+ if (existsSync14(file3) && readFileSync17(file3, "utf8").includes(SHIM_MARKER)) {
3993
4022
  rmSync9(file3, { force: true });
3994
4023
  removed = true;
3995
4024
  }
@@ -4033,7 +4062,7 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
4033
4062
  const file3 = shimFile(binDir, command, platform);
4034
4063
  let installed = false;
4035
4064
  try {
4036
- installed = readFileSync16(file3, "utf8").includes(SHIM_MARKER);
4065
+ installed = readFileSync17(file3, "utf8").includes(SHIM_MARKER);
4037
4066
  } catch {
4038
4067
  installed = false;
4039
4068
  }
@@ -4045,18 +4074,18 @@ function shimState(tool, binDir, pathEnv, platform = process.platform) {
4045
4074
 
4046
4075
  // src/daemon/workbuddyAppDb.ts
4047
4076
  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";
4077
+ 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
4078
  import { createRequire as createRequire3 } from "module";
4050
4079
  import { basename as basename4, dirname as dirname12, isAbsolute as isAbsolute2, join as join21 } from "path";
4051
4080
 
4052
4081
  // src/core/launch.ts
4053
- import { mkdirSync as mkdirSync18, readFileSync as readFileSync18, renameSync as renameSync12, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
4082
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync19, renameSync as renameSync12, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
4054
4083
  import { join as join17 } from "path";
4055
4084
 
4056
4085
  // src/core/wake.ts
4057
4086
  import { execFileSync as execFileSync8 } from "child_process";
4058
4087
  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";
4088
+ 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
4089
  import { tmpdir } from "os";
4061
4090
  import { join as join16 } from "path";
4062
4091
  function wakeDir(home = deskbuddyHome()) {
@@ -4125,7 +4154,7 @@ function isWakeMarked(sessionId, alive = pidExists) {
4125
4154
  const safe = safeSid(sessionId);
4126
4155
  if (!safe) return false;
4127
4156
  try {
4128
- const m = JSON.parse(readFileSync17(join16(marksDir(), `${safe}.json`), "utf8"));
4157
+ const m = JSON.parse(readFileSync18(join16(marksDir(), `${safe}.json`), "utf8"));
4129
4158
  const daemonPid = Number(m?.daemonPid) || 0;
4130
4159
  if (!daemonPid || !alive(daemonPid)) return false;
4131
4160
  const pid = Number(m?.agentPid) || 0;
@@ -4195,10 +4224,11 @@ function macEqual(a, b) {
4195
4224
  var WAKE_MARK_RE = /\[DeskBuddy#([0-9A-Za-z_-]{1,64})(?::[0-9a-f]{32})?\]/;
4196
4225
  var INTERRUPT_RE = /^\[Request interrupted by user/;
4197
4226
  var TRANSCRIPT_TAIL2 = 256 * 1024;
4227
+ var TEXT_PART_TYPES = /* @__PURE__ */ new Set(["text", "input_text", "output_text"]);
4198
4228
  function userText(content) {
4199
4229
  if (typeof content === "string") return content;
4200
4230
  if (!Array.isArray(content)) return "";
4201
- return content.filter((x) => x && x.type === "text").map((x) => String(x.text ?? "")).join("\n");
4231
+ return content.filter((x) => x && TEXT_PART_TYPES.has(x.type)).map((x) => String(x.text ?? "")).join("\n");
4202
4232
  }
4203
4233
  function analyzeTranscript(file3) {
4204
4234
  if (!file3) return null;
@@ -4223,7 +4253,9 @@ function analyzeTranscript(file3) {
4223
4253
  } catch {
4224
4254
  continue;
4225
4255
  }
4226
- if (!o || !o.message) continue;
4256
+ if (!o) continue;
4257
+ if (o.type === "message" && (o.role === "user" || o.role === "assistant")) o = { type: o.role, message: { content: o.content } };
4258
+ if (!o.message) continue;
4227
4259
  if (o.type === "assistant") {
4228
4260
  const t = userText(o.message.content).trim();
4229
4261
  if (t) {
@@ -4289,7 +4321,7 @@ function claimLaunch(runId) {
4289
4321
  return null;
4290
4322
  }
4291
4323
  try {
4292
- const p = JSON.parse(readFileSync18(claimed, "utf8"));
4324
+ const p = JSON.parse(readFileSync19(claimed, "utf8"));
4293
4325
  if (!p || typeof p.cwd !== "string" || typeof p.resume !== "string") return null;
4294
4326
  if (p.tool === void 0) p.tool = "claude_code";
4295
4327
  return validPlan(p) ? p : null;
@@ -4304,7 +4336,7 @@ function claimLaunch(runId) {
4304
4336
  }
4305
4337
  function launchPending(runId) {
4306
4338
  try {
4307
- readFileSync18(planFile(runId));
4339
+ readFileSync19(planFile(runId));
4308
4340
  return true;
4309
4341
  } catch {
4310
4342
  return false;
@@ -4312,7 +4344,7 @@ function launchPending(runId) {
4312
4344
  }
4313
4345
 
4314
4346
  // 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";
4347
+ import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync20, readSync as readSync3, statSync as statSync7 } from "fs";
4316
4348
  import { createRequire as createRequire2 } from "module";
4317
4349
  import { homedir as homedir5 } from "os";
4318
4350
  import { basename as basename3, dirname as dirname10, isAbsolute, join as join18 } from "path";
@@ -4374,7 +4406,7 @@ function qoderDbPaths(tool, platform = process.platform, home = homedir5(), env
4374
4406
 
4375
4407
  // src/daemon/locate.ts
4376
4408
  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";
4409
+ 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
4410
  import { homedir as homedir6 } from "os";
4379
4411
  import { delimiter as delimiter2, dirname as dirname11, join as join20, win32 as win325 } from "path";
4380
4412
 
@@ -4394,7 +4426,7 @@ function scrubForCommand(cmd, env = process.env) {
4394
4426
  }
4395
4427
 
4396
4428
  // 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";
4429
+ import { existsSync as existsSync16, mkdirSync as mkdirSync19, readdirSync as readdirSync8, readFileSync as readFileSync21, renameSync as renameSync13, writeFileSync as writeFileSync19 } from "fs";
4398
4430
  import { join as join19, win32 as win324 } from "path";
4399
4431
  var SOURCE_TEXT = {
4400
4432
  process: "\u6B63\u5728\u8FD0\u884C\u7684\u8FDB\u7A0B",
@@ -4427,14 +4459,7 @@ var WIN_APP_SPECS = {
4427
4459
  };
4428
4460
  var defaultLocFs = {
4429
4461
  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
- },
4462
+ readText: (p) => readSmallText(p),
4438
4463
  subdirs: (p) => {
4439
4464
  try {
4440
4465
  return readdirSync8(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
@@ -4530,7 +4555,7 @@ var LOCATE_EVERY_MS = 10 * 60 * 1e3;
4530
4555
  var cacheFile = () => join19(deskbuddyHome(), WIN_APPS_FILE);
4531
4556
  function loadCache(file3 = cacheFile()) {
4532
4557
  try {
4533
- const v = JSON.parse(readFileSync20(file3, "utf8"));
4558
+ const v = JSON.parse(readFileSync21(file3, "utf8"));
4534
4559
  const out = {};
4535
4560
  for (const [k, e] of Object.entries(v ?? {})) {
4536
4561
  const x = e;
@@ -4685,7 +4710,7 @@ var defaultLocateDeps = () => ({
4685
4710
  nodePath: process.execPath,
4686
4711
  isExecutable: (p) => {
4687
4712
  try {
4688
- if (!statSync9(p).isFile()) return false;
4713
+ if (!statSync8(p).isFile()) return false;
4689
4714
  accessSync(p, constants.X_OK);
4690
4715
  return true;
4691
4716
  } catch {
@@ -4706,7 +4731,7 @@ var defaultLocateDeps = () => ({
4706
4731
  localAppData: process.env.LOCALAPPDATA ?? "",
4707
4732
  readText: (p) => {
4708
4733
  try {
4709
- return readFileSync21(p, "utf8");
4734
+ return readFileSync22(p, "utf8");
4710
4735
  } catch {
4711
4736
  return null;
4712
4737
  }
@@ -4790,7 +4815,7 @@ function classifyAsyncError(e, stdout2, stderr) {
4790
4815
  var defaultProbe = createVersionProbe({
4791
4816
  stat: (p) => {
4792
4817
  try {
4793
- const st = statSync9(p);
4818
+ const st = statSync8(p);
4794
4819
  return { size: st.size, mtimeMs: st.mtimeMs };
4795
4820
  } catch {
4796
4821
  return null;
@@ -5303,7 +5328,7 @@ var SLICE = 64 * 1024;
5303
5328
  function readSlice(p, from) {
5304
5329
  const fd = openSync5(p, "r");
5305
5330
  try {
5306
- const size = statSync10(p).size;
5331
+ const size = statSync9(p).size;
5307
5332
  const len = Math.min(size, SLICE);
5308
5333
  const buf = Buffer.alloc(len);
5309
5334
  readSync5(fd, buf, 0, len, from === "head" ? 0 : size - len);
@@ -5347,7 +5372,7 @@ function userText2(o) {
5347
5372
  function wbTranscriptInfo(p) {
5348
5373
  const head = jsonLines(readSlice(p, "head"));
5349
5374
  const tail = jsonLines(readSlice(p, "tail"));
5350
- const mtime = Math.floor(statSync10(p).mtimeMs);
5375
+ const mtime = Math.floor(statSync9(p).mtimeMs);
5351
5376
  const hs = head.map((o) => tsOf(o.timestamp)).filter((n) => n !== null);
5352
5377
  const ts = tail.map((o) => tsOf(o.timestamp)).filter((n) => n !== null);
5353
5378
  const createdAt = hs.length ? Math.min(...hs) : mtime;
@@ -5428,7 +5453,7 @@ function pendingPath() {
5428
5453
  }
5429
5454
  function loadPendingFile() {
5430
5455
  try {
5431
- const v = JSON.parse(readFileSync22(pendingPath(), "utf8"));
5456
+ const v = JSON.parse(readFileSync23(pendingPath(), "utf8"));
5432
5457
  return Array.isArray(v) ? v.filter((j) => j && typeof j.sessionId === "string" && typeof j.cwd === "string") : [];
5433
5458
  } catch {
5434
5459
  return [];
@@ -5746,7 +5771,7 @@ var keeperThrottleFile = () => join22(deskbuddyHome(), "wbapp", "keeper.json");
5746
5771
  var filePersist = {
5747
5772
  load: () => {
5748
5773
  try {
5749
- return JSON.parse(readFileSync23(keeperThrottleFile(), "utf8"));
5774
+ return JSON.parse(readFileSync24(keeperThrottleFile(), "utf8"));
5750
5775
  } catch {
5751
5776
  return null;
5752
5777
  }
@@ -5940,7 +5965,7 @@ function workbuddyBusy(now = Date.now(), dir2 = stateDir(), alive = isAlive) {
5940
5965
  for (const f of readdirSync10(dir2)) {
5941
5966
  if (!f.endsWith(".json")) continue;
5942
5967
  try {
5943
- const s = JSON.parse(readFileSync23(join22(dir2, f), "utf8"));
5968
+ const s = JSON.parse(readFileSync24(join22(dir2, f), "utf8"));
5944
5969
  if (s.tool !== "workbuddy" || s.state !== "watch" && s.state !== "ask_approval") continue;
5945
5970
  if (typeof s.pid === "number" && s.pid > 0) {
5946
5971
  if (alive(s.pid, s.pidName)) return true;
@@ -7105,6 +7130,149 @@ var QoderAppTasks = class {
7105
7130
  }
7106
7131
  };
7107
7132
 
7133
+ // src/core/summaryTools.ts
7134
+ var SUMMARY_TOOLS = ["claude_code", "codex", "qoder", "qoder_cn", "opencode", "workbuddy", "qwenwork", "dumate", "deepseek_harness"];
7135
+ var SUMMARY_CAPS = SUMMARY_TOOLS.map((t) => `summary:${t}`);
7136
+
7137
+ // src/daemon/summary.ts
7138
+ var SUMMARY_TOOLS2 = SUMMARY_TOOLS;
7139
+ var SUMMARY_NO_OUTPUT = "no_output";
7140
+ var SUMMARY_TIMEOUT = "timeout";
7141
+ function isSummary(cmd) {
7142
+ return cmd.kind === "summary";
7143
+ }
7144
+ function summaryMark(instructionId) {
7145
+ return `[DeskBuddy#${instructionId}]`;
7146
+ }
7147
+ function withSummaryMark(text, instructionId) {
7148
+ if (text.includes(`[DeskBuddy#${instructionId}]`) || text.includes(`[DeskBuddy#${instructionId}:`)) return text;
7149
+ return `${text}
7150
+ ${summaryMark(instructionId)}`;
7151
+ }
7152
+ function clipOutput(text) {
7153
+ return text.length > COMMAND_OUTPUT_MAX ? text.slice(0, COMMAND_OUTPUT_MAX) : text;
7154
+ }
7155
+ var BUSY = /* @__PURE__ */ new Set(["watch", "ask_approval"]);
7156
+ var PTY_SETTLE_MS = 1500;
7157
+ var SUMMARY_WAIT_MS = 4 * 60 * 1e3;
7158
+ var PTY_SUMMARY_WAIT_MS = SUMMARY_WAIT_MS;
7159
+ function ptyVerdict(job, st, tail, now) {
7160
+ if (now - job.startedAt > PTY_SUMMARY_WAIT_MS) return { kind: "fail", reason: SUMMARY_TIMEOUT };
7161
+ if (!st) return { kind: "fail", reason: "session_gone" };
7162
+ if (!tail || tail.id !== job.instructionId) return { kind: "wait" };
7163
+ if (tail.humanAfter || tail.interrupted) return { kind: "fail", reason: "exec_failed" };
7164
+ if (!tail.answered) return { kind: "wait" };
7165
+ if (BUSY.has(st.state) || now - st.updatedAt < PTY_SETTLE_MS) return { kind: "wait" };
7166
+ const text = (tail.reply ?? "").trim();
7167
+ return text ? { kind: "done", text } : { kind: "fail", reason: SUMMARY_NO_OUTPUT };
7168
+ }
7169
+ function hasSummaryMark(text, instructionId) {
7170
+ return text.includes(`[DeskBuddy#${instructionId}]`) || text.includes(`[DeskBuddy#${instructionId}:`);
7171
+ }
7172
+ function messagesVerdict(list, instructionId, idle) {
7173
+ if (!Array.isArray(list)) return { kind: "wait" };
7174
+ const msgs = list;
7175
+ 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() : "";
7176
+ let at = -1;
7177
+ for (let i = msgs.length - 1; i >= 0; i--) {
7178
+ const m = msgs[i];
7179
+ if (m && m.info?.role === "user" && hasSummaryMark(textOf(m), instructionId)) {
7180
+ at = i;
7181
+ break;
7182
+ }
7183
+ }
7184
+ if (at < 0) return { kind: "wait" };
7185
+ const after = msgs.slice(at + 1).filter((m) => m && m.info);
7186
+ if (after.some((m) => m.info?.role === "user")) return { kind: "fail", reason: "exec_failed" };
7187
+ const markId = typeof msgs[at].info?.id === "string" ? msgs[at].info?.id : "";
7188
+ const replies = after.filter((m) => m.info?.role === "assistant" && (!markId || typeof m.info.parentID !== "string" || m.info.parentID === markId));
7189
+ if (!idle || replies.length === 0) return { kind: "wait" };
7190
+ const last = replies[replies.length - 1];
7191
+ if (!last.info?.time || last.info.time.completed == null) return { kind: "wait" };
7192
+ for (let i = replies.length - 1; i >= 0; i--) {
7193
+ const t = textOf(replies[i]);
7194
+ if (t) return { kind: "done", text: t };
7195
+ }
7196
+ return { kind: "fail", reason: SUMMARY_NO_OUTPUT };
7197
+ }
7198
+ function replyVerdict(r) {
7199
+ if (!r || typeof r !== "object") return { kind: "wait" };
7200
+ const v = r;
7201
+ if (v.ok === true) {
7202
+ const t = typeof v.text === "string" ? v.text.trim() : "";
7203
+ return t ? { kind: "done", text: t } : { kind: "fail", reason: SUMMARY_NO_OUTPUT };
7204
+ }
7205
+ const reason = typeof v.reason === "string" && /^[a-z_]{1,32}$/.test(v.reason) ? v.reason : "exec_failed";
7206
+ return { kind: "fail", reason };
7207
+ }
7208
+ var PtySummaryWatch = class {
7209
+ #d;
7210
+ #jobs = /* @__PURE__ */ new Map();
7211
+ constructor(deps) {
7212
+ this.#d = deps;
7213
+ }
7214
+ get size() {
7215
+ return this.#jobs.size;
7216
+ }
7217
+ has(instructionId) {
7218
+ return this.#jobs.has(instructionId);
7219
+ }
7220
+ /** 交出去(started / queued)时登记;handedAt = 交出去的时刻(缺省现在)。同一条重复登记保留最早的时刻 */
7221
+ begin(cmd, sessionId, handedAt, check) {
7222
+ const prev = this.#jobs.get(cmd.instructionId);
7223
+ this.#jobs.set(cmd.instructionId, { cmd, sessionId, startedAt: prev?.startedAt ?? handedAt ?? this.#d.now(), check: check ?? prev?.check });
7224
+ }
7225
+ drop(instructionId) {
7226
+ this.#jobs.delete(instructionId);
7227
+ }
7228
+ #settle(id, job, v) {
7229
+ if (v.kind === "wait" || this.#jobs.get(id) !== job) return;
7230
+ this.#jobs.delete(id);
7231
+ if (v.kind === "done") this.#d.done(job.cmd, job.sessionId, v.text);
7232
+ else this.#d.fail(job.cmd, job.sessionId, v.reason);
7233
+ }
7234
+ tick() {
7235
+ const now = this.#d.now();
7236
+ for (const [id, job] of [...this.#jobs]) {
7237
+ if (job.check) {
7238
+ if (now - job.startedAt > PTY_SUMMARY_WAIT_MS) {
7239
+ this.#settle(id, job, { kind: "fail", reason: SUMMARY_TIMEOUT });
7240
+ continue;
7241
+ }
7242
+ if (job.checking) continue;
7243
+ let r;
7244
+ try {
7245
+ r = job.check({ instructionId: id, sessionId: job.sessionId, startedAt: job.startedAt }, now);
7246
+ } catch {
7247
+ continue;
7248
+ }
7249
+ if (r && typeof r.then === "function") {
7250
+ job.checking = true;
7251
+ void r.then(
7252
+ (v) => {
7253
+ job.checking = false;
7254
+ this.#settle(id, job, v);
7255
+ },
7256
+ () => {
7257
+ job.checking = false;
7258
+ }
7259
+ );
7260
+ } else this.#settle(id, job, r);
7261
+ continue;
7262
+ }
7263
+ let st = null;
7264
+ let tail = null;
7265
+ try {
7266
+ st = this.#d.readState(job.sessionId);
7267
+ const path = st ? this.#d.transcriptOf(st) : null;
7268
+ tail = path ? this.#d.analyze(path) : null;
7269
+ } catch {
7270
+ }
7271
+ this.#settle(id, job, ptyVerdict({ instructionId: id, startedAt: job.startedAt }, st, tail, now));
7272
+ }
7273
+ }
7274
+ };
7275
+
7108
7276
  // src/daemon/dumateWatch.ts
7109
7277
  var APP_NOT_RUNNING = "app_not_running";
7110
7278
  function unavailableMessage(reason) {
@@ -7158,6 +7326,7 @@ function isRefused(e) {
7158
7326
  return code(e) === "ECONNREFUSED" || code(e?.cause) === "ECONNREFUSED";
7159
7327
  }
7160
7328
  var REPLY_HISTORY_LIMIT = 10;
7329
+ var SUMMARY_HISTORY_LIMIT = 100;
7161
7330
  function pickOfInfo(info) {
7162
7331
  const i = info && typeof info === "object" ? info : null;
7163
7332
  if (!i || i.role !== "user") return null;
@@ -7331,7 +7500,7 @@ function scanSessionDirs(root, now, maxAgeMs = ACTIVE_DIR_MS) {
7331
7500
  for (const day of list(u).sort().reverse().slice(0, 2))
7332
7501
  for (const dir2 of list(day)) {
7333
7502
  try {
7334
- const at = statSync11(dir2).mtimeMs;
7503
+ const at = statSync10(dir2).mtimeMs;
7335
7504
  if (now - at <= maxAgeMs) out.push({ dir: dir2, at });
7336
7505
  } catch {
7337
7506
  }
@@ -7530,6 +7699,25 @@ var DumateWatch = class {
7530
7699
  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
7700
  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
7701
  }
7702
+ /**
7703
+ * 任务总结的读回(spec 2026-10-11 summary-all-tools):GET /session/:id/message + /session/status,按标记认本轮(messagesVerdict)。
7704
+ * 连不上 / 读不出 → 等(总超时由调用方判);不唤起 App
7705
+ */
7706
+ async summaryCheck(sessionId, instructionId) {
7707
+ const wait = { kind: "wait" };
7708
+ const t = this.#target ?? this.#discover(false);
7709
+ if (!t) return wait;
7710
+ const http = this.#http(t);
7711
+ const dir2 = this.#sessionDir.get(sessionId) ?? "";
7712
+ const sid = encodeURIComponent(sessionId);
7713
+ const msgs = await http(t, { method: "GET", path: `/session/${sid}/message?limit=${SUMMARY_HISTORY_LIMIT}`, ...dir2 ? { directory: dir2 } : {} });
7714
+ if (msgs.status === 404) return { kind: "fail", reason: "session_gone" };
7715
+ if (msgs.status !== 200) return wait;
7716
+ const st = await http(t, { method: "GET", path: "/session/status", ...dir2 ? { directory: dir2 } : {} });
7717
+ if (st.status !== 200 || !st.body || typeof st.body !== "object") return wait;
7718
+ const type = st.body[sessionId]?.type;
7719
+ return messagesVerdict(msgs.body, instructionId, type !== "busy" && type !== "preparing" && type !== "retry");
7720
+ }
7533
7721
  /**
7534
7722
  * 设备回复:往百度搭子里这个会话发一轮(spec 2026-10-08 dumate-qwenwork-reply §3.1)。界面订着同一个 serve 的事件流,实时显示(10-08 实测)。
7535
7723
  * 请求体与界面自己发消息一致:带这个会话最后一条用户消息的 agent / model(没有就 build + /config 的 model)。
@@ -8065,7 +8253,7 @@ function runHook(node, input, agentPid, tool = "dumate") {
8065
8253
  }
8066
8254
 
8067
8255
  // 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";
8256
+ import { existsSync as existsSync20, mkdirSync as mkdirSync22, readdirSync as readdirSync12, readFileSync as readFileSync25, renameSync as renameSync16, writeFileSync as writeFileSync22 } from "fs";
8069
8257
  import { homedir as homedir7 } from "os";
8070
8258
  import { join as join24, win32 as win327 } from "path";
8071
8259
  var WAKE_LAUNCH_GAP_MS2 = 60 * 1e3;
@@ -8130,7 +8318,7 @@ function toolBusy(tool, now = Date.now(), dir2 = stateDir(), alive = isAlive) {
8130
8318
  for (const f of readdirSync12(dir2)) {
8131
8319
  if (!f.endsWith(".json")) continue;
8132
8320
  try {
8133
- const s = JSON.parse(readFileSync24(join24(dir2, f), "utf8"));
8321
+ const s = JSON.parse(readFileSync25(join24(dir2, f), "utf8"));
8134
8322
  if (s.tool !== tool || s.state !== "watch" && s.state !== "ask_approval") continue;
8135
8323
  if (typeof s.pid === "number" && s.pid > 0) {
8136
8324
  if (alive(s.pid, s.pidName)) return true;
@@ -8233,7 +8421,7 @@ var QoderCdpKeeper = class {
8233
8421
  /** 节流状态(按品牌一份,落盘;读不出当没有) */
8234
8422
  #loadThrottle() {
8235
8423
  try {
8236
- const all = JSON.parse(readFileSync24(this.#file(), "utf8"));
8424
+ const all = JSON.parse(readFileSync25(this.#file(), "utf8"));
8237
8425
  const t = all?.[this.#d.brand.tool] ?? {};
8238
8426
  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
8427
  if (this.#d.brand.win && isWinAppExe(t.appExe, this.#d.brand.win.exe)) out.appExe = t.appExe;
@@ -8247,7 +8435,7 @@ var QoderCdpKeeper = class {
8247
8435
  try {
8248
8436
  let all = {};
8249
8437
  try {
8250
- all = JSON.parse(readFileSync24(f, "utf8"));
8438
+ all = JSON.parse(readFileSync25(f, "utf8"));
8251
8439
  } catch {
8252
8440
  all = {};
8253
8441
  }
@@ -8623,12 +8811,12 @@ function dumateActivity(now = Date.now(), dataHome = dumateDataHome(), sessionsR
8623
8811
  for (const u of users) {
8624
8812
  const dir2 = join25(xdg, u, "data", "opencode");
8625
8813
  try {
8626
- latest = Math.max(latest, statSync12(join25(dir2, "opencode.db")).mtimeMs);
8814
+ latest = Math.max(latest, statSync11(join25(dir2, "opencode.db")).mtimeMs);
8627
8815
  found = true;
8628
8816
  } catch {
8629
8817
  }
8630
8818
  try {
8631
- const w = statSync12(join25(dir2, "opencode.db-wal"));
8819
+ const w = statSync11(join25(dir2, "opencode.db-wal"));
8632
8820
  if (w.size > 0) latest = Math.max(latest, w.mtimeMs);
8633
8821
  } catch {
8634
8822
  }
@@ -8836,7 +9024,7 @@ function restoreQoderShortcutsSync(tool, d, ps = defaultPsSync) {
8836
9024
  }
8837
9025
 
8838
9026
  // 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";
9027
+ 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
9028
  import { dirname as dirname13, join as join27 } from "path";
8841
9029
  var TRAE_EVENTS = ["UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop", "Notification"];
8842
9030
  var TRAE_NOTICE_TYPES = ["permission_prompt", "ask_user_question", "document_review", "browser_interaction"];
@@ -8844,7 +9032,7 @@ var TRAE_NOTICE_MATCHER = `^(${TRAE_NOTICE_TYPES.join("|")})$`;
8844
9032
  var TRAE_NOTICE_TIMEOUT_S = 7 * 24 * 60 * 60;
8845
9033
  function readHooksFile(path) {
8846
9034
  if (!existsSync21(path)) return {};
8847
- const raw = readFileSync25(path, "utf8");
9035
+ const raw = readFileSync26(path, "utf8");
8848
9036
  if (raw.trim() === "") return {};
8849
9037
  let parsed;
8850
9038
  try {
@@ -8870,7 +9058,7 @@ function writeHooksFile(linkPath, f) {
8870
9058
  const path = writeTarget(linkPath);
8871
9059
  let mode;
8872
9060
  try {
8873
- mode = statSync13(path).mode & 511;
9061
+ mode = statSync12(path).mode & 511;
8874
9062
  } catch {
8875
9063
  mode = void 0;
8876
9064
  }
@@ -8958,10 +9146,10 @@ function isTraeHookInstalled(path, hookPath) {
8958
9146
  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
9147
 
8960
9148
  // src/commands/tools.ts
8961
- import { existsSync as existsSync23, readFileSync as readFileSync27 } from "fs";
9149
+ import { existsSync as existsSync23, readFileSync as readFileSync28 } from "fs";
8962
9150
 
8963
9151
  // 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";
9152
+ 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
9153
  import { dirname as dirname14, join as join28 } from "path";
8966
9154
  var CB_MCP_NAME = "deskbuddy";
8967
9155
  var CB_CHANNEL_SCRIPT = "cbchannel.cjs";
@@ -8970,7 +9158,7 @@ function cbChannelScript(hookPath) {
8970
9158
  }
8971
9159
  function read(path) {
8972
9160
  if (!existsSync22(path)) return {};
8973
- const raw = readFileSync26(path, "utf8");
9161
+ const raw = readFileSync27(path, "utf8");
8974
9162
  if (raw.trim() === "") return {};
8975
9163
  let v;
8976
9164
  try {
@@ -8991,7 +9179,7 @@ function write2(file3, v) {
8991
9179
  mkdirSync24(dirname14(path), { recursive: true });
8992
9180
  let mode;
8993
9181
  try {
8994
- mode = statSync14(path).mode & 511;
9182
+ mode = statSync13(path).mode & 511;
8995
9183
  } catch {
8996
9184
  mode = void 0;
8997
9185
  }
@@ -9039,7 +9227,7 @@ function codebuddyWanted(d = { standalone: () => standaloneProbe() }) {
9039
9227
  function fileContains(path, needle) {
9040
9228
  try {
9041
9229
  if (!existsSync23(path)) return false;
9042
- return readFileSync27(path, "utf8").includes(needle);
9230
+ return readFileSync28(path, "utf8").includes(needle);
9043
9231
  } catch {
9044
9232
  return false;
9045
9233
  }
@@ -9086,6 +9274,7 @@ var ADAPTERS = {
9086
9274
  if (tool === "workbuddy") return installCodebuddyTerminalApprovals(gate);
9087
9275
  if (!WINDOW_GATE_TOOLS.has(tool)) return false;
9088
9276
  installCcWindowGate(p, gate, tool);
9277
+ if (tool === "qoder_cn" || tool === "qoder") installCcPreToolQuestion(p, gate, tool);
9089
9278
  return true;
9090
9279
  },
9091
9280
  // asyncRewake 只有 Claude Code 认(2.1.280 实测);别家当成同步 hook 会一直等
@@ -9140,7 +9329,7 @@ ADAPTERS["dumate-http"] = {
9140
9329
  uninstall: () => restoreDumateShortcutsSync({ log: dmLnkLog }),
9141
9330
  isInstalled: (p) => {
9142
9331
  try {
9143
- const enabled = JSON.parse(readFileSync27(p, "utf8")).enabledTools;
9332
+ const enabled = JSON.parse(readFileSync28(p, "utf8")).enabledTools;
9144
9333
  return Array.isArray(enabled) && enabled.includes("dumate");
9145
9334
  } catch {
9146
9335
  return false;
@@ -9173,7 +9362,7 @@ ADAPTERS["coze-cdp"] = {
9173
9362
  },
9174
9363
  isInstalled: (p) => {
9175
9364
  try {
9176
- const enabled = JSON.parse(readFileSync27(p, "utf8")).enabledTools;
9365
+ const enabled = JSON.parse(readFileSync28(p, "utf8")).enabledTools;
9177
9366
  return Array.isArray(enabled) && enabled.includes("coze");
9178
9367
  } catch {
9179
9368
  return false;
@@ -9204,7 +9393,7 @@ function subscribedEvents(registry, tool, fallback) {
9204
9393
  }
9205
9394
 
9206
9395
  // src/wrap/pty.ts
9207
- import { chmodSync as chmodSync7, existsSync as existsSync24, statSync as statSync15 } from "fs";
9396
+ import { chmodSync as chmodSync7, existsSync as existsSync24, statSync as statSync14 } from "fs";
9208
9397
  import { createRequire as createRequire4 } from "module";
9209
9398
  import { dirname as dirname15, join as join29 } from "path";
9210
9399
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -9228,7 +9417,7 @@ function fixSpawnHelper(ptyDir) {
9228
9417
  if (process.platform !== "darwin") return;
9229
9418
  try {
9230
9419
  const helper = join29(ptyDir, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
9231
- if (existsSync24(helper) && (statSync15(helper).mode & 73) === 0) chmodSync7(helper, 493);
9420
+ if (existsSync24(helper) && (statSync14(helper).mode & 73) === 0) chmodSync7(helper, 493);
9232
9421
  } catch {
9233
9422
  }
9234
9423
  }
@@ -9465,7 +9654,7 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
9465
9654
 
9466
9655
  // src/daemon/loginGuide.ts
9467
9656
  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";
9657
+ import { chmodSync as chmodSync9, existsSync as existsSync26, mkdirSync as mkdirSync26, readFileSync as readFileSync29, writeFileSync as writeFileSync26 } from "fs";
9469
9658
  import { homedir as homedir9 } from "os";
9470
9659
  import { join as join34 } from "path";
9471
9660
 
@@ -10148,7 +10337,7 @@ var defaultCheckDeps = () => ({
10148
10337
  home: homedir9(),
10149
10338
  codexConfig: () => {
10150
10339
  try {
10151
- return readFileSync28(join34(codexHome(), "config.toml"), "utf8");
10340
+ return readFileSync29(join34(codexHome(), "config.toml"), "utf8");
10152
10341
  } catch {
10153
10342
  return null;
10154
10343
  }
@@ -10306,7 +10495,7 @@ var defaultLoginOpenDeps = () => ({
10306
10495
  });
10307
10496
  async function installCodebuddyHooks(log) {
10308
10497
  try {
10309
- const { installTools: installTools2 } = await import("./enable-EDDFXBHM.js");
10498
+ const { installTools: installTools2 } = await import("./enable-SIY4AEF7.js");
10310
10499
  installTools2(["workbuddy"], () => {
10311
10500
  }, null, { auto: true });
10312
10501
  } catch (e) {
@@ -10820,7 +11009,7 @@ function defaultOfferDeps(log) {
10820
11009
  }),
10821
11010
  openLogin: () => defaultOpenLogin(platform),
10822
11011
  installHooks: async () => {
10823
- const { installTools: installTools2 } = await import("./enable-EDDFXBHM.js");
11012
+ const { installTools: installTools2 } = await import("./enable-SIY4AEF7.js");
10824
11013
  installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
10825
11014
  },
10826
11015
  log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
@@ -11071,6 +11260,7 @@ export {
11071
11260
  codebuddyConfigDir,
11072
11261
  qoderCnSettingsPath,
11073
11262
  qwenworkHome,
11263
+ qwenworkDataHome,
11074
11264
  qoderSettingsPath,
11075
11265
  opencodePluginPath,
11076
11266
  installedHookPath,
@@ -11084,7 +11274,6 @@ export {
11084
11274
  packageVersion,
11085
11275
  installedHookVersion,
11086
11276
  syncHookFile,
11087
- COMMAND_OUTPUT_MAX,
11088
11277
  APP_ID,
11089
11278
  APP_SECRET,
11090
11279
  sign,
@@ -11259,6 +11448,16 @@ export {
11259
11448
  APP_IN_USE_REASON,
11260
11449
  QODER_APP_POLL_MS,
11261
11450
  QoderAppTasks,
11451
+ SUMMARY_CAPS,
11452
+ SUMMARY_TOOLS2 as SUMMARY_TOOLS,
11453
+ SUMMARY_NO_OUTPUT,
11454
+ isSummary,
11455
+ withSummaryMark,
11456
+ clipOutput,
11457
+ SUMMARY_WAIT_MS,
11458
+ ptyVerdict,
11459
+ replyVerdict,
11460
+ PtySummaryWatch,
11262
11461
  APP_NOT_RUNNING,
11263
11462
  DumateWatch,
11264
11463
  runHook,