deskbuddy 0.2.0-beta.43 → 0.2.0-beta.46

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.
@@ -1433,6 +1433,13 @@ async function refreshRegistry() {
1433
1433
  } catch {
1434
1434
  }
1435
1435
  }
1436
+ var DEFAULT_TITLE_SOURCES = ["git-branch", "project"];
1437
+ function titleSources(registry, tool) {
1438
+ const fromRegistry = registry?.tools?.[tool]?.titleSources;
1439
+ if (fromRegistry?.length) return fromRegistry;
1440
+ const builtin = FALLBACK.tools[tool]?.titleSources;
1441
+ return builtin?.length ? builtin : DEFAULT_TITLE_SOURCES;
1442
+ }
1436
1443
 
1437
1444
  // src/adapters/ccHook.ts
1438
1445
  import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync as renameSync4, rmSync as rmSync3, statSync, writeFileSync as writeFileSync6 } from "fs";
@@ -2475,6 +2482,324 @@ function rememberTitle(titles, info) {
2475
2482
  titles.set(info.id, t.slice(0, 100));
2476
2483
  }
2477
2484
 
2485
+ // src/daemon/gate/options.ts
2486
+ import { homedir as homedir3 } from "os";
2487
+
2488
+ // src/daemon/gate/claudeLabels.ts
2489
+ var CC_MERGE_MAX = 8;
2490
+ var CC_LABEL_MAX_WIDTH = 160;
2491
+ var CC_VALUE_MAX = 256;
2492
+ var CC_SUGGESTIONS_MAX = 64;
2493
+ var CC_TEXT = {
2494
+ yes: "Yes",
2495
+ no: "No",
2496
+ noTell: "No, and tell Claude what to do differently",
2497
+ readHead: "Yes, allow reading from ",
2498
+ fromProject: " from this project",
2499
+ duringSession: " during this session",
2500
+ forSession: " for this session",
2501
+ alwaysAccessHead: "Yes, and always allow access to ",
2502
+ accessHead: "Yes, and allow access to ",
2503
+ allowHead: "Yes, and allow ",
2504
+ accessAnd: " access and",
2505
+ and: " and",
2506
+ commands: " commands",
2507
+ dontAskHead: "Yes, and don't ask again for ",
2508
+ /** 可编辑前缀项(单条子命令):标签 + `: ` + 前缀(弯撇号 U+2019) */
2509
+ dontAskPrefix: "Yes, and don\u2019t ask again for: ",
2510
+ switchHead: "Yes, and switch to ",
2511
+ claudeFolderProject: "Yes, and allow Claude to edit files in this project's .claude folder for this session",
2512
+ claudeFolderHome: "Yes, and allow Claude to edit files in its ~/.claude folder for this session",
2513
+ autoMode: "Yes, and switch to auto mode",
2514
+ autoModeNote: "\xB7 auto mode handles these prompts for you"
2515
+ };
2516
+ var CC_MODE_TEXT = {
2517
+ acceptEdits: "accept edits (auto-approve file edits and common file commands)"
2518
+ };
2519
+ function isWide(cp) {
2520
+ return cp >= 4352 && cp <= 4447 || cp >= 11904 && cp <= 12350 || cp >= 12353 && cp <= 13311 || cp >= 13312 && cp <= 19903 || cp >= 19968 && cp <= 40959 || cp >= 40960 && cp <= 42191 || cp >= 44032 && cp <= 55203 || cp >= 63744 && cp <= 64255 || cp >= 65072 && cp <= 65103 || cp >= 65280 && cp <= 65376 || cp >= 65504 && cp <= 65510;
2521
+ }
2522
+ function plainChars(s) {
2523
+ for (const ch of s) {
2524
+ const cp = ch.codePointAt(0);
2525
+ if (cp >= 32 && cp <= 126) continue;
2526
+ if (isWide(cp)) continue;
2527
+ return false;
2528
+ }
2529
+ return true;
2530
+ }
2531
+ function displayWidth(s) {
2532
+ let w = 0;
2533
+ for (const ch of s) w += isWide(ch.codePointAt(0)) ? 2 : 1;
2534
+ return w;
2535
+ }
2536
+ function shownAsIs(s) {
2537
+ return s.length > 0 && s.length <= CC_VALUE_MAX && s.trim() === s && !/\s\s/.test(s) && !s.startsWith('"') && !s.endsWith('"') && plainChars(s);
2538
+ }
2539
+ function listItemAsIs(s) {
2540
+ return shownAsIs(s) && !s.includes(",") && !s.includes(";") && !s.includes(" and ") && !s.startsWith("and ") && !s.endsWith(" and");
2541
+ }
2542
+ function joinAnd(items) {
2543
+ if (items.length <= 2) return items.join(" and ");
2544
+ return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
2545
+ }
2546
+ var uniq = (a) => [...new Set(a)];
2547
+ function distinctShown(raw, show) {
2548
+ const seen = /* @__PURE__ */ new Set();
2549
+ for (const r of raw) {
2550
+ const k = show(r).normalize("NFC");
2551
+ if (seen.has(k)) return false;
2552
+ seen.add(k);
2553
+ }
2554
+ return true;
2555
+ }
2556
+ var isObj = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
2557
+ var ruleOut = (r) => ({ toolName: r.toolName, ruleContent: r.ruleContent });
2558
+ var addRulesOut = (rules, destination) => ({ type: "addRules", rules: rules.map(ruleOut), behavior: "allow", destination });
2559
+ var addDirsOut = (directories, destination) => ({ type: "addDirectories", directories, destination });
2560
+ var DESTS = /* @__PURE__ */ new Set(["localSettings", "session"]);
2561
+ function readShown(rc) {
2562
+ if (rc.includes("\\")) return null;
2563
+ const s = rc.replace(/\/\*\*$/, "").replace(/^\.\//, "").replace(/^\/\//, "/");
2564
+ return s ? s : null;
2565
+ }
2566
+ function commandShown(rc) {
2567
+ const s = rc.endsWith(":*") || rc.endsWith(" *") ? rc.slice(0, -2) : rc;
2568
+ if (!s || /[<>]/.test(s)) return null;
2569
+ return s;
2570
+ }
2571
+ function shellApplies(sugg, tool) {
2572
+ if (sugg.length > CC_SUGGESTIONS_MAX) return null;
2573
+ const out = [];
2574
+ for (const s of sugg) {
2575
+ if (!isObj(s)) return null;
2576
+ if (s.type === "addRules") {
2577
+ if (s.behavior !== "allow" || !DESTS.has(s.destination)) continue;
2578
+ if (!Array.isArray(s.rules)) return null;
2579
+ const rules = [];
2580
+ for (const r of s.rules) {
2581
+ if (!isObj(r) || typeof r.toolName !== "string" || r.ruleContent !== void 0 && typeof r.ruleContent !== "string") return null;
2582
+ if (r.toolName === tool) {
2583
+ if (typeof r.ruleContent !== "string" || !r.ruleContent) continue;
2584
+ if (commandShown(r.ruleContent) === null) return null;
2585
+ rules.push(ruleOut(r));
2586
+ } else if (r.toolName === "Read") {
2587
+ if (typeof r.ruleContent !== "string" || !r.ruleContent) continue;
2588
+ if (readShown(r.ruleContent) === null) return null;
2589
+ rules.push(ruleOut(r));
2590
+ }
2591
+ }
2592
+ if (rules.length) out.push(addRulesOut(rules, s.destination));
2593
+ } else if (s.type === "addDirectories") {
2594
+ if (!DESTS.has(s.destination)) continue;
2595
+ if (!Array.isArray(s.directories)) return null;
2596
+ const dirs = s.directories.filter((d) => typeof d === "string" && d.trim() !== "");
2597
+ if (dirs.length !== s.directories.length) return null;
2598
+ if (dirs.length) out.push(addDirsOut(dirs, s.destination));
2599
+ }
2600
+ }
2601
+ return out;
2602
+ }
2603
+ function shellRowLabel(applies, tool, cwdShown) {
2604
+ const rules = applies.filter((s) => s.type === "addRules").flatMap((s) => s.rules);
2605
+ const dirsRaw = applies.filter((s) => s.type === "addDirectories").flatMap((s) => s.directories);
2606
+ if (rules.length + dirsRaw.length > CC_MERGE_MAX) return null;
2607
+ const dirs = uniq(dirsRaw);
2608
+ const reads = uniq(rules.filter((r) => r.toolName === "Read").map((r) => r.ruleContent));
2609
+ const cmds = uniq(rules.filter((r) => r.toolName === tool).map((r) => r.ruleContent));
2610
+ const readShow = (r) => readShown(r);
2611
+ const cmdShow = (r) => commandShown(r);
2612
+ const pathRaw = [...reads, ...dirs];
2613
+ const pathShow = (r) => reads.includes(r) ? readShow(r) : r;
2614
+ if (!distinctShown(pathRaw, pathShow) || !distinctShown(cmds, cmdShow)) return null;
2615
+ const R = cmds.map(cmdShow);
2616
+ const E = reads.map(readShow);
2617
+ const K = dirs;
2618
+ if (![...R, ...E, ...K].every(listItemAsIs)) return null;
2619
+ if (displayWidth([...R, ...E, ...K].join(" and ")) > CC_LABEL_MAX_WIDTH) return null;
2620
+ const hasDir = K.length > 0;
2621
+ const hasRead = E.length > 0;
2622
+ const hasCmd = R.length > 0;
2623
+ if (hasRead && !hasDir && !hasCmd) return CC_TEXT.readHead + joinAnd(E) + CC_TEXT.fromProject;
2624
+ if (!hasCmd && (hasDir || hasRead)) return CC_TEXT.alwaysAccessHead + joinAnd([...K, ...E]) + CC_TEXT.fromProject;
2625
+ if (hasCmd && !hasDir && !hasRead) {
2626
+ if (cwdShown === null) return null;
2627
+ return CC_TEXT.dontAskHead + joinAnd(R) + CC_TEXT.commands + " in " + cwdShown;
2628
+ }
2629
+ if (hasCmd) {
2630
+ const paths = [...K, ...E];
2631
+ if (paths.length === 1 && R.length === 1) return CC_TEXT.accessHead + paths[0] + CC_TEXT.and + " " + R[0] + CC_TEXT.commands;
2632
+ return CC_TEXT.allowHead + joinAnd(paths) + CC_TEXT.accessAnd + " " + joinAnd(R) + CC_TEXT.commands;
2633
+ }
2634
+ return null;
2635
+ }
2636
+ function projectSlug(p) {
2637
+ return p.replace(/[^a-zA-Z0-9]/g, "-");
2638
+ }
2639
+ function sessionRoot(cwd, transcriptPath) {
2640
+ if (typeof cwd !== "string" || !cwd || typeof transcriptPath !== "string" || !transcriptPath) return null;
2641
+ if (!shownAsIs(cwd) || /[\u0000-\u001f]/.test(cwd)) return null;
2642
+ const parts = transcriptPath.split(/[\\/]/);
2643
+ const dir2 = parts.length >= 2 ? parts[parts.length - 2] : "";
2644
+ const slug = projectSlug(cwd);
2645
+ if (slug.length <= 200 ? dir2 !== slug : !dir2.startsWith(`${slug.slice(0, 200)}-`)) return null;
2646
+ return cwd;
2647
+ }
2648
+ var CC_AUTO_LABEL = `${CC_TEXT.autoMode} ${CC_TEXT.autoModeNote}`;
2649
+ var CC_AUTO_DESC = "\u5141\u8BB8\u8FD9\u4E00\u6B21\uFF0C\u5E76\u628A\u6574\u4E2A\u4F1A\u8BDD\u5207\u5230\u81EA\u52A8\u6A21\u5F0F\uFF1A\u4E4B\u540E\u8FD9\u7C7B\u786E\u8BA4\u7531 Claude \u81EA\u5DF1\u5224\u65AD\u653E\u884C\uFF0C\u4E0D\u518D\u9010\u6761\u95EE\u4F60";
2650
+ var CC_AUTO_MODE_UPDATE = { type: "setMode", mode: "auto", destination: "session" };
2651
+ function yesRowNo(middle, action, opts = {}) {
2652
+ const options = [{ id: "allow", label: CC_TEXT.yes, kind: "allow" }];
2653
+ const actions = { allow: { decision: "allow" } };
2654
+ if (middle && action) {
2655
+ options.push(middle);
2656
+ actions[middle.id] = action;
2657
+ }
2658
+ if (opts.auto) {
2659
+ options.push({ id: "auto", label: CC_AUTO_LABEL, description: CC_AUTO_DESC, kind: "allow_session" });
2660
+ actions.auto = { decision: "allow", updatedPermissions: [{ ...CC_AUTO_MODE_UPDATE }] };
2661
+ }
2662
+ if (opts.noTell) options.push({ id: "deny", label: CC_TEXT.noTell, kind: "deny" });
2663
+ else options.push({ id: "deny", label: CC_TEXT.no, description: CC_TEXT.noTell, kind: "deny", input: true });
2664
+ actions.deny = { decision: "deny" };
2665
+ return { options, actions };
2666
+ }
2667
+ function claudeShellLabels(tool, sugg, auto, ctx = {}) {
2668
+ if (isObj(ctx.toolInput) && "_host" in ctx.toolInput) return null;
2669
+ const applies = shellApplies(sugg, tool);
2670
+ if (applies === null || applies.length === 0) return null;
2671
+ const mixed = applies.some((s) => s.type === "addDirectories" || s.rules?.some((r) => r.toolName !== tool));
2672
+ const cmds = uniq(applies.flatMap((s) => s.type === "addRules" ? s.rules : []).filter((r) => r.toolName === tool).map((r) => r.ruleContent));
2673
+ const autoOpt = tool === "Bash" && auto;
2674
+ if (mixed) {
2675
+ const label3 = shellRowLabel(applies, tool, null);
2676
+ if (label3 === null) return null;
2677
+ const kind2 = applies.some((s) => s.destination === "localSettings") ? "allow_always" : "allow_session";
2678
+ const id = cmds.length ? "always" : applies.some((s) => s.type === "addDirectories") ? "dir" : "read";
2679
+ return yesRowNo({ id, label: label3, kind: kind2 }, { decision: "allow", updatedPermissions: applies }, { auto: autoOpt });
2680
+ }
2681
+ if (tool === "PowerShell") return null;
2682
+ if (cmds.length === 1) {
2683
+ if (sugg.length !== 1) return null;
2684
+ const raw = sugg[0];
2685
+ if (!Array.isArray(raw.rules) || raw.rules.length !== 1) return null;
2686
+ const s = applies[0];
2687
+ const rules = s.rules;
2688
+ if (s.destination !== "localSettings" || rules.length !== 1) return null;
2689
+ const rc = rules[0].ruleContent;
2690
+ if (!isObj(raw.rules[0]) || raw.rules[0].toolName !== tool || raw.rules[0].ruleContent !== rc) return null;
2691
+ if (!rc.endsWith(" *") || rc.trim() === "*") return null;
2692
+ return yesRowNo(
2693
+ { id: "always", label: CC_TEXT.dontAskPrefix + rc, kind: "allow_always" },
2694
+ { decision: "allow", updatedPermissions: [addRulesOut([{ toolName: tool, ruleContent: rc }], "localSettings")] },
2695
+ { auto: autoOpt }
2696
+ );
2697
+ }
2698
+ const root = sessionRoot(ctx.cwd, ctx.transcriptPath);
2699
+ if (root === null) return null;
2700
+ const label2 = shellRowLabel(applies, tool, root);
2701
+ if (label2 === null) return null;
2702
+ const kind = applies.some((s) => s.destination === "localSettings") ? "allow_always" : "allow_session";
2703
+ return yesRowNo({ id: "always", label: label2, kind }, { decision: "allow", updatedPermissions: applies }, { auto: autoOpt });
2704
+ }
2705
+ function underDir(file3, dir2, platform) {
2706
+ const fold = platform === "darwin" || platform === "win32" ? (s) => s.toLowerCase() : (s) => s;
2707
+ return fold(file3).startsWith(fold(dir2.replace(/\/+$/, "")) + "/");
2708
+ }
2709
+ function claudeFileLabels(toolName, sugg, ctx = {}) {
2710
+ const read2 = toolName === "Read";
2711
+ if (read2 && ctx.permissionMode === "auto") return null;
2712
+ if (sugg.length === 0 || sugg.length > CC_SUGGESTIONS_MAX || !sugg.every(isObj)) return null;
2713
+ const sg = sugg;
2714
+ const file3 = isObj(ctx.toolInput) ? ctx.toolInput.file_path ?? ctx.toolInput.notebook_path : void 0;
2715
+ if (!read2 && typeof file3 === "string") {
2716
+ const platform = ctx.platform ?? process.platform;
2717
+ const home = ctx.home;
2718
+ const root = sessionRoot(ctx.cwd, ctx.transcriptPath);
2719
+ const absPosix = file3.startsWith("/") && !file3.split("/").includes("..");
2720
+ const inHome = !!home && absPosix && underDir(file3, `${home}/.claude`, platform);
2721
+ const inProject = !!root && absPosix && underDir(file3, `${root}/.claude`, platform);
2722
+ const claudeSegment = /(^|[\\/])\.claude([\\/]|$)/i.test(file3);
2723
+ if (claudeSegment && !inHome && !inProject) return null;
2724
+ if (inHome || inProject) {
2725
+ const content = inHome ? "~/.claude/**" : "/.claude/**";
2726
+ const want = { type: "addRules", rules: [{ toolName: "Edit", ruleContent: content }], behavior: "allow", destination: "session" };
2727
+ const s = sg.length === 1 ? sg[0] : null;
2728
+ const r = s && Array.isArray(s.rules) && s.rules.length === 1 && isObj(s.rules[0]) ? s.rules[0] : null;
2729
+ if (!s || s.type !== "addRules" || s.behavior !== "allow" || s.destination !== "session" || !r || r.toolName !== "Edit" || r.ruleContent !== content) return null;
2730
+ return yesRowNo(
2731
+ { id: "session", label: inHome ? CC_TEXT.claudeFolderHome : CC_TEXT.claudeFolderProject, kind: "allow_session" },
2732
+ { decision: "allow", updatedPermissions: [want] }
2733
+ );
2734
+ }
2735
+ }
2736
+ const rows = [];
2737
+ for (const s of sg) {
2738
+ if (s.destination !== "session") return null;
2739
+ if (s.type === "setMode") {
2740
+ if (read2 || s.mode !== "acceptEdits") return null;
2741
+ } else if (s.type === "addDirectories") {
2742
+ if (read2) return null;
2743
+ } else if (s.type === "addRules") {
2744
+ if (s.behavior !== "allow") return null;
2745
+ } else return null;
2746
+ }
2747
+ if (sg.filter((s) => s.type === "setMode").length > 1 || sg.filter((s) => s.type === "addDirectories").length > 1) return null;
2748
+ if (sg.some((s) => s.type === "setMode")) {
2749
+ rows.push({ label: CC_TEXT.switchHead + CC_MODE_TEXT.acceptEdits + CC_TEXT.forSession, applies: [{ type: "setMode", destination: "session", mode: "acceptEdits" }] });
2750
+ }
2751
+ const dirSugg = sg.find((s) => s.type === "addDirectories");
2752
+ if (dirSugg) {
2753
+ const dirsIn = Array.isArray(dirSugg.directories) ? dirSugg.directories : null;
2754
+ if (!dirsIn || dirsIn.some((d) => typeof d !== "string" || d.trim() === "")) return null;
2755
+ const dirs = uniq(dirsIn);
2756
+ if (dirs.length === 0 || !dirs.every(listItemAsIs) || !distinctShown(dirs, (d) => d)) return null;
2757
+ if (dirs.length <= CC_MERGE_MAX && displayWidth(dirs.join(", ")) <= CC_LABEL_MAX_WIDTH)
2758
+ rows.push({ label: CC_TEXT.alwaysAccessHead + dirs.join(", ") + CC_TEXT.forSession, applies: [{ type: "addDirectories", destination: "session", directories: dirs }] });
2759
+ }
2760
+ const ruleSuggs = sg.filter((s) => s.type === "addRules");
2761
+ if (ruleSuggs.length) {
2762
+ const applies = [];
2763
+ const reads = [];
2764
+ for (const s of ruleSuggs) {
2765
+ if (!Array.isArray(s.rules)) return null;
2766
+ const keep = [];
2767
+ for (const r of s.rules) {
2768
+ if (!isObj(r) || r.toolName !== "Read" || typeof r.ruleContent !== "string" || readShown(r.ruleContent) === null) return null;
2769
+ keep.push(ruleOut(r));
2770
+ reads.push(r.ruleContent);
2771
+ }
2772
+ if (keep.length) applies.push(addRulesOut(keep, s.destination));
2773
+ }
2774
+ if (reads.length === 0) return null;
2775
+ const u = uniq(reads);
2776
+ const shown = u.map((r) => readShown(r));
2777
+ if (!distinctShown(u, (r) => readShown(r)) || !shown.every(listItemAsIs)) return null;
2778
+ if (reads.length <= CC_MERGE_MAX && displayWidth(shown.join(" and ")) <= CC_LABEL_MAX_WIDTH)
2779
+ rows.push({ label: CC_TEXT.readHead + joinAnd(shown) + CC_TEXT.duringSession, applies });
2780
+ }
2781
+ if (rows.length === 0) return null;
2782
+ const label2 = rows.map((r) => r.label).join("; ");
2783
+ return yesRowNo({ id: "session", label: label2, kind: "allow_session" }, { decision: "allow", updatedPermissions: rows.flatMap((r) => r.applies) });
2784
+ }
2785
+ function claudeWebFetchLabels(sugg, ctx = {}) {
2786
+ if (sugg.length !== 1 || !isObj(sugg[0])) return null;
2787
+ const s = sugg[0];
2788
+ if (s.type !== "addRules" || s.behavior !== "allow" || s.destination !== "localSettings" || !Array.isArray(s.rules) || s.rules.length !== 1) return null;
2789
+ const r = s.rules[0];
2790
+ if (!isObj(r) || r.toolName !== "WebFetch" || typeof r.ruleContent !== "string" || !r.ruleContent.startsWith("domain:")) return null;
2791
+ const host = r.ruleContent.slice("domain:".length);
2792
+ const url = isObj(ctx.toolInput) ? ctx.toolInput.url : void 0;
2793
+ let urlHost = null;
2794
+ try {
2795
+ urlHost = typeof url === "string" ? new URL(url).hostname : null;
2796
+ } catch {
2797
+ urlHost = null;
2798
+ }
2799
+ if (!host || host !== urlHost || host.includes("*") || !shownAsIs(host)) return null;
2800
+ return yesRowNo({ id: "always", label: CC_TEXT.dontAskHead + host, kind: "allow_always" }, { decision: "allow", updatedPermissions: [addRulesOut([{ toolName: "WebFetch", ruleContent: r.ruleContent }], "localSettings")] }, { noTell: true });
2801
+ }
2802
+
2478
2803
  // src/daemon/gate/options.ts
2479
2804
  var OPTIONS_MAX = 16;
2480
2805
  var OPTION_LABEL_MAX = 2e3;
@@ -2514,95 +2839,40 @@ function checkOptions(set, limits = {}) {
2514
2839
  return { options: out, actions };
2515
2840
  }
2516
2841
  var CLAUDE_TEXT = {
2517
- yes: "Yes",
2518
- no: "No",
2519
- noInput: "No, and tell Claude what to do differently",
2842
+ yes: CC_TEXT.yes,
2843
+ no: CC_TEXT.no,
2844
+ noInput: CC_TEXT.noTell,
2520
2845
  /** 单条 Bash 前缀规则:`Yes, and don’t ask again for: <规则>`(注意是弯撇号 U+2019) */
2521
- dontAskPrefix: "Yes, and don\u2019t ask again for: ",
2846
+ dontAskPrefix: CC_TEXT.dontAskPrefix,
2522
2847
  /** 编辑类 setMode acceptEdits:整句作 label(101 字,用户拍板不拆;不含快捷键提示 `(shift+tab)`) */
2523
- acceptEdits: "Yes, and switch to accept edits (auto-approve file edits and common file commands) for this session",
2848
+ acceptEdits: CC_TEXT.switchHead + CC_MODE_TEXT.acceptEdits + CC_TEXT.forSession,
2524
2849
  /** Bash 的切 auto 模式(只在默认 / acceptEdits 模式下出现;非 workflow 来源时界面上带 ` · auto mode handles these prompts for you`) */
2525
- autoMode: "Yes, and switch to auto mode \xB7 auto mode handles these prompts for you",
2850
+ autoMode: CC_AUTO_LABEL,
2526
2851
  /** 设备上给「切 auto 模式」的说明(问题表 272:它会把整个会话切过去,要写清楚) */
2527
- autoModeDesc: "\u5141\u8BB8\u8FD9\u4E00\u6B21\uFF0C\u5E76\u628A\u6574\u4E2A\u4F1A\u8BDD\u5207\u5230\u81EA\u52A8\u6A21\u5F0F\uFF1A\u4E4B\u540E\u8FD9\u7C7B\u786E\u8BA4\u7531 Claude \u81EA\u5DF1\u5224\u65AD\u653E\u884C\uFF0C\u4E0D\u518D\u9010\u6761\u95EE\u4F60",
2528
- /**
2529
- * Bash 碰到工作区外的目录(2.1.295 实测,问题表 272):建议是 addDirectories(session) + setMode acceptEdits(session),
2530
- * 界面合成一项 `Yes, and always allow access to <目录> from this project`,选中两条一起生效
2531
- */
2532
- dirAccessHead: "Yes, and always allow access to ",
2533
- dirAccessTail: " from this project"
2852
+ autoModeDesc: CC_AUTO_DESC,
2853
+ /** Bash 碰到工作区外的目录(2.1.295 实测,问题表 272):`Yes, and always allow access to <目录> from this project` */
2854
+ dirAccessHead: CC_TEXT.alwaysAccessHead,
2855
+ dirAccessTail: CC_TEXT.fromProject,
2856
+ /** Bash 读工作区外的路径(问题表 278,2.1.295 实测 `ls /tmp | wc -l`):`Yes, allow reading from <目录> from this project` */
2857
+ readAccessHead: CC_TEXT.readHead
2534
2858
  };
2535
- var CLAUDE_AUTO_MODE_UPDATE = { type: "setMode", mode: "auto", destination: "session" };
2536
- var CLAUDE_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
2537
- function claudeYesNo(middle, action, auto = false) {
2538
- const options = [{ id: "allow", label: CLAUDE_TEXT.yes, kind: "allow" }];
2539
- const actions = { allow: { decision: "allow" } };
2540
- if (middle && action) {
2541
- options.push(middle);
2542
- actions[middle.id] = action;
2543
- }
2544
- if (auto) {
2545
- options.push({ id: "auto", label: CLAUDE_TEXT.autoMode, description: CLAUDE_TEXT.autoModeDesc, kind: "allow_session" });
2546
- actions.auto = { decision: "allow", updatedPermissions: [{ ...CLAUDE_AUTO_MODE_UPDATE }] };
2547
- }
2548
- options.push({ id: "deny", label: CLAUDE_TEXT.no, description: CLAUDE_TEXT.noInput, kind: "deny", input: true });
2549
- actions.deny = { decision: "deny" };
2550
- return { options, actions };
2551
- }
2552
- function claudeDirAccess(sugg) {
2553
- if (sugg.length < 1 || sugg.length > 2) return null;
2554
- let dir2 = null;
2555
- let mode = 0;
2556
- for (const x of sugg) {
2557
- const s = x;
2558
- if (s && s.type === "addDirectories" && s.destination === "session" && Array.isArray(s.directories) && s.directories.length === 1 && typeof s.directories[0] === "string" && s.directories[0]) {
2559
- if (dir2 !== null) return null;
2560
- dir2 = s.directories[0];
2561
- } else if (s && s.type === "setMode" && s.mode === "acceptEdits" && s.destination === "session") mode++;
2562
- else return null;
2563
- }
2564
- if (!dir2 || mode > 1 || /[\u0000-\u001f\u007f]/.test(dir2)) return null;
2565
- return dir2;
2566
- }
2859
+ var CLAUDE_FILE_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit", "Read"]);
2567
2860
  function claudeOptions(toolName, suggestions, ctx = {}) {
2568
- const sugg = suggestions === void 0 || suggestions === null ? [] : suggestions;
2569
- if (!Array.isArray(sugg)) return null;
2570
- if (toolName === "Bash") {
2571
- const auto = ctx.autoModeAllowed === true && (ctx.permissionMode === "default" || ctx.permissionMode === "acceptEdits");
2572
- if (sugg.length === 0) return checkOptions(claudeYesNo(null, void 0, auto));
2573
- const dir2 = claudeDirAccess(sugg);
2574
- if (dir2) {
2575
- return checkOptions(
2576
- claudeYesNo(
2577
- { id: "dir", label: CLAUDE_TEXT.dirAccessHead + dir2 + CLAUDE_TEXT.dirAccessTail, kind: "allow_session" },
2578
- { decision: "allow", updatedPermissions: sugg },
2579
- auto
2580
- )
2581
- );
2582
- }
2583
- if (sugg.length !== 1) return null;
2584
- const s = sugg[0];
2585
- if (!s || s.type !== "addRules" || s.behavior !== "allow" || s.destination !== "localSettings") return null;
2586
- const rules = Array.isArray(s.rules) ? s.rules : [];
2587
- if (rules.length !== 1 || rules[0]?.toolName !== "Bash") return null;
2588
- const rc = rules[0].ruleContent;
2589
- if (typeof rc !== "string" || !rc.endsWith(" *") || rc.trim() === "*") return null;
2590
- return checkOptions(
2591
- claudeYesNo({ id: "always", label: CLAUDE_TEXT.dontAskPrefix + rc, kind: "allow_always" }, { decision: "allow", updatedPermissions: [s] }, auto)
2592
- );
2593
- }
2594
- if (CLAUDE_EDIT_TOOLS.has(toolName)) {
2595
- if (sugg.length !== 1) return null;
2596
- const s = sugg[0];
2597
- if (!s || s.type !== "setMode" || s.mode !== "acceptEdits" || s.destination !== "session") return null;
2598
- return checkOptions(
2599
- claudeYesNo(
2600
- { id: "session", label: CLAUDE_TEXT.acceptEdits, kind: "allow_session" },
2601
- { decision: "allow", updatedPermissions: [s] }
2602
- )
2603
- );
2861
+ const fallback = (auto) => {
2862
+ const set = checkOptions(yesRowNo(null, null, { auto }));
2863
+ return set && Array.isArray(suggestions) && suggestions.length > 0 ? { ...set, pcAllowAmbiguous: true } : set;
2864
+ };
2865
+ const lctx = { cwd: ctx.cwd, toolInput: ctx.toolInput, transcriptPath: ctx.transcriptPath, permissionMode: ctx.permissionMode, home: ctx.home ?? homedir3(), platform: ctx.platform };
2866
+ if (toolName === "Bash" || toolName === "PowerShell") {
2867
+ const auto = toolName === "Bash" && Array.isArray(suggestions) && ctx.autoModeAllowed === true && (ctx.permissionMode === "default" || ctx.permissionMode === "acceptEdits");
2868
+ if (!Array.isArray(suggestions)) return fallback(false);
2869
+ if (suggestions.length === 0) return fallback(auto);
2870
+ return checkOptions(claudeShellLabels(toolName, suggestions, auto, lctx)) ?? fallback(auto);
2604
2871
  }
2605
- return null;
2872
+ const sugg = Array.isArray(suggestions) ? suggestions : [];
2873
+ if (CLAUDE_FILE_TOOLS.has(toolName)) return checkOptions(claudeFileLabels(toolName, sugg, lctx)) ?? fallback(false);
2874
+ if (toolName === "WebFetch") return checkOptions(claudeWebFetchLabels(sugg, lctx)) ?? fallback(false);
2875
+ return fallback(false);
2606
2876
  }
2607
2877
  var CODEX_TEXT = {
2608
2878
  mcpAllow: "Allow",
@@ -3747,7 +4017,7 @@ function resolveAlias(sessionId, now = Date.now()) {
3747
4017
  // src/wrap/shim.ts
3748
4018
  import { execFile as execFile3, execFileSync as execFileSync7 } from "child_process";
3749
4019
  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";
3750
- import { homedir as homedir3 } from "os";
4020
+ import { homedir as homedir4 } from "os";
3751
4021
  import { delimiter, join as join15, resolve as resolve4 } from "path";
3752
4022
  var SHIM_FALLBACK_EXIT = 213;
3753
4023
  var WIN_SHIM_ENABLED = true;
@@ -4073,7 +4343,7 @@ function psWinWhere(exec = execFileSync7) {
4073
4343
  function defaultShimEnv(nodePath, cliPath) {
4074
4344
  const env = process.env;
4075
4345
  const isolated = !!env.VITEST || !!env.DESKBUDDY_HOME;
4076
- const rcHome = env.DESKBUDDY_RC_HOME || (isolated ? null : homedir3());
4346
+ const rcHome = env.DESKBUDDY_RC_HOME || (isolated ? null : homedir4());
4077
4347
  return {
4078
4348
  platform: process.platform,
4079
4349
  binDir: shimDir(),
@@ -4497,11 +4767,11 @@ function launchPending(runId) {
4497
4767
  // src/core/title.ts
4498
4768
  import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3, readFileSync as readFileSync20, readSync as readSync3, statSync as statSync7 } from "fs";
4499
4769
  import { createRequire as createRequire2 } from "module";
4500
- import { homedir as homedir5 } from "os";
4770
+ import { homedir as homedir6 } from "os";
4501
4771
  import { basename as basename3, dirname as dirname10, isAbsolute, join as join18 } from "path";
4502
4772
 
4503
4773
  // src/core/dirFilter.ts
4504
- import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
4774
+ import { homedir as homedir5, tmpdir as tmpdir2 } from "os";
4505
4775
  import { posix, win32 as win323 } from "path";
4506
4776
  function norm(p, win) {
4507
4777
  if (win) return win323.resolve(p).replace(/[\\/]+$/, "").toLowerCase();
@@ -4514,7 +4784,7 @@ function isAutoWorkspace(p, opts = {}) {
4514
4784
  if (!p) return false;
4515
4785
  const win = (opts.platform ?? process.platform) === "win32";
4516
4786
  const P = win ? win323 : posix;
4517
- const home = norm(opts.home ?? homedir4(), win);
4787
+ const home = norm(opts.home ?? homedir5(), win);
4518
4788
  const full = norm(p, win);
4519
4789
  const name = P.basename(full);
4520
4790
  const parent = P.dirname(full);
@@ -4527,7 +4797,7 @@ function isReportableDir(p, opts = {}) {
4527
4797
  const P = win ? win323 : posix;
4528
4798
  const full = norm(p, win);
4529
4799
  if (full === norm(P.parse(P.resolve(p)).root, win)) return false;
4530
- if (full === norm(opts.home ?? homedir4(), win)) return false;
4800
+ if (full === norm(opts.home ?? homedir5(), win)) return false;
4531
4801
  const tmps = [opts.tmp ?? tmpdir2()];
4532
4802
  if (!win) tmps.push("/tmp", "/private/tmp", "/var/folders", "/private/var/folders");
4533
4803
  for (const t of tmps) if (t && isUnder(full, norm(t, win), win)) return false;
@@ -4536,6 +4806,7 @@ function isReportableDir(p, opts = {}) {
4536
4806
 
4537
4807
  // src/core/title.ts
4538
4808
  var TRANSCRIPT_TAIL_BYTES = 64 * 1024;
4809
+ var GIT_LOOKUP_MAX_UP = 5;
4539
4810
  var SESSION_TITLE_MAX = 100;
4540
4811
  function cleanTitle(text) {
4541
4812
  if (typeof text !== "string") return "";
@@ -4543,9 +4814,21 @@ function cleanTitle(text) {
4543
4814
  return Array.from(flat).slice(0, SESSION_TITLE_MAX).join("").trimEnd();
4544
4815
  }
4545
4816
  var requireHere = createRequire2(import.meta.url);
4817
+ function loadNodeSqlite() {
4818
+ const orig = process.emitWarning;
4819
+ process.emitWarning = function(...args) {
4820
+ if (String(args[0] ?? "").includes("SQLite")) return;
4821
+ return orig.apply(process, args);
4822
+ };
4823
+ try {
4824
+ return requireHere("node:sqlite");
4825
+ } finally {
4826
+ process.emitWarning = orig;
4827
+ }
4828
+ }
4546
4829
  var QODER_DATA_DIRS = { qoder_cn: "com.qodercn.app.stable", qoder: "com.qoder.app.stable" };
4547
4830
  var QODER_APP_DIR_ENV = { qoder_cn: "DESKBUDDY_QODER_CN_APP_DIR", qoder: "DESKBUDDY_QODER_APP_DIR" };
4548
- function qoderDbPaths(tool, platform = process.platform, home = homedir5(), env = process.env) {
4831
+ function qoderDbPaths(tool, platform = process.platform, home = homedir6(), env = process.env) {
4549
4832
  let root;
4550
4833
  if (platform === "darwin") root = join18(home, "Library", "Application Support");
4551
4834
  else if (platform === "win32") root = env.APPDATA || join18(home, "AppData", "Roaming");
@@ -4554,11 +4837,157 @@ function qoderDbPaths(tool, platform = process.platform, home = homedir5(), env
4554
4837
  const tools = one ? [tool] : ["qoder_cn", "qoder"];
4555
4838
  return tools.map((t) => join18(env[QODER_APP_DIR_ENV[t] ?? ""] || join18(root, QODER_DATA_DIRS[t] ?? ""), "main.sqlite"));
4556
4839
  }
4840
+ function readQoderSessionTitle(sessionId, paths = qoderDbPaths(null), load = loadNodeSqlite) {
4841
+ if (!sessionId) return null;
4842
+ const existing = paths.filter((p) => existsSync15(p));
4843
+ if (existing.length === 0) return null;
4844
+ let mod;
4845
+ try {
4846
+ mod = load();
4847
+ } catch {
4848
+ return null;
4849
+ }
4850
+ for (const p of existing) {
4851
+ let db;
4852
+ try {
4853
+ db = new mod.DatabaseSync(p, { readOnly: true });
4854
+ const row = db.prepare("select title from chat_sessions where session_id = ?").get(sessionId);
4855
+ const t = cleanTitle(row?.title);
4856
+ if (t) return t;
4857
+ } catch {
4858
+ } finally {
4859
+ try {
4860
+ db?.close();
4861
+ } catch {
4862
+ }
4863
+ }
4864
+ }
4865
+ return null;
4866
+ }
4867
+ function readTailLines(path, bytes) {
4868
+ let fd;
4869
+ try {
4870
+ const size = statSync7(path).size;
4871
+ if (size <= 0) return [];
4872
+ const len = Math.min(size, bytes);
4873
+ const buf = Buffer.alloc(len);
4874
+ fd = openSync3(path, "r");
4875
+ readSync3(fd, buf, 0, len, size - len);
4876
+ return buf.toString("utf8").split("\n");
4877
+ } catch {
4878
+ return [];
4879
+ } finally {
4880
+ if (fd !== void 0) {
4881
+ try {
4882
+ closeSync3(fd);
4883
+ } catch {
4884
+ }
4885
+ }
4886
+ }
4887
+ }
4888
+ function readAiTitle(transcriptPath) {
4889
+ if (!transcriptPath) return null;
4890
+ const lines = readTailLines(transcriptPath, TRANSCRIPT_TAIL_BYTES);
4891
+ for (let i = lines.length - 1; i >= 0; i--) {
4892
+ const line = lines[i];
4893
+ if (!line.includes('"ai-title"')) continue;
4894
+ try {
4895
+ const obj = JSON.parse(line);
4896
+ if (obj?.type === "ai-title") {
4897
+ const title = String(obj.aiTitle ?? "").trim();
4898
+ if (title !== "") return title;
4899
+ }
4900
+ } catch {
4901
+ }
4902
+ }
4903
+ return null;
4904
+ }
4905
+ function readCodexThreadName(sessionId, home) {
4906
+ if (!sessionId) return null;
4907
+ const indexPath = join18(home || codexHome(), "session_index.jsonl");
4908
+ const lines = readTailLines(indexPath, TRANSCRIPT_TAIL_BYTES);
4909
+ for (let i = lines.length - 1; i >= 0; i--) {
4910
+ const line = lines[i];
4911
+ if (!line.includes(sessionId)) continue;
4912
+ try {
4913
+ const obj = JSON.parse(line);
4914
+ if (obj?.id === sessionId) {
4915
+ const name = String(obj.thread_name ?? "").trim();
4916
+ if (name !== "") return name;
4917
+ }
4918
+ } catch {
4919
+ }
4920
+ }
4921
+ return null;
4922
+ }
4923
+ function readGitHead(dir2) {
4924
+ try {
4925
+ const dotGit = join18(dir2, ".git");
4926
+ let headPath = join18(dotGit, "HEAD");
4927
+ if (!statSync7(dotGit).isDirectory()) {
4928
+ const m = /^gitdir:\s*(.+)$/m.exec(readFileSync20(dotGit, "utf8"));
4929
+ if (!m) return null;
4930
+ const gitdir = m[1].trim();
4931
+ headPath = join18(isAbsolute(gitdir) ? gitdir : join18(dir2, gitdir), "HEAD");
4932
+ }
4933
+ return readFileSync20(headPath, "utf8").trim();
4934
+ } catch {
4935
+ return null;
4936
+ }
4937
+ }
4938
+ function readGitBranch(cwd, maxUp = GIT_LOOKUP_MAX_UP) {
4939
+ if (!cwd) return null;
4940
+ let dir2 = cwd;
4941
+ for (let up = 0; up <= maxUp; up++) {
4942
+ const head = readGitHead(dir2);
4943
+ if (head !== null) {
4944
+ const ref = /^ref:\s*refs\/heads\/(.+)$/.exec(head);
4945
+ if (!ref) return null;
4946
+ return ref[1].trim() || null;
4947
+ }
4948
+ const parent = dirname10(dir2);
4949
+ if (parent === dir2) break;
4950
+ dir2 = parent;
4951
+ }
4952
+ return null;
4953
+ }
4954
+ function resolveTitle(sources, ctx) {
4955
+ for (const source of sources ?? []) {
4956
+ let value = null;
4957
+ switch (source) {
4958
+ case "cc-ai-title":
4959
+ value = readAiTitle(ctx.transcriptPath);
4960
+ break;
4961
+ case "codex-thread-name":
4962
+ value = readCodexThreadName(ctx.sessionId, ctx.codexHome);
4963
+ break;
4964
+ case "git-branch":
4965
+ value = readGitBranch(ctx.cwd);
4966
+ break;
4967
+ case "first-prompt":
4968
+ value = ctx.firstPrompt || null;
4969
+ break;
4970
+ case "qoder-session-title":
4971
+ value = readQoderSessionTitle(ctx.sessionId, ctx.qoderDbPaths ?? qoderDbPaths(ctx.tool), ctx.loadSqlite);
4972
+ break;
4973
+ case "oc-session-title":
4974
+ value = typeof ctx.ocSessionTitle === "string" ? ctx.ocSessionTitle.trim() || null : null;
4975
+ break;
4976
+ case "project":
4977
+ value = ctx.cwd && !isAutoWorkspace(ctx.cwd) ? basename3(ctx.cwd) || null : null;
4978
+ break;
4979
+ default:
4980
+ value = null;
4981
+ }
4982
+ if (value) return value;
4983
+ }
4984
+ return "";
4985
+ }
4557
4986
 
4558
4987
  // src/daemon/locate.ts
4559
4988
  import { execFile as execFile4, execFileSync as execFileSync9 } from "child_process";
4560
4989
  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";
4561
- import { homedir as homedir6 } from "os";
4990
+ import { homedir as homedir7 } from "os";
4562
4991
  import { delimiter as delimiter2, dirname as dirname11, join as join20, win32 as win325 } from "path";
4563
4992
 
4564
4993
  // src/core/agentEnv.ts
@@ -4856,7 +5285,7 @@ function qoderWorker(d, worker, appBin) {
4856
5285
  return { file: d.nodePath, prefixArgs: [worker] };
4857
5286
  }
4858
5287
  var defaultLocateDeps = () => ({
4859
- home: homedir6(),
5288
+ home: homedir7(),
4860
5289
  path: process.env.PATH ?? "",
4861
5290
  nodePath: process.execPath,
4862
5291
  isExecutable: (p) => {
@@ -5540,7 +5969,7 @@ function markElectronBroken(v = true) {
5540
5969
  electronBroken = v;
5541
5970
  }
5542
5971
  var requireHere2 = createRequire3(import.meta.url);
5543
- function loadNodeSqlite() {
5972
+ function loadNodeSqlite2() {
5544
5973
  const orig = process.emitWarning;
5545
5974
  process.emitWarning = function(...args) {
5546
5975
  if (String(args[0] ?? "").includes("SQLite")) return;
@@ -5626,7 +6055,7 @@ function savePendingFile(jobs) {
5626
6055
  var defaultWbAppDbDeps = () => ({
5627
6056
  dbPath: () => workbuddyDbPath(),
5628
6057
  configDir: () => dirname12(workbuddySettingsPath()),
5629
- loadSqlite: loadNodeSqlite,
6058
+ loadSqlite: loadNodeSqlite2,
5630
6059
  electron: () => defaultWbElectron(),
5631
6060
  runElectron: (bin, script, input) => new Promise((resolve7, reject) => {
5632
6061
  const env = { ...process.env, ELECTRON_RUN_AS_NODE: "1" };
@@ -8535,7 +8964,7 @@ function runHook(node, input, agentPid, tool = "dumate") {
8535
8964
 
8536
8965
  // src/daemon/qoderApp/keeper.ts
8537
8966
  import { existsSync as existsSync20, mkdirSync as mkdirSync22, readdirSync as readdirSync12, readFileSync as readFileSync25, renameSync as renameSync16, writeFileSync as writeFileSync22 } from "fs";
8538
- import { homedir as homedir7 } from "os";
8967
+ import { homedir as homedir8 } from "os";
8539
8968
  import { join as join24, win32 as win327 } from "path";
8540
8969
  var WAKE_LAUNCH_GAP_MS2 = 60 * 1e3;
8541
8970
  var RESTART_GAP_MS2 = 30 * 60 * 1e3;
@@ -8836,7 +9265,7 @@ var QoderCdpKeeper = class {
8836
9265
  }
8837
9266
  if (this.#platform() !== "darwin") return null;
8838
9267
  const name = this.#d.brand.macApp.split("/").pop() ?? "";
8839
- for (const p of [this.#d.brand.macApp, join24(homedir7(), "Applications", name)]) if (existsSync20(p)) return p;
9268
+ for (const p of [this.#d.brand.macApp, join24(homedir8(), "Applications", name)]) if (existsSync20(p)) return p;
8840
9269
  return null;
8841
9270
  }
8842
9271
  /** 一轮:健康检查 → 活着核对属主。🔴 平时不重启 App;只有端口无响应满 HUNG_RESTART_MS 时按节流与在场规则重启 */
@@ -10272,12 +10701,12 @@ function migrateLegacyQoder(out, detect = () => detectTools()) {
10272
10701
  // src/daemon/loginGuide.ts
10273
10702
  import { execFile as execFile9, execFileSync as execFileSync13 } from "child_process";
10274
10703
  import { chmodSync as chmodSync9, existsSync as existsSync27, mkdirSync as mkdirSync26, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
10275
- import { homedir as homedir9 } from "os";
10704
+ import { homedir as homedir10 } from "os";
10276
10705
  import { join as join35 } from "path";
10277
10706
 
10278
10707
  // src/daemon/executor.ts
10279
10708
  import { execFile as execFile7, execFileSync as execFileSync11 } from "child_process";
10280
- import { homedir as homedir8 } from "os";
10709
+ import { homedir as homedir9 } from "os";
10281
10710
  import { join as join33 } from "path";
10282
10711
 
10283
10712
  // src/core/codebuddyDirs.ts
@@ -10371,7 +10800,7 @@ var TOOL_BINARY = {
10371
10800
  opencode: "opencode",
10372
10801
  deepseek_harness: "dsh"
10373
10802
  };
10374
- function buildSpawnPlan(cmd, cwd, gate, home = homedir8(), configDir, platform = process.platform) {
10803
+ function buildSpawnPlan(cmd, cwd, gate, home = homedir9(), configDir, platform = process.platform) {
10375
10804
  const file3 = TOOL_BINARY[cmd.tool];
10376
10805
  if (!file3) return null;
10377
10806
  switch (cmd.tool) {
@@ -10951,7 +11380,7 @@ var defaultCheckDeps = () => ({
10951
11380
  run: defaultProbeRun,
10952
11381
  env: process.env,
10953
11382
  childPath: () => childPath(),
10954
- home: homedir9(),
11383
+ home: homedir10(),
10955
11384
  codexConfig: () => {
10956
11385
  try {
10957
11386
  return readFileSync30(join35(codexHome(), "config.toml"), "utf8");
@@ -10963,7 +11392,7 @@ var defaultCheckDeps = () => ({
10963
11392
  workbuddyKind: () => locateWorkbuddy()?.kind ?? null,
10964
11393
  // 与设备任务唤起 App 同一个 locate(locateWorkbuddyAppExe:注册表卸载项 / App Paths / 开始菜单快捷方式…);App 自带 CLI 找得到也算
10965
11394
  workbuddyAppInstalled: () => locateWorkbuddyAppExe() !== null || locateWorkbuddyApp() !== null,
10966
- workbuddyAuthFile: () => workbuddyAuthFile(homedir9(), process.platform, process.env.LOCALAPPDATA ?? ""),
11395
+ workbuddyAuthFile: () => workbuddyAuthFile(homedir10(), process.platform, process.env.LOCALAPPDATA ?? ""),
10967
11396
  exists: (p) => existsSync27(p)
10968
11397
  });
10969
11398
  function daemonCheckDeps(base = defaultLocateDeps(), exeHintsAsync = winWorkbuddyLocatorHints) {
@@ -10986,7 +11415,7 @@ var SAFE_ARGS = /* @__PURE__ */ new Set(["auth", "login"]);
10986
11415
  var defaultCommandDeps = () => ({
10987
11416
  locate: (tool) => locate(tool),
10988
11417
  locateWorkbuddyTui: () => locateWorkbuddyTui(),
10989
- home: homedir9()
11418
+ home: homedir10()
10990
11419
  });
10991
11420
  var WORKBUDDY_LOGIN_HINT = "\uFF08\u5982\u679C\u5148\u5F39\u51FA\u4FE1\u4EFB\u6846\uFF0C\u9009 1 \u56DE\u8F66\uFF1B\u51FA\u73B0 Select login method \u65F6\u9009 Log in via Chinese Site \u56DE\u8F66\uFF0C\u5230\u6D4F\u89C8\u5668\u5B8C\u6210\u767B\u5F55\uFF1B\u82E5\u53EA\u770B\u5230\u8F93\u5165\u6846\uFF0C\u8F93\u5165 /login \u56DE\u8F66\uFF09";
10992
11421
  var WORKBUDDY_NEED_STANDALONE = "\u53EA\u88C5\u4E86 WorkBuddy App\uFF0C\u5B83\u81EA\u5E26\u7684\u547D\u4EE4\u884C\u7528\u4E0D\u4E86 App \u7684\u767B\u5F55\uFF1B\u8BBE\u5907\u4E0A\u65B0\u5EFA / \u56DE\u590D\u4EFB\u52A1\u9700\u8981\u72EC\u7ACB\u7248\u547D\u4EE4\u884C\uFF08\u8FD0\u884C deskbuddy workbuddy-setup \u5B89\u88C5\uFF09";
@@ -11112,7 +11541,7 @@ var defaultLoginOpenDeps = () => ({
11112
11541
  });
11113
11542
  async function installCodebuddyHooks(log) {
11114
11543
  try {
11115
- const { installTools: installTools2 } = await import("./enable-AF2A67ZD.js");
11544
+ const { installTools: installTools2 } = await import("./enable-XTCQ6IFF.js");
11116
11545
  installTools2(["workbuddy"], () => {
11117
11546
  }, null, { auto: true });
11118
11547
  } catch (e) {
@@ -11626,7 +12055,7 @@ function defaultOfferDeps(log) {
11626
12055
  }),
11627
12056
  openLogin: () => defaultOpenLogin(platform),
11628
12057
  installHooks: async () => {
11629
- const { installTools: installTools2 } = await import("./enable-AF2A67ZD.js");
12058
+ const { installTools: installTools2 } = await import("./enable-XTCQ6IFF.js");
11630
12059
  installTools2(["workbuddy"], (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`), null, { auto: true });
11631
12060
  },
11632
12061
  log: (l) => log(`[WorkBuddy \u72EC\u7ACB\u7248] ${l}`),
@@ -11962,6 +12391,7 @@ export {
11962
12391
  detectTools,
11963
12392
  loadRegistry,
11964
12393
  refreshRegistry,
12394
+ titleSources,
11965
12395
  waitModeFor,
11966
12396
  shQuote,
11967
12397
  winCmdPath,
@@ -12002,8 +12432,10 @@ export {
12002
12432
  isAppSession,
12003
12433
  stateDir,
12004
12434
  readState,
12435
+ renameRetrying,
12005
12436
  writeState,
12006
12437
  retireState,
12438
+ removeState,
12007
12439
  STALE_NO_PID_LOG,
12008
12440
  readAliveStates,
12009
12441
  writeNotice,
@@ -12045,6 +12477,7 @@ export {
12045
12477
  isReportableDir,
12046
12478
  cleanTitle,
12047
12479
  qoderDbPaths,
12480
+ resolveTitle,
12048
12481
  findWbTranscript,
12049
12482
  wbTranscriptInfo,
12050
12483
  registerWorkbuddySession,