deskbuddy 0.2.0-beta.41 → 0.2.0-beta.43

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.
@@ -7,14 +7,49 @@ import { dirname as dirname19, join as join37 } from "path";
7
7
  import { randomUUID } from "crypto";
8
8
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
9
9
  import { homedir, hostname } from "os";
10
- import { dirname, join } from "path";
11
- function defaultRemoteCwd(home = homedir(), platform = process.platform, exists = existsSync) {
12
- const desktop = join(home, "Desktop");
13
- if (platform === "win32" && !exists(desktop)) {
14
- const od = join(home, "OneDrive", "Desktop");
15
- if (exists(od)) return od;
10
+ import { dirname, join, resolve } from "path";
11
+ function defaultRemoteCwd(home = homedir()) {
12
+ return process.env.DESKBUDDY_DEFAULT_REMOTE_CWD || join(home, "DeskBuddy");
13
+ }
14
+ function legacyRemoteCwds(home = homedir()) {
15
+ return [join(home, "Desktop"), join(home, "OneDrive", "Desktop")];
16
+ }
17
+ function samePath(a, b, platform) {
18
+ const n = (p) => {
19
+ const r = resolve(p).replace(/[\\/]+$/, "");
20
+ return platform === "win32" ? r.toLowerCase() : r;
21
+ };
22
+ return n(a) === n(b);
23
+ }
24
+ function ensureDefaultRemoteCwd(cwd) {
25
+ if (!cwd || !samePath(cwd, defaultRemoteCwd(), process.platform)) return;
26
+ try {
27
+ mkdirSync(cwd, { recursive: true });
28
+ } catch {
16
29
  }
17
- return desktop;
30
+ }
31
+ function remoteCwdReady() {
32
+ const cwd = loadConfig().remoteCwd || "";
33
+ ensureDefaultRemoteCwd(cwd);
34
+ return cwd;
35
+ }
36
+ function migrateRemoteCwd(home = homedir(), platform = process.platform) {
37
+ const cfg = loadConfig();
38
+ if (cfg.remoteCwdMigrated || !cfg.boundAt) return null;
39
+ const from = cfg.remoteCwd || "";
40
+ const hit = !!from && legacyRemoteCwds(home).some((p) => samePath(from, p, platform));
41
+ const to = defaultRemoteCwd(home);
42
+ if (hit) {
43
+ try {
44
+ mkdirSync(to, { recursive: true });
45
+ } catch {
46
+ return null;
47
+ }
48
+ cfg.remoteCwd = to;
49
+ }
50
+ cfg.remoteCwdMigrated = true;
51
+ saveConfig(cfg);
52
+ return hit ? { from, to } : null;
18
53
  }
19
54
  var PROD_API_BASE = "https://api.shifengintelli.com";
20
55
  var TEST_API_BASE = "https://test-api.shifengintelli.com";
@@ -144,6 +179,7 @@ function loadConfig() {
144
179
  // 于是下一次保存还会把它抹掉),而且全程不报错
145
180
  boundApiBase: parsed.boundApiBase,
146
181
  remoteCwd: parsed.remoteCwd,
182
+ remoteCwdMigrated: parsed.remoteCwdMigrated === true ? true : void 0,
147
183
  // 不认识的值一律回落默认,不能让一个手滑写错的配置变成"全放行"或"全拦"
148
184
  approvalPolicy: parsed.approvalPolicy === "all" ? "all" : parsed.approvalPolicy === "commands" ? "commands" : void 0,
149
185
  codexAppServer: typeof parsed.codexAppServer === "string" ? parsed.codexAppServer : void 0,
@@ -314,13 +350,13 @@ import { execFile, spawn } from "child_process";
314
350
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
315
351
  import { homedir as homedir2 } from "os";
316
352
  import { fileURLToPath as fileURLToPath2 } from "url";
317
- import { basename as basename2, dirname as dirname4, join as join4, resolve as resolve2 } from "path";
353
+ import { basename as basename2, dirname as dirname4, join as join4, resolve as resolve3 } from "path";
318
354
  import { promisify } from "util";
319
355
 
320
356
  // src/core/versions.ts
321
357
  import { execFileSync } from "child_process";
322
358
  import { cpSync, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync3, renameSync as renameSync3, rmSync, writeFileSync as writeFileSync3 } from "fs";
323
- import { basename, dirname as dirname3, join as join3, relative, resolve, sep } from "path";
359
+ import { basename, dirname as dirname3, join as join3, relative, resolve as resolve2, sep } from "path";
324
360
  function versionsDir(home = deskbuddyHome()) {
325
361
  return join3(home, "versions");
326
362
  }
@@ -400,7 +436,7 @@ function markGood(version, home) {
400
436
  return true;
401
437
  }
402
438
  function versionDirOf(cliPath, home) {
403
- const rel = relative(versionsDir(home), resolve(cliPath));
439
+ const rel = relative(versionsDir(home), resolve2(cliPath));
404
440
  if (!rel || rel.startsWith("..") || rel.startsWith(sep) || /^[a-zA-Z]:/.test(rel)) return null;
405
441
  const first = rel.split(/[\\/]/)[0];
406
442
  return isValidVersion(first) ? first : null;
@@ -516,7 +552,7 @@ function registerRunningCli(running, deps = {}) {
516
552
  if (!isValidVersion(running.version) || running.version.startsWith("0.0.0")) {
517
553
  throw new Error(`\u5F00\u53D1\u7248\uFF08${running.version}\uFF09\u4E0D\u767B\u8BB0`);
518
554
  }
519
- let cliPath = resolve(running.cliPath);
555
+ let cliPath = resolve2(running.cliPath);
520
556
  if (!existsSync3(cliPath)) throw new Error(`\u5165\u53E3\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${cliPath}`);
521
557
  let how = "already";
522
558
  let note;
@@ -910,7 +946,7 @@ function autostartPointsTo(configText, home) {
910
946
  });
911
947
  }
912
948
  function isCustomHome(home = deskbuddyHome(), defaultHome = join4(homedir2(), ".deskbuddy")) {
913
- return resolve2(home) !== resolve2(defaultHome);
949
+ return resolve3(home) !== resolve3(defaultHome);
914
950
  }
915
951
  async function uninstallAutostart(platform = process.platform, deps = {}) {
916
952
  const d = { ...defaultUninstallDeps(), ...deps };
@@ -2640,10 +2676,12 @@ function codexPermissionsCard(p) {
2640
2676
  const summary = `\u7533\u8BF7${parts.join("\u3001")}${reason ? `\uFF1A${reason}` : ""}`;
2641
2677
  const options = [
2642
2678
  { id: "allow", label: "Allow once", description: "\u8FD9\u4E00\u8F6E\u653E\u5F00\u7533\u8BF7\u7684\u6743\u9650", kind: "allow" },
2679
+ { id: "session", label: "Allow this conversation", description: "\u8FD9\u4E2A\u5BF9\u8BDD\u91CC\u4E4B\u540E\u540C\u6837\u7684\u7533\u8BF7\u90FD\u653E\u5F00", kind: "allow_session" },
2643
2680
  { id: "deny", label: "Deny", kind: "deny" }
2644
2681
  ];
2645
2682
  const actions = {
2646
2683
  allow: { decision: "allow", native: { permissions: grant, scope: "turn" } },
2684
+ session: { decision: "allow", native: { permissions: grant, scope: "session" } },
2647
2685
  deny: { decision: "deny", native: { permissions: {}, scope: "turn" } }
2648
2686
  };
2649
2687
  const set = checkOptions({ options, actions });
@@ -3182,7 +3220,7 @@ function traeNoticeSummary(toolName, toolInput, described, notice) {
3182
3220
  // src/daemon/workbuddyApp/keeper.ts
3183
3221
  import { execFile as execFile6, spawn as spawn2 } from "child_process";
3184
3222
  import { existsSync as existsSync19, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync15, writeFileSync as writeFileSync21 } from "fs";
3185
- import { delimiter as delimiter3, join as join22, resolve as resolve4 } from "path";
3223
+ import { delimiter as delimiter3, join as join22, resolve as resolve5 } from "path";
3186
3224
 
3187
3225
  // src/core/process.ts
3188
3226
  import { execFileSync as execFileSync5 } from "child_process";
@@ -3710,7 +3748,7 @@ function resolveAlias(sessionId, now = Date.now()) {
3710
3748
  import { execFile as execFile3, execFileSync as execFileSync7 } from "child_process";
3711
3749
  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";
3712
3750
  import { homedir as homedir3 } from "os";
3713
- import { delimiter, join as join15, resolve as resolve3 } from "path";
3751
+ import { delimiter, join as join15, resolve as resolve4 } from "path";
3714
3752
  var SHIM_FALLBACK_EXIT = 213;
3715
3753
  var WIN_SHIM_ENABLED = true;
3716
3754
  var SHIM_COMMANDS = { claude_code: "claude", codex: "codex" };
@@ -3823,7 +3861,7 @@ function cmdScript(tool, command, node, cli, bin) {
3823
3861
  ].join("\r\n");
3824
3862
  }
3825
3863
  function rcBlock(binDir, rcHome) {
3826
- const std = resolve3(rcHome, ".deskbuddy", "bin") === resolve3(binDir);
3864
+ const std = resolve4(rcHome, ".deskbuddy", "bin") === resolve4(binDir);
3827
3865
  const dir2 = std ? "$HOME/.deskbuddy/bin" : binDir.replace(/(["\\$`])/g, "\\$1");
3828
3866
  return [
3829
3867
  RC_BEGIN,
@@ -4948,16 +4986,16 @@ var defaultProbe = createVersionProbe({
4948
4986
  return classifySyncError(e);
4949
4987
  }
4950
4988
  },
4951
- runAsync: (loc) => new Promise((resolve6) => {
4989
+ runAsync: (loc) => new Promise((resolve7) => {
4952
4990
  try {
4953
4991
  execFile4(
4954
4992
  loc.file,
4955
4993
  [...loc.prefixArgs, "--version"],
4956
4994
  { encoding: "utf8", windowsHide: true, timeout: PROBE_TIMEOUT_MS, env: probeEnv(loc) },
4957
- (err, stdout2, stderr) => resolve6(err ? classifyAsyncError(err, String(stdout2 ?? ""), String(stderr ?? "")) : { kind: "done", out: `${stdout2}${stderr}` })
4995
+ (err, stdout2, stderr) => resolve7(err ? classifyAsyncError(err, String(stdout2 ?? ""), String(stderr ?? "")) : { kind: "done", out: `${stdout2}${stderr}` })
4958
4996
  );
4959
4997
  } catch {
4960
- resolve6({ kind: "spawn_error" });
4998
+ resolve7({ kind: "spawn_error" });
4961
4999
  }
4962
5000
  }),
4963
5001
  now: () => Date.now()
@@ -5535,12 +5573,12 @@ function defaultWbElectron(d = defaultLocateDeps()) {
5535
5573
  }
5536
5574
  }
5537
5575
  function defaultAppRunning(platform = process.platform) {
5538
- return new Promise((resolve6) => {
5576
+ return new Promise((resolve7) => {
5539
5577
  try {
5540
5578
  if (platform === "darwin") {
5541
5579
  execFile5("pgrep", ["-f", "WorkBuddy.app/Contents/MacOS/"], { timeout: 5e3 }, (err) => {
5542
5580
  const code = err?.code;
5543
- resolve6(!err ? true : code === 1 ? false : true);
5581
+ resolve7(!err ? true : code === 1 ? false : true);
5544
5582
  });
5545
5583
  return;
5546
5584
  }
@@ -5549,13 +5587,13 @@ function defaultAppRunning(platform = process.platform) {
5549
5587
  "tasklist",
5550
5588
  ["/FI", "IMAGENAME eq WorkBuddy.exe", "/FO", "CSV", "/NH"],
5551
5589
  { timeout: 1e4, windowsHide: true, encoding: "utf8" },
5552
- (err, stdout2) => resolve6(err ? true : /"WorkBuddy\.exe"/i.test(String(stdout2)))
5590
+ (err, stdout2) => resolve7(err ? true : /"WorkBuddy\.exe"/i.test(String(stdout2)))
5553
5591
  );
5554
5592
  return;
5555
5593
  }
5556
- resolve6(true);
5594
+ resolve7(true);
5557
5595
  } catch {
5558
- resolve6(true);
5596
+ resolve7(true);
5559
5597
  }
5560
5598
  });
5561
5599
  }
@@ -5590,13 +5628,13 @@ var defaultWbAppDbDeps = () => ({
5590
5628
  configDir: () => dirname12(workbuddySettingsPath()),
5591
5629
  loadSqlite: loadNodeSqlite,
5592
5630
  electron: () => defaultWbElectron(),
5593
- runElectron: (bin, script, input) => new Promise((resolve6, reject) => {
5631
+ runElectron: (bin, script, input) => new Promise((resolve7, reject) => {
5594
5632
  const env = { ...process.env, ELECTRON_RUN_AS_NODE: "1" };
5595
5633
  const c = execFile5(
5596
5634
  bin,
5597
5635
  ["-e", script],
5598
5636
  { env, timeout: 15e3, windowsHide: true, maxBuffer: 1024 * 1024 },
5599
- (err, stdout2) => err ? reject(err) : resolve6(String(stdout2))
5637
+ (err, stdout2) => err ? reject(err) : resolve7(String(stdout2))
5600
5638
  );
5601
5639
  c.stdin?.on("error", () => {
5602
5640
  });
@@ -5741,12 +5779,12 @@ function openWs(target, port, d, info) {
5741
5779
  const url = loopbackWsUrl(target.webSocketDebuggerUrl, port);
5742
5780
  if (!url) return Promise.reject(new Error("\u4E3B\u7A97\u53E3\u7684\u8C03\u8BD5\u5730\u5740\u4E0D\u5BF9"));
5743
5781
  const ws = (d.ws ?? ((u) => new WebSocket(u, { handshakeTimeout: 5e3 })))(url);
5744
- return new Promise((resolve6, reject) => {
5782
+ return new Promise((resolve7, reject) => {
5745
5783
  let opened = false;
5746
5784
  const client = new WsCdpClient(ws, info);
5747
5785
  ws.on("open", () => {
5748
5786
  opened = true;
5749
- resolve6(client);
5787
+ resolve7(client);
5750
5788
  });
5751
5789
  ws.on("error", (e) => {
5752
5790
  if (!opened) reject(e instanceof Error ? e : new Error("CDP \u8FDE\u63A5\u5931\u8D25"));
@@ -5844,12 +5882,12 @@ var WsCdpClient = class {
5844
5882
  #rpc(method, params, timeoutMs, raw) {
5845
5883
  if (this.#closed) return Promise.reject(new Error("CDP \u8FDE\u63A5\u5DF2\u65AD\u5F00"));
5846
5884
  const id = ++this.#id;
5847
- return new Promise((resolve6, reject) => {
5885
+ return new Promise((resolve7, reject) => {
5848
5886
  const timer = setTimeout(() => {
5849
5887
  this.#waiting.delete(id);
5850
5888
  reject(new Error("\u9875\u9762\u811A\u672C\u8D85\u65F6"));
5851
5889
  }, timeoutMs);
5852
- this.#waiting.set(id, { resolve: resolve6, reject, timer, ...raw ? { raw } : {} });
5890
+ this.#waiting.set(id, { resolve: resolve7, reject, timer, ...raw ? { raw } : {} });
5853
5891
  try {
5854
5892
  this.#ws.send(JSON.stringify({ id, method, params }));
5855
5893
  } catch (e) {
@@ -5909,7 +5947,7 @@ function cleanLaunchEnv(src = process.env, shim = shimDir()) {
5909
5947
  const out = {};
5910
5948
  const shimReal = (() => {
5911
5949
  try {
5912
- return resolve4(shim);
5950
+ return resolve5(shim);
5913
5951
  } catch {
5914
5952
  return shim;
5915
5953
  }
@@ -5922,7 +5960,7 @@ function cleanLaunchEnv(src = process.env, shim = shimDir()) {
5922
5960
  if (pathKey && typeof out[pathKey] === "string") {
5923
5961
  out[pathKey] = out[pathKey].split(delimiter3).filter((p) => {
5924
5962
  try {
5925
- return resolve4(p) !== shimReal;
5963
+ return resolve5(p) !== shimReal;
5926
5964
  } catch {
5927
5965
  return p !== shim;
5928
5966
  }
@@ -6722,7 +6760,7 @@ async function defaultWinProcs() {
6722
6760
  // src/daemon/qoderApp/task.ts
6723
6761
  import { createHash as createHash3 } from "crypto";
6724
6762
  import { realpathSync as realpathSync3 } from "fs";
6725
- import { resolve as resolve5 } from "path";
6763
+ import { resolve as resolve6 } from "path";
6726
6764
 
6727
6765
  // src/daemon/command.ts
6728
6766
  var SERVICE_COMMAND = "deskbuddy.command";
@@ -6994,7 +7032,7 @@ function normalizeCwd(p, platform = process.platform, real = (x) => realpathSync
6994
7032
  r = r.replace(/\//g, "\\").replace(/\\+$/, "");
6995
7033
  return (/^[a-z]:$/i.test(r) ? r + "\\" : r).toLowerCase().replace(/\\/g, "/");
6996
7034
  }
6997
- r = resolve5(r);
7035
+ r = resolve6(r);
6998
7036
  return r.length > 1 ? r.replace(/\/+$/, "") : r;
6999
7037
  }
7000
7038
  function appBusy(st) {
@@ -8468,7 +8506,7 @@ var DumateWatch = class {
8468
8506
  }
8469
8507
  };
8470
8508
  function runHook(node, input, agentPid, tool = "dumate") {
8471
- return new Promise((resolve6) => {
8509
+ return new Promise((resolve7) => {
8472
8510
  let child;
8473
8511
  try {
8474
8512
  child = spawn3(node, [installedHookPath(), tool], {
@@ -8476,18 +8514,18 @@ function runHook(node, input, agentPid, tool = "dumate") {
8476
8514
  env: { ...process.env, DESKBUDDY_AGENT_PID: String(agentPid) }
8477
8515
  });
8478
8516
  } catch {
8479
- resolve6();
8517
+ resolve7();
8480
8518
  return;
8481
8519
  }
8482
8520
  const timer = setTimeout(() => child.kill("SIGKILL"), HOOK_KILL_MS);
8483
8521
  timer.unref?.();
8484
8522
  child.on("error", () => {
8485
8523
  clearTimeout(timer);
8486
- resolve6();
8524
+ resolve7();
8487
8525
  });
8488
8526
  child.on("close", () => {
8489
8527
  clearTimeout(timer);
8490
- resolve6();
8528
+ resolve7();
8491
8529
  });
8492
8530
  child.stdin.on("error", () => {
8493
8531
  });
@@ -10538,7 +10576,7 @@ function startCommand(plan, tool, limitMs = EXEC_TIMEOUT_MS) {
10538
10576
  }, Math.max(0, remaining));
10539
10577
  };
10540
10578
  let timedOut = false;
10541
- const done = new Promise((resolve6) => {
10579
+ const done = new Promise((resolve7) => {
10542
10580
  child = execFile7(
10543
10581
  plan.file,
10544
10582
  plan.args,
@@ -10558,10 +10596,10 @@ function startCommand(plan, tool, limitMs = EXEC_TIMEOUT_MS) {
10558
10596
  if (err || timedOut) {
10559
10597
  const e = err;
10560
10598
  const msg = timedOut ? `\u6267\u884C\u8D85\u8FC7 ${Math.round(limitMs / 1e3)} \u79D2\u6D3B\u52A8\u65F6\u95F4\uFF0C\u5DF2\u7EC8\u6B62` : e && typeof e.code === "number" ? `\u9000\u51FA\u7801 ${e.code}` : e && e.signal ? `\u88AB\u4FE1\u53F7 ${String(e.signal)} \u7ED3\u675F` : `\u8D77\u4E0D\u6765\uFF08${String(e?.code ?? "unknown")}\uFF09`;
10561
- resolve6({ ok: false, sessionId: parseSessionId(tool, out), stdout: out, stderr: errOut, error: msg });
10599
+ resolve7({ ok: false, sessionId: parseSessionId(tool, out), stdout: out, stderr: errOut, error: msg });
10562
10600
  return;
10563
10601
  }
10564
- resolve6({ ok: true, sessionId: parseSessionId(tool, out), stdout: out, stderr: errOut });
10602
+ resolve7({ ok: true, sessionId: parseSessionId(tool, out), stdout: out, stderr: errOut });
10565
10603
  }
10566
10604
  );
10567
10605
  child?.stdin?.end();
@@ -10700,8 +10738,8 @@ var defaultGuiDeps = () => ({
10700
10738
  var defaultOpenerDeps = (findWt2) => ({
10701
10739
  platform: process.platform,
10702
10740
  findWt: findWt2,
10703
- run: (file3, args) => new Promise((resolve6, reject) => {
10704
- execFile8(file3, args, { windowsHide: true, timeout: 15e3 }, (err) => err ? reject(err) : resolve6());
10741
+ run: (file3, args) => new Promise((resolve7, reject) => {
10742
+ execFile8(file3, args, { windowsHide: true, timeout: 15e3 }, (err) => err ? reject(err) : resolve7());
10705
10743
  }),
10706
10744
  spawnDetached: (file3, args) => {
10707
10745
  const c = spawn4(file3, args, { detached: true, stdio: "ignore", shell: false, windowsHide: false });
@@ -10872,12 +10910,12 @@ async function checkLogin(tool, d) {
10872
10910
  return { tool, state: "unknown", note: `\u68C0\u6D4B\u51FA\u9519\uFF1A${e?.message ?? e}` };
10873
10911
  }
10874
10912
  }
10875
- var defaultProbeRun = (file3, args, env, timeoutMs) => new Promise((resolve6) => {
10913
+ var defaultProbeRun = (file3, args, env, timeoutMs) => new Promise((resolve7) => {
10876
10914
  let settled = false;
10877
10915
  const done = (r) => {
10878
10916
  if (settled) return;
10879
10917
  settled = true;
10880
- resolve6(r);
10918
+ resolve7(r);
10881
10919
  };
10882
10920
  const win = process.platform === "win32";
10883
10921
  const opts = { env, windowsHide: true, maxBuffer: 8 * 1024 * 1024, detached: !win };
@@ -11074,7 +11112,7 @@ var defaultLoginOpenDeps = () => ({
11074
11112
  });
11075
11113
  async function installCodebuddyHooks(log) {
11076
11114
  try {
11077
- const { installTools: installTools2 } = await import("./enable-3G3TWPSH.js");
11115
+ const { installTools: installTools2 } = await import("./enable-AF2A67ZD.js");
11078
11116
  installTools2(["workbuddy"], () => {
11079
11117
  }, null, { auto: true });
11080
11118
  } catch (e) {
@@ -11277,7 +11315,7 @@ var DIALOG_TEXT = [
11277
11315
  `\u73B0\u5728\u5B89\u88C5\u5417\uFF1F\uFF08\u4F1A\u6267\u884C npm i -g ${WORKBUDDY_STANDALONE_PKG}\uFF0C\u7EA6\u9700\u4E00\u4E24\u5206\u949F\uFF0C\u88C5\u5B8C\u4F1A\u6253\u5F00\u4E00\u4E2A\u7EC8\u7AEF\u7A97\u53E3\uFF0C\u6309\u63D0\u793A\u9009 Log in via Chinese Site\uFF08\u56FD\u5185\u7248\uFF09\u767B\u5F55\uFF1B\u7EC8\u7AEF\u7A97\u53E3\u5982\u679C\u662F\u9ED1\u7684\uFF0C\u6309\u4E00\u4E0B\u56DE\u8F66\u5C31\u4F1A\u663E\u793A\uFF09`
11278
11316
  ].join("\n");
11279
11317
  var LIMITED_NOTE = "\u8BBE\u5907\u4E0A\u53EA\u80FD\u770B\u4EFB\u52A1\u72B6\u6001\u3001\u56DE\u7B54\u6388\u6743";
11280
- var defaultRunner = (file3, args, opts) => new Promise((resolve6) => {
11318
+ var defaultRunner = (file3, args, opts) => new Promise((resolve7) => {
11281
11319
  try {
11282
11320
  const child = execFile10(
11283
11321
  file3,
@@ -11285,7 +11323,7 @@ var defaultRunner = (file3, args, opts) => new Promise((resolve6) => {
11285
11323
  { env: opts.env, timeout: opts.timeoutMs, windowsHide: true, maxBuffer: 8 * 1024 * 1024, encoding: "utf8" },
11286
11324
  (err, stdout2, stderr) => {
11287
11325
  const e = err;
11288
- resolve6({
11326
+ resolve7({
11289
11327
  code: e ? typeof e.code === "number" ? e.code : null : 0,
11290
11328
  stdout: String(stdout2 ?? ""),
11291
11329
  stderr: String(stderr ?? ""),
@@ -11296,7 +11334,7 @@ var defaultRunner = (file3, args, opts) => new Promise((resolve6) => {
11296
11334
  );
11297
11335
  child.stdin?.end();
11298
11336
  } catch {
11299
- resolve6({ code: null, stdout: "", stderr: "", timedOut: false, spawnError: true });
11337
+ resolve7({ code: null, stdout: "", stderr: "", timedOut: false, spawnError: true });
11300
11338
  }
11301
11339
  });
11302
11340
  function checkTimeout(s) {
@@ -11588,7 +11626,7 @@ function defaultOfferDeps(log) {
11588
11626
  }),
11589
11627
  openLogin: () => defaultOpenLogin(platform),
11590
11628
  installHooks: async () => {
11591
- const { installTools: installTools2 } = await import("./enable-3G3TWPSH.js");
11629
+ const { installTools: installTools2 } = await import("./enable-AF2A67ZD.js");
11592
11630
  installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
11593
11631
  },
11594
11632
  log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
@@ -11829,6 +11867,9 @@ async function runEnable(tools, opts = {}) {
11829
11867
 
11830
11868
  export {
11831
11869
  defaultRemoteCwd,
11870
+ ensureDefaultRemoteCwd,
11871
+ remoteCwdReady,
11872
+ migrateRemoteCwd,
11832
11873
  PROD_API_BASE,
11833
11874
  TEST_API_BASE,
11834
11875
  environmentLabel,
package/dist/cli.js CHANGED
@@ -114,6 +114,7 @@ import {
114
114
  detectTools,
115
115
  dshOptions,
116
116
  ensureClientId,
117
+ ensureDefaultRemoteCwd,
117
118
  ensureDumateShortcuts,
118
119
  ensureQoderShortcuts,
119
120
  ensureQwenworkShortcuts,
@@ -173,6 +174,7 @@ import {
173
174
  markWbAppSession,
174
175
  materialize,
175
176
  migrateLegacyQoder,
177
+ migrateRemoteCwd,
176
178
  ocPluginModule,
177
179
  openTerminal,
178
180
  opencodeOptions,
@@ -210,6 +212,7 @@ import {
210
212
  recordAttemptFailure,
211
213
  refreshRegistry,
212
214
  registerWorkbuddySession,
215
+ remoteCwdReady,
213
216
  removeCommandFile,
214
217
  removeWakeMark,
215
218
  replyVerdict,
@@ -271,7 +274,7 @@ import {
271
274
  writeState,
272
275
  writeWakeMark,
273
276
  writeWakeSecret
274
- } from "./chunk-W2GIOQDI.js";
277
+ } from "./chunk-ET52BEIS.js";
275
278
 
276
279
  // src/commands/config.ts
277
280
  function runConfig(args, out = (s2) => process.stdout.write(s2 + "\n")) {
@@ -16296,6 +16299,12 @@ var Daemon = class {
16296
16299
  log(`\u6388\u6743\u7AEF\u70B9\u5DF2\u5C31\u7EEA 127.0.0.1:${port}`);
16297
16300
  enableFatalReport(deskbuddyHome());
16298
16301
  log(`${envLine()}\uFF1B${memLine()}`);
16302
+ try {
16303
+ const m = migrateRemoteCwd();
16304
+ if (m) log(`\u8FDC\u7A0B\u65B0\u5EFA\u4EFB\u52A1\u7684\u9ED8\u8BA4\u76EE\u5F55\u5DF2\u4ECE ${m.from} \u6539\u4E3A ${m.to}\uFF08\u684C\u9762\u53D7\u7CFB\u7EDF\u4FDD\u62A4\u3001\u4F1A\u88AB\u540C\u6B65\u4E0A\u4E91\uFF1B\u60F3\u6362\u56DE\u6765\u8DD1 deskbuddy setup\uFF09`);
16305
+ } catch (e) {
16306
+ log(`\u8FDC\u7A0B\u65B0\u5EFA\u4EFB\u52A1\u76EE\u5F55\u8FC1\u79FB\u51FA\u9519\uFF1A${e?.message ?? e}`);
16307
+ }
16299
16308
  this.#memLog = setInterval(() => log(memLine()), MEM_LOG_MS);
16300
16309
  this.#memLog.unref();
16301
16310
  this.#windowScan = setInterval(() => this.#coord.scanWindows(), 1e3);
@@ -17033,7 +17042,7 @@ var Daemon = class {
17033
17042
  this.#report(cmd, "", "rejected", "", "dir_gone");
17034
17043
  return;
17035
17044
  }
17036
- } else cwd = loadConfig().remoteCwd || "";
17045
+ } else cwd = remoteCwdReady();
17037
17046
  this.#toDumateNew(cmd, cwd);
17038
17047
  return;
17039
17048
  }
@@ -17064,7 +17073,7 @@ var Daemon = class {
17064
17073
  return;
17065
17074
  }
17066
17075
  } else {
17067
- cwd = loadConfig().remoteCwd || "";
17076
+ cwd = remoteCwdReady();
17068
17077
  if (!cwd) {
17069
17078
  this.#report(cmd, "", "rejected", "", "no_remote_cwd");
17070
17079
  return;
@@ -17082,7 +17091,7 @@ var Daemon = class {
17082
17091
  return;
17083
17092
  }
17084
17093
  } else {
17085
- cwd = loadConfig().remoteCwd || "";
17094
+ cwd = remoteCwdReady();
17086
17095
  if (!cwd) {
17087
17096
  this.#report(cmd, "", "rejected", "", "no_remote_cwd");
17088
17097
  return;
@@ -17288,7 +17297,7 @@ var Daemon = class {
17288
17297
  return;
17289
17298
  }
17290
17299
  } else {
17291
- cwd = loadConfig().remoteCwd || "";
17300
+ cwd = remoteCwdReady();
17292
17301
  if (!cwd) {
17293
17302
  this.#report(cmd, "", "rejected", "", "no_remote_cwd");
17294
17303
  return;
@@ -18054,7 +18063,7 @@ var Daemon = class {
18054
18063
  }
18055
18064
  const target = resolveTarget(cmd, {
18056
18065
  readState,
18057
- remoteCwd: () => loadConfig().remoteCwd || "",
18066
+ remoteCwd: () => remoteCwdReady(),
18058
18067
  alias: resolveAlias,
18059
18068
  dirOf: (ref) => dirOf(ref),
18060
18069
  windowOpen: (s2) => s2.interactive === true && !!s2.pid && isAlive(s2.pid, s2.pidName)
@@ -18794,6 +18803,8 @@ function verdictMessage(reason, path) {
18794
18803
  var MAX_ATTEMPTS = 3;
18795
18804
  async function askRemoteCwd(deps2) {
18796
18805
  const defaultPath = deps2.defaultPath ?? defaultRemoteCwd();
18806
+ if (!deps2.defaultPath) ensureDefaultRemoteCwd(defaultPath);
18807
+ deps2.out(" \u8FDC\u7A0B\u4EFB\u52A1\u9ED8\u8BA4\u653E\u5728 DeskBuddy \u6587\u4EF6\u5939\u91CC\uFF08\u4E0D\u7528\u684C\u9762\uFF1A\u684C\u9762\u53D7\u7CFB\u7EDF\u4FDD\u62A4\u3001\u53EF\u80FD\u88AB\u540C\u6B65\u4E0A\u4E91\uFF09\uFF0C\u56DE\u8F66\u5373\u7528");
18797
18808
  for (let i = 0; i < MAX_ATTEMPTS; i++) {
18798
18809
  const raw = await deps2.ask(`\u8FDC\u7A0B\u300C\u65B0\u5EFA\u4EFB\u52A1\u300D\u7684\u5DE5\u4F5C\u76EE\u5F55 [${defaultPath}]\uFF1A`);
18799
18810
  if (raw === null) {
@@ -18919,6 +18930,7 @@ async function runSetup(opts = {}) {
18919
18930
  const remoteCwd = await askRemoteCwd({ out, ask: terminalAsk });
18920
18931
  const bound = loadConfig();
18921
18932
  bound.remoteCwd = remoteCwd;
18933
+ bound.remoteCwdMigrated = true;
18922
18934
  saveConfig(bound);
18923
18935
  out(` \u5DF2\u8BB0\u4E0B\uFF1A${remoteCwd}`);
18924
18936
  out(" \u63D0\u793A\uFF1AClaude Code \u7B2C\u4E00\u6B21\u5728\u65B0\u76EE\u5F55\u91CC\u542F\u52A8\u4F1A\u95EE\u300C\u662F\u5426\u4FE1\u4EFB\u6B64\u6587\u4EF6\u5939\u300D\uFF0CDeskBuddy \u4E0D\u4F1A\u66FF\u4F60\u56DE\u7B54\u3002");
@@ -19093,8 +19105,10 @@ async function runInstall(opts, deps2 = defaultInstallDeps()) {
19093
19105
  const bound = loadConfig();
19094
19106
  if (!bound.remoteCwd) {
19095
19107
  bound.remoteCwd = defaultRemoteCwd();
19108
+ bound.remoteCwdMigrated = true;
19096
19109
  saveConfig(bound);
19097
19110
  }
19111
+ ensureDefaultRemoteCwd(bound.remoteCwd);
19098
19112
  const auto = await deps2.autostart();
19099
19113
  let logins = [];
19100
19114
  try {
@@ -19206,6 +19220,7 @@ function formatStatus(input) {
19206
19220
  const account = cfg.boundAt ? `\u5DF2\u6388\u6743\uFF08clientId ${cfg.clientId.slice(0, 4)}\u2026\uFF0C\u7ED1\u5B9A\u4E8E ${fmtTime(cfg.boundAt)}\uFF09` : "\u672A\u6388\u6743 \u2014\u2014 \u8FD0\u884C deskbuddy setup \u626B\u7801\u6388\u6743";
19207
19221
  lines3.push(` ${pad("\u8D26\u53F7", 10)}${account}`);
19208
19222
  lines3.push(` ${pad("\u670D\u52A1\u7AEF", 10)}${cfg.apiBase}\uFF08${environmentLabel(cfg.apiBase)}\uFF09`);
19223
+ if (cfg.remoteCwd) lines3.push(` ${pad("\u65B0\u5EFA\u4EFB\u52A1\u76EE\u5F55", 10)}${cfg.remoteCwd}`);
19209
19224
  if (cfg.boundAt && cfg.boundApiBase && cfg.boundApiBase !== cfg.apiBase) {
19210
19225
  lines3.push(
19211
19226
  ` \u26A0\uFE0F \u6388\u6743\u65F6\u8FDE\u7684\u662F ${cfg.boundApiBase}\uFF08${environmentLabel(cfg.boundApiBase)}\uFF09\uFF0C\u4E0E\u5F53\u524D\u4E0D\u4E00\u81F4 \u2014\u2014 \u5F53\u524D\u73AF\u5883\u5E76\u4E0D\u8BA4\u8BC6\u8FD9\u53F0\u673A\u5668\uFF0C\u9700\u8981\u91CD\u65B0 deskbuddy setup`
@@ -5,7 +5,7 @@ import {
5
5
  installTools,
6
6
  parseTools,
7
7
  runEnable
8
- } from "./chunk-W2GIOQDI.js";
8
+ } from "./chunk-ET52BEIS.js";
9
9
  export {
10
10
  defaultShimEnvForInstall,
11
11
  installShims,
package/dist/hook.cjs CHANGED
@@ -2666,13 +2666,17 @@ async function main(argv) {
2666
2666
  if (event === 'UserPromptSubmit') recordDir(payload.cwd, now)
2667
2667
  // 窗口对话轮数(spec 2026-10-02 §2.1):一轮开始的事件加 1
2668
2668
  const internal = event === 'UserPromptSubmit' && isInternalPrompt(payload.prompt)
2669
- const isTurn = !internal && turnEvents(registry, tool).indexOf(event) >= 0
2669
+ // 子代理发的事件(带 agent_id):Codex 0.159 实测(10-13)子代理 thread 的 hook 带父会话的 session_id,
2670
+ // 但 turn_id / transcript_path 是子代理自己的,派它时那句话还会以 UserPromptSubmit 触发一次。
2671
+ // 归到父会话(状态、授权照常),但不算父会话的一轮、不当首句、不换掉父会话的 transcript
2672
+ const sub = typeof payload.agent_id === 'string' && payload.agent_id !== ''
2673
+ const isTurn = !internal && !sub && turnEvents(registry, tool).indexOf(event) >= 0
2670
2674
  // 首条指令(标题来源 first-prompt):只记第一次
2671
2675
  // 状态没了(会话结束后被续跑)就接已结束记录里的首句;DeskBuddy 注入的话不算首句
2672
2676
  const firstPrompt =
2673
2677
  (prev && prev.firstPrompt) ||
2674
2678
  (prev ? undefined : endedFirstPrompt(sessionId)) ||
2675
- (event === 'UserPromptSubmit' && !internal ? cleanPrompt(payload.prompt) : '') ||
2679
+ (event === 'UserPromptSubmit' && !internal && !sub ? cleanPrompt(payload.prompt) : '') ||
2676
2680
  undefined
2677
2681
  if (superseded(prev, eventAt)) {
2678
2682
  // 被并发的更晚事件(多半是同一轮的 Stop)抢先写了:状态不覆盖,但首条指令要补上,不然标题就成了第二条指令
@@ -2754,7 +2758,7 @@ async function main(argv) {
2754
2758
  firstPrompt: firstPrompt,
2755
2759
  // transcript 路径(Claude Code 的 hook 输入带):daemon 据此认 Esc 打断(Bug 表 160)。🔴 只落本机、不上报
2756
2760
  transcriptPath:
2757
- typeof payload.transcript_path === 'string' && payload.transcript_path ? payload.transcript_path : (prev && prev.transcriptPath) || undefined,
2761
+ !sub && typeof payload.transcript_path === 'string' && payload.transcript_path ? payload.transcript_path : (prev && prev.transcriptPath) || undefined,
2758
2762
  // WorkBuddy:会话在 ~/.workbuddy 还是 ~/.codebuddy(spec 2026-10-08 codebuddy-default-dir),续写按它选目录。🔴 只落本机、不上报
2759
2763
  configDir: tool === 'workbuddy' ? workbuddyConfigDir(payload, process.env) || (prev && prev.configDir) || undefined : undefined,
2760
2764
  // 进程号是按窗口登记先记下的、还没核对过祖先链(spec §3.5)。🔴 只落本机
@@ -2780,7 +2784,7 @@ async function main(argv) {
2780
2784
  // cc-ai-title 要读 transcript,长任务期间 PreToolUse/PostToolUse 触发极频繁
2781
2785
  next.title =
2782
2786
  resolveTitle(titleSources(registry, tool), {
2783
- transcriptPath: payload.transcript_path,
2787
+ transcriptPath: sub ? next.transcriptPath : payload.transcript_path,
2784
2788
  cwd: next.project,
2785
2789
  sessionId: sessionId,
2786
2790
  tool: tool,
@@ -482,3 +482,33 @@
482
482
  2026-10-13T02:29:35.919Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
483
483
  2026-10-13T02:29:35.919Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
484
484
  2026-10-13T02:29:38.734Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
485
+ 2026-10-13T03:30:01.372Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
486
+ 2026-10-13T03:30:06.278Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
487
+ 2026-10-13T03:30:06.278Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
488
+ 2026-10-13T03:30:06.390Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
489
+ 2026-10-13T03:30:06.390Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
490
+ 2026-10-13T03:30:08.716Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
491
+ 2026-10-13T03:32:18.623Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
492
+ 2026-10-13T03:32:23.571Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
493
+ 2026-10-13T03:32:23.571Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
494
+ 2026-10-13T03:32:23.683Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
495
+ 2026-10-13T03:32:23.683Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
496
+ 2026-10-13T03:32:26.513Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
497
+ 2026-10-13T03:35:16.340Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
498
+ 2026-10-13T03:35:21.305Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
499
+ 2026-10-13T03:35:21.305Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
500
+ 2026-10-13T03:35:21.411Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
501
+ 2026-10-13T03:35:21.411Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
502
+ 2026-10-13T03:35:23.952Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
503
+ 2026-10-13T06:01:27.324Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
504
+ 2026-10-13T06:01:32.581Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
505
+ 2026-10-13T06:01:32.581Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
506
+ 2026-10-13T06:01:32.676Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
507
+ 2026-10-13T06:01:32.676Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
508
+ 2026-10-13T06:01:35.436Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
509
+ 2026-10-13T06:06:34.568Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
510
+ 2026-10-13T06:06:39.868Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
511
+ 2026-10-13T06:06:39.869Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
512
+ 2026-10-13T06:06:40.053Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
513
+ 2026-10-13T06:06:40.053Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
514
+ 2026-10-13T06:06:42.597Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
package/hook/hook.cjs CHANGED
@@ -2666,13 +2666,17 @@ async function main(argv) {
2666
2666
  if (event === 'UserPromptSubmit') recordDir(payload.cwd, now)
2667
2667
  // 窗口对话轮数(spec 2026-10-02 §2.1):一轮开始的事件加 1
2668
2668
  const internal = event === 'UserPromptSubmit' && isInternalPrompt(payload.prompt)
2669
- const isTurn = !internal && turnEvents(registry, tool).indexOf(event) >= 0
2669
+ // 子代理发的事件(带 agent_id):Codex 0.159 实测(10-13)子代理 thread 的 hook 带父会话的 session_id,
2670
+ // 但 turn_id / transcript_path 是子代理自己的,派它时那句话还会以 UserPromptSubmit 触发一次。
2671
+ // 归到父会话(状态、授权照常),但不算父会话的一轮、不当首句、不换掉父会话的 transcript
2672
+ const sub = typeof payload.agent_id === 'string' && payload.agent_id !== ''
2673
+ const isTurn = !internal && !sub && turnEvents(registry, tool).indexOf(event) >= 0
2670
2674
  // 首条指令(标题来源 first-prompt):只记第一次
2671
2675
  // 状态没了(会话结束后被续跑)就接已结束记录里的首句;DeskBuddy 注入的话不算首句
2672
2676
  const firstPrompt =
2673
2677
  (prev && prev.firstPrompt) ||
2674
2678
  (prev ? undefined : endedFirstPrompt(sessionId)) ||
2675
- (event === 'UserPromptSubmit' && !internal ? cleanPrompt(payload.prompt) : '') ||
2679
+ (event === 'UserPromptSubmit' && !internal && !sub ? cleanPrompt(payload.prompt) : '') ||
2676
2680
  undefined
2677
2681
  if (superseded(prev, eventAt)) {
2678
2682
  // 被并发的更晚事件(多半是同一轮的 Stop)抢先写了:状态不覆盖,但首条指令要补上,不然标题就成了第二条指令
@@ -2754,7 +2758,7 @@ async function main(argv) {
2754
2758
  firstPrompt: firstPrompt,
2755
2759
  // transcript 路径(Claude Code 的 hook 输入带):daemon 据此认 Esc 打断(Bug 表 160)。🔴 只落本机、不上报
2756
2760
  transcriptPath:
2757
- typeof payload.transcript_path === 'string' && payload.transcript_path ? payload.transcript_path : (prev && prev.transcriptPath) || undefined,
2761
+ !sub && typeof payload.transcript_path === 'string' && payload.transcript_path ? payload.transcript_path : (prev && prev.transcriptPath) || undefined,
2758
2762
  // WorkBuddy:会话在 ~/.workbuddy 还是 ~/.codebuddy(spec 2026-10-08 codebuddy-default-dir),续写按它选目录。🔴 只落本机、不上报
2759
2763
  configDir: tool === 'workbuddy' ? workbuddyConfigDir(payload, process.env) || (prev && prev.configDir) || undefined : undefined,
2760
2764
  // 进程号是按窗口登记先记下的、还没核对过祖先链(spec §3.5)。🔴 只落本机
@@ -2780,7 +2784,7 @@ async function main(argv) {
2780
2784
  // cc-ai-title 要读 transcript,长任务期间 PreToolUse/PostToolUse 触发极频繁
2781
2785
  next.title =
2782
2786
  resolveTitle(titleSources(registry, tool), {
2783
- transcriptPath: payload.transcript_path,
2787
+ transcriptPath: sub ? next.transcriptPath : payload.transcript_path,
2784
2788
  cwd: next.project,
2785
2789
  sessionId: sessionId,
2786
2790
  tool: tool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deskbuddy",
3
- "version": "0.2.0-beta.41",
3
+ "version": "0.2.0-beta.43",
4
4
  "description": "把 Claude Code、Codex 等 AI 编码智能体每个会话窗口的状态,实时同步到桌面硬件屏幕",
5
5
  "keywords": [
6
6
  "ai",