adhdev 0.8.28 → 0.8.30

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.
package/dist/cli/index.js CHANGED
@@ -649,17 +649,17 @@ function checkPathExists(paths) {
649
649
  return null;
650
650
  }
651
651
  async function detectIDEs(providerLoader) {
652
- const os24 = (0, import_os2.platform)();
652
+ const os25 = (0, import_os2.platform)();
653
653
  const results = [];
654
654
  for (const def of getMergedDefinitions()) {
655
655
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
656
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os24] || []) || []);
656
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os25] || []) || []);
657
657
  let resolvedCli = cliPath;
658
- if (!resolvedCli && appPath && os24 === "darwin") {
658
+ if (!resolvedCli && appPath && os25 === "darwin") {
659
659
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
660
660
  if ((0, import_fs3.existsSync)(bundledCli)) resolvedCli = bundledCli;
661
661
  }
662
- if (!resolvedCli && appPath && os24 === "win32") {
662
+ if (!resolvedCli && appPath && os25 === "win32") {
663
663
  const { dirname: dirname9 } = await import("path");
664
664
  const appDir = dirname9(appPath);
665
665
  const candidates = [
@@ -676,7 +676,7 @@ async function detectIDEs(providerLoader) {
676
676
  }
677
677
  }
678
678
  }
679
- const installed = os24 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
679
+ const installed = os25 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
680
680
  const version2 = resolvedCli ? getIdeVersion(resolvedCli) : null;
681
681
  results.push({
682
682
  id: def.id,
@@ -2595,6 +2595,62 @@ var init_control_effects = __esm({
2595
2595
  });
2596
2596
 
2597
2597
  // ../../oss/packages/daemon-core/src/config/chat-history.ts
2598
+ function normalizeHistoryComparable(text) {
2599
+ return String(text || "").replace(/\s+/g, " ").trim();
2600
+ }
2601
+ function cleanupHistoryContent(agentType, role, content) {
2602
+ let value = String(content || "").replace(/\r\n/g, "\n").trim();
2603
+ if (!value) return "";
2604
+ if (agentType === "codex-cli" && role === "assistant") {
2605
+ const filtered = value.split("\n").filter((line) => !CODEX_STARTER_PROMPT_RE.test(line.trim())).join("\n").replace(/\n{3,}/g, "\n\n").trim();
2606
+ value = filtered;
2607
+ }
2608
+ return value;
2609
+ }
2610
+ function buildHistoryMessageHash(agentType, message) {
2611
+ if (message.historyDedupKey) return message.historyDedupKey;
2612
+ const cleaned = cleanupHistoryContent(agentType, message.role, message.content);
2613
+ return `${message.kind || "standard"}:${message.role}:${message.receivedAt || 0}:${normalizeHistoryComparable(cleaned)}`;
2614
+ }
2615
+ function buildHistoryMessageSignature(agentType, message) {
2616
+ const cleaned = cleanupHistoryContent(agentType, message.role, message.content);
2617
+ return `${message.kind || "standard"}:${message.role}:${normalizeHistoryComparable(cleaned)}`;
2618
+ }
2619
+ function isAdjacentHistoryDuplicate(agentType, previous, next) {
2620
+ if (!previous || !next) return false;
2621
+ return buildHistoryMessageSignature(agentType, previous) === buildHistoryMessageSignature(agentType, next);
2622
+ }
2623
+ function collapseReplayAssistantTurns(agentType, messages) {
2624
+ if (agentType !== "codex-cli") return messages;
2625
+ const collapsed = [];
2626
+ let sawAssistantSinceLastUser = false;
2627
+ for (const message of messages) {
2628
+ if (message.role === "user") {
2629
+ sawAssistantSinceLastUser = false;
2630
+ collapsed.push(message);
2631
+ continue;
2632
+ }
2633
+ if (message.role === "assistant") {
2634
+ if (sawAssistantSinceLastUser) continue;
2635
+ sawAssistantSinceLastUser = true;
2636
+ collapsed.push(message);
2637
+ continue;
2638
+ }
2639
+ collapsed.push(message);
2640
+ }
2641
+ return collapsed;
2642
+ }
2643
+ function sanitizeHistoryMessage(agentType, message) {
2644
+ if (!message || message.role !== "user" && message.role !== "assistant" && message.role !== "system") {
2645
+ return null;
2646
+ }
2647
+ const content = cleanupHistoryContent(agentType, message.role, message.content);
2648
+ if (!content) return null;
2649
+ return {
2650
+ ...message,
2651
+ content
2652
+ };
2653
+ }
2598
2654
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId) {
2599
2655
  try {
2600
2656
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -2609,23 +2665,37 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId) {
2609
2665
  return true;
2610
2666
  }).sort().reverse();
2611
2667
  const allMessages = [];
2612
- const needed = offset + limit + 1;
2668
+ const seen = /* @__PURE__ */ new Set();
2613
2669
  for (const file2 of files) {
2614
- if (allMessages.length >= needed) break;
2615
2670
  const filePath = path7.join(dir, file2);
2616
2671
  const content = fs3.readFileSync(filePath, "utf-8");
2617
2672
  const lines = content.trim().split("\n").filter(Boolean);
2618
- for (let i = lines.length - 1; i >= 0; i--) {
2619
- if (allMessages.length >= needed) break;
2673
+ for (let i = 0; i < lines.length; i++) {
2620
2674
  try {
2621
- allMessages.push(JSON.parse(lines[i]));
2675
+ const parsed = JSON.parse(lines[i]);
2676
+ const sanitizedMessage = sanitizeHistoryMessage(agentType, parsed);
2677
+ if (!sanitizedMessage) continue;
2678
+ const hash2 = buildHistoryMessageHash(agentType, sanitizedMessage);
2679
+ if (seen.has(hash2)) continue;
2680
+ seen.add(hash2);
2681
+ allMessages.push(sanitizedMessage);
2622
2682
  } catch {
2623
2683
  }
2624
2684
  }
2625
2685
  }
2626
- const sliced = allMessages.slice(offset, offset + limit);
2627
- const hasMore = allMessages.length > offset + limit;
2628
- sliced.reverse();
2686
+ allMessages.sort((a, b) => a.receivedAt - b.receivedAt);
2687
+ const chronological = [];
2688
+ let lastTurn = null;
2689
+ for (const message of allMessages) {
2690
+ const previous = chronological[chronological.length - 1];
2691
+ if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
2692
+ if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
2693
+ chronological.push(message);
2694
+ if (message.role !== "system") lastTurn = message;
2695
+ }
2696
+ const collapsed = collapseReplayAssistantTurns(agentType, chronological);
2697
+ const sliced = collapsed.slice(offset, offset + limit);
2698
+ const hasMore = collapsed.length > offset + limit;
2629
2699
  return { messages: sliced, hasMore };
2630
2700
  } catch {
2631
2701
  return { messages: [], hasMore: false };
@@ -2695,7 +2765,7 @@ function listSavedHistorySessions(agentType, options = {}) {
2695
2765
  return { sessions: [], hasMore: false };
2696
2766
  }
2697
2767
  }
2698
- var fs3, path7, os5, HISTORY_DIR, RETAIN_DAYS, ChatHistoryWriter;
2768
+ var fs3, path7, os5, HISTORY_DIR, RETAIN_DAYS, CODEX_STARTER_PROMPT_RE, ChatHistoryWriter;
2699
2769
  var init_chat_history = __esm({
2700
2770
  "../../oss/packages/daemon-core/src/config/chat-history.ts"() {
2701
2771
  "use strict";
@@ -2704,11 +2774,16 @@ var init_chat_history = __esm({
2704
2774
  os5 = __toESM(require("os"));
2705
2775
  HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
2706
2776
  RETAIN_DAYS = 30;
2777
+ CODEX_STARTER_PROMPT_RE = /^(?:[›❯]\s*)?(?:Find and fix a bug in @filename|Improve documentation in @filename|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Use \/skills(?: to list available skills)?|Run \/review on my current changes)$/i;
2707
2778
  ChatHistoryWriter = class {
2708
2779
  /** Last seen message count per agent (deduplication) */
2709
2780
  lastSeenCounts = /* @__PURE__ */ new Map();
2710
2781
  /** Last seen message hash per agent (deduplication) */
2711
2782
  lastSeenHashes = /* @__PURE__ */ new Map();
2783
+ /** Last appended normalized message signature per agent/session */
2784
+ lastSeenSignatures = /* @__PURE__ */ new Map();
2785
+ /** Last appended normalized non-system turn signature per agent/session */
2786
+ lastSeenTurnSignatures = /* @__PURE__ */ new Map();
2712
2787
  rotated = false;
2713
2788
  /**
2714
2789
  * Append new messages to history
@@ -2730,14 +2805,36 @@ var init_chat_history = __esm({
2730
2805
  }
2731
2806
  const newMessages = [];
2732
2807
  for (const msg of messages) {
2733
- const hash2 = msg.historyDedupKey || `${msg.kind || "standard"}:${msg.role}:${(msg.content || "").slice(0, 50)}`;
2808
+ const role = msg.role;
2809
+ if (role !== "user" && role !== "assistant" && role !== "system") continue;
2810
+ const content = cleanupHistoryContent(agentType, role, msg.content || "");
2811
+ if (!content) continue;
2812
+ const receivedAt = msg.receivedAt || Date.now();
2813
+ const hash2 = buildHistoryMessageHash(agentType, {
2814
+ role,
2815
+ content,
2816
+ receivedAt,
2817
+ kind: typeof msg.kind === "string" ? msg.kind : void 0,
2818
+ historyDedupKey: msg.historyDedupKey
2819
+ });
2820
+ const signature = buildHistoryMessageSignature(agentType, {
2821
+ role,
2822
+ content,
2823
+ kind: typeof msg.kind === "string" ? msg.kind : void 0
2824
+ });
2734
2825
  if (seenHashes.has(hash2)) continue;
2826
+ if (this.lastSeenSignatures.get(dedupKey) === signature) continue;
2827
+ if (role !== "system" && this.lastSeenTurnSignatures.get(dedupKey) === signature) continue;
2735
2828
  seenHashes.add(hash2);
2829
+ this.lastSeenSignatures.set(dedupKey, signature);
2830
+ if (role !== "system") {
2831
+ this.lastSeenTurnSignatures.set(dedupKey, signature);
2832
+ }
2736
2833
  newMessages.push({
2737
- ts: new Date(msg.receivedAt || Date.now()).toISOString(),
2738
- receivedAt: msg.receivedAt || Date.now(),
2739
- role: msg.role,
2740
- content: msg.content || "",
2834
+ ts: new Date(receivedAt).toISOString(),
2835
+ receivedAt,
2836
+ role,
2837
+ content,
2741
2838
  kind: typeof msg.kind === "string" ? msg.kind : void 0,
2742
2839
  senderName: typeof msg.senderName === "string" ? msg.senderName : void 0,
2743
2840
  agent: agentType,
@@ -2757,6 +2854,8 @@ var init_chat_history = __esm({
2757
2854
  const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
2758
2855
  if (messages.length < prevCount * 0.5 && prevCount > 3) {
2759
2856
  seenHashes.clear();
2857
+ this.lastSeenSignatures.delete(dedupKey);
2858
+ this.lastSeenTurnSignatures.delete(dedupKey);
2760
2859
  for (const msg of messages) {
2761
2860
  seenHashes.add(msg.historyDedupKey || `${msg.kind || "standard"}:${msg.role}:${(msg.content || "").slice(0, 50)}`);
2762
2861
  }
@@ -2770,6 +2869,54 @@ var init_chat_history = __esm({
2770
2869
  } catch {
2771
2870
  }
2772
2871
  }
2872
+ seedSessionHistory(agentType, messages = [], historySessionId, instanceId) {
2873
+ const effectiveHistoryKey = historySessionId || instanceId;
2874
+ const dedupKey = effectiveHistoryKey ? `${agentType}:${effectiveHistoryKey}` : agentType;
2875
+ const seenHashes = /* @__PURE__ */ new Set();
2876
+ for (const raw of messages) {
2877
+ const role = raw?.role;
2878
+ if (role !== "user" && role !== "assistant" && role !== "system") continue;
2879
+ const content = cleanupHistoryContent(agentType, role, raw?.content || "");
2880
+ if (!content) continue;
2881
+ seenHashes.add(buildHistoryMessageHash(agentType, {
2882
+ role,
2883
+ content,
2884
+ receivedAt: raw?.receivedAt || 0,
2885
+ kind: typeof raw?.kind === "string" ? raw.kind : void 0,
2886
+ historyDedupKey: raw?.historyDedupKey
2887
+ }));
2888
+ }
2889
+ this.lastSeenHashes.set(dedupKey, seenHashes);
2890
+ this.lastSeenCounts.set(dedupKey, messages.length);
2891
+ const lastMessage = [...messages].reverse().find((raw) => {
2892
+ const role = raw?.role;
2893
+ if (role !== "user" && role !== "assistant" && role !== "system") return false;
2894
+ return !!cleanupHistoryContent(agentType, role, raw?.content || "");
2895
+ });
2896
+ const lastTurnMessage = [...messages].reverse().find((raw) => {
2897
+ const role = raw?.role;
2898
+ if (role !== "user" && role !== "assistant") return false;
2899
+ return !!cleanupHistoryContent(agentType, role, raw?.content || "");
2900
+ });
2901
+ if (lastMessage) {
2902
+ this.lastSeenSignatures.set(dedupKey, buildHistoryMessageSignature(agentType, {
2903
+ role: lastMessage.role,
2904
+ content: lastMessage.content,
2905
+ kind: typeof lastMessage.kind === "string" ? lastMessage.kind : void 0
2906
+ }));
2907
+ } else {
2908
+ this.lastSeenSignatures.delete(dedupKey);
2909
+ }
2910
+ if (lastTurnMessage) {
2911
+ this.lastSeenTurnSignatures.set(dedupKey, buildHistoryMessageSignature(agentType, {
2912
+ role: lastTurnMessage.role,
2913
+ content: lastTurnMessage.content,
2914
+ kind: typeof lastTurnMessage.kind === "string" ? lastTurnMessage.kind : void 0
2915
+ }));
2916
+ } else {
2917
+ this.lastSeenTurnSignatures.delete(dedupKey);
2918
+ }
2919
+ }
2773
2920
  appendSystemMarker(agentType, content, options = {}) {
2774
2921
  this.appendNewMessages(
2775
2922
  agentType,
@@ -2800,6 +2947,16 @@ var init_chat_history = __esm({
2800
2947
  this.lastSeenHashes.set(toDedupKey, nextHashes);
2801
2948
  this.lastSeenHashes.delete(fromDedupKey);
2802
2949
  }
2950
+ const fromSignature = this.lastSeenSignatures.get(fromDedupKey);
2951
+ if (fromSignature) {
2952
+ this.lastSeenSignatures.set(toDedupKey, fromSignature);
2953
+ this.lastSeenSignatures.delete(fromDedupKey);
2954
+ }
2955
+ const fromTurnSignature = this.lastSeenTurnSignatures.get(fromDedupKey);
2956
+ if (fromTurnSignature) {
2957
+ this.lastSeenTurnSignatures.set(toDedupKey, fromTurnSignature);
2958
+ this.lastSeenTurnSignatures.delete(fromDedupKey);
2959
+ }
2803
2960
  const fromCount = this.lastSeenCounts.get(fromDedupKey);
2804
2961
  if (typeof fromCount === "number") {
2805
2962
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
@@ -2841,10 +2998,61 @@ var init_chat_history = __esm({
2841
2998
  } catch {
2842
2999
  }
2843
3000
  }
3001
+ compactHistorySession(agentType, historySessionId) {
3002
+ const sessionId = String(historySessionId || "").trim();
3003
+ if (!sessionId) return;
3004
+ try {
3005
+ const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
3006
+ if (!fs3.existsSync(dir)) return;
3007
+ const prefix = `${this.sanitize(sessionId)}_`;
3008
+ const files = fs3.readdirSync(dir).filter((file2) => file2.startsWith(prefix) && file2.endsWith(".jsonl")).sort();
3009
+ const seen = /* @__PURE__ */ new Set();
3010
+ for (const file2 of files) {
3011
+ const filePath = path7.join(dir, file2);
3012
+ const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
3013
+ const next = [];
3014
+ for (const line of lines) {
3015
+ let parsed = null;
3016
+ try {
3017
+ parsed = JSON.parse(line);
3018
+ } catch {
3019
+ parsed = null;
3020
+ }
3021
+ if (!parsed || parsed.historySessionId !== sessionId) continue;
3022
+ const sanitized = sanitizeHistoryMessage(agentType, parsed);
3023
+ if (!sanitized) continue;
3024
+ const hash2 = buildHistoryMessageHash(agentType, sanitized);
3025
+ if (seen.has(hash2)) continue;
3026
+ seen.add(hash2);
3027
+ next.push(sanitized);
3028
+ }
3029
+ next.sort((a, b) => a.receivedAt - b.receivedAt);
3030
+ const dedupedAdjacent = [];
3031
+ let lastTurn = null;
3032
+ for (const entry of next) {
3033
+ const previous = dedupedAdjacent[dedupedAdjacent.length - 1];
3034
+ if (isAdjacentHistoryDuplicate(agentType, previous, entry)) continue;
3035
+ if (entry.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, entry)) continue;
3036
+ dedupedAdjacent.push(entry);
3037
+ if (entry.role !== "system") lastTurn = entry;
3038
+ }
3039
+ const collapsed = collapseReplayAssistantTurns(agentType, dedupedAdjacent);
3040
+ if (collapsed.length === 0) {
3041
+ fs3.unlinkSync(filePath);
3042
+ continue;
3043
+ }
3044
+ fs3.writeFileSync(filePath, `${collapsed.map((entry) => JSON.stringify(entry)).join("\n")}
3045
+ `, "utf-8");
3046
+ }
3047
+ } catch {
3048
+ }
3049
+ }
2844
3050
  /** Called when agent session is explicitly changed */
2845
3051
  onSessionChange(agentType) {
2846
3052
  this.lastSeenHashes.delete(agentType);
2847
3053
  this.lastSeenCounts.delete(agentType);
3054
+ this.lastSeenSignatures.delete(agentType);
3055
+ this.lastSeenTurnSignatures.delete(agentType);
2848
3056
  }
2849
3057
  /** Delete history files older than 30 days */
2850
3058
  async rotateOldFiles() {
@@ -3232,6 +3440,59 @@ ${effect.notification.body || ""}`.trim();
3232
3440
  }
3233
3441
  });
3234
3442
 
3443
+ // ../../oss/packages/daemon-core/src/providers/approval-utils.ts
3444
+ function normalizeApprovalLabel(value) {
3445
+ return String(value || "").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
3446
+ }
3447
+ function getApprovalPositiveHints(provider) {
3448
+ const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
3449
+ return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
3450
+ }
3451
+ function pickApprovalButton(buttons, provider) {
3452
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
3453
+ if (labels.length === 0) {
3454
+ return { index: 0, label: "Approve" };
3455
+ }
3456
+ const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
3457
+ const hints = getApprovalPositiveHints(provider);
3458
+ for (const hint of hints) {
3459
+ const exactIndex = normalizedButtons.findIndex((label) => label === hint);
3460
+ if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
3461
+ const prefixIndex = normalizedButtons.findIndex((label) => label.startsWith(hint));
3462
+ if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
3463
+ const includeIndex = normalizedButtons.findIndex((label) => label.includes(hint));
3464
+ if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
3465
+ }
3466
+ return { index: 0, label: labels[0] };
3467
+ }
3468
+ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
3469
+ const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
3470
+ const cleanMessage = String(modalMessage || "").trim();
3471
+ if (cleanMessage) lines.push(cleanMessage);
3472
+ return lines.join("\n");
3473
+ }
3474
+ var DEFAULT_APPROVAL_POSITIVE_HINTS;
3475
+ var init_approval_utils = __esm({
3476
+ "../../oss/packages/daemon-core/src/providers/approval-utils.ts"() {
3477
+ "use strict";
3478
+ DEFAULT_APPROVAL_POSITIVE_HINTS = [
3479
+ "run",
3480
+ "approve",
3481
+ "accept",
3482
+ "allow once",
3483
+ "always allow",
3484
+ "allow",
3485
+ "yes",
3486
+ "proceed",
3487
+ "continue",
3488
+ "confirm",
3489
+ "save",
3490
+ "ok",
3491
+ "trust"
3492
+ ];
3493
+ }
3494
+ });
3495
+
3235
3496
  // ../../oss/packages/daemon-core/src/providers/ide-provider-instance.ts
3236
3497
  var crypto2, IdeProviderInstance;
3237
3498
  var init_ide_provider_instance = __esm({
@@ -3243,6 +3504,7 @@ var init_ide_provider_instance = __esm({
3243
3504
  init_chat_history();
3244
3505
  init_logger();
3245
3506
  init_control_effects();
3507
+ init_approval_utils();
3246
3508
  IdeProviderInstance = class {
3247
3509
  type;
3248
3510
  category = "ide";
@@ -3309,6 +3571,8 @@ var init_ide_provider_instance = __esm({
3309
3571
  }
3310
3572
  getState() {
3311
3573
  const cdp = this.context?.cdp;
3574
+ const autoApproveActive = (this.currentStatus === "waiting_approval" || this.cachedChat?.status === "waiting_approval") && this.canAutoApprove();
3575
+ const visibleStatus = autoApproveActive ? "generating" : this.currentStatus;
3312
3576
  const extensionStates = [];
3313
3577
  for (const ext of this.extensions.values()) {
3314
3578
  extensionStates.push(ext.getState());
@@ -3317,13 +3581,13 @@ var init_ide_provider_instance = __esm({
3317
3581
  type: this.type,
3318
3582
  name: this.provider.name,
3319
3583
  category: "ide",
3320
- status: this.currentStatus,
3584
+ status: visibleStatus,
3321
3585
  activeChat: this.cachedChat ? {
3322
3586
  id: this.cachedChat.id || "active_session",
3323
3587
  title: this.cachedChat.title || this.type,
3324
- status: this.cachedChat.status || this.currentStatus,
3588
+ status: autoApproveActive && this.cachedChat.status === "waiting_approval" ? "generating" : this.cachedChat.status || visibleStatus,
3325
3589
  messages: this.mergeConversationMessages(this.cachedChat.messages || []),
3326
- activeModal: this.cachedChat.activeModal || null,
3590
+ activeModal: autoApproveActive ? null : this.cachedChat.activeModal || null,
3327
3591
  inputContent: this.cachedChat.inputContent || ""
3328
3592
  } : null,
3329
3593
  workspace: this.workspace || null,
@@ -3542,7 +3806,9 @@ var init_ide_provider_instance = __esm({
3542
3806
  const chatStatus = chatData?.status;
3543
3807
  if (!chatStatus) return;
3544
3808
  const agentKey = `${this.type}:native`;
3545
- const agentStatus = chatStatus === "streaming" || chatStatus === "generating" ? "generating" : chatStatus === "waiting_approval" ? "waiting_approval" : "idle";
3809
+ const rawAgentStatus = chatStatus === "streaming" || chatStatus === "generating" ? "generating" : chatStatus === "waiting_approval" ? "waiting_approval" : "idle";
3810
+ const autoApproveActive = rawAgentStatus === "waiting_approval" && this.canAutoApprove();
3811
+ const agentStatus = autoApproveActive ? "generating" : rawAgentStatus;
3546
3812
  const lastMsg = Array.isArray(chatData?.messages) && chatData.messages.length > 0 ? chatData.messages[chatData.messages.length - 1] : null;
3547
3813
  const progressFingerprint = agentStatus === "generating" ? `${lastMsg?.role || ""}:${typeof lastMsg?.content === "string" ? lastMsg.content : JSON.stringify(lastMsg?.content || "")}`.slice(-2e3) : void 0;
3548
3814
  this.currentStatus = agentStatus;
@@ -3574,7 +3840,7 @@ var init_ide_provider_instance = __esm({
3574
3840
  this.applyProviderResponse(chatData, {
3575
3841
  phase: agentStatus === "idle" && (lastStatus === "generating" || lastStatus === "waiting_approval") ? "turn_completed" : "immediate"
3576
3842
  });
3577
- if (agentStatus === "waiting_approval" && this.settings.autoApprove && !this.autoApproveBusy) {
3843
+ if (rawAgentStatus === "waiting_approval" && autoApproveActive && !this.autoApproveBusy) {
3578
3844
  this.autoApproveViaScript(chatData);
3579
3845
  }
3580
3846
  const monitorEvents = this.monitor.check(agentKey, agentStatus, now, progressFingerprint);
@@ -3725,6 +3991,9 @@ ${effect.notification.body || ""}`.trim();
3725
3991
  updateCdp(cdp) {
3726
3992
  if (this.context) this.context.cdp = cdp;
3727
3993
  }
3994
+ canAutoApprove() {
3995
+ return this.settings.autoApprove !== false && typeof this.provider.scripts?.resolveAction === "function" && !!this.context?.cdp?.isConnected;
3996
+ }
3728
3997
  // ─── Auto-approve via CDP script ────────────────────
3729
3998
  async autoApproveViaScript(_chatData) {
3730
3999
  const cdp = this.context?.cdp;
@@ -3736,17 +4005,15 @@ ${effect.notification.body || ""}`.trim();
3736
4005
  }
3737
4006
  this.autoApproveBusy = true;
3738
4007
  try {
3739
- let targetButton = _chatData?.activeModal?.buttons?.[0] || "Run";
3740
- const buttons = _chatData?.activeModal?.buttons || [];
3741
- for (const b of buttons) {
3742
- const lower = String(b).toLowerCase().replace(/[^\w]/g, "");
3743
- if (/^(run|approve|accept|yes|allow|always|proceed|save)/.test(lower)) {
3744
- targetButton = b;
3745
- break;
3746
- }
3747
- }
4008
+ const { label: targetButton } = pickApprovalButton(_chatData?.activeModal?.buttons, this.provider);
3748
4009
  const script = scriptFn({ action: "approve", button: targetButton, buttonText: targetButton });
3749
4010
  if (!script) return;
4011
+ const now = Date.now();
4012
+ this.appendRuntimeSystemMessage(
4013
+ formatAutoApprovalMessage(_chatData?.activeModal?.message, targetButton),
4014
+ `auto_approval:${now}:${targetButton}`,
4015
+ now
4016
+ );
3750
4017
  LOG.info("IdeInstance", `[IdeInstance:${this.type}] autoApprove: executing resolveAction for "${targetButton}"`);
3751
4018
  let rawResult = await cdp.evaluate(script, 1e4);
3752
4019
  if (typeof rawResult === "string") {
@@ -3768,12 +4035,6 @@ ${effect.notification.body || ""}`.trim();
3768
4035
  LOG.warn("IdeInstance", `[IdeInstance:${this.type}] autoApprove: cdp.send() not available for coordinate click`);
3769
4036
  }
3770
4037
  }
3771
- this.pushEvent({
3772
- event: "agent:auto_approved",
3773
- chatTitle: _chatData?.title || this.provider.name,
3774
- timestamp: Date.now(),
3775
- ideType: this.type
3776
- });
3777
4038
  } catch (e) {
3778
4039
  LOG.warn("IdeInstance", `[IdeInstance:${this.type}] autoApprove error: ${e?.message}`);
3779
4040
  } finally {
@@ -4713,6 +4974,46 @@ function didProviderConfirmSend(result) {
4713
4974
  if (!parsed || typeof parsed !== "object") return false;
4714
4975
  return parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true;
4715
4976
  }
4977
+ async function readExtensionChatState(h) {
4978
+ try {
4979
+ const evalResult = await h.evaluateProviderScript("readChat", void 0, 5e4);
4980
+ if (!evalResult?.result) return null;
4981
+ const parsed = parseMaybeJson(evalResult.result);
4982
+ return parsed && typeof parsed === "object" ? parsed : null;
4983
+ } catch {
4984
+ return null;
4985
+ }
4986
+ }
4987
+ function getStateMessageCount(state) {
4988
+ return Array.isArray(state?.messages) ? state.messages.length : 0;
4989
+ }
4990
+ function getStateLastSignature(state) {
4991
+ const messages = Array.isArray(state?.messages) ? state.messages : [];
4992
+ const last = messages[messages.length - 1];
4993
+ if (!last) return "";
4994
+ return `${last.role || ""}:${String(last.content || "").replace(/\s+/g, " ").trim()}`;
4995
+ }
4996
+ async function getStableExtensionBaseline(h) {
4997
+ const first = await readExtensionChatState(h);
4998
+ if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
4999
+ await new Promise((resolve17) => setTimeout(resolve17, 150));
5000
+ const second = await readExtensionChatState(h);
5001
+ return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
5002
+ }
5003
+ async function verifyExtensionSendObserved(h, before) {
5004
+ const beforeCount = getStateMessageCount(before);
5005
+ const beforeSignature = getStateLastSignature(before);
5006
+ for (let attempt = 0; attempt < 12; attempt += 1) {
5007
+ await new Promise((resolve17) => setTimeout(resolve17, 250));
5008
+ const state = await readExtensionChatState(h);
5009
+ if (state?.status === "waiting_approval") return true;
5010
+ const afterCount = getStateMessageCount(state);
5011
+ const afterSignature = getStateLastSignature(state);
5012
+ if (afterCount > beforeCount) return true;
5013
+ if (afterSignature && afterSignature !== beforeSignature) return true;
5014
+ }
5015
+ return false;
5016
+ }
4716
5017
  async function handleChatHistory(h, args) {
4717
5018
  const { agentType, offset, limit } = args;
4718
5019
  const historySessionId = getHistorySessionId(h, args);
@@ -4893,12 +5194,17 @@ async function handleSendChat(h, args) {
4893
5194
  if (isExtensionTransport(transport)) {
4894
5195
  _log(`Extension: ${provider?.type || "unknown_extension"}`);
4895
5196
  try {
5197
+ const beforeState = await getStableExtensionBaseline(h);
4896
5198
  const evalResult = await h.evaluateProviderScript("sendMessage", { message: text }, 3e4);
4897
5199
  if (evalResult?.result) {
4898
5200
  const parsed = parseMaybeJson(evalResult.result);
4899
5201
  if (didProviderConfirmSend(parsed)) {
4900
- _log(`Extension script sent OK`);
4901
- return _logSendSuccess("extension-script");
5202
+ const observed = await verifyExtensionSendObserved(h, beforeState);
5203
+ if (observed) {
5204
+ _log(`Extension script sent OK`);
5205
+ return _logSendSuccess("extension-script");
5206
+ }
5207
+ _log(`Extension script reported send but no chat-state change was observed`);
4902
5208
  }
4903
5209
  if (parsed?.needsTypeAndSend) {
4904
5210
  _log(`Extension needsTypeAndSend \u2192 AgentStreamManager`);
@@ -5403,7 +5709,7 @@ async function handleResolveAction(h, args) {
5403
5709
  return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
5404
5710
  }
5405
5711
  if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
5406
- const ok = await h.agentStream.resolveSessionAction(h.getCdp(), h.currentSession.sessionId, action);
5712
+ const ok = await h.agentStream.resolveSessionAction(h.getCdp(), h.currentSession.sessionId, action, button);
5407
5713
  return { success: ok };
5408
5714
  }
5409
5715
  if (transport === "acp") {
@@ -7188,10 +7494,12 @@ function sanitizeSpawnEnv(baseEnv, overrides) {
7188
7494
  env[key] = value;
7189
7495
  }
7190
7496
  for (const key of Object.keys(env)) {
7191
- if (key === "INIT_CWD" || key === "npm_command" || key === "npm_execpath" || key === "npm_node_execpath" || key.startsWith("npm_") || key.startsWith("npm_config_") || key.startsWith("npm_package_") || key.startsWith("npm_lifecycle_") || key.startsWith("PNPM_") || key.startsWith("YARN_") || key.startsWith("BUN_")) {
7497
+ if (key === "INIT_CWD" || key === "npm_command" || key === "npm_execpath" || key === "npm_node_execpath" || key.startsWith("npm_") || key.startsWith("npm_config_") || key.startsWith("npm_package_") || key.startsWith("npm_lifecycle_") || key.startsWith("PNPM_") || key.startsWith("YARN_") || key.startsWith("BUN_") || key.startsWith("VSCODE_") || key.startsWith("ELECTRON_")) {
7192
7498
  delete env[key];
7193
7499
  }
7194
7500
  }
7501
+ delete env.CODEX_THREAD_ID;
7502
+ delete env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;
7195
7503
  applyTerminalColorEnv(env);
7196
7504
  return env;
7197
7505
  }
@@ -7209,14 +7517,14 @@ function applyTerminalColorEnv(env) {
7209
7517
  function ensureNodePtySpawnHelperPermissions(logFn) {
7210
7518
  if (os22.platform() === "win32") return;
7211
7519
  try {
7212
- const fs19 = __require("fs");
7520
+ const fs20 = __require("fs");
7213
7521
  const ptyDir = path32.resolve(path32.dirname(__require.resolve("node-pty")), "..");
7214
7522
  const platformArch = `${os22.platform()}-${os22.arch()}`;
7215
7523
  const helper = path32.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
7216
- if (fs19.existsSync(helper)) {
7217
- const stat4 = fs19.statSync(helper);
7524
+ if (fs20.existsSync(helper)) {
7525
+ const stat4 = fs20.statSync(helper);
7218
7526
  if (!(stat4.mode & 73)) {
7219
- fs19.chmodSync(helper, stat4.mode | 493);
7527
+ fs20.chmodSync(helper, stat4.mode | 493);
7220
7528
  logFn?.(`Fixed spawn-helper permissions: ${helper}`);
7221
7529
  }
7222
7530
  }
@@ -7493,6 +7801,9 @@ var init_dist = __esm({
7493
7801
  state.record.lastActivityAt = Date.now();
7494
7802
  return this.cloneRecord(state.record);
7495
7803
  }
7804
+ deleteSession(sessionId) {
7805
+ return this.sessions.delete(sessionId);
7806
+ }
7496
7807
  requireSession(sessionId) {
7497
7808
  const state = this.sessions.get(sessionId);
7498
7809
  if (!state) throw new Error(`Unknown session: ${sessionId}`);
@@ -7682,8 +7993,8 @@ var init_pty_transport = __esm({
7682
7993
  let cwd = options.cwd;
7683
7994
  if (cwd) {
7684
7995
  try {
7685
- const fs19 = require("fs");
7686
- const stat4 = fs19.statSync(cwd);
7996
+ const fs20 = require("fs");
7997
+ const stat4 = fs20.statSync(cwd);
7687
7998
  if (!stat4.isDirectory()) cwd = os8.homedir();
7688
7999
  } catch {
7689
8000
  cwd = os8.homedir();
@@ -7794,12 +8105,12 @@ function findBinary(name) {
7794
8105
  function isScriptBinary(binaryPath) {
7795
8106
  if (!path10.isAbsolute(binaryPath)) return false;
7796
8107
  try {
7797
- const fs19 = require("fs");
7798
- const resolved = fs19.realpathSync(binaryPath);
8108
+ const fs20 = require("fs");
8109
+ const resolved = fs20.realpathSync(binaryPath);
7799
8110
  const head = Buffer.alloc(8);
7800
- const fd = fs19.openSync(resolved, "r");
7801
- fs19.readSync(fd, head, 0, 8, 0);
7802
- fs19.closeSync(fd);
8111
+ const fd = fs20.openSync(resolved, "r");
8112
+ fs20.readSync(fd, head, 0, 8, 0);
8113
+ fs20.closeSync(fd);
7803
8114
  let i = 0;
7804
8115
  if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
7805
8116
  return head[i] === 35 && head[i + 1] === 33;
@@ -7810,12 +8121,12 @@ function isScriptBinary(binaryPath) {
7810
8121
  function looksLikeMachOOrElf(filePath) {
7811
8122
  if (!path10.isAbsolute(filePath)) return false;
7812
8123
  try {
7813
- const fs19 = require("fs");
7814
- const resolved = fs19.realpathSync(filePath);
8124
+ const fs20 = require("fs");
8125
+ const resolved = fs20.realpathSync(filePath);
7815
8126
  const buf = Buffer.alloc(8);
7816
- const fd = fs19.openSync(resolved, "r");
7817
- fs19.readSync(fd, buf, 0, 8, 0);
7818
- fs19.closeSync(fd);
8127
+ const fd = fs20.openSync(resolved, "r");
8128
+ fs20.readSync(fd, buf, 0, 8, 0);
8129
+ fs20.closeSync(fd);
7819
8130
  let i = 0;
7820
8131
  if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
7821
8132
  const b = buf.subarray(i);
@@ -8547,6 +8858,9 @@ var init_provider_cli_adapter = __esm({
8547
8858
  looksLikeVisibleIdlePrompt(screenText) {
8548
8859
  const text = String(screenText || "");
8549
8860
  if (!text.trim()) return false;
8861
+ if (this.cliType === "codex-cli" && /(^|\n)\s*[❯›>]\s+(?:Find and fix a bug in @filename|Improve documentation in @filename|Use \/skills|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Run \/review on my current changes)(?:\n|$)/im.test(text)) {
8862
+ return true;
8863
+ }
8550
8864
  return /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(text) || /⏎\s+send/i.test(text) || /\?\s*for\s*shortcuts/i.test(text) || /Type your message(?:\s+or\s+@path\/to\/file)?/i.test(text) || /workspace\s*\(\/directory\)/i.test(text) || /for\s*shortcuts/i.test(text);
8551
8865
  }
8552
8866
  findLastMatchingLineIndex(lines, predicate) {
@@ -9732,6 +10046,7 @@ var init_cli_provider_instance = __esm({
9732
10046
  init_chat_history();
9733
10047
  init_logger();
9734
10048
  init_control_effects();
10049
+ init_approval_utils();
9735
10050
  CachedDatabaseSync = null;
9736
10051
  CliProviderInstance = class {
9737
10052
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
@@ -9765,6 +10080,7 @@ var init_cli_provider_instance = __esm({
9765
10080
  historyWriter;
9766
10081
  runtimeMessages = [];
9767
10082
  instanceId;
10083
+ suppressIdleHistoryReplay = false;
9768
10084
  presentationMode;
9769
10085
  providerSessionId;
9770
10086
  launchMode;
@@ -9792,7 +10108,15 @@ var init_cli_provider_instance = __esm({
9792
10108
  await this.adapter.spawn();
9793
10109
  this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
9794
10110
  if (this.providerSessionId) {
10111
+ this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
9795
10112
  const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
10113
+ this.historyWriter.seedSessionHistory(
10114
+ this.type,
10115
+ restoredHistory.messages,
10116
+ this.providerSessionId,
10117
+ this.instanceId
10118
+ );
10119
+ this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
9796
10120
  if (restoredHistory.messages.length > 0) {
9797
10121
  this.adapter.seedCommittedMessages(
9798
10122
  restoredHistory.messages.map((message) => ({
@@ -9836,7 +10160,7 @@ var init_cli_provider_instance = __esm({
9836
10160
  } else if (this.type === "codex-cli") {
9837
10161
  probedSessionId = this.probeSessionIdFromConfig({
9838
10162
  dbPath: "~/.codex/state_5.sqlite",
9839
- query: "select id from threads where cwd in ({dirs}) and created_at >= ? and archived = 0 order by created_at desc limit 1",
10163
+ query: "select id from threads where cwd in ({dirs}) and updated_at >= ? and archived = 0 order by updated_at desc limit 1",
9840
10164
  timestampFormat: "unix_s"
9841
10165
  });
9842
10166
  } else if (this.type === "goose-cli") {
@@ -9880,6 +10204,8 @@ var init_cli_provider_instance = __esm({
9880
10204
  getState() {
9881
10205
  const adapterStatus = this.adapter.getStatus();
9882
10206
  const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
10207
+ const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
10208
+ const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
9883
10209
  const parsedProviderSessionId = typeof parsedStatus?.providerSessionId === "string" ? parsedStatus.providerSessionId.trim() : "";
9884
10210
  if (parsedProviderSessionId) {
9885
10211
  this.promoteProviderSessionId(parsedProviderSessionId);
@@ -9896,6 +10222,7 @@ var init_cli_provider_instance = __esm({
9896
10222
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
9897
10223
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9898
10224
  if (parsedMessages.length > 0) {
10225
+ const shouldSkipReplayPersist = this.suppressIdleHistoryReplay && adapterStatus.status === "idle" && parsedStatus?.status === "idle";
9899
10226
  let messagesToSave = parsedMessages;
9900
10227
  if (parsedStatus?.status === "generating" || parsedStatus?.status === "long_generating") {
9901
10228
  const lastIdx = messagesToSave.length - 1;
@@ -9903,7 +10230,7 @@ var init_cli_provider_instance = __esm({
9903
10230
  messagesToSave = messagesToSave.slice(0, lastIdx);
9904
10231
  }
9905
10232
  }
9906
- if (messagesToSave.length > 0) {
10233
+ if (!shouldSkipReplayPersist && messagesToSave.length > 0) {
9907
10234
  this.historyWriter.appendNewMessages(
9908
10235
  this.type,
9909
10236
  messagesToSave,
@@ -9918,14 +10245,14 @@ var init_cli_provider_instance = __esm({
9918
10245
  type: this.type,
9919
10246
  name: this.provider.name,
9920
10247
  category: "cli",
9921
- status: adapterStatus.status,
10248
+ status: visibleStatus,
9922
10249
  mode: this.presentationMode,
9923
10250
  activeChat: {
9924
10251
  id: `${this.type}_${this.workingDir}`,
9925
10252
  title: parsedStatus?.title || dirName,
9926
- status: parsedStatus?.status || adapterStatus.status,
10253
+ status: autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
9927
10254
  messages: mergedMessages,
9928
- activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
10255
+ activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
9929
10256
  inputContent: ""
9930
10257
  },
9931
10258
  workspace: this.workingDir,
@@ -9989,7 +10316,16 @@ var init_cli_provider_instance = __esm({
9989
10316
  const now = Date.now();
9990
10317
  const adapterStatus = this.adapter.getStatus();
9991
10318
  const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
9992
- const newStatus = adapterStatus.status;
10319
+ const rawStatus = adapterStatus.status;
10320
+ const autoApproveActive = rawStatus === "waiting_approval" && this.shouldAutoApprove();
10321
+ if (autoApproveActive) {
10322
+ const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(adapterStatus.activeModal?.buttons, this.provider);
10323
+ this.recordAutoApproval(adapterStatus.activeModal?.message, buttonLabel, now);
10324
+ setTimeout(() => {
10325
+ this.adapter.resolveModal(buttonIndex);
10326
+ }, 0);
10327
+ }
10328
+ const newStatus = autoApproveActive ? "generating" : rawStatus;
9993
10329
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
9994
10330
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
9995
10331
  const partial2 = this.adapter.getPartialResponse();
@@ -9998,6 +10334,7 @@ var init_cli_provider_instance = __esm({
9998
10334
  if (newStatus !== this.lastStatus) {
9999
10335
  LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
10000
10336
  if (this.lastStatus === "idle" && newStatus === "generating") {
10337
+ this.suppressIdleHistoryReplay = false;
10001
10338
  if (this.completedDebouncePending) {
10002
10339
  LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating)`);
10003
10340
  if (this.completedDebounceTimer) {
@@ -10017,6 +10354,7 @@ var init_cli_provider_instance = __esm({
10017
10354
  this.generatingDebounceTimer = null;
10018
10355
  }, 1e3);
10019
10356
  } else if (newStatus === "waiting_approval") {
10357
+ this.suppressIdleHistoryReplay = false;
10020
10358
  if (this.generatingDebouncePending) {
10021
10359
  if (this.generatingDebounceTimer) {
10022
10360
  clearTimeout(this.generatingDebounceTimer);
@@ -10197,6 +10535,16 @@ ${effect.notification.body || ""}`.trim();
10197
10535
  get cliName() {
10198
10536
  return this.provider.name;
10199
10537
  }
10538
+ shouldAutoApprove() {
10539
+ return this.settings.autoApprove !== false;
10540
+ }
10541
+ recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
10542
+ this.appendRuntimeSystemMessage(
10543
+ formatAutoApprovalMessage(modalMessage, buttonLabel),
10544
+ `auto_approval:${now}:${buttonLabel || "approve"}`,
10545
+ now
10546
+ );
10547
+ }
10200
10548
  recordApprovalSelection(buttonText) {
10201
10549
  const cleanButton = String(buttonText || "").trim();
10202
10550
  if (!cleanButton) return;
@@ -10592,10 +10940,10 @@ function mergeDefs(...defs) {
10592
10940
  function cloneDef(schema) {
10593
10941
  return mergeDefs(schema._zod.def);
10594
10942
  }
10595
- function getElementAtPath(obj, path27) {
10596
- if (!path27)
10943
+ function getElementAtPath(obj, path28) {
10944
+ if (!path28)
10597
10945
  return obj;
10598
- return path27.reduce((acc, key) => acc?.[key], obj);
10946
+ return path28.reduce((acc, key) => acc?.[key], obj);
10599
10947
  }
10600
10948
  function promiseAllObject(promisesObj) {
10601
10949
  const keys = Object.keys(promisesObj);
@@ -10907,11 +11255,11 @@ function aborted(x, startIndex = 0) {
10907
11255
  }
10908
11256
  return false;
10909
11257
  }
10910
- function prefixIssues(path27, issues) {
11258
+ function prefixIssues(path28, issues) {
10911
11259
  return issues.map((iss) => {
10912
11260
  var _a2;
10913
11261
  (_a2 = iss).path ?? (_a2.path = []);
10914
- iss.path.unshift(path27);
11262
+ iss.path.unshift(path28);
10915
11263
  return iss;
10916
11264
  });
10917
11265
  }
@@ -11154,7 +11502,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
11154
11502
  }
11155
11503
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
11156
11504
  const result = { errors: [] };
11157
- const processError = (error49, path27 = []) => {
11505
+ const processError = (error49, path28 = []) => {
11158
11506
  var _a2, _b;
11159
11507
  for (const issue2 of error49.issues) {
11160
11508
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -11164,7 +11512,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
11164
11512
  } else if (issue2.code === "invalid_element") {
11165
11513
  processError({ issues: issue2.issues }, issue2.path);
11166
11514
  } else {
11167
- const fullpath = [...path27, ...issue2.path];
11515
+ const fullpath = [...path28, ...issue2.path];
11168
11516
  if (fullpath.length === 0) {
11169
11517
  result.errors.push(mapper(issue2));
11170
11518
  continue;
@@ -11196,8 +11544,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
11196
11544
  }
11197
11545
  function toDotPath(_path) {
11198
11546
  const segs = [];
11199
- const path27 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
11200
- for (const seg of path27) {
11547
+ const path28 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
11548
+ for (const seg of path28) {
11201
11549
  if (typeof seg === "number")
11202
11550
  segs.push(`[${seg}]`);
11203
11551
  else if (typeof seg === "symbol")
@@ -23961,13 +24309,13 @@ function resolveRef(ref, ctx) {
23961
24309
  if (!ref.startsWith("#")) {
23962
24310
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
23963
24311
  }
23964
- const path27 = ref.slice(1).split("/").filter(Boolean);
23965
- if (path27.length === 0) {
24312
+ const path28 = ref.slice(1).split("/").filter(Boolean);
24313
+ if (path28.length === 0) {
23966
24314
  return ctx.rootSchema;
23967
24315
  }
23968
24316
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
23969
- if (path27[0] === defsKey) {
23970
- const key = path27[1];
24317
+ if (path28[0] === defsKey) {
24318
+ const key = path28[1];
23971
24319
  if (!key || !ctx.defs[key]) {
23972
24320
  throw new Error(`Reference not found: ${ref}`);
23973
24321
  }
@@ -27082,8 +27430,10 @@ var init_acp_provider_instance = __esm({
27082
27430
  input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
27083
27431
  });
27084
27432
  }
27085
- if (this.settings.autoApprove) {
27086
- this.log.info(`[${this.type}] Auto-approving: ${tc.title || tc.toolCallId}`);
27433
+ if (this.settings.autoApprove !== false) {
27434
+ const toolTitle = tc.title || tc.toolCallId || "tool call";
27435
+ this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
27436
+ this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
27087
27437
  const allowOption = params.options.find((o) => o.kind === "allow_once") || params.options.find((o) => o.kind === "allow_always");
27088
27438
  if (allowOption) {
27089
27439
  return { outcome: { outcome: "selected", optionId: allowOption.optionId } };
@@ -27535,6 +27885,18 @@ var init_acp_provider_instance = __esm({
27535
27885
  this.events.push(event);
27536
27886
  if (this.events.length > 50) this.events = this.events.slice(-50);
27537
27887
  }
27888
+ appendSystemMessage(content, timestamp = Date.now()) {
27889
+ const normalizedContent = String(content || "").trim();
27890
+ if (!normalizedContent) return;
27891
+ this.messages.push({
27892
+ role: "system",
27893
+ content: normalizedContent,
27894
+ timestamp
27895
+ });
27896
+ if (this.messages.length > 200) {
27897
+ this.messages = this.messages.slice(-100);
27898
+ }
27899
+ }
27538
27900
  flushEvents() {
27539
27901
  const events = [...this.events];
27540
27902
  this.events = [];
@@ -27835,8 +28197,8 @@ var init_cli_manager = __esm({
27835
28197
  const spawnCmd = provider.spawn?.command;
27836
28198
  if (spawnCmd) {
27837
28199
  try {
27838
- const { execSync: execSync7 } = require("child_process");
27839
- execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
28200
+ const { execSync: execSync8 } = require("child_process");
28201
+ execSync8(`which ${spawnCmd}`, { stdio: "ignore" });
27840
28202
  } catch {
27841
28203
  const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
27842
28204
  throw new Error(
@@ -28060,6 +28422,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
28060
28422
  if (!instanceManager) return 0;
28061
28423
  const sessions = records || await this.deps.listHostedCliRuntimes?.() || [];
28062
28424
  let restored = 0;
28425
+ const restoredBindings = /* @__PURE__ */ new Set();
28063
28426
  for (const record2 of sessions) {
28064
28427
  if (!record2?.runtimeId || !record2?.cliType || !record2?.workspace) continue;
28065
28428
  if (this.adapters.has(record2.runtimeId) || instanceManager.getInstance(record2.runtimeId)) continue;
@@ -28073,6 +28436,18 @@ Run 'adhdev doctor' for detailed diagnostics.`
28073
28436
  record2.cliArgs,
28074
28437
  record2.providerSessionId
28075
28438
  );
28439
+ const bindingKey = [
28440
+ normalizedType,
28441
+ record2.workspace,
28442
+ sessionBinding.providerSessionId || record2.runtimeId
28443
+ ].join("::");
28444
+ if (restoredBindings.has(bindingKey)) {
28445
+ LOG.info(
28446
+ "CLI",
28447
+ `\u21B7 Skipping duplicate hosted runtime restore: ${record2.runtimeKey || record2.runtimeId} (${normalizedType} @ ${record2.workspace}) binding=${sessionBinding.providerSessionId || "runtime"}`
28448
+ );
28449
+ continue;
28450
+ }
28076
28451
  try {
28077
28452
  await this.registerCliInstance(
28078
28453
  record2.runtimeId,
@@ -28088,6 +28463,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
28088
28463
  launchMode: "manual"
28089
28464
  }
28090
28465
  );
28466
+ restoredBindings.add(bindingKey);
28091
28467
  restored += 1;
28092
28468
  LOG.info("CLI", `\u267B Restored hosted runtime: ${record2.runtimeKey || record2.runtimeId} (${record2.displayName || record2.workspace})`);
28093
28469
  } catch (error48) {
@@ -28376,7 +28752,7 @@ var init_readdirp = __esm({
28376
28752
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
28377
28753
  const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
28378
28754
  if (wantBigintFsStats) {
28379
- this._stat = (path27) => statMethod(path27, { bigint: true });
28755
+ this._stat = (path28) => statMethod(path28, { bigint: true });
28380
28756
  } else {
28381
28757
  this._stat = statMethod;
28382
28758
  }
@@ -28401,8 +28777,8 @@ var init_readdirp = __esm({
28401
28777
  const par = this.parent;
28402
28778
  const fil = par && par.files;
28403
28779
  if (fil && fil.length > 0) {
28404
- const { path: path27, depth } = par;
28405
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path27));
28780
+ const { path: path28, depth } = par;
28781
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path28));
28406
28782
  const awaited = await Promise.all(slice);
28407
28783
  for (const entry of awaited) {
28408
28784
  if (!entry)
@@ -28442,20 +28818,20 @@ var init_readdirp = __esm({
28442
28818
  this.reading = false;
28443
28819
  }
28444
28820
  }
28445
- async _exploreDir(path27, depth) {
28821
+ async _exploreDir(path28, depth) {
28446
28822
  let files;
28447
28823
  try {
28448
- files = await (0, import_promises.readdir)(path27, this._rdOptions);
28824
+ files = await (0, import_promises.readdir)(path28, this._rdOptions);
28449
28825
  } catch (error48) {
28450
28826
  this._onError(error48);
28451
28827
  }
28452
- return { files, depth, path: path27 };
28828
+ return { files, depth, path: path28 };
28453
28829
  }
28454
- async _formatEntry(dirent, path27) {
28830
+ async _formatEntry(dirent, path28) {
28455
28831
  let entry;
28456
28832
  const basename8 = this._isDirent ? dirent.name : dirent;
28457
28833
  try {
28458
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path27, basename8));
28834
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path28, basename8));
28459
28835
  entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename8 };
28460
28836
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
28461
28837
  } catch (err) {
@@ -28512,16 +28888,16 @@ var init_readdirp = __esm({
28512
28888
  });
28513
28889
 
28514
28890
  // ../../oss/packages/daemon-core/node_modules/chokidar/handler.js
28515
- function createFsWatchInstance(path27, options, listener, errHandler, emitRaw) {
28891
+ function createFsWatchInstance(path28, options, listener, errHandler, emitRaw) {
28516
28892
  const handleEvent = (rawEvent, evPath) => {
28517
- listener(path27);
28518
- emitRaw(rawEvent, evPath, { watchedPath: path27 });
28519
- if (evPath && path27 !== evPath) {
28520
- fsWatchBroadcast(sp.resolve(path27, evPath), KEY_LISTENERS, sp.join(path27, evPath));
28893
+ listener(path28);
28894
+ emitRaw(rawEvent, evPath, { watchedPath: path28 });
28895
+ if (evPath && path28 !== evPath) {
28896
+ fsWatchBroadcast(sp.resolve(path28, evPath), KEY_LISTENERS, sp.join(path28, evPath));
28521
28897
  }
28522
28898
  };
28523
28899
  try {
28524
- return (0, import_node_fs.watch)(path27, {
28900
+ return (0, import_node_fs.watch)(path28, {
28525
28901
  persistent: options.persistent
28526
28902
  }, handleEvent);
28527
28903
  } catch (error48) {
@@ -28870,12 +29246,12 @@ var init_handler2 = __esm({
28870
29246
  listener(val1, val2, val3);
28871
29247
  });
28872
29248
  };
28873
- setFsWatchListener = (path27, fullPath, options, handlers) => {
29249
+ setFsWatchListener = (path28, fullPath, options, handlers) => {
28874
29250
  const { listener, errHandler, rawEmitter } = handlers;
28875
29251
  let cont = FsWatchInstances.get(fullPath);
28876
29252
  let watcher;
28877
29253
  if (!options.persistent) {
28878
- watcher = createFsWatchInstance(path27, options, listener, errHandler, rawEmitter);
29254
+ watcher = createFsWatchInstance(path28, options, listener, errHandler, rawEmitter);
28879
29255
  if (!watcher)
28880
29256
  return;
28881
29257
  return watcher.close.bind(watcher);
@@ -28886,7 +29262,7 @@ var init_handler2 = __esm({
28886
29262
  addAndConvert(cont, KEY_RAW, rawEmitter);
28887
29263
  } else {
28888
29264
  watcher = createFsWatchInstance(
28889
- path27,
29265
+ path28,
28890
29266
  options,
28891
29267
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
28892
29268
  errHandler,
@@ -28901,7 +29277,7 @@ var init_handler2 = __esm({
28901
29277
  cont.watcherUnusable = true;
28902
29278
  if (isWindows && error48.code === "EPERM") {
28903
29279
  try {
28904
- const fd = await (0, import_promises2.open)(path27, "r");
29280
+ const fd = await (0, import_promises2.open)(path28, "r");
28905
29281
  await fd.close();
28906
29282
  broadcastErr(error48);
28907
29283
  } catch (err) {
@@ -28932,7 +29308,7 @@ var init_handler2 = __esm({
28932
29308
  };
28933
29309
  };
28934
29310
  FsWatchFileInstances = /* @__PURE__ */ new Map();
28935
- setFsWatchFileListener = (path27, fullPath, options, handlers) => {
29311
+ setFsWatchFileListener = (path28, fullPath, options, handlers) => {
28936
29312
  const { listener, rawEmitter } = handlers;
28937
29313
  let cont = FsWatchFileInstances.get(fullPath);
28938
29314
  const copts = cont && cont.options;
@@ -28954,7 +29330,7 @@ var init_handler2 = __esm({
28954
29330
  });
28955
29331
  const currmtime = curr.mtimeMs;
28956
29332
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
28957
- foreach(cont.listeners, (listener2) => listener2(path27, curr));
29333
+ foreach(cont.listeners, (listener2) => listener2(path28, curr));
28958
29334
  }
28959
29335
  })
28960
29336
  };
@@ -28984,13 +29360,13 @@ var init_handler2 = __esm({
28984
29360
  * @param listener on fs change
28985
29361
  * @returns closer for the watcher instance
28986
29362
  */
28987
- _watchWithNodeFs(path27, listener) {
29363
+ _watchWithNodeFs(path28, listener) {
28988
29364
  const opts = this.fsw.options;
28989
- const directory = sp.dirname(path27);
28990
- const basename8 = sp.basename(path27);
29365
+ const directory = sp.dirname(path28);
29366
+ const basename8 = sp.basename(path28);
28991
29367
  const parent = this.fsw._getWatchedDir(directory);
28992
29368
  parent.add(basename8);
28993
- const absolutePath = sp.resolve(path27);
29369
+ const absolutePath = sp.resolve(path28);
28994
29370
  const options = {
28995
29371
  persistent: opts.persistent
28996
29372
  };
@@ -29000,12 +29376,12 @@ var init_handler2 = __esm({
29000
29376
  if (opts.usePolling) {
29001
29377
  const enableBin = opts.interval !== opts.binaryInterval;
29002
29378
  options.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
29003
- closer = setFsWatchFileListener(path27, absolutePath, options, {
29379
+ closer = setFsWatchFileListener(path28, absolutePath, options, {
29004
29380
  listener,
29005
29381
  rawEmitter: this.fsw._emitRaw
29006
29382
  });
29007
29383
  } else {
29008
- closer = setFsWatchListener(path27, absolutePath, options, {
29384
+ closer = setFsWatchListener(path28, absolutePath, options, {
29009
29385
  listener,
29010
29386
  errHandler: this._boundHandleError,
29011
29387
  rawEmitter: this.fsw._emitRaw
@@ -29027,7 +29403,7 @@ var init_handler2 = __esm({
29027
29403
  let prevStats = stats;
29028
29404
  if (parent.has(basename8))
29029
29405
  return;
29030
- const listener = async (path27, newStats) => {
29406
+ const listener = async (path28, newStats) => {
29031
29407
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
29032
29408
  return;
29033
29409
  if (!newStats || newStats.mtimeMs === 0) {
@@ -29041,11 +29417,11 @@ var init_handler2 = __esm({
29041
29417
  this.fsw._emit(EV.CHANGE, file2, newStats2);
29042
29418
  }
29043
29419
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
29044
- this.fsw._closeFile(path27);
29420
+ this.fsw._closeFile(path28);
29045
29421
  prevStats = newStats2;
29046
29422
  const closer2 = this._watchWithNodeFs(file2, listener);
29047
29423
  if (closer2)
29048
- this.fsw._addPathCloser(path27, closer2);
29424
+ this.fsw._addPathCloser(path28, closer2);
29049
29425
  } else {
29050
29426
  prevStats = newStats2;
29051
29427
  }
@@ -29077,7 +29453,7 @@ var init_handler2 = __esm({
29077
29453
  * @param item basename of this item
29078
29454
  * @returns true if no more processing is needed for this entry.
29079
29455
  */
29080
- async _handleSymlink(entry, directory, path27, item) {
29456
+ async _handleSymlink(entry, directory, path28, item) {
29081
29457
  if (this.fsw.closed) {
29082
29458
  return;
29083
29459
  }
@@ -29087,7 +29463,7 @@ var init_handler2 = __esm({
29087
29463
  this.fsw._incrReadyCount();
29088
29464
  let linkPath;
29089
29465
  try {
29090
- linkPath = await (0, import_promises2.realpath)(path27);
29466
+ linkPath = await (0, import_promises2.realpath)(path28);
29091
29467
  } catch (e) {
29092
29468
  this.fsw._emitReady();
29093
29469
  return true;
@@ -29097,12 +29473,12 @@ var init_handler2 = __esm({
29097
29473
  if (dir.has(item)) {
29098
29474
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
29099
29475
  this.fsw._symlinkPaths.set(full, linkPath);
29100
- this.fsw._emit(EV.CHANGE, path27, entry.stats);
29476
+ this.fsw._emit(EV.CHANGE, path28, entry.stats);
29101
29477
  }
29102
29478
  } else {
29103
29479
  dir.add(item);
29104
29480
  this.fsw._symlinkPaths.set(full, linkPath);
29105
- this.fsw._emit(EV.ADD, path27, entry.stats);
29481
+ this.fsw._emit(EV.ADD, path28, entry.stats);
29106
29482
  }
29107
29483
  this.fsw._emitReady();
29108
29484
  return true;
@@ -29132,9 +29508,9 @@ var init_handler2 = __esm({
29132
29508
  return;
29133
29509
  }
29134
29510
  const item = entry.path;
29135
- let path27 = sp.join(directory, item);
29511
+ let path28 = sp.join(directory, item);
29136
29512
  current.add(item);
29137
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path27, item)) {
29513
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path28, item)) {
29138
29514
  return;
29139
29515
  }
29140
29516
  if (this.fsw.closed) {
@@ -29143,8 +29519,8 @@ var init_handler2 = __esm({
29143
29519
  }
29144
29520
  if (item === target || !target && !previous.has(item)) {
29145
29521
  this.fsw._incrReadyCount();
29146
- path27 = sp.join(dir, sp.relative(dir, path27));
29147
- this._addToNodeFs(path27, initialAdd, wh, depth + 1);
29522
+ path28 = sp.join(dir, sp.relative(dir, path28));
29523
+ this._addToNodeFs(path28, initialAdd, wh, depth + 1);
29148
29524
  }
29149
29525
  }).on(EV.ERROR, this._boundHandleError);
29150
29526
  return new Promise((resolve17, reject) => {
@@ -29213,13 +29589,13 @@ var init_handler2 = __esm({
29213
29589
  * @param depth Child path actually targeted for watch
29214
29590
  * @param target Child path actually targeted for watch
29215
29591
  */
29216
- async _addToNodeFs(path27, initialAdd, priorWh, depth, target) {
29592
+ async _addToNodeFs(path28, initialAdd, priorWh, depth, target) {
29217
29593
  const ready = this.fsw._emitReady;
29218
- if (this.fsw._isIgnored(path27) || this.fsw.closed) {
29594
+ if (this.fsw._isIgnored(path28) || this.fsw.closed) {
29219
29595
  ready();
29220
29596
  return false;
29221
29597
  }
29222
- const wh = this.fsw._getWatchHelpers(path27);
29598
+ const wh = this.fsw._getWatchHelpers(path28);
29223
29599
  if (priorWh) {
29224
29600
  wh.filterPath = (entry) => priorWh.filterPath(entry);
29225
29601
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -29235,8 +29611,8 @@ var init_handler2 = __esm({
29235
29611
  const follow = this.fsw.options.followSymlinks;
29236
29612
  let closer;
29237
29613
  if (stats.isDirectory()) {
29238
- const absPath = sp.resolve(path27);
29239
- const targetPath = follow ? await (0, import_promises2.realpath)(path27) : path27;
29614
+ const absPath = sp.resolve(path28);
29615
+ const targetPath = follow ? await (0, import_promises2.realpath)(path28) : path28;
29240
29616
  if (this.fsw.closed)
29241
29617
  return;
29242
29618
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -29246,29 +29622,29 @@ var init_handler2 = __esm({
29246
29622
  this.fsw._symlinkPaths.set(absPath, targetPath);
29247
29623
  }
29248
29624
  } else if (stats.isSymbolicLink()) {
29249
- const targetPath = follow ? await (0, import_promises2.realpath)(path27) : path27;
29625
+ const targetPath = follow ? await (0, import_promises2.realpath)(path28) : path28;
29250
29626
  if (this.fsw.closed)
29251
29627
  return;
29252
29628
  const parent = sp.dirname(wh.watchPath);
29253
29629
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
29254
29630
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
29255
- closer = await this._handleDir(parent, stats, initialAdd, depth, path27, wh, targetPath);
29631
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path28, wh, targetPath);
29256
29632
  if (this.fsw.closed)
29257
29633
  return;
29258
29634
  if (targetPath !== void 0) {
29259
- this.fsw._symlinkPaths.set(sp.resolve(path27), targetPath);
29635
+ this.fsw._symlinkPaths.set(sp.resolve(path28), targetPath);
29260
29636
  }
29261
29637
  } else {
29262
29638
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
29263
29639
  }
29264
29640
  ready();
29265
29641
  if (closer)
29266
- this.fsw._addPathCloser(path27, closer);
29642
+ this.fsw._addPathCloser(path28, closer);
29267
29643
  return false;
29268
29644
  } catch (error48) {
29269
29645
  if (this.fsw._handleError(error48)) {
29270
29646
  ready();
29271
- return path27;
29647
+ return path28;
29272
29648
  }
29273
29649
  }
29274
29650
  }
@@ -29303,24 +29679,24 @@ function createPattern(matcher) {
29303
29679
  }
29304
29680
  return () => false;
29305
29681
  }
29306
- function normalizePath(path27) {
29307
- if (typeof path27 !== "string")
29682
+ function normalizePath(path28) {
29683
+ if (typeof path28 !== "string")
29308
29684
  throw new Error("string expected");
29309
- path27 = sp2.normalize(path27);
29310
- path27 = path27.replace(/\\/g, "/");
29685
+ path28 = sp2.normalize(path28);
29686
+ path28 = path28.replace(/\\/g, "/");
29311
29687
  let prepend = false;
29312
- if (path27.startsWith("//"))
29688
+ if (path28.startsWith("//"))
29313
29689
  prepend = true;
29314
- path27 = path27.replace(DOUBLE_SLASH_RE, "/");
29690
+ path28 = path28.replace(DOUBLE_SLASH_RE, "/");
29315
29691
  if (prepend)
29316
- path27 = "/" + path27;
29317
- return path27;
29692
+ path28 = "/" + path28;
29693
+ return path28;
29318
29694
  }
29319
29695
  function matchPatterns(patterns, testString, stats) {
29320
- const path27 = normalizePath(testString);
29696
+ const path28 = normalizePath(testString);
29321
29697
  for (let index = 0; index < patterns.length; index++) {
29322
29698
  const pattern = patterns[index];
29323
- if (pattern(path27, stats)) {
29699
+ if (pattern(path28, stats)) {
29324
29700
  return true;
29325
29701
  }
29326
29702
  }
@@ -29383,19 +29759,19 @@ var init_chokidar = __esm({
29383
29759
  }
29384
29760
  return str;
29385
29761
  };
29386
- normalizePathToUnix = (path27) => toUnix(sp2.normalize(toUnix(path27)));
29387
- normalizeIgnored = (cwd = "") => (path27) => {
29388
- if (typeof path27 === "string") {
29389
- return normalizePathToUnix(sp2.isAbsolute(path27) ? path27 : sp2.join(cwd, path27));
29762
+ normalizePathToUnix = (path28) => toUnix(sp2.normalize(toUnix(path28)));
29763
+ normalizeIgnored = (cwd = "") => (path28) => {
29764
+ if (typeof path28 === "string") {
29765
+ return normalizePathToUnix(sp2.isAbsolute(path28) ? path28 : sp2.join(cwd, path28));
29390
29766
  } else {
29391
- return path27;
29767
+ return path28;
29392
29768
  }
29393
29769
  };
29394
- getAbsolutePath = (path27, cwd) => {
29395
- if (sp2.isAbsolute(path27)) {
29396
- return path27;
29770
+ getAbsolutePath = (path28, cwd) => {
29771
+ if (sp2.isAbsolute(path28)) {
29772
+ return path28;
29397
29773
  }
29398
- return sp2.join(cwd, path27);
29774
+ return sp2.join(cwd, path28);
29399
29775
  };
29400
29776
  EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
29401
29777
  DirEntry = class {
@@ -29460,10 +29836,10 @@ var init_chokidar = __esm({
29460
29836
  dirParts;
29461
29837
  followSymlinks;
29462
29838
  statMethod;
29463
- constructor(path27, follow, fsw) {
29839
+ constructor(path28, follow, fsw) {
29464
29840
  this.fsw = fsw;
29465
- const watchPath = path27;
29466
- this.path = path27 = path27.replace(REPLACER_RE, "");
29841
+ const watchPath = path28;
29842
+ this.path = path28 = path28.replace(REPLACER_RE, "");
29467
29843
  this.watchPath = watchPath;
29468
29844
  this.fullWatchPath = sp2.resolve(watchPath);
29469
29845
  this.dirParts = [];
@@ -29603,20 +29979,20 @@ var init_chokidar = __esm({
29603
29979
  this._closePromise = void 0;
29604
29980
  let paths = unifyPaths(paths_);
29605
29981
  if (cwd) {
29606
- paths = paths.map((path27) => {
29607
- const absPath = getAbsolutePath(path27, cwd);
29982
+ paths = paths.map((path28) => {
29983
+ const absPath = getAbsolutePath(path28, cwd);
29608
29984
  return absPath;
29609
29985
  });
29610
29986
  }
29611
- paths.forEach((path27) => {
29612
- this._removeIgnoredPath(path27);
29987
+ paths.forEach((path28) => {
29988
+ this._removeIgnoredPath(path28);
29613
29989
  });
29614
29990
  this._userIgnored = void 0;
29615
29991
  if (!this._readyCount)
29616
29992
  this._readyCount = 0;
29617
29993
  this._readyCount += paths.length;
29618
- Promise.all(paths.map(async (path27) => {
29619
- const res = await this._nodeFsHandler._addToNodeFs(path27, !_internal, void 0, 0, _origAdd);
29994
+ Promise.all(paths.map(async (path28) => {
29995
+ const res = await this._nodeFsHandler._addToNodeFs(path28, !_internal, void 0, 0, _origAdd);
29620
29996
  if (res)
29621
29997
  this._emitReady();
29622
29998
  return res;
@@ -29638,17 +30014,17 @@ var init_chokidar = __esm({
29638
30014
  return this;
29639
30015
  const paths = unifyPaths(paths_);
29640
30016
  const { cwd } = this.options;
29641
- paths.forEach((path27) => {
29642
- if (!sp2.isAbsolute(path27) && !this._closers.has(path27)) {
30017
+ paths.forEach((path28) => {
30018
+ if (!sp2.isAbsolute(path28) && !this._closers.has(path28)) {
29643
30019
  if (cwd)
29644
- path27 = sp2.join(cwd, path27);
29645
- path27 = sp2.resolve(path27);
30020
+ path28 = sp2.join(cwd, path28);
30021
+ path28 = sp2.resolve(path28);
29646
30022
  }
29647
- this._closePath(path27);
29648
- this._addIgnoredPath(path27);
29649
- if (this._watched.has(path27)) {
30023
+ this._closePath(path28);
30024
+ this._addIgnoredPath(path28);
30025
+ if (this._watched.has(path28)) {
29650
30026
  this._addIgnoredPath({
29651
- path: path27,
30027
+ path: path28,
29652
30028
  recursive: true
29653
30029
  });
29654
30030
  }
@@ -29712,38 +30088,38 @@ var init_chokidar = __esm({
29712
30088
  * @param stats arguments to be passed with event
29713
30089
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
29714
30090
  */
29715
- async _emit(event, path27, stats) {
30091
+ async _emit(event, path28, stats) {
29716
30092
  if (this.closed)
29717
30093
  return;
29718
30094
  const opts = this.options;
29719
30095
  if (isWindows)
29720
- path27 = sp2.normalize(path27);
30096
+ path28 = sp2.normalize(path28);
29721
30097
  if (opts.cwd)
29722
- path27 = sp2.relative(opts.cwd, path27);
29723
- const args = [path27];
30098
+ path28 = sp2.relative(opts.cwd, path28);
30099
+ const args = [path28];
29724
30100
  if (stats != null)
29725
30101
  args.push(stats);
29726
30102
  const awf = opts.awaitWriteFinish;
29727
30103
  let pw;
29728
- if (awf && (pw = this._pendingWrites.get(path27))) {
30104
+ if (awf && (pw = this._pendingWrites.get(path28))) {
29729
30105
  pw.lastChange = /* @__PURE__ */ new Date();
29730
30106
  return this;
29731
30107
  }
29732
30108
  if (opts.atomic) {
29733
30109
  if (event === EVENTS.UNLINK) {
29734
- this._pendingUnlinks.set(path27, [event, ...args]);
30110
+ this._pendingUnlinks.set(path28, [event, ...args]);
29735
30111
  setTimeout(() => {
29736
- this._pendingUnlinks.forEach((entry, path28) => {
30112
+ this._pendingUnlinks.forEach((entry, path29) => {
29737
30113
  this.emit(...entry);
29738
30114
  this.emit(EVENTS.ALL, ...entry);
29739
- this._pendingUnlinks.delete(path28);
30115
+ this._pendingUnlinks.delete(path29);
29740
30116
  });
29741
30117
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
29742
30118
  return this;
29743
30119
  }
29744
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path27)) {
30120
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path28)) {
29745
30121
  event = EVENTS.CHANGE;
29746
- this._pendingUnlinks.delete(path27);
30122
+ this._pendingUnlinks.delete(path28);
29747
30123
  }
29748
30124
  }
29749
30125
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -29761,16 +30137,16 @@ var init_chokidar = __esm({
29761
30137
  this.emitWithAll(event, args);
29762
30138
  }
29763
30139
  };
29764
- this._awaitWriteFinish(path27, awf.stabilityThreshold, event, awfEmit);
30140
+ this._awaitWriteFinish(path28, awf.stabilityThreshold, event, awfEmit);
29765
30141
  return this;
29766
30142
  }
29767
30143
  if (event === EVENTS.CHANGE) {
29768
- const isThrottled = !this._throttle(EVENTS.CHANGE, path27, 50);
30144
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path28, 50);
29769
30145
  if (isThrottled)
29770
30146
  return this;
29771
30147
  }
29772
30148
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
29773
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path27) : path27;
30149
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path28) : path28;
29774
30150
  let stats2;
29775
30151
  try {
29776
30152
  stats2 = await (0, import_promises3.stat)(fullPath);
@@ -29801,23 +30177,23 @@ var init_chokidar = __esm({
29801
30177
  * @param timeout duration of time to suppress duplicate actions
29802
30178
  * @returns tracking object or false if action should be suppressed
29803
30179
  */
29804
- _throttle(actionType, path27, timeout) {
30180
+ _throttle(actionType, path28, timeout) {
29805
30181
  if (!this._throttled.has(actionType)) {
29806
30182
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
29807
30183
  }
29808
30184
  const action = this._throttled.get(actionType);
29809
30185
  if (!action)
29810
30186
  throw new Error("invalid throttle");
29811
- const actionPath = action.get(path27);
30187
+ const actionPath = action.get(path28);
29812
30188
  if (actionPath) {
29813
30189
  actionPath.count++;
29814
30190
  return false;
29815
30191
  }
29816
30192
  let timeoutObject;
29817
30193
  const clear = () => {
29818
- const item = action.get(path27);
30194
+ const item = action.get(path28);
29819
30195
  const count = item ? item.count : 0;
29820
- action.delete(path27);
30196
+ action.delete(path28);
29821
30197
  clearTimeout(timeoutObject);
29822
30198
  if (item)
29823
30199
  clearTimeout(item.timeoutObject);
@@ -29825,7 +30201,7 @@ var init_chokidar = __esm({
29825
30201
  };
29826
30202
  timeoutObject = setTimeout(clear, timeout);
29827
30203
  const thr = { timeoutObject, clear, count: 0 };
29828
- action.set(path27, thr);
30204
+ action.set(path28, thr);
29829
30205
  return thr;
29830
30206
  }
29831
30207
  _incrReadyCount() {
@@ -29839,44 +30215,44 @@ var init_chokidar = __esm({
29839
30215
  * @param event
29840
30216
  * @param awfEmit Callback to be called when ready for event to be emitted.
29841
30217
  */
29842
- _awaitWriteFinish(path27, threshold, event, awfEmit) {
30218
+ _awaitWriteFinish(path28, threshold, event, awfEmit) {
29843
30219
  const awf = this.options.awaitWriteFinish;
29844
30220
  if (typeof awf !== "object")
29845
30221
  return;
29846
30222
  const pollInterval = awf.pollInterval;
29847
30223
  let timeoutHandler;
29848
- let fullPath = path27;
29849
- if (this.options.cwd && !sp2.isAbsolute(path27)) {
29850
- fullPath = sp2.join(this.options.cwd, path27);
30224
+ let fullPath = path28;
30225
+ if (this.options.cwd && !sp2.isAbsolute(path28)) {
30226
+ fullPath = sp2.join(this.options.cwd, path28);
29851
30227
  }
29852
30228
  const now = /* @__PURE__ */ new Date();
29853
30229
  const writes = this._pendingWrites;
29854
30230
  function awaitWriteFinishFn(prevStat) {
29855
30231
  (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
29856
- if (err || !writes.has(path27)) {
30232
+ if (err || !writes.has(path28)) {
29857
30233
  if (err && err.code !== "ENOENT")
29858
30234
  awfEmit(err);
29859
30235
  return;
29860
30236
  }
29861
30237
  const now2 = Number(/* @__PURE__ */ new Date());
29862
30238
  if (prevStat && curStat.size !== prevStat.size) {
29863
- writes.get(path27).lastChange = now2;
30239
+ writes.get(path28).lastChange = now2;
29864
30240
  }
29865
- const pw = writes.get(path27);
30241
+ const pw = writes.get(path28);
29866
30242
  const df = now2 - pw.lastChange;
29867
30243
  if (df >= threshold) {
29868
- writes.delete(path27);
30244
+ writes.delete(path28);
29869
30245
  awfEmit(void 0, curStat);
29870
30246
  } else {
29871
30247
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
29872
30248
  }
29873
30249
  });
29874
30250
  }
29875
- if (!writes.has(path27)) {
29876
- writes.set(path27, {
30251
+ if (!writes.has(path28)) {
30252
+ writes.set(path28, {
29877
30253
  lastChange: now,
29878
30254
  cancelWait: () => {
29879
- writes.delete(path27);
30255
+ writes.delete(path28);
29880
30256
  clearTimeout(timeoutHandler);
29881
30257
  return event;
29882
30258
  }
@@ -29887,8 +30263,8 @@ var init_chokidar = __esm({
29887
30263
  /**
29888
30264
  * Determines whether user has asked to ignore this path.
29889
30265
  */
29890
- _isIgnored(path27, stats) {
29891
- if (this.options.atomic && DOT_RE.test(path27))
30266
+ _isIgnored(path28, stats) {
30267
+ if (this.options.atomic && DOT_RE.test(path28))
29892
30268
  return true;
29893
30269
  if (!this._userIgnored) {
29894
30270
  const { cwd } = this.options;
@@ -29898,17 +30274,17 @@ var init_chokidar = __esm({
29898
30274
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
29899
30275
  this._userIgnored = anymatch(list, void 0);
29900
30276
  }
29901
- return this._userIgnored(path27, stats);
30277
+ return this._userIgnored(path28, stats);
29902
30278
  }
29903
- _isntIgnored(path27, stat4) {
29904
- return !this._isIgnored(path27, stat4);
30279
+ _isntIgnored(path28, stat4) {
30280
+ return !this._isIgnored(path28, stat4);
29905
30281
  }
29906
30282
  /**
29907
30283
  * Provides a set of common helpers and properties relating to symlink handling.
29908
30284
  * @param path file or directory pattern being watched
29909
30285
  */
29910
- _getWatchHelpers(path27) {
29911
- return new WatchHelper(path27, this.options.followSymlinks, this);
30286
+ _getWatchHelpers(path28) {
30287
+ return new WatchHelper(path28, this.options.followSymlinks, this);
29912
30288
  }
29913
30289
  // Directory helpers
29914
30290
  // -----------------
@@ -29940,63 +30316,63 @@ var init_chokidar = __esm({
29940
30316
  * @param item base path of item/directory
29941
30317
  */
29942
30318
  _remove(directory, item, isDirectory) {
29943
- const path27 = sp2.join(directory, item);
29944
- const fullPath = sp2.resolve(path27);
29945
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path27) || this._watched.has(fullPath);
29946
- if (!this._throttle("remove", path27, 100))
30319
+ const path28 = sp2.join(directory, item);
30320
+ const fullPath = sp2.resolve(path28);
30321
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path28) || this._watched.has(fullPath);
30322
+ if (!this._throttle("remove", path28, 100))
29947
30323
  return;
29948
30324
  if (!isDirectory && this._watched.size === 1) {
29949
30325
  this.add(directory, item, true);
29950
30326
  }
29951
- const wp = this._getWatchedDir(path27);
30327
+ const wp = this._getWatchedDir(path28);
29952
30328
  const nestedDirectoryChildren = wp.getChildren();
29953
- nestedDirectoryChildren.forEach((nested) => this._remove(path27, nested));
30329
+ nestedDirectoryChildren.forEach((nested) => this._remove(path28, nested));
29954
30330
  const parent = this._getWatchedDir(directory);
29955
30331
  const wasTracked = parent.has(item);
29956
30332
  parent.remove(item);
29957
30333
  if (this._symlinkPaths.has(fullPath)) {
29958
30334
  this._symlinkPaths.delete(fullPath);
29959
30335
  }
29960
- let relPath = path27;
30336
+ let relPath = path28;
29961
30337
  if (this.options.cwd)
29962
- relPath = sp2.relative(this.options.cwd, path27);
30338
+ relPath = sp2.relative(this.options.cwd, path28);
29963
30339
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
29964
30340
  const event = this._pendingWrites.get(relPath).cancelWait();
29965
30341
  if (event === EVENTS.ADD)
29966
30342
  return;
29967
30343
  }
29968
- this._watched.delete(path27);
30344
+ this._watched.delete(path28);
29969
30345
  this._watched.delete(fullPath);
29970
30346
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
29971
- if (wasTracked && !this._isIgnored(path27))
29972
- this._emit(eventName, path27);
29973
- this._closePath(path27);
30347
+ if (wasTracked && !this._isIgnored(path28))
30348
+ this._emit(eventName, path28);
30349
+ this._closePath(path28);
29974
30350
  }
29975
30351
  /**
29976
30352
  * Closes all watchers for a path
29977
30353
  */
29978
- _closePath(path27) {
29979
- this._closeFile(path27);
29980
- const dir = sp2.dirname(path27);
29981
- this._getWatchedDir(dir).remove(sp2.basename(path27));
30354
+ _closePath(path28) {
30355
+ this._closeFile(path28);
30356
+ const dir = sp2.dirname(path28);
30357
+ this._getWatchedDir(dir).remove(sp2.basename(path28));
29982
30358
  }
29983
30359
  /**
29984
30360
  * Closes only file-specific watchers
29985
30361
  */
29986
- _closeFile(path27) {
29987
- const closers = this._closers.get(path27);
30362
+ _closeFile(path28) {
30363
+ const closers = this._closers.get(path28);
29988
30364
  if (!closers)
29989
30365
  return;
29990
30366
  closers.forEach((closer) => closer());
29991
- this._closers.delete(path27);
30367
+ this._closers.delete(path28);
29992
30368
  }
29993
- _addPathCloser(path27, closer) {
30369
+ _addPathCloser(path28, closer) {
29994
30370
  if (!closer)
29995
30371
  return;
29996
- let list = this._closers.get(path27);
30372
+ let list = this._closers.get(path28);
29997
30373
  if (!list) {
29998
30374
  list = [];
29999
- this._closers.set(path27, list);
30375
+ this._closers.set(path28, list);
30000
30376
  }
30001
30377
  list.push(closer);
30002
30378
  }
@@ -30656,7 +31032,7 @@ var init_provider_loader = __esm({
30656
31032
  return { updated: false };
30657
31033
  }
30658
31034
  const https = require("https");
30659
- const { execSync: execSync7 } = require("child_process");
31035
+ const { execSync: execSync8 } = require("child_process");
30660
31036
  const metaPath = path13.join(this.upstreamDir, _ProviderLoader.META_FILE);
30661
31037
  let prevEtag = "";
30662
31038
  let prevTimestamp = 0;
@@ -30721,7 +31097,7 @@ var init_provider_loader = __esm({
30721
31097
  const tmpExtract = path13.join(os12.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
30722
31098
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
30723
31099
  fs6.mkdirSync(tmpExtract, { recursive: true });
30724
- execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
31100
+ execSync8(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
30725
31101
  const extracted = fs6.readdirSync(tmpExtract);
30726
31102
  const rootDir = extracted.find(
30727
31103
  (d) => fs6.statSync(path13.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
@@ -30864,7 +31240,7 @@ var init_provider_loader = __esm({
30864
31240
  */
30865
31241
  getSettingValue(type, key) {
30866
31242
  const schemaDef = this.getSettingsSchema(type)[key];
30867
- const defaultVal = schemaDef ? schemaDef.default : void 0;
31243
+ const defaultVal = schemaDef ? key === "autoApprove" && schemaDef.type === "boolean" ? true : schemaDef.default : void 0;
30868
31244
  try {
30869
31245
  const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
30870
31246
  const config2 = loadConfig2();
@@ -30923,13 +31299,32 @@ var init_provider_loader = __esm({
30923
31299
  getSettingsSchema(type) {
30924
31300
  const provider = this.providers.get(type);
30925
31301
  if (!provider) return {};
30926
- return {
31302
+ const result = {
30927
31303
  ...this.getSyntheticSettings(type, provider),
30928
31304
  ...provider.settings || {}
30929
31305
  };
31306
+ if (result.autoApprove?.type === "boolean") {
31307
+ result.autoApprove = {
31308
+ ...result.autoApprove,
31309
+ default: true,
31310
+ public: true,
31311
+ label: result.autoApprove.label || "Auto Approve",
31312
+ description: result.autoApprove.description || "Automatically approve actionable prompts without sending approval alerts."
31313
+ };
31314
+ }
31315
+ return result;
30930
31316
  }
30931
31317
  getSyntheticSettings(type, provider) {
30932
31318
  const result = {};
31319
+ if (!provider.settings?.autoApprove) {
31320
+ result.autoApprove = {
31321
+ type: "boolean",
31322
+ default: true,
31323
+ public: true,
31324
+ label: "Auto Approve",
31325
+ description: "Automatically approve actionable prompts without sending approval alerts."
31326
+ };
31327
+ }
30933
31328
  if ((provider.category === "cli" || provider.category === "acp") && provider.spawn?.command && !provider.settings?.executablePath) {
30934
31329
  result.executablePath = {
30935
31330
  type: "string",
@@ -31369,7 +31764,7 @@ function detectCurrentWorkspace(ideId) {
31369
31764
  }
31370
31765
  } else if (plat === "win32") {
31371
31766
  try {
31372
- const fs19 = require("fs");
31767
+ const fs20 = require("fs");
31373
31768
  const appNameMap = getMacAppIdentifiers();
31374
31769
  const appName = appNameMap[ideId];
31375
31770
  if (appName) {
@@ -31378,8 +31773,8 @@ function detectCurrentWorkspace(ideId) {
31378
31773
  appName,
31379
31774
  "storage.json"
31380
31775
  );
31381
- if (fs19.existsSync(storagePath)) {
31382
- const data = JSON.parse(fs19.readFileSync(storagePath, "utf-8"));
31776
+ if (fs20.existsSync(storagePath)) {
31777
+ const data = JSON.parse(fs20.readFileSync(storagePath, "utf-8"));
31383
31778
  const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
31384
31779
  if (workspaces.length > 0) {
31385
31780
  const recent = workspaces[0];
@@ -32240,6 +32635,15 @@ var init_router = __esm({
32240
32635
  const record2 = await this.deps.sessionHostControl.forceDetachClient(sessionId, clientId);
32241
32636
  return { success: true, record: record2 };
32242
32637
  }
32638
+ case "session_host_prune_duplicate_sessions": {
32639
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
32640
+ const result = await this.deps.sessionHostControl.pruneDuplicateSessions({
32641
+ providerType: typeof args?.providerType === "string" ? args.providerType : void 0,
32642
+ workspace: typeof args?.workspace === "string" ? args.workspace : void 0,
32643
+ dryRun: args?.dryRun === true
32644
+ });
32645
+ return { success: true, result };
32646
+ }
32243
32647
  case "session_host_acquire_write": {
32244
32648
  if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
32245
32649
  const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
@@ -32450,14 +32854,14 @@ var init_router = __esm({
32450
32854
  case "daemon_upgrade": {
32451
32855
  LOG.info("Upgrade", "Remote upgrade requested from dashboard");
32452
32856
  try {
32453
- const { execSync: execSync7 } = await import("child_process");
32857
+ const { execSync: execSync8 } = await import("child_process");
32454
32858
  const isStandalone = this.deps.packageName === "@adhdev/daemon-standalone" || process.argv[1]?.includes("daemon-standalone");
32455
32859
  const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
32456
- const latest = execSync7(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
32860
+ const latest = execSync8(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
32457
32861
  LOG.info("Upgrade", `Latest ${pkgName}: v${latest}`);
32458
32862
  let currentInstalled = null;
32459
32863
  try {
32460
- const currentJson = execSync7(`npm ls -g ${pkgName} --depth=0 --json`, {
32864
+ const currentJson = execSync8(`npm ls -g ${pkgName} --depth=0 --json`, {
32461
32865
  encoding: "utf-8",
32462
32866
  timeout: 1e4,
32463
32867
  stdio: ["pipe", "pipe", "pipe"]
@@ -32843,6 +33247,51 @@ var init_provider_adapter = __esm({
32843
33247
  isTransportError(reason) {
32844
33248
  return /Session with given id not found/i.test(reason) || /CDP not connected/i.test(reason) || /Target closed/i.test(reason) || /WebSocket not open/i.test(reason) || /not connected/i.test(reason) || /execution context/i.test(reason) || /Cannot find context with specified id/i.test(reason);
32845
33249
  }
33250
+ titlesMatch(actual, expected) {
33251
+ const lhs = actual.trim().toLowerCase();
33252
+ const rhs = expected.trim().toLowerCase();
33253
+ if (!lhs || !rhs) return false;
33254
+ return lhs === rhs || lhs.includes(rhs) || rhs.includes(lhs);
33255
+ }
33256
+ messageCount(state) {
33257
+ return Array.isArray(state?.messages) ? state.messages.length : 0;
33258
+ }
33259
+ lastMessageSignature(state) {
33260
+ const messages = Array.isArray(state?.messages) ? state.messages : [];
33261
+ const last = messages[messages.length - 1];
33262
+ if (!last) return "";
33263
+ return `${last.role || ""}:${String(last.content || "").replace(/\s+/g, " ").trim()}`;
33264
+ }
33265
+ async verifySendOutcome(evaluate, before) {
33266
+ const beforeCount = this.messageCount(before);
33267
+ const beforeSignature = this.lastMessageSignature(before);
33268
+ for (let attempt = 0; attempt < 12; attempt += 1) {
33269
+ await new Promise((resolve17) => setTimeout(resolve17, 250));
33270
+ let state;
33271
+ try {
33272
+ state = await this.readChat(evaluate);
33273
+ } catch {
33274
+ continue;
33275
+ }
33276
+ if (state.status === "waiting_approval") {
33277
+ return true;
33278
+ }
33279
+ const afterCount = this.messageCount(state);
33280
+ const afterSignature = this.lastMessageSignature(state);
33281
+ if (afterCount > beforeCount) return true;
33282
+ if (afterSignature && afterSignature !== beforeSignature) return true;
33283
+ }
33284
+ return false;
33285
+ }
33286
+ async readStableBaselineState(evaluate) {
33287
+ const first = await this.readChat(evaluate);
33288
+ if (this.messageCount(first) > 0 || this.lastMessageSignature(first)) {
33289
+ return first;
33290
+ }
33291
+ await new Promise((resolve17) => setTimeout(resolve17, 150));
33292
+ const second = await this.readChat(evaluate);
33293
+ return this.messageCount(second) >= this.messageCount(first) ? second : first;
33294
+ }
32846
33295
  async readChat(evaluate) {
32847
33296
  const script = this.callScript("readChat");
32848
33297
  if (!script) return this.errorState("readChat script not available");
@@ -32868,6 +33317,9 @@ var init_provider_adapter = __esm({
32868
33317
  mode: data.mode,
32869
33318
  activeModal: data.activeModal
32870
33319
  };
33320
+ if (typeof data.title === "string" && data.title.trim()) {
33321
+ state.title = data.title.trim();
33322
+ }
32871
33323
  const controlValues = extractProviderControlValues(this.provider.controls, data);
32872
33324
  if (controlValues) state.controlValues = controlValues;
32873
33325
  const effects = normalizeProviderEffects(data);
@@ -32891,6 +33343,12 @@ var init_provider_adapter = __esm({
32891
33343
  }
32892
33344
  }
32893
33345
  async sendMessage(evaluate, text) {
33346
+ let beforeState = null;
33347
+ try {
33348
+ beforeState = await this.readStableBaselineState(evaluate);
33349
+ } catch {
33350
+ beforeState = null;
33351
+ }
32894
33352
  const params = { message: text };
32895
33353
  const script = this.callScript("sendMessage", params) || this.callScript("sendMessage", text);
32896
33354
  if (!script) throw new Error(`[${this.agentName}] sendMessage script not available`);
@@ -32908,7 +33366,9 @@ var init_provider_adapter = __esm({
32908
33366
  }
32909
33367
  if (parsed && typeof parsed === "object") {
32910
33368
  if (parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true) {
32911
- return;
33369
+ const verified = await this.verifySendOutcome(evaluate, beforeState);
33370
+ if (verified) return;
33371
+ throw new Error(`[${this.agentName}] sendMessage was not observed in chat state`);
32912
33372
  }
32913
33373
  if (typeof parsed.error === "string" && parsed.error.trim()) {
32914
33374
  throw new Error(`[${this.agentName}] sendMessage failed: ${parsed.error}`);
@@ -32919,7 +33379,15 @@ var init_provider_adapter = __esm({
32919
33379
  async resolveAction(evaluate, action, button) {
32920
33380
  const script = this.callScript("resolveAction", { action, button });
32921
33381
  if (!script) return false;
32922
- return await evaluate(script) === true;
33382
+ const result = await evaluate(script);
33383
+ const parsed = this.parseMaybeJson(result);
33384
+ if (parsed === true) return true;
33385
+ if (typeof parsed === "string") {
33386
+ const normalized = parsed.trim().toLowerCase();
33387
+ return normalized === "ok" || normalized === "success" || normalized === "true" || normalized === "resolved" || normalized === "approved" || normalized === "rejected";
33388
+ }
33389
+ if (!parsed || typeof parsed !== "object") return false;
33390
+ return parsed.resolved === true || parsed.success === true || parsed.ok === true || parsed.found === true;
32923
33391
  }
32924
33392
  async newSession(evaluate) {
32925
33393
  const script = this.callScript("newSession");
@@ -32956,7 +33424,14 @@ var init_provider_adapter = __esm({
32956
33424
  return normalized === "true" || normalized === "ok" || normalized === "switched" || normalized === "success";
32957
33425
  }
32958
33426
  if (data && typeof data === "object") {
32959
- return data.switched === true || data.success === true || data.ok === true;
33427
+ if (data.switched === true || data.success === true || data.ok === true) return true;
33428
+ if (typeof data.error === "string" && data.error.trim()) return false;
33429
+ }
33430
+ for (let attempt = 0; attempt < 6; attempt += 1) {
33431
+ await new Promise((resolve17) => setTimeout(resolve17, 250));
33432
+ const state = await this.readChat(evaluate);
33433
+ const title = typeof state.title === "string" ? state.title : "";
33434
+ if (this.titlesMatch(title, sessionId)) return true;
32960
33435
  }
32961
33436
  return false;
32962
33437
  }
@@ -33171,7 +33646,7 @@ var init_manager2 = __esm({
33171
33646
  return false;
33172
33647
  }
33173
33648
  }
33174
- async resolveSessionAction(cdp, sessionId, action) {
33649
+ async resolveSessionAction(cdp, sessionId, action, button) {
33175
33650
  await this.ensureSessionPanelOpen(sessionId);
33176
33651
  const target = this.getSessionTarget(sessionId);
33177
33652
  if (!target?.parentSessionId) return false;
@@ -33181,7 +33656,7 @@ var init_manager2 = __esm({
33181
33656
  if (!agent) return false;
33182
33657
  try {
33183
33658
  const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
33184
- return await agent.adapter.resolveAction(evaluate, action);
33659
+ return await agent.adapter.resolveAction(evaluate, action, button);
33185
33660
  } catch (e) {
33186
33661
  this.logFn(`[AgentStream] resolveAction(${sessionId}) error: ${e.message}`);
33187
33662
  return false;
@@ -33296,6 +33771,7 @@ var init_poller = __esm({
33296
33771
  init_setup();
33297
33772
  init_reconcile();
33298
33773
  init_logger();
33774
+ init_approval_utils();
33299
33775
  AgentStreamPoller = class {
33300
33776
  deps;
33301
33777
  timer = null;
@@ -33426,7 +33902,43 @@ var init_poller = __esm({
33426
33902
  }
33427
33903
  try {
33428
33904
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
33429
- const stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
33905
+ let stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
33906
+ if (stream?.status === "waiting_approval") {
33907
+ const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
33908
+ if (autoApprove && resolvedActiveSessionId) {
33909
+ const provider = providerLoader.getMeta(stream.agentType);
33910
+ const { label: buttonLabel } = pickApprovalButton(stream.activeModal?.buttons, provider);
33911
+ const approved = await agentStreamManager.resolveSessionAction(cdp, resolvedActiveSessionId, "approve", buttonLabel);
33912
+ if (approved) {
33913
+ const effectId = [
33914
+ "auto_approval",
33915
+ resolvedActiveSessionId,
33916
+ String(stream.messages?.length || 0),
33917
+ buttonLabel,
33918
+ String(stream.activeModal?.message || "").trim()
33919
+ ].join(":");
33920
+ stream = {
33921
+ ...stream,
33922
+ status: "streaming",
33923
+ activeModal: void 0,
33924
+ effects: [
33925
+ ...stream.effects || [],
33926
+ {
33927
+ type: "message",
33928
+ id: effectId,
33929
+ persist: true,
33930
+ message: {
33931
+ role: "system",
33932
+ senderName: "System",
33933
+ kind: "system",
33934
+ content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
33935
+ }
33936
+ }
33937
+ ]
33938
+ };
33939
+ }
33940
+ }
33941
+ }
33430
33942
  this.deps.onStreamsUpdated?.(ideType, stream ? [stream] : []);
33431
33943
  } catch {
33432
33944
  }
@@ -37592,8 +38104,8 @@ var init_dev_server = __esm({
37592
38104
  }
37593
38105
  getEndpointList() {
37594
38106
  return this.routes.map((r) => {
37595
- const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
37596
- return `${r.method.padEnd(5)} ${path27}`;
38107
+ const path28 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
38108
+ return `${r.method.padEnd(5)} ${path28}`;
37597
38109
  });
37598
38110
  }
37599
38111
  async start(port = DEV_SERVER_PORT) {
@@ -39484,8 +39996,8 @@ async function installExtension(ide, extension) {
39484
39996
  const res = await fetch(extension.vsixUrl);
39485
39997
  if (res.ok) {
39486
39998
  const buffer = Buffer.from(await res.arrayBuffer());
39487
- const fs19 = await import("fs");
39488
- fs19.writeFileSync(vsixPath, buffer);
39999
+ const fs20 = await import("fs");
40000
+ fs20.writeFileSync(vsixPath, buffer);
39489
40001
  return new Promise((resolve17) => {
39490
40002
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
39491
40003
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
@@ -41348,27 +41860,27 @@ var require_process = __commonJS({
41348
41860
  var require_filesystem = __commonJS({
41349
41861
  "../../node_modules/detect-libc/lib/filesystem.js"(exports2, module2) {
41350
41862
  "use strict";
41351
- var fs19 = require("fs");
41863
+ var fs20 = require("fs");
41352
41864
  var LDD_PATH = "/usr/bin/ldd";
41353
41865
  var SELF_PATH = "/proc/self/exe";
41354
41866
  var MAX_LENGTH = 2048;
41355
- var readFileSync18 = (path27) => {
41356
- const fd = fs19.openSync(path27, "r");
41867
+ var readFileSync18 = (path28) => {
41868
+ const fd = fs20.openSync(path28, "r");
41357
41869
  const buffer = Buffer.alloc(MAX_LENGTH);
41358
- const bytesRead = fs19.readSync(fd, buffer, 0, MAX_LENGTH, 0);
41359
- fs19.close(fd, () => {
41870
+ const bytesRead = fs20.readSync(fd, buffer, 0, MAX_LENGTH, 0);
41871
+ fs20.close(fd, () => {
41360
41872
  });
41361
41873
  return buffer.subarray(0, bytesRead);
41362
41874
  };
41363
- var readFile = (path27) => new Promise((resolve17, reject) => {
41364
- fs19.open(path27, "r", (err, fd) => {
41875
+ var readFile = (path28) => new Promise((resolve17, reject) => {
41876
+ fs20.open(path28, "r", (err, fd) => {
41365
41877
  if (err) {
41366
41878
  reject(err);
41367
41879
  } else {
41368
41880
  const buffer = Buffer.alloc(MAX_LENGTH);
41369
- fs19.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
41881
+ fs20.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
41370
41882
  resolve17(buffer.subarray(0, bytesRead));
41371
- fs19.close(fd, () => {
41883
+ fs20.close(fd, () => {
41372
41884
  });
41373
41885
  });
41374
41886
  }
@@ -41480,11 +41992,11 @@ var require_detect_libc = __commonJS({
41480
41992
  }
41481
41993
  return null;
41482
41994
  };
41483
- var familyFromInterpreterPath = (path27) => {
41484
- if (path27) {
41485
- if (path27.includes("/ld-musl-")) {
41995
+ var familyFromInterpreterPath = (path28) => {
41996
+ if (path28) {
41997
+ if (path28.includes("/ld-musl-")) {
41486
41998
  return MUSL;
41487
- } else if (path27.includes("/ld-linux-")) {
41999
+ } else if (path28.includes("/ld-linux-")) {
41488
42000
  return GLIBC;
41489
42001
  }
41490
42002
  }
@@ -41531,8 +42043,8 @@ var require_detect_libc = __commonJS({
41531
42043
  cachedFamilyInterpreter = null;
41532
42044
  try {
41533
42045
  const selfContent = await readFile(SELF_PATH);
41534
- const path27 = interpreterPath(selfContent);
41535
- cachedFamilyInterpreter = familyFromInterpreterPath(path27);
42046
+ const path28 = interpreterPath(selfContent);
42047
+ cachedFamilyInterpreter = familyFromInterpreterPath(path28);
41536
42048
  } catch (e) {
41537
42049
  }
41538
42050
  return cachedFamilyInterpreter;
@@ -41544,8 +42056,8 @@ var require_detect_libc = __commonJS({
41544
42056
  cachedFamilyInterpreter = null;
41545
42057
  try {
41546
42058
  const selfContent = readFileSync18(SELF_PATH);
41547
- const path27 = interpreterPath(selfContent);
41548
- cachedFamilyInterpreter = familyFromInterpreterPath(path27);
42059
+ const path28 = interpreterPath(selfContent);
42060
+ cachedFamilyInterpreter = familyFromInterpreterPath(path28);
41549
42061
  } catch (e) {
41550
42062
  }
41551
42063
  return cachedFamilyInterpreter;
@@ -43264,18 +43776,18 @@ var require_sharp = __commonJS({
43264
43776
  `@img/sharp-${runtimePlatform}/sharp.node`,
43265
43777
  "@img/sharp-wasm32/sharp.node"
43266
43778
  ];
43267
- var path27;
43779
+ var path28;
43268
43780
  var sharp;
43269
43781
  var errors = [];
43270
- for (path27 of paths) {
43782
+ for (path28 of paths) {
43271
43783
  try {
43272
- sharp = require(path27);
43784
+ sharp = require(path28);
43273
43785
  break;
43274
43786
  } catch (err) {
43275
43787
  errors.push(err);
43276
43788
  }
43277
43789
  }
43278
- if (sharp && path27.startsWith("@img/sharp-linux-x64") && !sharp._isUsingX64V2()) {
43790
+ if (sharp && path28.startsWith("@img/sharp-linux-x64") && !sharp._isUsingX64V2()) {
43279
43791
  const err = new Error("Prebuilt binaries for linux-x64 require v2 microarchitecture");
43280
43792
  err.code = "Unsupported CPU";
43281
43793
  errors.push(err);
@@ -43284,7 +43796,7 @@ var require_sharp = __commonJS({
43284
43796
  if (sharp) {
43285
43797
  module2.exports = sharp;
43286
43798
  } else {
43287
- const [isLinux2, isMacOs, isWindows2] = ["linux", "darwin", "win32"].map((os24) => runtimePlatform.startsWith(os24));
43799
+ const [isLinux2, isMacOs, isWindows2] = ["linux", "darwin", "win32"].map((os25) => runtimePlatform.startsWith(os25));
43288
43800
  const help = [`Could not load the "sharp" module using the ${runtimePlatform} runtime`];
43289
43801
  errors.forEach((err) => {
43290
43802
  if (err.code !== "MODULE_NOT_FOUND") {
@@ -43301,15 +43813,15 @@ var require_sharp = __commonJS({
43301
43813
  ` Requires ${expected}`
43302
43814
  );
43303
43815
  } else if (prebuiltPlatforms.includes(runtimePlatform)) {
43304
- const [os24, cpu] = runtimePlatform.split("-");
43305
- const libc = os24.endsWith("musl") ? " --libc=musl" : "";
43816
+ const [os25, cpu] = runtimePlatform.split("-");
43817
+ const libc = os25.endsWith("musl") ? " --libc=musl" : "";
43306
43818
  help.push(
43307
43819
  "- Ensure optional dependencies can be installed:",
43308
43820
  " npm install --include=optional sharp",
43309
43821
  "- Ensure your package manager supports multi-platform installation:",
43310
43822
  " See https://sharp.pixelplumbing.com/install#cross-platform",
43311
43823
  "- Add platform-specific dependencies:",
43312
- ` npm install --os=${os24.replace("musl", "")}${libc} --cpu=${cpu} sharp`
43824
+ ` npm install --os=${os25.replace("musl", "")}${libc} --cpu=${cpu} sharp`
43313
43825
  );
43314
43826
  } else {
43315
43827
  help.push(
@@ -46184,15 +46696,15 @@ var require_color = __commonJS({
46184
46696
  };
46185
46697
  }
46186
46698
  function wrapConversion(toModel, graph) {
46187
- const path27 = [graph[toModel].parent, toModel];
46699
+ const path28 = [graph[toModel].parent, toModel];
46188
46700
  let fn = conversions_default[graph[toModel].parent][toModel];
46189
46701
  let cur = graph[toModel].parent;
46190
46702
  while (graph[cur].parent) {
46191
- path27.unshift(graph[cur].parent);
46703
+ path28.unshift(graph[cur].parent);
46192
46704
  fn = link(conversions_default[graph[cur].parent][cur], fn);
46193
46705
  cur = graph[cur].parent;
46194
46706
  }
46195
- fn.conversion = path27;
46707
+ fn.conversion = path28;
46196
46708
  return fn;
46197
46709
  }
46198
46710
  function route(fromModel) {
@@ -46809,7 +47321,7 @@ var require_channel = __commonJS({
46809
47321
  var require_output = __commonJS({
46810
47322
  "../../node_modules/sharp/lib/output.js"(exports2, module2) {
46811
47323
  "use strict";
46812
- var path27 = require("path");
47324
+ var path28 = require("path");
46813
47325
  var is = require_is();
46814
47326
  var sharp = require_sharp();
46815
47327
  var formats = /* @__PURE__ */ new Map([
@@ -46840,9 +47352,9 @@ var require_output = __commonJS({
46840
47352
  let err;
46841
47353
  if (!is.string(fileOut)) {
46842
47354
  err = new Error("Missing output file path");
46843
- } else if (is.string(this.options.input.file) && path27.resolve(this.options.input.file) === path27.resolve(fileOut)) {
47355
+ } else if (is.string(this.options.input.file) && path28.resolve(this.options.input.file) === path28.resolve(fileOut)) {
46844
47356
  err = new Error("Cannot use same file for input and output");
46845
- } else if (jp2Regex.test(path27.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
47357
+ } else if (jp2Regex.test(path28.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
46846
47358
  err = errJp2Save();
46847
47359
  }
46848
47360
  if (err) {
@@ -48340,6 +48852,12 @@ var init_session_host_controller = __esm({
48340
48852
  payload: { sessionId, clientId }
48341
48853
  });
48342
48854
  }
48855
+ async pruneDuplicateSessions(payload = {}) {
48856
+ return this.request({
48857
+ type: "prune_duplicate_sessions",
48858
+ payload
48859
+ });
48860
+ }
48343
48861
  async acquireWrite(payload) {
48344
48862
  return this.request({
48345
48863
  type: "acquire_write",
@@ -48506,7 +49024,7 @@ var init_adhdev_daemon = __esm({
48506
49024
  import_ws3 = require("ws");
48507
49025
  import_chalk2 = __toESM(require("chalk"));
48508
49026
  init_version();
48509
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.28" });
49027
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.30" });
48510
49028
  DANGEROUS_PATTERNS = [
48511
49029
  /\brm\s+(-[a-z]*f|-[a-z]*r|--force|--recursive)/i,
48512
49030
  /\bsudo\b/i,
@@ -49157,10 +49675,10 @@ async function runWizard(options = {}) {
49157
49675
  }
49158
49676
  async function checkForUpdate() {
49159
49677
  try {
49160
- const { execSync: execSync7 } = await import("child_process");
49678
+ const { execSync: execSync8 } = await import("child_process");
49161
49679
  let currentVersion = null;
49162
49680
  try {
49163
- currentVersion = execSync7("adhdev --version", {
49681
+ currentVersion = execSync8("adhdev --version", {
49164
49682
  encoding: "utf-8",
49165
49683
  timeout: 3e3,
49166
49684
  stdio: ["pipe", "pipe", "pipe"]
@@ -49170,7 +49688,7 @@ async function checkForUpdate() {
49170
49688
  }
49171
49689
  let latestVersion = null;
49172
49690
  try {
49173
- latestVersion = execSync7("npm show adhdev version", {
49691
+ latestVersion = execSync8("npm show adhdev version", {
49174
49692
  encoding: "utf-8",
49175
49693
  timeout: 5e3,
49176
49694
  stdio: ["pipe", "pipe", "pipe"]
@@ -49192,7 +49710,7 @@ async function checkForUpdate() {
49192
49710
  }
49193
49711
  const spinner = (await import("ora")).default("Updating adhdev CLI...").start();
49194
49712
  try {
49195
- execSync7("npm install -g adhdev@latest", {
49713
+ execSync8("npm install -g adhdev@latest", {
49196
49714
  encoding: "utf-8",
49197
49715
  timeout: 6e4,
49198
49716
  stdio: ["pipe", "pipe", "pipe"]
@@ -49276,16 +49794,16 @@ async function loginFlow() {
49276
49794
  let verificationUrl;
49277
49795
  try {
49278
49796
  const config2 = loadConfig();
49279
- const os24 = await import("os");
49797
+ const os25 = await import("os");
49280
49798
  const res = await fetch(`${SERVER_URL}/auth/cli/init`, {
49281
49799
  method: "POST",
49282
49800
  headers: { "Content-Type": "application/json" },
49283
49801
  body: JSON.stringify({
49284
49802
  clientMachineId: config2.machineId,
49285
49803
  registeredMachineId: config2.registeredMachineId,
49286
- hostname: os24.hostname(),
49287
- platform: os24.platform(),
49288
- arch: os24.arch()
49804
+ hostname: os25.hostname(),
49805
+ platform: os25.platform(),
49806
+ arch: os25.arch()
49289
49807
  })
49290
49808
  });
49291
49809
  if (!res.ok) {
@@ -49383,20 +49901,20 @@ async function startDaemonFlow() {
49383
49901
  try {
49384
49902
  const { AdhdevDaemon: AdhdevDaemon2 } = await Promise.resolve().then(() => (init_adhdev_daemon(), adhdev_daemon_exports));
49385
49903
  const daemon = new AdhdevDaemon2();
49386
- const { execSync: execSync7 } = await import("child_process");
49904
+ const { execSync: execSync8 } = await import("child_process");
49387
49905
  const { getCurrentDaemonLogPath: getCurrentDaemonLogPath2 } = await Promise.resolve().then(() => (init_src(), src_exports));
49388
49906
  const logPath = getCurrentDaemonLogPath2();
49389
- const os24 = await import("os");
49390
- const platform11 = os24.platform();
49907
+ const os25 = await import("os");
49908
+ const platform11 = os25.platform();
49391
49909
  try {
49392
49910
  if (platform11 === "win32") {
49393
- execSync7("start /B adhdev daemon >NUL 2>&1", {
49911
+ execSync8("start /B adhdev daemon >NUL 2>&1", {
49394
49912
  timeout: 3e3,
49395
49913
  stdio: "ignore",
49396
49914
  shell: "cmd.exe"
49397
49915
  });
49398
49916
  } else {
49399
- execSync7("nohup adhdev daemon >/dev/null 2>&1 &", {
49917
+ execSync8("nohup adhdev daemon >/dev/null 2>&1 &", {
49400
49918
  timeout: 3e3,
49401
49919
  stdio: "ignore"
49402
49920
  });
@@ -49825,7 +50343,7 @@ var init_supported = __esm({
49825
50343
  "source": "docs/site/data/provider-catalog.mjs"
49826
50344
  },
49827
50345
  "codex-cli": {
49828
- "status": "unverified",
50346
+ "status": "partial",
49829
50347
  "testedOn": [
49830
50348
  "macOS 26.4"
49831
50349
  ],
@@ -49837,11 +50355,12 @@ var init_supported = __esm({
49837
50355
  "send_chat",
49838
50356
  "read_chat",
49839
50357
  "resume",
50358
+ "reconnect",
49840
50359
  "stop"
49841
50360
  ],
49842
50361
  "lastValidated": "2026-04-09",
49843
- "notes": "Saved-session resume works locally, but reconnect after daemon or transport disruption is still unverified. Fresh launch still lands in an onboarding-style prompt state often enough that exact-answer send/read validation is not yet trustworthy.",
49844
- "evidence": "Manual local validation via standalone API on 2026-04-09",
50362
+ "notes": "Fresh launch, live send/read, saved-session resume, daemon-restart reconnect, and stop were validated locally after tightening onboarding-screen parsing, providerSessionId recovery, and history replay dedupe. Some older saved transcripts may still need one-time compaction if they were polluted before the fix.",
50363
+ "evidence": "Manual local validation via standalone API and session-host restart recovery on 2026-04-09",
49845
50364
  "owner": "core",
49846
50365
  "source": "docs/site/data/provider-catalog.mjs"
49847
50366
  },
@@ -49922,11 +50441,14 @@ var init_supported = __esm({
49922
50441
  "validatedFlows": [
49923
50442
  "read_chat",
49924
50443
  "new_session",
49925
- "send_chat"
50444
+ "send_chat",
50445
+ "list_sessions",
50446
+ "switch_session",
50447
+ "resolve_action"
49926
50448
  ],
49927
- "lastValidated": "2026-04-09",
49928
- "notes": "A fresh Codex extension chat could be created and answered correctly inside Antigravity. The current provider surface still does not expose dedicated list_sessions or switch_session scripts, and extension history listing remains empty in local validation.",
49929
- "evidence": "Manual local validation via standalone API on 2026-04-09",
50449
+ "lastValidated": "2026-04-10",
50450
+ "notes": "Cursor-hosted Codex on macOS now has locale-agnostic read/list/switch handling, approve-path resolve_action, and transcript cleanup for localized timestamps plus stale replay turns. It remains Partial because recent-task history can still collapse to the current chat and some send_chat attempts still fail to materialize as a real turn, even though false-success reporting is now blocked.",
50451
+ "evidence": "Manual local validation via standalone API on 2026-04-10 against Cursor-hosted Codex webview, including recent-task list/switch, approve-path resolve_action, and transcript cleanup verification",
49930
50452
  "owner": "core",
49931
50453
  "source": "docs/site/data/provider-catalog.mjs"
49932
50454
  },
@@ -50352,7 +50874,7 @@ var init_supported = __esm({
50352
50874
  "windsurf": "unverified",
50353
50875
  "aider-cli": "unverified",
50354
50876
  "claude-cli": "partial",
50355
- "codex-cli": "unverified",
50877
+ "codex-cli": "partial",
50356
50878
  "cursor-cli": "unverified",
50357
50879
  "gemini-cli": "unverified",
50358
50880
  "github-copilot-cli": "unverified",
@@ -50469,7 +50991,7 @@ var init_supported = __esm({
50469
50991
 
50470
50992
  // src/cli/index.ts
50471
50993
  var import_commander = require("commander");
50472
- var import_chalk8 = __toESM(require("chalk"));
50994
+ var import_chalk9 = __toESM(require("chalk"));
50473
50995
  init_src();
50474
50996
 
50475
50997
  // src/cli/setup-commands.ts
@@ -50859,7 +51381,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
50859
51381
  });
50860
51382
  });
50861
51383
  program2.command("standalone").description("\u{1F5A5}\uFE0F Start ADHDev Standalone Server (Local Dashboard & Embedded Daemon)").option("-p, --port <port>", "Local HTTP/WS server port", "3847").option("--host <host>", "Bind to specific host (use 0.0.0.0 for LAN access)").option("--no-open", "Prevent opening browser automatically").option("--token <token>", "Require token authentication").option("--dev", "Enable Dev Mode").action(async (options) => {
50862
- const { spawn: spawn5, execSync: execSync7 } = await import("child_process");
51384
+ const { spawn: spawn5, execSync: execSync8 } = await import("child_process");
50863
51385
  console.log(import_chalk5.default.cyan("\n Starting ADHDev Standalone Server..."));
50864
51386
  const args = [];
50865
51387
  if (options.port) args.push("--port", options.port);
@@ -50870,7 +51392,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
50870
51392
  let bin = "npx";
50871
51393
  const npxArgs = ["-y", "@adhdev/daemon-standalone@latest", ...args];
50872
51394
  try {
50873
- execSync7("adhdev-standalone --help", { stdio: "ignore" });
51395
+ execSync8("adhdev-standalone --help", { stdio: "ignore" });
50874
51396
  bin = "adhdev-standalone";
50875
51397
  } catch {
50876
51398
  console.log(import_chalk5.default.gray(" Standalone server package not found locally."));
@@ -50976,7 +51498,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
50976
51498
  `));
50977
51499
  }
50978
51500
  }));
50979
- hideCommand(program2.command("daemon:session-host").description("Inspect and control the session host").option("-p, --port <port>", "Local WS server port", "19222").option("--json", "Print raw JSON diagnostics/result").option("--limit <count>", "Number of diagnostics entries to include", "20").option("--session <sessionId>", "Target session ID").option("--restart", "Restart the target session").option("--resume", "Resume the target session").option("--stop", "Stop the target session").option("--signal <signal>", "Send a signal to the target session").option("--detach-client <clientId>", "Force-detach a client from the target session").option("--acquire-write <clientId>", "Force-acquire write ownership for a client").option("--release-write <clientId>", "Release write ownership for a client").option("--owner-type <type>", "ownerType for --acquire-write (user|agent)", "user").action(async (options) => {
51501
+ hideCommand(program2.command("daemon:session-host").description("Inspect and control the session host").option("-p, --port <port>", "Local WS server port", "19222").option("--json", "Print raw JSON diagnostics/result").option("--limit <count>", "Number of diagnostics entries to include", "20").option("--session <sessionId>", "Target session ID").option("--restart", "Restart the target session").option("--resume", "Resume the target session").option("--stop", "Stop the target session").option("--signal <signal>", "Send a signal to the target session").option("--detach-client <clientId>", "Force-detach a client from the target session").option("--prune-duplicates", "Stop and remove duplicate hosted runtimes that share the same provider session binding").option("--acquire-write <clientId>", "Force-acquire write ownership for a client").option("--release-write <clientId>", "Release write ownership for a client").option("--owner-type <type>", "ownerType for --acquire-write (user|agent)", "user").action(async (options) => {
50980
51502
  const sessionId = typeof options.session === "string" ? options.session.trim() : "";
50981
51503
  const limit = Math.max(1, Math.min(200, parseInt(options.limit, 10) || 20));
50982
51504
  const port = parseInt(options.port, 10) || 19222;
@@ -51023,6 +51545,10 @@ function registerDaemonCommands(program2, pkgVersion3) {
51023
51545
  daemonCommand = "session_host_force_detach_client";
51024
51546
  daemonArgs = { sessionId, clientId: String(options.detachClient) };
51025
51547
  directRequest = { type: "force_detach_client", payload: { sessionId, clientId: String(options.detachClient) } };
51548
+ } else if (options.pruneDuplicates) {
51549
+ daemonCommand = "session_host_prune_duplicate_sessions";
51550
+ daemonArgs = {};
51551
+ directRequest = { type: "prune_duplicate_sessions", payload: {} };
51026
51552
  } else if (options.acquireWrite) {
51027
51553
  requireSessionId();
51028
51554
  daemonCommand = "session_host_acquire_write";
@@ -51063,7 +51589,17 @@ function registerDaemonCommands(program2, pkgVersion3) {
51063
51589
  console.log(JSON.stringify(payload, null, 2));
51064
51590
  return;
51065
51591
  }
51066
- if (options.restart || options.resume || options.stop || options.signal || options.detachClient || options.acquireWrite || options.releaseWrite) {
51592
+ if (options.restart || options.resume || options.stop || options.signal || options.detachClient || options.pruneDuplicates || options.acquireWrite || options.releaseWrite) {
51593
+ if (options.pruneDuplicates) {
51594
+ const result = payload || {};
51595
+ console.log(import_chalk5.default.green("\n \u2713 Session host duplicate prune completed.\n"));
51596
+ console.log(import_chalk5.default.gray(` Source: ${source === "daemon" ? "daemon control plane" : "direct host fallback"}`));
51597
+ console.log(import_chalk5.default.gray(` Groups: ${result?.duplicateGroupCount || 0}`));
51598
+ console.log(import_chalk5.default.gray(` Kept: ${Array.isArray(result?.keptSessionIds) ? result.keptSessionIds.length : 0}`));
51599
+ console.log(import_chalk5.default.gray(` Pruned: ${Array.isArray(result?.prunedSessionIds) ? result.prunedSessionIds.length : 0}`));
51600
+ console.log();
51601
+ return;
51602
+ }
51067
51603
  const record2 = payload;
51068
51604
  console.log(import_chalk5.default.green("\n \u2713 Session host action completed.\n"));
51069
51605
  console.log(import_chalk5.default.gray(` Source: ${source === "daemon" ? "daemon control plane" : "direct host fallback"}`));
@@ -51153,7 +51689,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
51153
51689
  hideCommand(program2.command("daemon:upgrade").description("Upgrade ADHDev to latest version and restart daemon").option("--no-restart", "Upgrade only, skip daemon restart").action(async (options) => {
51154
51690
  const { isDaemonRunning: isDaemonRunning2, stopDaemon: stopDaemon2 } = await Promise.resolve().then(() => (init_adhdev_daemon(), adhdev_daemon_exports));
51155
51691
  const { stopSessionHost: stopSessionHost2 } = await Promise.resolve().then(() => (init_session_host(), session_host_exports));
51156
- const { execSync: execSync7, spawn: spawn5 } = await import("child_process");
51692
+ const { execSync: execSync8, spawn: spawn5 } = await import("child_process");
51157
51693
  const fsMod = await import("fs");
51158
51694
  const pathMod = await import("path");
51159
51695
  console.log(import_chalk5.default.bold("\n \u{1F504} ADHDev Upgrade\n"));
@@ -51173,10 +51709,10 @@ function registerDaemonCommands(program2, pkgVersion3) {
51173
51709
  while (!fsMod.existsSync(pathMod.join(gitRoot, ".git")) && gitRoot !== "/") {
51174
51710
  gitRoot = pathMod.dirname(gitRoot);
51175
51711
  }
51176
- execSync7("git pull --rebase", { cwd: gitRoot, stdio: "inherit" });
51712
+ execSync8("git pull --rebase", { cwd: gitRoot, stdio: "inherit" });
51177
51713
  console.log(import_chalk5.default.cyan("\n Building..."));
51178
- execSync7("npm run build", { cwd: launcherDir, stdio: "inherit" });
51179
- execSync7("npm link", { cwd: launcherDir, stdio: "inherit" });
51714
+ execSync8("npm run build", { cwd: launcherDir, stdio: "inherit" });
51715
+ execSync8("npm link", { cwd: launcherDir, stdio: "inherit" });
51180
51716
  console.log(import_chalk5.default.green("\n \u2713 Build complete"));
51181
51717
  } catch (e) {
51182
51718
  console.log(import_chalk5.default.red(`
@@ -51188,7 +51724,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
51188
51724
  console.log(import_chalk5.default.cyan("\n Checking for updates..."));
51189
51725
  let latest;
51190
51726
  try {
51191
- latest = execSync7("npm view adhdev version", { encoding: "utf-8" }).trim();
51727
+ latest = execSync8("npm view adhdev version", { encoding: "utf-8" }).trim();
51192
51728
  } catch (e) {
51193
51729
  console.log(import_chalk5.default.red(`
51194
51730
  \u2717 Failed to check latest version: ${e?.message}
@@ -51857,35 +52393,35 @@ function registerProviderCommands(program2) {
51857
52393
  let osPaths = {};
51858
52394
  let processNames = {};
51859
52395
  if (category === "ide") {
51860
- const fs19 = await import("fs");
51861
- const path27 = await import("path");
51862
- const os24 = await import("os");
51863
- if (os24.platform() === "darwin") {
52396
+ const fs20 = await import("fs");
52397
+ const path28 = await import("path");
52398
+ const os25 = await import("os");
52399
+ if (os25.platform() === "darwin") {
51864
52400
  while (true) {
51865
52401
  const p = (await rl.question(`macOS Application Path (e.g. /Applications/${defaultName}.app): `)).trim() || `/Applications/${defaultName}.app`;
51866
52402
  if (p === "skip") break;
51867
- if (!fs19.existsSync(p)) {
52403
+ if (!fs20.existsSync(p)) {
51868
52404
  console.log(import_chalk7.default.red(` \u2717 Path not found: ${p}`));
51869
52405
  console.log(import_chalk7.default.gray(` (Please provide the exact absolute path to the .app or binary, or type 'skip')`));
51870
52406
  continue;
51871
52407
  }
51872
52408
  console.log(import_chalk7.default.green(` \u2713 Path verified: ${p}`));
51873
52409
  osPaths["darwin"] = [p];
51874
- processNames["darwin"] = path27.basename(p, ".app");
52410
+ processNames["darwin"] = path28.basename(p, ".app");
51875
52411
  break;
51876
52412
  }
51877
- } else if (os24.platform() === "win32") {
52413
+ } else if (os25.platform() === "win32") {
51878
52414
  while (true) {
51879
52415
  const p = (await rl.question(`Windows Executable Path (e.g. C:\\Program Files\\${defaultName}\\${defaultName}.exe): `)).trim();
51880
52416
  if (!p || p === "skip") break;
51881
- if (!fs19.existsSync(p)) {
52417
+ if (!fs20.existsSync(p)) {
51882
52418
  console.log(import_chalk7.default.red(` \u2717 Path not found: ${p}`));
51883
52419
  console.log(import_chalk7.default.gray(` (Please provide the exact absolute path, or type 'skip')`));
51884
52420
  continue;
51885
52421
  }
51886
52422
  console.log(import_chalk7.default.green(` \u2713 Path verified: ${p}`));
51887
52423
  osPaths["win32"] = [p];
51888
- processNames["win32"] = path27.basename(p, ".exe");
52424
+ processNames["win32"] = path28.basename(p, ".exe");
51889
52425
  break;
51890
52426
  }
51891
52427
  }
@@ -52571,8 +53107,8 @@ function registerCdpCommands(program2) {
52571
53107
  }
52572
53108
  const output = typeof result === "string" ? result : JSON.stringify(result, null, 2);
52573
53109
  if (options.output) {
52574
- const fs19 = await import("fs");
52575
- fs19.writeFileSync(options.output, output, "utf-8");
53110
+ const fs20 = await import("fs");
53111
+ fs20.writeFileSync(options.output, output, "utf-8");
52576
53112
  console.log(import_chalk7.default.green(`
52577
53113
  \u2713 Saved to ${options.output} (${output.length} chars)
52578
53114
  `));
@@ -52675,8 +53211,8 @@ function registerCdpCommands(program2) {
52675
53211
  ws.on("message", async (data) => {
52676
53212
  const msg = JSON.parse(data.toString());
52677
53213
  if (msg.id === 1 && msg.result?.data) {
52678
- const fs19 = await import("fs");
52679
- fs19.writeFileSync(options.output, Buffer.from(msg.result.data, "base64"));
53214
+ const fs20 = await import("fs");
53215
+ fs20.writeFileSync(options.output, Buffer.from(msg.result.data, "base64"));
52680
53216
  console.log(import_chalk7.default.green(`
52681
53217
  \u2713 Screenshot saved to ${options.output}
52682
53218
  `));
@@ -52695,14 +53231,197 @@ function registerCdpCommands(program2) {
52695
53231
  });
52696
53232
  }
52697
53233
 
53234
+ // src/cli/service-commands.ts
53235
+ var import_node_fs3 = __toESM(require("fs"));
53236
+ var import_node_path2 = __toESM(require("path"));
53237
+ var import_node_os2 = __toESM(require("os"));
53238
+ var import_node_child_process = require("child_process");
53239
+ var import_chalk8 = __toESM(require("chalk"));
53240
+ var LAUNCHD_LABEL = "dev.adhf.daemon";
53241
+ var ADHDEV_DIR = import_node_path2.default.join(import_node_os2.default.homedir(), ".adhdev");
53242
+ function getDarwinPlistPath() {
53243
+ return import_node_path2.default.join(import_node_os2.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
53244
+ }
53245
+ function getWindowsStartupDir() {
53246
+ const appData = process.env.APPDATA || import_node_path2.default.join(import_node_os2.default.homedir(), "AppData", "Roaming");
53247
+ return import_node_path2.default.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
53248
+ }
53249
+ function getWindowsVbsPath() {
53250
+ return import_node_path2.default.join(getWindowsStartupDir(), "adhdev-daemon.vbs");
53251
+ }
53252
+ function resolveCliPath() {
53253
+ return import_node_fs3.default.realpathSync(process.argv[1]);
53254
+ }
53255
+ function ensureDir(dir) {
53256
+ if (!import_node_fs3.default.existsSync(dir)) import_node_fs3.default.mkdirSync(dir, { recursive: true });
53257
+ }
53258
+ function buildPlist(nodeExe, cliExe) {
53259
+ const outLog = import_node_path2.default.join(ADHDEV_DIR, "daemon-launchd.out");
53260
+ const errLog = import_node_path2.default.join(ADHDEV_DIR, "daemon-launchd.err");
53261
+ const brewPrefix = import_node_fs3.default.existsSync("/opt/homebrew/bin") ? "/opt/homebrew/bin" : "/usr/local/bin";
53262
+ return `<?xml version="1.0" encoding="UTF-8"?>
53263
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
53264
+ <plist version="1.0">
53265
+ <dict>
53266
+ <key>Label</key>
53267
+ <string>${LAUNCHD_LABEL}</string>
53268
+ <key>ProgramArguments</key>
53269
+ <array>
53270
+ <string>${nodeExe}</string>
53271
+ <string>${cliExe}</string>
53272
+ <string>daemon</string>
53273
+ </array>
53274
+ <key>RunAtLoad</key>
53275
+ <true/>
53276
+ <key>KeepAlive</key>
53277
+ <dict>
53278
+ <key>SuccessfulExit</key>
53279
+ <false/>
53280
+ </dict>
53281
+ <key>ThrottleInterval</key>
53282
+ <integer>10</integer>
53283
+ <key>StandardOutPath</key>
53284
+ <string>${outLog}</string>
53285
+ <key>StandardErrorPath</key>
53286
+ <string>${errLog}</string>
53287
+ <key>EnvironmentVariables</key>
53288
+ <dict>
53289
+ <key>PATH</key>
53290
+ <string>${brewPrefix}:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
53291
+ </dict>
53292
+ </dict>
53293
+ </plist>`;
53294
+ }
53295
+ function installDarwin(nodeExe, cliExe) {
53296
+ const plistPath = getDarwinPlistPath();
53297
+ ensureDir(ADHDEV_DIR);
53298
+ ensureDir(import_node_path2.default.dirname(plistPath));
53299
+ import_node_fs3.default.writeFileSync(plistPath, buildPlist(nodeExe, cliExe), "utf-8");
53300
+ console.log(import_chalk8.default.gray(` Plist: ${plistPath}`));
53301
+ try {
53302
+ (0, import_node_child_process.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
53303
+ } catch {
53304
+ }
53305
+ try {
53306
+ (0, import_node_child_process.execSync)(`launchctl load -w "${plistPath}"`, { stdio: "ignore" });
53307
+ console.log(import_chalk8.default.green("\n \u2713 Registered as LaunchAgent \u2014 daemon will start on login."));
53308
+ console.log(import_chalk8.default.gray(` Logs: ~/.adhdev/daemon-launchd.{out,err}`));
53309
+ } catch (e) {
53310
+ console.log(import_chalk8.default.red(`
53311
+ \u2717 launchctl load failed: ${e.message}`));
53312
+ console.log(import_chalk8.default.gray(" Try: launchctl load -w ~/Library/LaunchAgents/dev.adhf.daemon.plist"));
53313
+ }
53314
+ }
53315
+ function uninstallDarwin() {
53316
+ const plistPath = getDarwinPlistPath();
53317
+ if (!import_node_fs3.default.existsSync(plistPath)) {
53318
+ console.log(import_chalk8.default.yellow("\n \u26A0 Service is not installed."));
53319
+ return;
53320
+ }
53321
+ try {
53322
+ (0, import_node_child_process.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
53323
+ } catch {
53324
+ }
53325
+ import_node_fs3.default.unlinkSync(plistPath);
53326
+ console.log(import_chalk8.default.green("\n \u2713 Removed LaunchAgent. Daemon will no longer auto-start."));
53327
+ }
53328
+ function statusDarwin() {
53329
+ const plistPath = getDarwinPlistPath();
53330
+ if (!import_node_fs3.default.existsSync(plistPath)) return "not-installed";
53331
+ return "installed";
53332
+ }
53333
+ function buildVbs(cliExe) {
53334
+ return `' ADHDev Daemon Auto-Start (generated by adhdev service install)
53335
+ Set WshShell = CreateObject("WScript.Shell")
53336
+ WshShell.Run "cmd.exe /c ""node"" ""${cliExe.replace(/\\/g, "\\\\")}"" daemon", 0, False
53337
+ `;
53338
+ }
53339
+ function installWindows(cliExe) {
53340
+ const vbsPath = getWindowsVbsPath();
53341
+ ensureDir(ADHDEV_DIR);
53342
+ ensureDir(import_node_path2.default.dirname(vbsPath));
53343
+ import_node_fs3.default.writeFileSync(vbsPath, buildVbs(cliExe), "utf-8");
53344
+ console.log(import_chalk8.default.gray(` Startup script: ${vbsPath}`));
53345
+ console.log(import_chalk8.default.green("\n \u2713 Registered in Startup folder \u2014 daemon will start on login (hidden)."));
53346
+ console.log(import_chalk8.default.gray(" To start now without rebooting, run: adhdev daemon"));
53347
+ }
53348
+ function uninstallWindows() {
53349
+ const vbsPath = getWindowsVbsPath();
53350
+ if (!import_node_fs3.default.existsSync(vbsPath)) {
53351
+ console.log(import_chalk8.default.yellow("\n \u26A0 Service is not installed."));
53352
+ return;
53353
+ }
53354
+ import_node_fs3.default.unlinkSync(vbsPath);
53355
+ console.log(import_chalk8.default.green("\n \u2713 Removed Startup script. Daemon will no longer auto-start."));
53356
+ console.log(import_chalk8.default.gray(" Note: a currently running daemon is not affected. Stop with: adhdev daemon:stop"));
53357
+ }
53358
+ function statusWindows() {
53359
+ return import_node_fs3.default.existsSync(getWindowsVbsPath()) ? "installed" : "not-installed";
53360
+ }
53361
+ function registerServiceCommands(program2) {
53362
+ const svc = program2.command("service").description("\u{1F50C} Manage ADHDev as an OS background auto-start service");
53363
+ svc.command("install").description("Register ADHDev daemon to start automatically on login").action(async () => {
53364
+ console.log(import_chalk8.default.bold("\n \u{1F680} Installing ADHDev Background Service"));
53365
+ const platform11 = import_node_os2.default.platform();
53366
+ const nodeExe = process.execPath;
53367
+ const cliExe = resolveCliPath();
53368
+ console.log(import_chalk8.default.gray(` Node: ${nodeExe}`));
53369
+ console.log(import_chalk8.default.gray(` CLI: ${cliExe}`));
53370
+ console.log(import_chalk8.default.gray(` Platform: ${platform11}`));
53371
+ if (platform11 === "darwin") {
53372
+ installDarwin(nodeExe, cliExe);
53373
+ } else if (platform11 === "win32") {
53374
+ installWindows(cliExe);
53375
+ } else {
53376
+ console.log(import_chalk8.default.yellow("\n \u26A0 Auto-start service install is not supported on this platform."));
53377
+ console.log(import_chalk8.default.gray(" On Linux, create a systemd user unit manually:"));
53378
+ console.log(import_chalk8.default.gray(" ~/.config/systemd/user/adhdev-daemon.service"));
53379
+ }
53380
+ console.log();
53381
+ });
53382
+ svc.command("uninstall").description("Remove the OS background service").action(async () => {
53383
+ console.log(import_chalk8.default.bold("\n \u{1F5D1}\uFE0F Removing ADHDev Background Service"));
53384
+ const platform11 = import_node_os2.default.platform();
53385
+ if (platform11 === "darwin") {
53386
+ uninstallDarwin();
53387
+ } else if (platform11 === "win32") {
53388
+ uninstallWindows();
53389
+ } else {
53390
+ console.log(import_chalk8.default.yellow("\n \u26A0 Not supported on this platform."));
53391
+ }
53392
+ console.log();
53393
+ });
53394
+ svc.command("status").description("Check whether the OS background service is installed").action(async () => {
53395
+ const platform11 = import_node_os2.default.platform();
53396
+ let state = "not-installed";
53397
+ if (platform11 === "darwin") {
53398
+ state = statusDarwin();
53399
+ } else if (platform11 === "win32") {
53400
+ state = statusWindows();
53401
+ }
53402
+ if (state === "installed") {
53403
+ console.log(import_chalk8.default.green("\n \u2713 Service is installed. Daemon auto-starts on login."));
53404
+ if (platform11 === "darwin") {
53405
+ console.log(import_chalk8.default.gray(` Plist: ${getDarwinPlistPath()}`));
53406
+ } else {
53407
+ console.log(import_chalk8.default.gray(` Script: ${getWindowsVbsPath()}`));
53408
+ }
53409
+ } else {
53410
+ console.log(import_chalk8.default.gray("\n \u2717 Service is not installed."));
53411
+ console.log(import_chalk8.default.gray(" Run: adhdev service install"));
53412
+ }
53413
+ console.log();
53414
+ });
53415
+ }
53416
+
52698
53417
  // src/cli/index.ts
52699
53418
  init_version();
52700
53419
  var pkgVersion2 = resolvePackageVersion();
52701
53420
  if (process.platform === "win32") {
52702
53421
  const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] || "0", 10);
52703
53422
  if (nodeMajor >= 24) {
52704
- console.error(import_chalk8.default.red("\n\u2717 Windows is currently unsupported on Node.js 24+ for ADHDev."));
52705
- console.error(import_chalk8.default.gray(" Install Node.js 22.x on Windows, then retry.\n"));
53423
+ console.error(import_chalk9.default.red("\n\u2717 Windows is currently unsupported on Node.js 24+ for ADHDev."));
53424
+ console.error(import_chalk9.default.gray(" Install Node.js 22.x on Windows, then retry.\n"));
52706
53425
  process.exit(1);
52707
53426
  }
52708
53427
  }
@@ -52717,6 +53436,7 @@ registerDaemonCommands(program, pkgVersion2);
52717
53436
  registerDoctorCommands(program, pkgVersion2);
52718
53437
  registerProviderCommands(program);
52719
53438
  registerCdpCommands(program);
53439
+ registerServiceCommands(program);
52720
53440
  void (async () => {
52721
53441
  const helperMode = await maybeRunDaemonUpgradeHelperFromEnv();
52722
53442
  if (helperMode) {
@@ -52725,25 +53445,26 @@ void (async () => {
52725
53445
  if (process.argv.length <= 2) {
52726
53446
  program.outputHelp();
52727
53447
  console.log();
52728
- console.log(import_chalk8.default.gray(" Quick start:"));
52729
- console.log(import_chalk8.default.gray(" adhdev setup \u2014 First-time setup & login"));
52730
- console.log(import_chalk8.default.gray(" adhdev daemon \u2014 Start unified daemon (Required)"));
52731
- console.log(import_chalk8.default.gray(" adhdev standalone \u2014 Start standalone local dashboard & daemon"));
52732
- console.log(import_chalk8.default.gray(" adhdev launch cursor \u2014 Launch IDE with CDP (e.g. cursor, windsurf)"));
52733
- console.log(import_chalk8.default.gray(" adhdev launch claude \u2014 Launch CLI agent via the running daemon"));
52734
- console.log(import_chalk8.default.gray(" adhdev status \u2014 Check current setup"));
52735
- console.log(import_chalk8.default.gray(" adhdev doctor \u2014 Diagnose install & native dependencies"));
52736
- console.log(import_chalk8.default.gray(" adhdev update \u2014 Upgrade to latest version"));
53448
+ console.log(import_chalk9.default.gray(" Quick start:"));
53449
+ console.log(import_chalk9.default.gray(" adhdev setup \u2014 First-time setup & login"));
53450
+ console.log(import_chalk9.default.gray(" adhdev daemon \u2014 Start unified daemon (Required)"));
53451
+ console.log(import_chalk9.default.gray(" adhdev standalone \u2014 Start standalone local dashboard & daemon"));
53452
+ console.log(import_chalk9.default.gray(" adhdev launch cursor \u2014 Launch IDE with CDP (e.g. cursor, windsurf)"));
53453
+ console.log(import_chalk9.default.gray(" adhdev launch claude \u2014 Launch CLI agent via the running daemon"));
53454
+ console.log(import_chalk9.default.gray(" adhdev status \u2014 Check current setup"));
53455
+ console.log(import_chalk9.default.gray(" adhdev doctor \u2014 Diagnose install & native dependencies"));
53456
+ console.log(import_chalk9.default.gray(" adhdev update \u2014 Upgrade to latest version"));
52737
53457
  console.log();
52738
- console.log(import_chalk8.default.gray(" Advanced tools:"));
52739
- console.log(import_chalk8.default.gray(" adhdev provider ... \u2014 Provider development commands"));
52740
- console.log(import_chalk8.default.gray(" adhdev cdp ... \u2014 CDP debugging tools"));
53458
+ console.log(import_chalk9.default.gray(" Advanced tools:"));
53459
+ console.log(import_chalk9.default.gray(" adhdev service \u2014 Manage OS background auto-start service"));
53460
+ console.log(import_chalk9.default.gray(" adhdev provider ... \u2014 Provider development commands"));
53461
+ console.log(import_chalk9.default.gray(" adhdev cdp ... \u2014 CDP debugging tools"));
52741
53462
  console.log();
52742
53463
  return;
52743
53464
  }
52744
53465
  await program.parseAsync(process.argv);
52745
53466
  })().catch((err) => {
52746
- console.error(import_chalk8.default.red(`
53467
+ console.error(import_chalk9.default.red(`
52747
53468
  \u2717 ${err.message}`));
52748
53469
  process.exit(1);
52749
53470
  });