deskbuddy 0.2.0-beta.40 → 0.2.0-beta.42
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()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 {
|
|
29
|
+
}
|
|
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;
|
|
16
49
|
}
|
|
17
|
-
|
|
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
|
|
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),
|
|
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 =
|
|
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
|
|
949
|
+
return resolve3(home) !== resolve3(defaultHome);
|
|
914
950
|
}
|
|
915
951
|
async function uninstallAutostart(platform = process.platform, deps = {}) {
|
|
916
952
|
const d = { ...defaultUninstallDeps(), ...deps };
|
|
@@ -3182,7 +3218,7 @@ function traeNoticeSummary(toolName, toolInput, described, notice) {
|
|
|
3182
3218
|
// src/daemon/workbuddyApp/keeper.ts
|
|
3183
3219
|
import { execFile as execFile6, spawn as spawn2 } from "child_process";
|
|
3184
3220
|
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
|
|
3221
|
+
import { delimiter as delimiter3, join as join22, resolve as resolve5 } from "path";
|
|
3186
3222
|
|
|
3187
3223
|
// src/core/process.ts
|
|
3188
3224
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
@@ -3710,7 +3746,7 @@ function resolveAlias(sessionId, now = Date.now()) {
|
|
|
3710
3746
|
import { execFile as execFile3, execFileSync as execFileSync7 } from "child_process";
|
|
3711
3747
|
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
3748
|
import { homedir as homedir3 } from "os";
|
|
3713
|
-
import { delimiter, join as join15, resolve as
|
|
3749
|
+
import { delimiter, join as join15, resolve as resolve4 } from "path";
|
|
3714
3750
|
var SHIM_FALLBACK_EXIT = 213;
|
|
3715
3751
|
var WIN_SHIM_ENABLED = true;
|
|
3716
3752
|
var SHIM_COMMANDS = { claude_code: "claude", codex: "codex" };
|
|
@@ -3823,7 +3859,7 @@ function cmdScript(tool, command, node, cli, bin) {
|
|
|
3823
3859
|
].join("\r\n");
|
|
3824
3860
|
}
|
|
3825
3861
|
function rcBlock(binDir, rcHome) {
|
|
3826
|
-
const std =
|
|
3862
|
+
const std = resolve4(rcHome, ".deskbuddy", "bin") === resolve4(binDir);
|
|
3827
3863
|
const dir2 = std ? "$HOME/.deskbuddy/bin" : binDir.replace(/(["\\$`])/g, "\\$1");
|
|
3828
3864
|
return [
|
|
3829
3865
|
RC_BEGIN,
|
|
@@ -4948,16 +4984,16 @@ var defaultProbe = createVersionProbe({
|
|
|
4948
4984
|
return classifySyncError(e);
|
|
4949
4985
|
}
|
|
4950
4986
|
},
|
|
4951
|
-
runAsync: (loc) => new Promise((
|
|
4987
|
+
runAsync: (loc) => new Promise((resolve7) => {
|
|
4952
4988
|
try {
|
|
4953
4989
|
execFile4(
|
|
4954
4990
|
loc.file,
|
|
4955
4991
|
[...loc.prefixArgs, "--version"],
|
|
4956
4992
|
{ encoding: "utf8", windowsHide: true, timeout: PROBE_TIMEOUT_MS, env: probeEnv(loc) },
|
|
4957
|
-
(err, stdout2, stderr) =>
|
|
4993
|
+
(err, stdout2, stderr) => resolve7(err ? classifyAsyncError(err, String(stdout2 ?? ""), String(stderr ?? "")) : { kind: "done", out: `${stdout2}${stderr}` })
|
|
4958
4994
|
);
|
|
4959
4995
|
} catch {
|
|
4960
|
-
|
|
4996
|
+
resolve7({ kind: "spawn_error" });
|
|
4961
4997
|
}
|
|
4962
4998
|
}),
|
|
4963
4999
|
now: () => Date.now()
|
|
@@ -5535,12 +5571,12 @@ function defaultWbElectron(d = defaultLocateDeps()) {
|
|
|
5535
5571
|
}
|
|
5536
5572
|
}
|
|
5537
5573
|
function defaultAppRunning(platform = process.platform) {
|
|
5538
|
-
return new Promise((
|
|
5574
|
+
return new Promise((resolve7) => {
|
|
5539
5575
|
try {
|
|
5540
5576
|
if (platform === "darwin") {
|
|
5541
5577
|
execFile5("pgrep", ["-f", "WorkBuddy.app/Contents/MacOS/"], { timeout: 5e3 }, (err) => {
|
|
5542
5578
|
const code = err?.code;
|
|
5543
|
-
|
|
5579
|
+
resolve7(!err ? true : code === 1 ? false : true);
|
|
5544
5580
|
});
|
|
5545
5581
|
return;
|
|
5546
5582
|
}
|
|
@@ -5549,13 +5585,13 @@ function defaultAppRunning(platform = process.platform) {
|
|
|
5549
5585
|
"tasklist",
|
|
5550
5586
|
["/FI", "IMAGENAME eq WorkBuddy.exe", "/FO", "CSV", "/NH"],
|
|
5551
5587
|
{ timeout: 1e4, windowsHide: true, encoding: "utf8" },
|
|
5552
|
-
(err, stdout2) =>
|
|
5588
|
+
(err, stdout2) => resolve7(err ? true : /"WorkBuddy\.exe"/i.test(String(stdout2)))
|
|
5553
5589
|
);
|
|
5554
5590
|
return;
|
|
5555
5591
|
}
|
|
5556
|
-
|
|
5592
|
+
resolve7(true);
|
|
5557
5593
|
} catch {
|
|
5558
|
-
|
|
5594
|
+
resolve7(true);
|
|
5559
5595
|
}
|
|
5560
5596
|
});
|
|
5561
5597
|
}
|
|
@@ -5590,13 +5626,13 @@ var defaultWbAppDbDeps = () => ({
|
|
|
5590
5626
|
configDir: () => dirname12(workbuddySettingsPath()),
|
|
5591
5627
|
loadSqlite: loadNodeSqlite,
|
|
5592
5628
|
electron: () => defaultWbElectron(),
|
|
5593
|
-
runElectron: (bin, script, input) => new Promise((
|
|
5629
|
+
runElectron: (bin, script, input) => new Promise((resolve7, reject) => {
|
|
5594
5630
|
const env = { ...process.env, ELECTRON_RUN_AS_NODE: "1" };
|
|
5595
5631
|
const c = execFile5(
|
|
5596
5632
|
bin,
|
|
5597
5633
|
["-e", script],
|
|
5598
5634
|
{ env, timeout: 15e3, windowsHide: true, maxBuffer: 1024 * 1024 },
|
|
5599
|
-
(err, stdout2) => err ? reject(err) :
|
|
5635
|
+
(err, stdout2) => err ? reject(err) : resolve7(String(stdout2))
|
|
5600
5636
|
);
|
|
5601
5637
|
c.stdin?.on("error", () => {
|
|
5602
5638
|
});
|
|
@@ -5741,12 +5777,12 @@ function openWs(target, port, d, info) {
|
|
|
5741
5777
|
const url = loopbackWsUrl(target.webSocketDebuggerUrl, port);
|
|
5742
5778
|
if (!url) return Promise.reject(new Error("\u4E3B\u7A97\u53E3\u7684\u8C03\u8BD5\u5730\u5740\u4E0D\u5BF9"));
|
|
5743
5779
|
const ws = (d.ws ?? ((u) => new WebSocket(u, { handshakeTimeout: 5e3 })))(url);
|
|
5744
|
-
return new Promise((
|
|
5780
|
+
return new Promise((resolve7, reject) => {
|
|
5745
5781
|
let opened = false;
|
|
5746
5782
|
const client = new WsCdpClient(ws, info);
|
|
5747
5783
|
ws.on("open", () => {
|
|
5748
5784
|
opened = true;
|
|
5749
|
-
|
|
5785
|
+
resolve7(client);
|
|
5750
5786
|
});
|
|
5751
5787
|
ws.on("error", (e) => {
|
|
5752
5788
|
if (!opened) reject(e instanceof Error ? e : new Error("CDP \u8FDE\u63A5\u5931\u8D25"));
|
|
@@ -5844,12 +5880,12 @@ var WsCdpClient = class {
|
|
|
5844
5880
|
#rpc(method, params, timeoutMs, raw) {
|
|
5845
5881
|
if (this.#closed) return Promise.reject(new Error("CDP \u8FDE\u63A5\u5DF2\u65AD\u5F00"));
|
|
5846
5882
|
const id = ++this.#id;
|
|
5847
|
-
return new Promise((
|
|
5883
|
+
return new Promise((resolve7, reject) => {
|
|
5848
5884
|
const timer = setTimeout(() => {
|
|
5849
5885
|
this.#waiting.delete(id);
|
|
5850
5886
|
reject(new Error("\u9875\u9762\u811A\u672C\u8D85\u65F6"));
|
|
5851
5887
|
}, timeoutMs);
|
|
5852
|
-
this.#waiting.set(id, { resolve:
|
|
5888
|
+
this.#waiting.set(id, { resolve: resolve7, reject, timer, ...raw ? { raw } : {} });
|
|
5853
5889
|
try {
|
|
5854
5890
|
this.#ws.send(JSON.stringify({ id, method, params }));
|
|
5855
5891
|
} catch (e) {
|
|
@@ -5909,7 +5945,7 @@ function cleanLaunchEnv(src = process.env, shim = shimDir()) {
|
|
|
5909
5945
|
const out = {};
|
|
5910
5946
|
const shimReal = (() => {
|
|
5911
5947
|
try {
|
|
5912
|
-
return
|
|
5948
|
+
return resolve5(shim);
|
|
5913
5949
|
} catch {
|
|
5914
5950
|
return shim;
|
|
5915
5951
|
}
|
|
@@ -5922,7 +5958,7 @@ function cleanLaunchEnv(src = process.env, shim = shimDir()) {
|
|
|
5922
5958
|
if (pathKey && typeof out[pathKey] === "string") {
|
|
5923
5959
|
out[pathKey] = out[pathKey].split(delimiter3).filter((p) => {
|
|
5924
5960
|
try {
|
|
5925
|
-
return
|
|
5961
|
+
return resolve5(p) !== shimReal;
|
|
5926
5962
|
} catch {
|
|
5927
5963
|
return p !== shim;
|
|
5928
5964
|
}
|
|
@@ -6722,7 +6758,7 @@ async function defaultWinProcs() {
|
|
|
6722
6758
|
// src/daemon/qoderApp/task.ts
|
|
6723
6759
|
import { createHash as createHash3 } from "crypto";
|
|
6724
6760
|
import { realpathSync as realpathSync3 } from "fs";
|
|
6725
|
-
import { resolve as
|
|
6761
|
+
import { resolve as resolve6 } from "path";
|
|
6726
6762
|
|
|
6727
6763
|
// src/daemon/command.ts
|
|
6728
6764
|
var SERVICE_COMMAND = "deskbuddy.command";
|
|
@@ -6994,7 +7030,7 @@ function normalizeCwd(p, platform = process.platform, real = (x) => realpathSync
|
|
|
6994
7030
|
r = r.replace(/\//g, "\\").replace(/\\+$/, "");
|
|
6995
7031
|
return (/^[a-z]:$/i.test(r) ? r + "\\" : r).toLowerCase().replace(/\\/g, "/");
|
|
6996
7032
|
}
|
|
6997
|
-
r =
|
|
7033
|
+
r = resolve6(r);
|
|
6998
7034
|
return r.length > 1 ? r.replace(/\/+$/, "") : r;
|
|
6999
7035
|
}
|
|
7000
7036
|
function appBusy(st) {
|
|
@@ -8468,7 +8504,7 @@ var DumateWatch = class {
|
|
|
8468
8504
|
}
|
|
8469
8505
|
};
|
|
8470
8506
|
function runHook(node, input, agentPid, tool = "dumate") {
|
|
8471
|
-
return new Promise((
|
|
8507
|
+
return new Promise((resolve7) => {
|
|
8472
8508
|
let child;
|
|
8473
8509
|
try {
|
|
8474
8510
|
child = spawn3(node, [installedHookPath(), tool], {
|
|
@@ -8476,18 +8512,18 @@ function runHook(node, input, agentPid, tool = "dumate") {
|
|
|
8476
8512
|
env: { ...process.env, DESKBUDDY_AGENT_PID: String(agentPid) }
|
|
8477
8513
|
});
|
|
8478
8514
|
} catch {
|
|
8479
|
-
|
|
8515
|
+
resolve7();
|
|
8480
8516
|
return;
|
|
8481
8517
|
}
|
|
8482
8518
|
const timer = setTimeout(() => child.kill("SIGKILL"), HOOK_KILL_MS);
|
|
8483
8519
|
timer.unref?.();
|
|
8484
8520
|
child.on("error", () => {
|
|
8485
8521
|
clearTimeout(timer);
|
|
8486
|
-
|
|
8522
|
+
resolve7();
|
|
8487
8523
|
});
|
|
8488
8524
|
child.on("close", () => {
|
|
8489
8525
|
clearTimeout(timer);
|
|
8490
|
-
|
|
8526
|
+
resolve7();
|
|
8491
8527
|
});
|
|
8492
8528
|
child.stdin.on("error", () => {
|
|
8493
8529
|
});
|
|
@@ -8509,6 +8545,10 @@ var LAUNCH_FRESH_MS = 10 * 1e3;
|
|
|
8509
8545
|
var LAUNCH_PORT_WINDOW_MS = 10 * 60 * 1e3;
|
|
8510
8546
|
var LAUNCH_PORT_MAX = 2;
|
|
8511
8547
|
var LAUNCH_SEEN_MAX = 32;
|
|
8548
|
+
function macOpenArgs(brand, app, port, background) {
|
|
8549
|
+
const env = Object.entries(brand.macLaunchEnv ?? {}).flatMap(([k, v]) => ["--env", `${k}=${v}`]);
|
|
8550
|
+
return [...env, ...background ? ["-g"] : [], "-a", app, "--args", `--remote-debugging-port=${port}`];
|
|
8551
|
+
}
|
|
8512
8552
|
function winBrandMainProc(procs, exe) {
|
|
8513
8553
|
const want = exe.toLowerCase();
|
|
8514
8554
|
for (const p of procs) {
|
|
@@ -8671,7 +8711,7 @@ var QoderCdpKeeper = class {
|
|
|
8671
8711
|
}
|
|
8672
8712
|
return await launch(app, [`--remote-debugging-port=${port}`], env);
|
|
8673
8713
|
}
|
|
8674
|
-
return await launch("open",
|
|
8714
|
+
return await launch("open", macOpenArgs(this.#d.brand, app, port, true), env);
|
|
8675
8715
|
}
|
|
8676
8716
|
#exec() {
|
|
8677
8717
|
return this.#d.exec ?? defaultExec;
|
|
@@ -8766,11 +8806,14 @@ var QoderCdpKeeper = class {
|
|
|
8766
8806
|
const r = await exec("lsof", ["-nP", `-iTCP:${this.#d.port()}`, "-sTCP:LISTEN"]);
|
|
8767
8807
|
const rows = parseLsof(r.stdout);
|
|
8768
8808
|
if (rows.length === 0 || rows.some((x) => x.addr !== "127.0.0.1")) return false;
|
|
8809
|
+
const b = this.#d.brand;
|
|
8810
|
+
let own = false;
|
|
8769
8811
|
for (const { pid } of rows) {
|
|
8770
8812
|
const p = await exec("ps", ["-o", "comm=", "-p", String(pid)]);
|
|
8771
|
-
if (
|
|
8813
|
+
if (b.comm.test(p.stdout)) own = true;
|
|
8814
|
+
else if (!b.macInheritors?.test(p.stdout)) return false;
|
|
8772
8815
|
}
|
|
8773
|
-
return
|
|
8816
|
+
return own;
|
|
8774
8817
|
}
|
|
8775
8818
|
async appRunning() {
|
|
8776
8819
|
if (this.#d.appRunning) return this.#d.appRunning();
|
|
@@ -8939,7 +8982,7 @@ var QoderCdpKeeper = class {
|
|
|
8939
8982
|
const port = this.#d.port();
|
|
8940
8983
|
const launch = this.#d.launch ?? defaultLaunch;
|
|
8941
8984
|
const env = (this.#d.launchEnv ?? cleanLaunchEnv)();
|
|
8942
|
-
const ok = await launch("open",
|
|
8985
|
+
const ok = await launch("open", macOpenArgs(b, app, port, false), env);
|
|
8943
8986
|
this.#d.log(ok ? `${b.label} \u521A\u542F\u52A8\u6CA1\u5E26\u8C03\u8BD5\u7AEF\u53E3\uFF0C\u5DF2\u5E26\u7AEF\u53E3\u91CD\u5F00\uFF08\u7AEF\u53E3 ${port}\uFF09` : `${b.label} \u521A\u542F\u52A8\u6CA1\u5E26\u8C03\u8BD5\u7AEF\u53E3\uFF0C\u5DF2\u9000\u51FA\u4F46\u5E26\u7AEF\u53E3\u62C9\u8D77\u5931\u8D25\uFF08\u4E0D\u518D\u91CD\u8BD5\uFF09`);
|
|
8944
8987
|
return ok ? "reopened" : "failed";
|
|
8945
8988
|
}
|
|
@@ -10531,7 +10574,7 @@ function startCommand(plan, tool, limitMs = EXEC_TIMEOUT_MS) {
|
|
|
10531
10574
|
}, Math.max(0, remaining));
|
|
10532
10575
|
};
|
|
10533
10576
|
let timedOut = false;
|
|
10534
|
-
const done = new Promise((
|
|
10577
|
+
const done = new Promise((resolve7) => {
|
|
10535
10578
|
child = execFile7(
|
|
10536
10579
|
plan.file,
|
|
10537
10580
|
plan.args,
|
|
@@ -10551,10 +10594,10 @@ function startCommand(plan, tool, limitMs = EXEC_TIMEOUT_MS) {
|
|
|
10551
10594
|
if (err || timedOut) {
|
|
10552
10595
|
const e = err;
|
|
10553
10596
|
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`;
|
|
10554
|
-
|
|
10597
|
+
resolve7({ ok: false, sessionId: parseSessionId(tool, out), stdout: out, stderr: errOut, error: msg });
|
|
10555
10598
|
return;
|
|
10556
10599
|
}
|
|
10557
|
-
|
|
10600
|
+
resolve7({ ok: true, sessionId: parseSessionId(tool, out), stdout: out, stderr: errOut });
|
|
10558
10601
|
}
|
|
10559
10602
|
);
|
|
10560
10603
|
child?.stdin?.end();
|
|
@@ -10693,8 +10736,8 @@ var defaultGuiDeps = () => ({
|
|
|
10693
10736
|
var defaultOpenerDeps = (findWt2) => ({
|
|
10694
10737
|
platform: process.platform,
|
|
10695
10738
|
findWt: findWt2,
|
|
10696
|
-
run: (file3, args) => new Promise((
|
|
10697
|
-
execFile8(file3, args, { windowsHide: true, timeout: 15e3 }, (err) => err ? reject(err) :
|
|
10739
|
+
run: (file3, args) => new Promise((resolve7, reject) => {
|
|
10740
|
+
execFile8(file3, args, { windowsHide: true, timeout: 15e3 }, (err) => err ? reject(err) : resolve7());
|
|
10698
10741
|
}),
|
|
10699
10742
|
spawnDetached: (file3, args) => {
|
|
10700
10743
|
const c = spawn4(file3, args, { detached: true, stdio: "ignore", shell: false, windowsHide: false });
|
|
@@ -10865,12 +10908,12 @@ async function checkLogin(tool, d) {
|
|
|
10865
10908
|
return { tool, state: "unknown", note: `\u68C0\u6D4B\u51FA\u9519\uFF1A${e?.message ?? e}` };
|
|
10866
10909
|
}
|
|
10867
10910
|
}
|
|
10868
|
-
var defaultProbeRun = (file3, args, env, timeoutMs) => new Promise((
|
|
10911
|
+
var defaultProbeRun = (file3, args, env, timeoutMs) => new Promise((resolve7) => {
|
|
10869
10912
|
let settled = false;
|
|
10870
10913
|
const done = (r) => {
|
|
10871
10914
|
if (settled) return;
|
|
10872
10915
|
settled = true;
|
|
10873
|
-
|
|
10916
|
+
resolve7(r);
|
|
10874
10917
|
};
|
|
10875
10918
|
const win = process.platform === "win32";
|
|
10876
10919
|
const opts = { env, windowsHide: true, maxBuffer: 8 * 1024 * 1024, detached: !win };
|
|
@@ -11067,7 +11110,7 @@ var defaultLoginOpenDeps = () => ({
|
|
|
11067
11110
|
});
|
|
11068
11111
|
async function installCodebuddyHooks(log) {
|
|
11069
11112
|
try {
|
|
11070
|
-
const { installTools: installTools2 } = await import("./enable-
|
|
11113
|
+
const { installTools: installTools2 } = await import("./enable-RN5EXNR3.js");
|
|
11071
11114
|
installTools2(["workbuddy"], () => {
|
|
11072
11115
|
}, null, { auto: true });
|
|
11073
11116
|
} catch (e) {
|
|
@@ -11270,7 +11313,7 @@ var DIALOG_TEXT = [
|
|
|
11270
11313
|
`\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`
|
|
11271
11314
|
].join("\n");
|
|
11272
11315
|
var LIMITED_NOTE = "\u8BBE\u5907\u4E0A\u53EA\u80FD\u770B\u4EFB\u52A1\u72B6\u6001\u3001\u56DE\u7B54\u6388\u6743";
|
|
11273
|
-
var defaultRunner = (file3, args, opts) => new Promise((
|
|
11316
|
+
var defaultRunner = (file3, args, opts) => new Promise((resolve7) => {
|
|
11274
11317
|
try {
|
|
11275
11318
|
const child = execFile10(
|
|
11276
11319
|
file3,
|
|
@@ -11278,7 +11321,7 @@ var defaultRunner = (file3, args, opts) => new Promise((resolve6) => {
|
|
|
11278
11321
|
{ env: opts.env, timeout: opts.timeoutMs, windowsHide: true, maxBuffer: 8 * 1024 * 1024, encoding: "utf8" },
|
|
11279
11322
|
(err, stdout2, stderr) => {
|
|
11280
11323
|
const e = err;
|
|
11281
|
-
|
|
11324
|
+
resolve7({
|
|
11282
11325
|
code: e ? typeof e.code === "number" ? e.code : null : 0,
|
|
11283
11326
|
stdout: String(stdout2 ?? ""),
|
|
11284
11327
|
stderr: String(stderr ?? ""),
|
|
@@ -11289,7 +11332,7 @@ var defaultRunner = (file3, args, opts) => new Promise((resolve6) => {
|
|
|
11289
11332
|
);
|
|
11290
11333
|
child.stdin?.end();
|
|
11291
11334
|
} catch {
|
|
11292
|
-
|
|
11335
|
+
resolve7({ code: null, stdout: "", stderr: "", timedOut: false, spawnError: true });
|
|
11293
11336
|
}
|
|
11294
11337
|
});
|
|
11295
11338
|
function checkTimeout(s) {
|
|
@@ -11581,7 +11624,7 @@ function defaultOfferDeps(log) {
|
|
|
11581
11624
|
}),
|
|
11582
11625
|
openLogin: () => defaultOpenLogin(platform),
|
|
11583
11626
|
installHooks: async () => {
|
|
11584
|
-
const { installTools: installTools2 } = await import("./enable-
|
|
11627
|
+
const { installTools: installTools2 } = await import("./enable-RN5EXNR3.js");
|
|
11585
11628
|
installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
|
|
11586
11629
|
},
|
|
11587
11630
|
log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
|
|
@@ -11822,6 +11865,9 @@ async function runEnable(tools, opts = {}) {
|
|
|
11822
11865
|
|
|
11823
11866
|
export {
|
|
11824
11867
|
defaultRemoteCwd,
|
|
11868
|
+
ensureDefaultRemoteCwd,
|
|
11869
|
+
remoteCwdReady,
|
|
11870
|
+
migrateRemoteCwd,
|
|
11825
11871
|
PROD_API_BASE,
|
|
11826
11872
|
TEST_API_BASE,
|
|
11827
11873
|
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-
|
|
277
|
+
} from "./chunk-RDJUEATP.js";
|
|
275
278
|
|
|
276
279
|
// src/commands/config.ts
|
|
277
280
|
function runConfig(args, out = (s2) => process.stdout.write(s2 + "\n")) {
|
|
@@ -14331,10 +14334,16 @@ var CHATGPT_BRAND = {
|
|
|
14331
14334
|
appName: "ChatGPT",
|
|
14332
14335
|
// 26.1007 的 Info.plist:CFBundleIdentifier = com.openai.codex
|
|
14333
14336
|
bundleId: "com.openai.codex",
|
|
14334
|
-
//
|
|
14335
|
-
|
|
14337
|
+
// 10-13 实测 26.1007:/json/version 的 UA 是纯 Chrome(不带 Codex/ChatGPT 字样);
|
|
14338
|
+
// 是不是这个 App 靠监听者核对(lsof 回环 + ps comm 在 ChatGPT.app 里)把关
|
|
14339
|
+
ua: /\b(Codex|ChatGPT|Chrome)\/\d/,
|
|
14336
14340
|
comm: /\/ChatGPT\.app\//,
|
|
14337
|
-
defaultPort: CHATGPT_DEFAULT_CDP_PORT
|
|
14341
|
+
defaultPort: CHATGPT_DEFAULT_CDP_PORT,
|
|
14342
|
+
// 用户 10-13 拍板:有进行中的本地会话 / 开了定时任务时 App 退出会弹「Quit ChatGPT?」(默认 Quit),
|
|
14343
|
+
// keeper 的 osascript quit 会被它拦下;由 DeskBuddy 拉起的 App 带上 App 自带的开关关掉这道确认
|
|
14344
|
+
macLaunchEnv: { CODEX_ELECTRON_DISABLE_QUIT_CONFIRMATION: "1" },
|
|
14345
|
+
// 10-13 实测:App 拉起的 Codex Computer Use(~/.codex/computer-use/…)继承了调试端口的监听句柄,lsof 里两个进程同一个 socket
|
|
14346
|
+
macInheritors: /\/\.codex\/computer-use\/Codex Computer Use\.app\//
|
|
14338
14347
|
};
|
|
14339
14348
|
var CODEX_ACTIVE_MS = 5 * 60 * 1e3;
|
|
14340
14349
|
var ROLLOUT_MAX_ENTRIES = 2e4;
|
|
@@ -16290,6 +16299,12 @@ var Daemon = class {
|
|
|
16290
16299
|
log(`\u6388\u6743\u7AEF\u70B9\u5DF2\u5C31\u7EEA 127.0.0.1:${port}`);
|
|
16291
16300
|
enableFatalReport(deskbuddyHome());
|
|
16292
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
|
+
}
|
|
16293
16308
|
this.#memLog = setInterval(() => log(memLine()), MEM_LOG_MS);
|
|
16294
16309
|
this.#memLog.unref();
|
|
16295
16310
|
this.#windowScan = setInterval(() => this.#coord.scanWindows(), 1e3);
|
|
@@ -17027,7 +17042,7 @@ var Daemon = class {
|
|
|
17027
17042
|
this.#report(cmd, "", "rejected", "", "dir_gone");
|
|
17028
17043
|
return;
|
|
17029
17044
|
}
|
|
17030
|
-
} else cwd =
|
|
17045
|
+
} else cwd = remoteCwdReady();
|
|
17031
17046
|
this.#toDumateNew(cmd, cwd);
|
|
17032
17047
|
return;
|
|
17033
17048
|
}
|
|
@@ -17058,7 +17073,7 @@ var Daemon = class {
|
|
|
17058
17073
|
return;
|
|
17059
17074
|
}
|
|
17060
17075
|
} else {
|
|
17061
|
-
cwd =
|
|
17076
|
+
cwd = remoteCwdReady();
|
|
17062
17077
|
if (!cwd) {
|
|
17063
17078
|
this.#report(cmd, "", "rejected", "", "no_remote_cwd");
|
|
17064
17079
|
return;
|
|
@@ -17076,7 +17091,7 @@ var Daemon = class {
|
|
|
17076
17091
|
return;
|
|
17077
17092
|
}
|
|
17078
17093
|
} else {
|
|
17079
|
-
cwd =
|
|
17094
|
+
cwd = remoteCwdReady();
|
|
17080
17095
|
if (!cwd) {
|
|
17081
17096
|
this.#report(cmd, "", "rejected", "", "no_remote_cwd");
|
|
17082
17097
|
return;
|
|
@@ -17282,7 +17297,7 @@ var Daemon = class {
|
|
|
17282
17297
|
return;
|
|
17283
17298
|
}
|
|
17284
17299
|
} else {
|
|
17285
|
-
cwd =
|
|
17300
|
+
cwd = remoteCwdReady();
|
|
17286
17301
|
if (!cwd) {
|
|
17287
17302
|
this.#report(cmd, "", "rejected", "", "no_remote_cwd");
|
|
17288
17303
|
return;
|
|
@@ -18048,7 +18063,7 @@ var Daemon = class {
|
|
|
18048
18063
|
}
|
|
18049
18064
|
const target = resolveTarget(cmd, {
|
|
18050
18065
|
readState,
|
|
18051
|
-
remoteCwd: () =>
|
|
18066
|
+
remoteCwd: () => remoteCwdReady(),
|
|
18052
18067
|
alias: resolveAlias,
|
|
18053
18068
|
dirOf: (ref) => dirOf(ref),
|
|
18054
18069
|
windowOpen: (s2) => s2.interactive === true && !!s2.pid && isAlive(s2.pid, s2.pidName)
|
|
@@ -18788,6 +18803,8 @@ function verdictMessage(reason, path) {
|
|
|
18788
18803
|
var MAX_ATTEMPTS = 3;
|
|
18789
18804
|
async function askRemoteCwd(deps2) {
|
|
18790
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");
|
|
18791
18808
|
for (let i = 0; i < MAX_ATTEMPTS; i++) {
|
|
18792
18809
|
const raw = await deps2.ask(`\u8FDC\u7A0B\u300C\u65B0\u5EFA\u4EFB\u52A1\u300D\u7684\u5DE5\u4F5C\u76EE\u5F55 [${defaultPath}]\uFF1A`);
|
|
18793
18810
|
if (raw === null) {
|
|
@@ -18913,6 +18930,7 @@ async function runSetup(opts = {}) {
|
|
|
18913
18930
|
const remoteCwd = await askRemoteCwd({ out, ask: terminalAsk });
|
|
18914
18931
|
const bound = loadConfig();
|
|
18915
18932
|
bound.remoteCwd = remoteCwd;
|
|
18933
|
+
bound.remoteCwdMigrated = true;
|
|
18916
18934
|
saveConfig(bound);
|
|
18917
18935
|
out(` \u5DF2\u8BB0\u4E0B\uFF1A${remoteCwd}`);
|
|
18918
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");
|
|
@@ -19087,8 +19105,10 @@ async function runInstall(opts, deps2 = defaultInstallDeps()) {
|
|
|
19087
19105
|
const bound = loadConfig();
|
|
19088
19106
|
if (!bound.remoteCwd) {
|
|
19089
19107
|
bound.remoteCwd = defaultRemoteCwd();
|
|
19108
|
+
bound.remoteCwdMigrated = true;
|
|
19090
19109
|
saveConfig(bound);
|
|
19091
19110
|
}
|
|
19111
|
+
ensureDefaultRemoteCwd(bound.remoteCwd);
|
|
19092
19112
|
const auto = await deps2.autostart();
|
|
19093
19113
|
let logins = [];
|
|
19094
19114
|
try {
|
|
@@ -19200,6 +19220,7 @@ function formatStatus(input) {
|
|
|
19200
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";
|
|
19201
19221
|
lines3.push(` ${pad("\u8D26\u53F7", 10)}${account}`);
|
|
19202
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}`);
|
|
19203
19224
|
if (cfg.boundAt && cfg.boundApiBase && cfg.boundApiBase !== cfg.apiBase) {
|
|
19204
19225
|
lines3.push(
|
|
19205
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`
|
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
|
-
|
|
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/hook/hook-debug.log
CHANGED
|
@@ -464,3 +464,39 @@
|
|
|
464
464
|
2026-10-12T15:21:56.191Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
465
465
|
2026-10-12T15:21:56.192Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
466
466
|
2026-10-12T15:21:58.689Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
467
|
+
2026-10-13T02:00:47.491Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
468
|
+
2026-10-13T02:00:52.742Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
469
|
+
2026-10-13T02:00:52.742Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
470
|
+
2026-10-13T02:00:52.899Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
471
|
+
2026-10-13T02:00:52.899Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
472
|
+
2026-10-13T02:00:56.217Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
473
|
+
2026-10-13T02:04:00.351Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
474
|
+
2026-10-13T02:04:05.491Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
475
|
+
2026-10-13T02:04:05.491Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
476
|
+
2026-10-13T02:04:05.629Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
477
|
+
2026-10-13T02:04:05.629Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
478
|
+
2026-10-13T02:04:09.075Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
479
|
+
2026-10-13T02:29:30.508Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
480
|
+
2026-10-13T02:29:35.742Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
481
|
+
2026-10-13T02:29:35.742Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
482
|
+
2026-10-13T02:29:35.919Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
483
|
+
2026-10-13T02:29:35.919Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
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 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
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
|
-
|
|
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,
|