@adhdev/daemon-core 0.8.12 → 0.8.13

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/index.mjs CHANGED
@@ -632,6 +632,13 @@ function logTerminalBackendSelection(preference, ghosttyAvailable, backendKind)
632
632
  const key = `${preference}:${ghosttyAvailable}:${backendKind}`;
633
633
  if (loggedTerminalBackends.has(key)) return;
634
634
  loggedTerminalBackends.add(key);
635
+ if (backendKind === "xterm" && preference !== "xterm" && !ghosttyAvailable) {
636
+ LOG.warn(
637
+ "Terminal",
638
+ `[terminal-screen] ghostty-vt unavailable; using xterm fallback (preference=${preference})`
639
+ );
640
+ return;
641
+ }
635
642
  LOG.info(
636
643
  "Terminal",
637
644
  `[terminal-screen] backend=${backendKind} preference=${preference} ghosttyAvailable=${ghosttyAvailable}`
@@ -694,6 +701,7 @@ var init_terminal_screen = __esm({
694
701
  });
695
702
 
696
703
  // src/cli-adapters/pty-transport.ts
704
+ import * as os7 from "os";
697
705
  var pty, NodePtyRuntimeTransport, NodePtyTransportFactory;
698
706
  var init_pty_transport = __esm({
699
707
  "src/cli-adapters/pty-transport.ts"() {
@@ -734,11 +742,21 @@ var init_pty_transport = __esm({
734
742
  NodePtyTransportFactory = class {
735
743
  spawn(command, args, options) {
736
744
  if (!pty) throw new Error("node-pty is not installed");
745
+ let cwd = options.cwd;
746
+ if (cwd) {
747
+ try {
748
+ const fs15 = __require("fs");
749
+ const stat = fs15.statSync(cwd);
750
+ if (!stat.isDirectory()) cwd = os7.homedir();
751
+ } catch {
752
+ cwd = os7.homedir();
753
+ }
754
+ }
737
755
  const handle = pty.spawn(command, args, {
738
756
  name: "xterm-256color",
739
757
  cols: options.cols,
740
758
  rows: options.rows,
741
- cwd: options.cwd,
759
+ cwd,
742
760
  env: options.env
743
761
  });
744
762
  return new NodePtyRuntimeTransport(handle);
@@ -747,13 +765,25 @@ var init_pty_transport = __esm({
747
765
  }
748
766
  });
749
767
 
768
+ // src/cli-adapters/spawn-env.ts
769
+ import {
770
+ sanitizeSpawnEnv,
771
+ applyTerminalColorEnv,
772
+ ensureNodePtySpawnHelperPermissions
773
+ } from "@adhdev/session-host-core";
774
+ var init_spawn_env = __esm({
775
+ "src/cli-adapters/spawn-env.ts"() {
776
+ "use strict";
777
+ }
778
+ });
779
+
750
780
  // src/cli-adapters/provider-cli-adapter.ts
751
781
  var provider_cli_adapter_exports = {};
752
782
  __export(provider_cli_adapter_exports, {
753
783
  ProviderCliAdapter: () => ProviderCliAdapter,
754
784
  normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
755
785
  });
756
- import * as os7 from "os";
786
+ import * as os8 from "os";
757
787
  import * as path7 from "path";
758
788
  import { execSync as execSync3 } from "child_process";
759
789
  function stripAnsi(str) {
@@ -765,32 +795,6 @@ function stripTerminalNoise(str) {
765
795
  function sanitizeTerminalText(str) {
766
796
  return stripTerminalNoise(stripAnsi(str));
767
797
  }
768
- function applyPreferredTerminalColorEnv(env) {
769
- if (env.NO_COLOR) return;
770
- if (!env.TERM || env.TERM === "xterm-color") {
771
- env.TERM = "xterm-256color";
772
- }
773
- if (!env.COLORTERM) env.COLORTERM = "truecolor";
774
- if (process.platform === "win32") {
775
- if (!env.FORCE_COLOR) env.FORCE_COLOR = "1";
776
- if (!env.CLICOLOR) env.CLICOLOR = "1";
777
- }
778
- }
779
- function buildCliSpawnEnv(baseEnv, overrides) {
780
- const env = {};
781
- const source = { ...baseEnv, ...overrides || {} };
782
- for (const [key, value] of Object.entries(source)) {
783
- if (typeof value !== "string") continue;
784
- env[key] = value;
785
- }
786
- for (const key of Object.keys(env)) {
787
- 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_")) {
788
- delete env[key];
789
- }
790
- }
791
- applyPreferredTerminalColorEnv(env);
792
- return env;
793
- }
794
798
  function computeTerminalQueryTail(buffer) {
795
799
  const prefixes = ["\x1B[6n", "\x1B[?6n"];
796
800
  const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
@@ -804,7 +808,7 @@ function computeTerminalQueryTail(buffer) {
804
808
  return "";
805
809
  }
806
810
  function findBinary(name) {
807
- const isWin = os7.platform() === "win32";
811
+ const isWin = os8.platform() === "win32";
808
812
  try {
809
813
  const cmd = isWin ? `where ${name}` : `which ${name}`;
810
814
  return execSync3(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
@@ -852,7 +856,7 @@ function looksLikeMachOOrElf(filePath) {
852
856
  }
853
857
  function shSingleQuote(arg) {
854
858
  if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
855
- if (os7.platform() === "win32") {
859
+ if (os8.platform() === "win32") {
856
860
  return `"${arg.replace(/"/g, '""')}"`;
857
861
  }
858
862
  return `'${arg.replace(/'/g, `'\\''`)}'`;
@@ -919,34 +923,21 @@ function normalizeCliProviderForRuntime(raw) {
919
923
  }
920
924
  };
921
925
  }
922
- var pty2, ProviderCliAdapter;
926
+ var pty2, buildCliSpawnEnv, ProviderCliAdapter;
923
927
  var init_provider_cli_adapter = __esm({
924
928
  "src/cli-adapters/provider-cli-adapter.ts"() {
925
929
  "use strict";
926
930
  init_logger();
927
931
  init_terminal_screen();
928
932
  init_pty_transport();
933
+ init_spawn_env();
929
934
  try {
930
935
  pty2 = __require("node-pty");
931
- if (os7.platform() !== "win32") {
932
- try {
933
- const fs15 = __require("fs");
934
- const ptyDir = path7.resolve(path7.dirname(__require.resolve("node-pty")), "..");
935
- const platformArch = `${os7.platform()}-${os7.arch()}`;
936
- const helper = path7.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
937
- if (fs15.existsSync(helper)) {
938
- const stat = fs15.statSync(helper);
939
- if (!(stat.mode & 73)) {
940
- fs15.chmodSync(helper, stat.mode | 493);
941
- LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
942
- }
943
- }
944
- } catch {
945
- }
946
- }
936
+ ensureNodePtySpawnHelperPermissions((msg) => LOG.info("CLI", msg));
947
937
  } catch {
948
938
  LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Terminal features disabled.");
949
939
  }
940
+ buildCliSpawnEnv = sanitizeSpawnEnv;
950
941
  ProviderCliAdapter = class _ProviderCliAdapter {
951
942
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
952
943
  this.extraArgs = extraArgs;
@@ -954,7 +945,7 @@ var init_provider_cli_adapter = __esm({
954
945
  this.transportFactory = transportFactory;
955
946
  this.cliType = provider.type;
956
947
  this.cliName = provider.name;
957
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os7.homedir()) : workingDir;
948
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
958
949
  const t = provider.timeouts || {};
959
950
  this.timeouts = {
960
951
  ptyFlush: t.ptyFlush ?? 50,
@@ -1261,7 +1252,7 @@ var init_provider_cli_adapter = __esm({
1261
1252
  if (this.ptyProcess) return;
1262
1253
  const { spawn: spawnConfig } = this.provider;
1263
1254
  const binaryPath = findBinary(spawnConfig.command);
1264
- const isWin = os7.platform() === "win32";
1255
+ const isWin = os8.platform() === "win32";
1265
1256
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
1266
1257
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1267
1258
  this.resetTraceSession();
@@ -1313,6 +1304,12 @@ var init_provider_cli_adapter = __esm({
1313
1304
  shellArgs = ["-l", "-c", fullCmd];
1314
1305
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1315
1306
  } else {
1307
+ if (isWin) {
1308
+ const hint = /error code 267|ERROR_DIRECTORY/i.test(msg) ? " (working directory does not exist or is not a directory)" : /error code 740|elevation/i.test(msg) ? " (requires administrator privileges)" : /error code 2|ENOENT|not found/i.test(msg) ? ` (executable not found: ${shellCmd})` : "";
1309
+ if (hint) {
1310
+ throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1311
+ }
1312
+ }
1316
1313
  throw err;
1317
1314
  }
1318
1315
  }
@@ -1487,7 +1484,7 @@ var init_provider_cli_adapter = __esm({
1487
1484
  `[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)}`
1488
1485
  );
1489
1486
  }
1490
- await new Promise((resolve10) => setTimeout(resolve10, 50));
1487
+ await new Promise((resolve9) => setTimeout(resolve9, 50));
1491
1488
  }
1492
1489
  const finalScreenText = this.terminalScreen.getText() || "";
1493
1490
  LOG.warn(
@@ -1874,7 +1871,7 @@ ${data.message || ""}`.trim();
1874
1871
  if (this.startupParseGate) {
1875
1872
  const deadline = Date.now() + 1e4;
1876
1873
  while (this.startupParseGate && Date.now() < deadline) {
1877
- await new Promise((resolve10) => setTimeout(resolve10, 50));
1874
+ await new Promise((resolve9) => setTimeout(resolve9, 50));
1878
1875
  }
1879
1876
  }
1880
1877
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
@@ -2065,7 +2062,8 @@ ${data.message || ""}`.trim();
2065
2062
  const payload = stopCommand.endsWith("\r") || stopCommand.endsWith("\n") ? stopCommand : `${stopCommand}${this.sendKey}`;
2066
2063
  this.ptyProcess.write(payload);
2067
2064
  };
2068
- if (wasProcessing) setTimeout(writeCommand, 250);
2065
+ const interruptGraceMs = typeof resume.interruptGraceMs === "number" ? Math.max(100, resume.interruptGraceMs) : 500;
2066
+ if (wasProcessing) setTimeout(writeCommand, interruptGraceMs);
2069
2067
  else writeCommand();
2070
2068
  } else {
2071
2069
  this.ptyProcess.write("");
@@ -2081,17 +2079,17 @@ ${data.message || ""}`.trim();
2081
2079
  }
2082
2080
  }
2083
2081
  waitForStopped(timeoutMs) {
2084
- return new Promise((resolve10) => {
2082
+ return new Promise((resolve9) => {
2085
2083
  const startedAt = Date.now();
2086
2084
  const timer = setInterval(() => {
2087
2085
  if (!this.ptyProcess || this.currentStatus === "stopped") {
2088
2086
  clearInterval(timer);
2089
- resolve10(true);
2087
+ resolve9(true);
2090
2088
  return;
2091
2089
  }
2092
2090
  if (Date.now() - startedAt >= timeoutMs) {
2093
2091
  clearInterval(timer);
2094
- resolve10(false);
2092
+ resolve9(false);
2095
2093
  }
2096
2094
  }, 100);
2097
2095
  });
@@ -2110,6 +2108,18 @@ ${data.message || ""}`.trim();
2110
2108
  clearTimeout(this.submitRetryTimer);
2111
2109
  this.submitRetryTimer = null;
2112
2110
  }
2111
+ if (this.responseTimeout) {
2112
+ clearTimeout(this.responseTimeout);
2113
+ this.responseTimeout = null;
2114
+ }
2115
+ if (this.idleTimeout) {
2116
+ clearTimeout(this.idleTimeout);
2117
+ this.idleTimeout = null;
2118
+ }
2119
+ if (this.pendingScriptStatusTimer) {
2120
+ clearTimeout(this.pendingScriptStatusTimer);
2121
+ this.pendingScriptStatusTimer = null;
2122
+ }
2113
2123
  if (this.pendingOutputParseTimer) {
2114
2124
  clearTimeout(this.pendingOutputParseTimer);
2115
2125
  this.pendingOutputParseTimer = null;
@@ -2151,6 +2161,18 @@ ${data.message || ""}`.trim();
2151
2161
  clearTimeout(this.submitRetryTimer);
2152
2162
  this.submitRetryTimer = null;
2153
2163
  }
2164
+ if (this.responseTimeout) {
2165
+ clearTimeout(this.responseTimeout);
2166
+ this.responseTimeout = null;
2167
+ }
2168
+ if (this.idleTimeout) {
2169
+ clearTimeout(this.idleTimeout);
2170
+ this.idleTimeout = null;
2171
+ }
2172
+ if (this.pendingScriptStatusTimer) {
2173
+ clearTimeout(this.pendingScriptStatusTimer);
2174
+ this.pendingScriptStatusTimer = null;
2175
+ }
2154
2176
  if (this.pendingOutputParseTimer) {
2155
2177
  clearTimeout(this.pendingOutputParseTimer);
2156
2178
  this.pendingOutputParseTimer = null;
@@ -2665,20 +2687,20 @@ function checkPathExists(paths) {
2665
2687
  return null;
2666
2688
  }
2667
2689
  async function detectIDEs() {
2668
- const os17 = platform();
2690
+ const os18 = platform();
2669
2691
  const results = [];
2670
2692
  for (const def of getMergedDefinitions()) {
2671
2693
  const cliPath = findCliCommand(def.cli);
2672
- const appPath = checkPathExists(def.paths[os17] || []);
2694
+ const appPath = checkPathExists(def.paths[os18] || []);
2673
2695
  const installed = !!(cliPath || appPath);
2674
2696
  let resolvedCli = cliPath;
2675
- if (!resolvedCli && appPath && os17 === "darwin") {
2697
+ if (!resolvedCli && appPath && os18 === "darwin") {
2676
2698
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
2677
2699
  if (existsSync3(bundledCli)) resolvedCli = bundledCli;
2678
2700
  }
2679
- if (!resolvedCli && appPath && os17 === "win32") {
2680
- const { dirname: dirname7 } = await import("path");
2681
- const appDir = dirname7(appPath);
2701
+ if (!resolvedCli && appPath && os18 === "win32") {
2702
+ const { dirname: dirname6 } = await import("path");
2703
+ const appDir = dirname6(appPath);
2682
2704
  const candidates = [
2683
2705
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
2684
2706
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -2716,15 +2738,15 @@ function parseVersion(raw) {
2716
2738
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
2717
2739
  }
2718
2740
  function execAsync(cmd, timeoutMs = 5e3) {
2719
- return new Promise((resolve10) => {
2741
+ return new Promise((resolve9) => {
2720
2742
  const child = exec(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
2721
2743
  if (err || !stdout?.trim()) {
2722
- resolve10(null);
2744
+ resolve9(null);
2723
2745
  } else {
2724
- resolve10(stdout.trim());
2746
+ resolve9(stdout.trim());
2725
2747
  }
2726
2748
  });
2727
- child.on("error", () => resolve10(null));
2749
+ child.on("error", () => resolve9(null));
2728
2750
  });
2729
2751
  }
2730
2752
  async function detectCLIs(providerLoader) {
@@ -2764,6 +2786,39 @@ async function detectCLIs(providerLoader) {
2764
2786
  }
2765
2787
  async function detectCLI(cliId, providerLoader) {
2766
2788
  const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
2789
+ if (providerLoader) {
2790
+ const cliList = providerLoader.getCliDetectionList();
2791
+ const target = cliList.find((c) => c.id === resolvedId);
2792
+ if (target) {
2793
+ const platform9 = os2.platform();
2794
+ const whichCmd = platform9 === "win32" ? "where" : "which";
2795
+ try {
2796
+ const pathResult = await execAsync(`${whichCmd} ${target.command}`);
2797
+ if (!pathResult) return null;
2798
+ const firstPath = pathResult.split("\n")[0];
2799
+ let version;
2800
+ try {
2801
+ const versionCommands = [
2802
+ target.versionCommand,
2803
+ `${target.command} --version`,
2804
+ `${target.command} -V`,
2805
+ `${target.command} -v`
2806
+ ].filter((v) => !!v);
2807
+ for (const versionCommand of versionCommands) {
2808
+ const versionResult = await execAsync(versionCommand, 3e3);
2809
+ if (versionResult) {
2810
+ version = parseVersion(versionResult);
2811
+ break;
2812
+ }
2813
+ }
2814
+ } catch {
2815
+ }
2816
+ return { ...target, installed: true, version, path: firstPath };
2817
+ } catch {
2818
+ return null;
2819
+ }
2820
+ }
2821
+ }
2767
2822
  const all = await detectCLIs(providerLoader);
2768
2823
  return all.find((c) => c.id === resolvedId && c.installed) || null;
2769
2824
  }
@@ -2891,7 +2946,7 @@ var DaemonCdpManager = class {
2891
2946
  * Returns multiple entries if multiple IDE windows are open on same port
2892
2947
  */
2893
2948
  static listAllTargets(port) {
2894
- return new Promise((resolve10) => {
2949
+ return new Promise((resolve9) => {
2895
2950
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
2896
2951
  let data = "";
2897
2952
  res.on("data", (chunk) => data += chunk.toString());
@@ -2907,16 +2962,16 @@ var DaemonCdpManager = class {
2907
2962
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
2908
2963
  );
2909
2964
  const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
2910
- resolve10(mainPages.length > 0 ? mainPages : fallbackPages);
2965
+ resolve9(mainPages.length > 0 ? mainPages : fallbackPages);
2911
2966
  } catch {
2912
- resolve10([]);
2967
+ resolve9([]);
2913
2968
  }
2914
2969
  });
2915
2970
  });
2916
- req.on("error", () => resolve10([]));
2971
+ req.on("error", () => resolve9([]));
2917
2972
  req.setTimeout(2e3, () => {
2918
2973
  req.destroy();
2919
- resolve10([]);
2974
+ resolve9([]);
2920
2975
  });
2921
2976
  });
2922
2977
  }
@@ -2956,7 +3011,7 @@ var DaemonCdpManager = class {
2956
3011
  }
2957
3012
  }
2958
3013
  findTargetOnPort(port) {
2959
- return new Promise((resolve10) => {
3014
+ return new Promise((resolve9) => {
2960
3015
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
2961
3016
  let data = "";
2962
3017
  res.on("data", (chunk) => data += chunk.toString());
@@ -2967,7 +3022,7 @@ var DaemonCdpManager = class {
2967
3022
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
2968
3023
  );
2969
3024
  if (pages.length === 0) {
2970
- resolve10(targets.find((t) => t.webSocketDebuggerUrl) || null);
3025
+ resolve9(targets.find((t) => t.webSocketDebuggerUrl) || null);
2971
3026
  return;
2972
3027
  }
2973
3028
  const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
@@ -2977,24 +3032,24 @@ var DaemonCdpManager = class {
2977
3032
  const specific = list.find((t) => t.id === this._targetId);
2978
3033
  if (specific) {
2979
3034
  this._pageTitle = specific.title || "";
2980
- resolve10(specific);
3035
+ resolve9(specific);
2981
3036
  } else {
2982
3037
  this.log(`[CDP] Target ${this._targetId} not found in page list`);
2983
- resolve10(null);
3038
+ resolve9(null);
2984
3039
  }
2985
3040
  return;
2986
3041
  }
2987
3042
  this._pageTitle = list[0]?.title || "";
2988
- resolve10(list[0]);
3043
+ resolve9(list[0]);
2989
3044
  } catch {
2990
- resolve10(null);
3045
+ resolve9(null);
2991
3046
  }
2992
3047
  });
2993
3048
  });
2994
- req.on("error", () => resolve10(null));
3049
+ req.on("error", () => resolve9(null));
2995
3050
  req.setTimeout(2e3, () => {
2996
3051
  req.destroy();
2997
- resolve10(null);
3052
+ resolve9(null);
2998
3053
  });
2999
3054
  });
3000
3055
  }
@@ -3005,7 +3060,7 @@ var DaemonCdpManager = class {
3005
3060
  this.extensionProviders = providers;
3006
3061
  }
3007
3062
  connectToTarget(wsUrl) {
3008
- return new Promise((resolve10) => {
3063
+ return new Promise((resolve9) => {
3009
3064
  this.ws = new WebSocket(wsUrl);
3010
3065
  this.ws.on("open", async () => {
3011
3066
  this._connected = true;
@@ -3015,17 +3070,17 @@ var DaemonCdpManager = class {
3015
3070
  }
3016
3071
  this.connectBrowserWs().catch(() => {
3017
3072
  });
3018
- resolve10(true);
3073
+ resolve9(true);
3019
3074
  });
3020
3075
  this.ws.on("message", (data) => {
3021
3076
  try {
3022
3077
  const msg = JSON.parse(data.toString());
3023
3078
  if (msg.id && this.pending.has(msg.id)) {
3024
- const { resolve: resolve11, reject } = this.pending.get(msg.id);
3079
+ const { resolve: resolve10, reject } = this.pending.get(msg.id);
3025
3080
  this.pending.delete(msg.id);
3026
3081
  this.failureCount = 0;
3027
3082
  if (msg.error) reject(new Error(msg.error.message));
3028
- else resolve11(msg.result);
3083
+ else resolve10(msg.result);
3029
3084
  } else if (msg.method === "Runtime.executionContextCreated") {
3030
3085
  this.contexts.add(msg.params.context.id);
3031
3086
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -3048,7 +3103,7 @@ var DaemonCdpManager = class {
3048
3103
  this.ws.on("error", (err) => {
3049
3104
  this.log(`[CDP] WebSocket error: ${err.message}`);
3050
3105
  this._connected = false;
3051
- resolve10(false);
3106
+ resolve9(false);
3052
3107
  });
3053
3108
  });
3054
3109
  }
@@ -3062,7 +3117,7 @@ var DaemonCdpManager = class {
3062
3117
  return;
3063
3118
  }
3064
3119
  this.log(`[CDP] Connecting browser WS for target discovery...`);
3065
- await new Promise((resolve10, reject) => {
3120
+ await new Promise((resolve9, reject) => {
3066
3121
  this.browserWs = new WebSocket(browserWsUrl);
3067
3122
  this.browserWs.on("open", async () => {
3068
3123
  this._browserConnected = true;
@@ -3072,16 +3127,16 @@ var DaemonCdpManager = class {
3072
3127
  } catch (e) {
3073
3128
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
3074
3129
  }
3075
- resolve10();
3130
+ resolve9();
3076
3131
  });
3077
3132
  this.browserWs.on("message", (data) => {
3078
3133
  try {
3079
3134
  const msg = JSON.parse(data.toString());
3080
3135
  if (msg.id && this.browserPending.has(msg.id)) {
3081
- const { resolve: resolve11, reject: reject2 } = this.browserPending.get(msg.id);
3136
+ const { resolve: resolve10, reject: reject2 } = this.browserPending.get(msg.id);
3082
3137
  this.browserPending.delete(msg.id);
3083
3138
  if (msg.error) reject2(new Error(msg.error.message));
3084
- else resolve11(msg.result);
3139
+ else resolve10(msg.result);
3085
3140
  }
3086
3141
  } catch {
3087
3142
  }
@@ -3101,31 +3156,31 @@ var DaemonCdpManager = class {
3101
3156
  }
3102
3157
  }
3103
3158
  getBrowserWsUrl() {
3104
- return new Promise((resolve10) => {
3159
+ return new Promise((resolve9) => {
3105
3160
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
3106
3161
  let data = "";
3107
3162
  res.on("data", (chunk) => data += chunk.toString());
3108
3163
  res.on("end", () => {
3109
3164
  try {
3110
3165
  const info = JSON.parse(data);
3111
- resolve10(info.webSocketDebuggerUrl || null);
3166
+ resolve9(info.webSocketDebuggerUrl || null);
3112
3167
  } catch {
3113
- resolve10(null);
3168
+ resolve9(null);
3114
3169
  }
3115
3170
  });
3116
3171
  });
3117
- req.on("error", () => resolve10(null));
3172
+ req.on("error", () => resolve9(null));
3118
3173
  req.setTimeout(3e3, () => {
3119
3174
  req.destroy();
3120
- resolve10(null);
3175
+ resolve9(null);
3121
3176
  });
3122
3177
  });
3123
3178
  }
3124
3179
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
3125
- return new Promise((resolve10, reject) => {
3180
+ return new Promise((resolve9, reject) => {
3126
3181
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
3127
3182
  const id = this.browserMsgId++;
3128
- this.browserPending.set(id, { resolve: resolve10, reject });
3183
+ this.browserPending.set(id, { resolve: resolve9, reject });
3129
3184
  this.browserWs.send(JSON.stringify({ id, method, params }));
3130
3185
  setTimeout(() => {
3131
3186
  if (this.browserPending.has(id)) {
@@ -3165,11 +3220,11 @@ var DaemonCdpManager = class {
3165
3220
  }
3166
3221
  // ─── CDP Protocol ────────────────────────────────────────
3167
3222
  sendInternal(method, params = {}, timeoutMs = 15e3) {
3168
- return new Promise((resolve10, reject) => {
3223
+ return new Promise((resolve9, reject) => {
3169
3224
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
3170
3225
  if (this.ws.readyState !== WebSocket.OPEN) return reject(new Error("WebSocket not open"));
3171
3226
  const id = this.msgId++;
3172
- this.pending.set(id, { resolve: resolve10, reject });
3227
+ this.pending.set(id, { resolve: resolve9, reject });
3173
3228
  this.ws.send(JSON.stringify({ id, method, params }));
3174
3229
  setTimeout(() => {
3175
3230
  if (this.pending.has(id)) {
@@ -3418,7 +3473,7 @@ var DaemonCdpManager = class {
3418
3473
  const browserWs = this.browserWs;
3419
3474
  let msgId = this.browserMsgId;
3420
3475
  const sendWs = (method, params = {}, sessionId) => {
3421
- return new Promise((resolve10, reject) => {
3476
+ return new Promise((resolve9, reject) => {
3422
3477
  const mid = msgId++;
3423
3478
  this.browserMsgId = msgId;
3424
3479
  const handler = (raw) => {
@@ -3427,7 +3482,7 @@ var DaemonCdpManager = class {
3427
3482
  if (msg.id === mid) {
3428
3483
  browserWs.removeListener("message", handler);
3429
3484
  if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
3430
- else resolve10(msg.result);
3485
+ else resolve9(msg.result);
3431
3486
  }
3432
3487
  } catch {
3433
3488
  }
@@ -3618,14 +3673,14 @@ var DaemonCdpManager = class {
3618
3673
  if (!ws || ws.readyState !== WebSocket.OPEN) {
3619
3674
  throw new Error("CDP not connected");
3620
3675
  }
3621
- return new Promise((resolve10, reject) => {
3676
+ return new Promise((resolve9, reject) => {
3622
3677
  const id = getNextId();
3623
3678
  pendingMap.set(id, {
3624
3679
  resolve: (result) => {
3625
3680
  if (result?.result?.subtype === "error") {
3626
3681
  reject(new Error(result.result.description));
3627
3682
  } else {
3628
- resolve10(result?.result?.value);
3683
+ resolve9(result?.result?.value);
3629
3684
  }
3630
3685
  },
3631
3686
  reject
@@ -3657,10 +3712,10 @@ var DaemonCdpManager = class {
3657
3712
  throw new Error("CDP not connected");
3658
3713
  }
3659
3714
  const sendViaSession = (method, params = {}) => {
3660
- return new Promise((resolve10, reject) => {
3715
+ return new Promise((resolve9, reject) => {
3661
3716
  const pendingMap = this._browserConnected ? this.browserPending : this.pending;
3662
3717
  const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
3663
- pendingMap.set(id, { resolve: resolve10, reject });
3718
+ pendingMap.set(id, { resolve: resolve9, reject });
3664
3719
  ws.send(JSON.stringify({ id, sessionId, method, params }));
3665
3720
  setTimeout(() => {
3666
3721
  if (pendingMap.has(id)) {
@@ -7661,7 +7716,7 @@ var DaemonCommandHandler = class {
7661
7716
  try {
7662
7717
  const http3 = await import("http");
7663
7718
  const postData = JSON.stringify(body);
7664
- const result = await new Promise((resolve10, reject) => {
7719
+ const result = await new Promise((resolve9, reject) => {
7665
7720
  const req = http3.request({
7666
7721
  hostname: "127.0.0.1",
7667
7722
  port: 19280,
@@ -7673,9 +7728,9 @@ var DaemonCommandHandler = class {
7673
7728
  res.on("data", (chunk) => data += chunk);
7674
7729
  res.on("end", () => {
7675
7730
  try {
7676
- resolve10(JSON.parse(data));
7731
+ resolve9(JSON.parse(data));
7677
7732
  } catch {
7678
- resolve10({ raw: data });
7733
+ resolve9({ raw: data });
7679
7734
  }
7680
7735
  });
7681
7736
  });
@@ -7693,15 +7748,15 @@ var DaemonCommandHandler = class {
7693
7748
  if (!providerType) return { success: false, error: "providerType required" };
7694
7749
  try {
7695
7750
  const http3 = await import("http");
7696
- const result = await new Promise((resolve10, reject) => {
7751
+ const result = await new Promise((resolve9, reject) => {
7697
7752
  http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
7698
7753
  let data = "";
7699
7754
  res.on("data", (chunk) => data += chunk);
7700
7755
  res.on("end", () => {
7701
7756
  try {
7702
- resolve10(JSON.parse(data));
7757
+ resolve9(JSON.parse(data));
7703
7758
  } catch {
7704
- resolve10({ raw: data });
7759
+ resolve9({ raw: data });
7705
7760
  }
7706
7761
  });
7707
7762
  }).on("error", reject);
@@ -7715,7 +7770,7 @@ var DaemonCommandHandler = class {
7715
7770
  try {
7716
7771
  const http3 = await import("http");
7717
7772
  const postData = JSON.stringify(args || {});
7718
- const result = await new Promise((resolve10, reject) => {
7773
+ const result = await new Promise((resolve9, reject) => {
7719
7774
  const req = http3.request({
7720
7775
  hostname: "127.0.0.1",
7721
7776
  port: 19280,
@@ -7727,9 +7782,9 @@ var DaemonCommandHandler = class {
7727
7782
  res.on("data", (chunk) => data += chunk);
7728
7783
  res.on("end", () => {
7729
7784
  try {
7730
- resolve10(JSON.parse(data));
7785
+ resolve9(JSON.parse(data));
7731
7786
  } catch {
7732
- resolve10({ raw: data });
7787
+ resolve9({ raw: data });
7733
7788
  }
7734
7789
  });
7735
7790
  });
@@ -7746,7 +7801,7 @@ var DaemonCommandHandler = class {
7746
7801
 
7747
7802
  // src/commands/cli-manager.ts
7748
7803
  init_provider_cli_adapter();
7749
- import * as os9 from "os";
7804
+ import * as os10 from "os";
7750
7805
  import * as path9 from "path";
7751
7806
  import * as crypto4 from "crypto";
7752
7807
  import chalk from "chalk";
@@ -7754,7 +7809,7 @@ init_config();
7754
7809
 
7755
7810
  // src/providers/cli-provider-instance.ts
7756
7811
  init_provider_cli_adapter();
7757
- import * as os8 from "os";
7812
+ import * as os9 from "os";
7758
7813
  import * as path8 from "path";
7759
7814
  import * as crypto3 from "crypto";
7760
7815
  import * as fs5 from "fs";
@@ -7842,17 +7897,60 @@ var CliProviderInstance = class {
7842
7897
  async onTick() {
7843
7898
  if (this.providerSessionId) return;
7844
7899
  let probedSessionId = null;
7845
- if (this.type === "opencode-cli") {
7846
- probedSessionId = this.probeOpenCodeSessionId();
7847
- } else if (this.type === "codex-cli") {
7848
- probedSessionId = this.probeCodexSessionId();
7849
- } else if (this.type === "goose-cli") {
7850
- probedSessionId = this.probeGooseSessionId();
7900
+ const probeConfig = this.provider.sessionProbe;
7901
+ if (probeConfig) {
7902
+ probedSessionId = this.probeSessionIdFromConfig(probeConfig);
7903
+ } else {
7904
+ if (this.type === "opencode-cli") {
7905
+ probedSessionId = this.probeSessionIdFromConfig({
7906
+ dbPath: "~/.local/share/opencode/opencode.db",
7907
+ query: "select id from session where directory in ({dirs}) and time_created >= ? and time_archived is null order by time_updated desc limit 1",
7908
+ timestampFormat: "unix_ms"
7909
+ });
7910
+ } else if (this.type === "codex-cli") {
7911
+ probedSessionId = this.probeSessionIdFromConfig({
7912
+ dbPath: "~/.codex/state_5.sqlite",
7913
+ query: "select id from threads where cwd in ({dirs}) and created_at >= ? and archived = 0 order by created_at desc limit 1",
7914
+ timestampFormat: "unix_s"
7915
+ });
7916
+ } else if (this.type === "goose-cli") {
7917
+ probedSessionId = this.probeSessionIdFromConfig({
7918
+ dbPath: "~/.local/share/goose/sessions/sessions.db",
7919
+ query: "select id from sessions where working_dir in ({dirs}) and created_at >= ? order by updated_at desc limit 1",
7920
+ timestampFormat: "iso"
7921
+ });
7922
+ }
7851
7923
  }
7852
7924
  if (probedSessionId) {
7853
7925
  this.promoteProviderSessionId(probedSessionId);
7854
7926
  }
7855
7927
  }
7928
+ /**
7929
+ * Generic session ID probe using declarative ProviderSessionProbe config.
7930
+ * Replaces the previously duplicated probeOpenCode/Codex/Goose functions.
7931
+ */
7932
+ probeSessionIdFromConfig(probe) {
7933
+ const resolvedDbPath = probe.dbPath.replace(/^~/, os9.homedir());
7934
+ if (!fs5.existsSync(resolvedDbPath)) return null;
7935
+ const directories = this.getProbeDirectories();
7936
+ const minCreatedAt = Math.max(0, this.startedAt - 6e4);
7937
+ const tsFormat = probe.timestampFormat || "unix_ms";
7938
+ let timestampParam;
7939
+ if (tsFormat === "unix_s") {
7940
+ timestampParam = Math.floor(minCreatedAt / 1e3);
7941
+ } else if (tsFormat === "iso") {
7942
+ timestampParam = new Date(minCreatedAt).toISOString().slice(0, 19).replace("T", " ");
7943
+ } else {
7944
+ timestampParam = minCreatedAt;
7945
+ }
7946
+ const placeholders = this.buildSqlPlaceholderList(directories.length);
7947
+ const query = probe.query.replace("{dirs}", placeholders);
7948
+ try {
7949
+ return this.querySqliteText(resolvedDbPath, query, [...directories, timestampParam]);
7950
+ } catch {
7951
+ return null;
7952
+ }
7953
+ }
7856
7954
  getState() {
7857
7955
  const adapterStatus = this.adapter.getStatus();
7858
7956
  const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
@@ -8150,34 +8248,6 @@ var CliProviderInstance = class {
8150
8248
  });
8151
8249
  LOG.info("CLI", `[${this.type}] discovered provider session id: ${nextSessionId}`);
8152
8250
  }
8153
- probeOpenCodeSessionId() {
8154
- const dbPath = path8.join(os8.homedir(), ".local", "share", "opencode", "opencode.db");
8155
- if (!fs5.existsSync(dbPath)) return null;
8156
- const minCreatedAt = Math.max(0, this.startedAt - 6e4);
8157
- const directories = this.getProbeDirectories();
8158
- const query = `select id from session where directory in (${this.buildSqlPlaceholderList(directories.length)}) and time_created >= ? and time_archived is null order by time_updated desc limit 1;`;
8159
- return this.querySqliteText(dbPath, query, [...directories, minCreatedAt]);
8160
- }
8161
- probeCodexSessionId() {
8162
- const dbPath = path8.join(os8.homedir(), ".codex", "state_5.sqlite");
8163
- if (!fs5.existsSync(dbPath)) return null;
8164
- const minCreatedAt = Math.max(0, Math.floor((this.startedAt - 6e4) / 1e3));
8165
- const directories = this.getProbeDirectories();
8166
- const query = `select id from threads where cwd in (${this.buildSqlPlaceholderList(directories.length)}) and created_at >= ? and archived = 0 order by created_at desc limit 1;`;
8167
- return this.querySqliteText(dbPath, query, [...directories, minCreatedAt]);
8168
- }
8169
- probeGooseSessionId() {
8170
- const dbPath = path8.join(os8.homedir(), ".local", "share", "goose", "sessions", "sessions.db");
8171
- if (!fs5.existsSync(dbPath)) return null;
8172
- const minCreatedAtIso = new Date(Math.max(0, this.startedAt - 6e4)).toISOString().slice(0, 19).replace("T", " ");
8173
- const directories = this.getProbeDirectories();
8174
- const query = `select id from sessions where working_dir in (${this.buildSqlPlaceholderList(directories.length)}) and created_at >= ? order by updated_at desc limit 1;`;
8175
- try {
8176
- return this.querySqliteText(dbPath, query, [...directories, minCreatedAtIso]);
8177
- } catch {
8178
- return null;
8179
- }
8180
- }
8181
8251
  getProbeDirectories() {
8182
8252
  const dirs = /* @__PURE__ */ new Set();
8183
8253
  const addDir = (value) => {
@@ -8654,13 +8724,13 @@ var AcpProviderInstance = class {
8654
8724
  }
8655
8725
  this.currentStatus = "waiting_approval";
8656
8726
  this.detectStatusTransition();
8657
- const approved = await new Promise((resolve10) => {
8658
- this.permissionResolvers.push(resolve10);
8727
+ const approved = await new Promise((resolve9) => {
8728
+ this.permissionResolvers.push(resolve9);
8659
8729
  setTimeout(() => {
8660
- const idx = this.permissionResolvers.indexOf(resolve10);
8730
+ const idx = this.permissionResolvers.indexOf(resolve9);
8661
8731
  if (idx >= 0) {
8662
8732
  this.permissionResolvers.splice(idx, 1);
8663
- resolve10(false);
8733
+ resolve9(false);
8664
8734
  }
8665
8735
  }, 3e5);
8666
8736
  });
@@ -9367,7 +9437,7 @@ var DaemonCliManager = class {
9367
9437
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
9368
9438
  const trimmed = (workingDir || "").trim();
9369
9439
  if (!trimmed) throw new Error("working directory required");
9370
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os9.homedir()) : path9.resolve(trimmed);
9440
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path9.resolve(trimmed);
9371
9441
  const normalizedType = this.providerLoader.resolveAlias(cliType);
9372
9442
  const provider = this.providerLoader.getByAlias(cliType);
9373
9443
  const key = crypto4.randomUUID();
@@ -9451,7 +9521,19 @@ ${installInfo}`
9451
9521
  return { runtimeSessionId: sessionId };
9452
9522
  }
9453
9523
  const cliInfo = await detectCLI(cliType, this.providerLoader);
9454
- if (!cliInfo) throw new Error(`${cliType} not found`);
9524
+ if (!cliInfo) {
9525
+ const installHint = provider?.install || "";
9526
+ const displayName = provider?.displayName || provider?.name || cliType;
9527
+ const spawnCmd = provider?.spawn?.command || cliType;
9528
+ throw new Error(
9529
+ `${displayName} is not installed.
9530
+ Command '${spawnCmd}' not found on PATH.
9531
+ ` + (installHint ? `
9532
+ ${installHint}
9533
+ ` : "") + `
9534
+ Run 'adhdev doctor' for detailed diagnostics.`
9535
+ );
9536
+ }
9455
9537
  console.log(colorize("yellow", ` \u26A1 Starting CLI ${cliType} in ${resolvedDir}...`));
9456
9538
  if (provider) {
9457
9539
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
@@ -9767,8 +9849,9 @@ ${installInfo}`
9767
9849
  const dir = rdir.path;
9768
9850
  if (!cliType) throw new Error("cliType required");
9769
9851
  const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
9852
+ const prevCliArgs = found ? found.adapter.extraArgs : void 0;
9770
9853
  if (found) await this.stopSession(found.key);
9771
- await this.startSession(cliType, dir);
9854
+ await this.startSession(cliType, dir, args?.cliArgs || prevCliArgs, args?.initialModel);
9772
9855
  return { success: true, restarted: true };
9773
9856
  }
9774
9857
  case "agent_command": {
@@ -9803,13 +9886,13 @@ ${installInfo}`
9803
9886
  // src/launch.ts
9804
9887
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
9805
9888
  import * as net from "net";
9806
- import * as os11 from "os";
9889
+ import * as os12 from "os";
9807
9890
  import * as path11 from "path";
9808
9891
 
9809
9892
  // src/providers/provider-loader.ts
9810
9893
  import * as fs6 from "fs";
9811
9894
  import * as path10 from "path";
9812
- import * as os10 from "os";
9895
+ import * as os11 from "os";
9813
9896
  import * as chokidar from "chokidar";
9814
9897
  init_logger();
9815
9898
  var ProviderLoader = class _ProviderLoader {
@@ -9829,7 +9912,7 @@ var ProviderLoader = class _ProviderLoader {
9829
9912
  static META_FILE = ".meta.json";
9830
9913
  constructor(options) {
9831
9914
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
9832
- const defaultProvidersDir = path10.join(os10.homedir(), ".adhdev", "providers");
9915
+ const defaultProvidersDir = path10.join(os11.homedir(), ".adhdev", "providers");
9833
9916
  if (options?.userDir) {
9834
9917
  this.userDir = options.userDir;
9835
9918
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -10386,7 +10469,7 @@ var ProviderLoader = class _ProviderLoader {
10386
10469
  return { updated: false };
10387
10470
  }
10388
10471
  try {
10389
- const etag = await new Promise((resolve10, reject) => {
10472
+ const etag = await new Promise((resolve9, reject) => {
10390
10473
  const options = {
10391
10474
  method: "HEAD",
10392
10475
  hostname: "github.com",
@@ -10404,7 +10487,7 @@ var ProviderLoader = class _ProviderLoader {
10404
10487
  headers: { "User-Agent": "adhdev-launcher" },
10405
10488
  timeout: 1e4
10406
10489
  }, (res2) => {
10407
- resolve10(res2.headers.etag || res2.headers["last-modified"] || "");
10490
+ resolve9(res2.headers.etag || res2.headers["last-modified"] || "");
10408
10491
  });
10409
10492
  req2.on("error", reject);
10410
10493
  req2.on("timeout", () => {
@@ -10413,7 +10496,7 @@ var ProviderLoader = class _ProviderLoader {
10413
10496
  });
10414
10497
  req2.end();
10415
10498
  } else {
10416
- resolve10(res.headers.etag || res.headers["last-modified"] || "");
10499
+ resolve9(res.headers.etag || res.headers["last-modified"] || "");
10417
10500
  }
10418
10501
  });
10419
10502
  req.on("error", reject);
@@ -10429,8 +10512,8 @@ var ProviderLoader = class _ProviderLoader {
10429
10512
  return { updated: false };
10430
10513
  }
10431
10514
  this.log("Downloading latest providers from GitHub...");
10432
- const tmpTar = path10.join(os10.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
10433
- const tmpExtract = path10.join(os10.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
10515
+ const tmpTar = path10.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
10516
+ const tmpExtract = path10.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
10434
10517
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
10435
10518
  fs6.mkdirSync(tmpExtract, { recursive: true });
10436
10519
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
@@ -10477,7 +10560,7 @@ var ProviderLoader = class _ProviderLoader {
10477
10560
  downloadFile(url, destPath) {
10478
10561
  const https = __require("https");
10479
10562
  const http3 = __require("http");
10480
- return new Promise((resolve10, reject) => {
10563
+ return new Promise((resolve9, reject) => {
10481
10564
  const doRequest = (reqUrl, redirectCount = 0) => {
10482
10565
  if (redirectCount > 5) {
10483
10566
  reject(new Error("Too many redirects"));
@@ -10497,7 +10580,7 @@ var ProviderLoader = class _ProviderLoader {
10497
10580
  res.pipe(ws);
10498
10581
  ws.on("finish", () => {
10499
10582
  ws.close();
10500
- resolve10();
10583
+ resolve9();
10501
10584
  });
10502
10585
  ws.on("error", reject);
10503
10586
  });
@@ -10862,17 +10945,17 @@ async function findFreePort(ports) {
10862
10945
  throw new Error("No free port found");
10863
10946
  }
10864
10947
  function checkPortFree(port) {
10865
- return new Promise((resolve10) => {
10948
+ return new Promise((resolve9) => {
10866
10949
  const server = net.createServer();
10867
10950
  server.unref();
10868
- server.on("error", () => resolve10(false));
10951
+ server.on("error", () => resolve9(false));
10869
10952
  server.listen(port, "127.0.0.1", () => {
10870
- server.close(() => resolve10(true));
10953
+ server.close(() => resolve9(true));
10871
10954
  });
10872
10955
  });
10873
10956
  }
10874
10957
  async function isCdpActive(port) {
10875
- return new Promise((resolve10) => {
10958
+ return new Promise((resolve9) => {
10876
10959
  const req = __require("http").get(`http://127.0.0.1:${port}/json/version`, {
10877
10960
  timeout: 2e3
10878
10961
  }, (res) => {
@@ -10881,21 +10964,21 @@ async function isCdpActive(port) {
10881
10964
  res.on("end", () => {
10882
10965
  try {
10883
10966
  const info = JSON.parse(data);
10884
- resolve10(!!info["WebKit-Version"] || !!info["Browser"]);
10967
+ resolve9(!!info["WebKit-Version"] || !!info["Browser"]);
10885
10968
  } catch {
10886
- resolve10(false);
10969
+ resolve9(false);
10887
10970
  }
10888
10971
  });
10889
10972
  });
10890
- req.on("error", () => resolve10(false));
10973
+ req.on("error", () => resolve9(false));
10891
10974
  req.on("timeout", () => {
10892
10975
  req.destroy();
10893
- resolve10(false);
10976
+ resolve9(false);
10894
10977
  });
10895
10978
  });
10896
10979
  }
10897
10980
  async function killIdeProcess(ideId) {
10898
- const plat = os11.platform();
10981
+ const plat = os12.platform();
10899
10982
  const appName = getMacAppIdentifiers()[ideId];
10900
10983
  const winProcesses = getWinProcessNames()[ideId];
10901
10984
  try {
@@ -10954,7 +11037,7 @@ async function killIdeProcess(ideId) {
10954
11037
  }
10955
11038
  }
10956
11039
  function isIdeRunning(ideId) {
10957
- const plat = os11.platform();
11040
+ const plat = os12.platform();
10958
11041
  try {
10959
11042
  if (plat === "darwin") {
10960
11043
  const appName = getMacAppIdentifiers()[ideId];
@@ -10990,7 +11073,7 @@ function isIdeRunning(ideId) {
10990
11073
  }
10991
11074
  }
10992
11075
  function detectCurrentWorkspace(ideId) {
10993
- const plat = os11.platform();
11076
+ const plat = os12.platform();
10994
11077
  if (plat === "darwin") {
10995
11078
  try {
10996
11079
  const appName = getMacAppIdentifiers()[ideId];
@@ -11010,7 +11093,7 @@ function detectCurrentWorkspace(ideId) {
11010
11093
  const appName = appNameMap[ideId];
11011
11094
  if (appName) {
11012
11095
  const storagePath = path11.join(
11013
- process.env.APPDATA || path11.join(os11.homedir(), "AppData", "Roaming"),
11096
+ process.env.APPDATA || path11.join(os12.homedir(), "AppData", "Roaming"),
11014
11097
  appName,
11015
11098
  "storage.json"
11016
11099
  );
@@ -11032,7 +11115,7 @@ function detectCurrentWorkspace(ideId) {
11032
11115
  return void 0;
11033
11116
  }
11034
11117
  async function launchWithCdp(options = {}) {
11035
- const platform9 = os11.platform();
11118
+ const platform9 = os12.platform();
11036
11119
  let targetIde;
11037
11120
  const ides = await detectIDEs();
11038
11121
  if (options.ideId) {
@@ -11184,8 +11267,8 @@ init_logger();
11184
11267
  // src/logging/command-log.ts
11185
11268
  import * as fs7 from "fs";
11186
11269
  import * as path12 from "path";
11187
- import * as os12 from "os";
11188
- var LOG_DIR2 = process.platform === "win32" ? path12.join(process.env.LOCALAPPDATA || process.env.APPDATA || path12.join(os12.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path12.join(os12.homedir(), "Library", "Logs", "adhdev") : path12.join(os12.homedir(), ".local", "share", "adhdev", "logs");
11270
+ import * as os13 from "os";
11271
+ var LOG_DIR2 = process.platform === "win32" ? path12.join(process.env.LOCALAPPDATA || process.env.APPDATA || path12.join(os13.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path12.join(os13.homedir(), "Library", "Logs", "adhdev") : path12.join(os13.homedir(), ".local", "share", "adhdev", "logs");
11189
11272
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
11190
11273
  var MAX_DAYS = 7;
11191
11274
  try {
@@ -11321,7 +11404,7 @@ init_logger();
11321
11404
 
11322
11405
  // src/status/snapshot.ts
11323
11406
  init_config();
11324
- import * as os13 from "os";
11407
+ import * as os14 from "os";
11325
11408
  init_terminal_screen();
11326
11409
  init_logger();
11327
11410
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -11436,16 +11519,16 @@ function buildStatusSnapshot(options) {
11436
11519
  version: options.version,
11437
11520
  daemonMode: options.daemonMode,
11438
11521
  machine: {
11439
- hostname: os13.hostname(),
11440
- platform: os13.platform(),
11441
- arch: os13.arch(),
11442
- cpus: os13.cpus().length,
11522
+ hostname: os14.hostname(),
11523
+ platform: os14.platform(),
11524
+ arch: os14.arch(),
11525
+ cpus: os14.cpus().length,
11443
11526
  totalMem: memSnap.totalMem,
11444
11527
  freeMem: memSnap.freeMem,
11445
11528
  availableMem: memSnap.availableMem,
11446
- loadavg: os13.loadavg(),
11447
- uptime: os13.uptime(),
11448
- release: os13.release()
11529
+ loadavg: os14.loadavg(),
11530
+ uptime: os14.uptime(),
11531
+ release: os14.release()
11449
11532
  },
11450
11533
  machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
11451
11534
  timestamp: options.timestamp ?? Date.now(),
@@ -11465,11 +11548,11 @@ function buildStatusSnapshot(options) {
11465
11548
  import { execFileSync } from "child_process";
11466
11549
  import { spawn as spawn3 } from "child_process";
11467
11550
  import * as fs8 from "fs";
11468
- import * as os14 from "os";
11551
+ import * as os15 from "os";
11469
11552
  import * as path13 from "path";
11470
11553
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
11471
11554
  function getUpgradeLogPath() {
11472
- const home = os14.homedir();
11555
+ const home = os15.homedir();
11473
11556
  const dir = path13.join(home, ".adhdev");
11474
11557
  fs8.mkdirSync(dir, { recursive: true });
11475
11558
  return path13.join(dir, "daemon-upgrade.log");
@@ -11502,14 +11585,14 @@ async function waitForPidExit(pid, timeoutMs) {
11502
11585
  while (Date.now() - start < timeoutMs) {
11503
11586
  try {
11504
11587
  process.kill(pid, 0);
11505
- await new Promise((resolve10) => setTimeout(resolve10, 250));
11588
+ await new Promise((resolve9) => setTimeout(resolve9, 250));
11506
11589
  } catch {
11507
11590
  return;
11508
11591
  }
11509
11592
  }
11510
11593
  }
11511
11594
  function stopSessionHostProcesses(appName) {
11512
- const pidFile = path13.join(os14.homedir(), ".adhdev", `${appName}-session-host.pid`);
11595
+ const pidFile = path13.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
11513
11596
  try {
11514
11597
  if (fs8.existsSync(pidFile)) {
11515
11598
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -11538,7 +11621,7 @@ function stopSessionHostProcesses(appName) {
11538
11621
  }
11539
11622
  }
11540
11623
  function removeDaemonPidFile() {
11541
- const pidFile = path13.join(os14.homedir(), ".adhdev", "daemon.pid");
11624
+ const pidFile = path13.join(os15.homedir(), ".adhdev", "daemon.pid");
11542
11625
  try {
11543
11626
  fs8.unlinkSync(pidFile);
11544
11627
  } catch {
@@ -13048,10 +13131,10 @@ var ProviderInstanceManager = class {
13048
13131
  // src/providers/version-archive.ts
13049
13132
  import * as fs10 from "fs";
13050
13133
  import * as path14 from "path";
13051
- import * as os15 from "os";
13134
+ import * as os16 from "os";
13052
13135
  import { execSync as execSync5 } from "child_process";
13053
13136
  import { platform as platform7 } from "os";
13054
- var ARCHIVE_PATH = path14.join(os15.homedir(), ".adhdev", "version-history.json");
13137
+ var ARCHIVE_PATH = path14.join(os16.homedir(), ".adhdev", "version-history.json");
13055
13138
  var MAX_ENTRIES_PER_PROVIDER = 20;
13056
13139
  var VersionArchive = class {
13057
13140
  history = {};
@@ -13138,7 +13221,7 @@ function getVersion(binary, versionCommand) {
13138
13221
  function checkPathExists2(paths) {
13139
13222
  for (const p of paths) {
13140
13223
  if (p.includes("*")) {
13141
- const home = os15.homedir();
13224
+ const home = os16.homedir();
13142
13225
  const resolved = p.replace(/\*/g, home.split(path14.sep).pop() || "");
13143
13226
  if (fs10.existsSync(resolved)) return resolved;
13144
13227
  } else {
@@ -14735,7 +14818,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
14735
14818
  return { target, instance, adapter };
14736
14819
  }
14737
14820
  function sleep(ms) {
14738
- return new Promise((resolve10) => setTimeout(resolve10, ms));
14821
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
14739
14822
  }
14740
14823
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
14741
14824
  const startedAt = Date.now();
@@ -15466,7 +15549,7 @@ async function handleCliRaw(ctx, req, res) {
15466
15549
  // src/daemon/dev-auto-implement.ts
15467
15550
  import * as fs13 from "fs";
15468
15551
  import * as path17 from "path";
15469
- import * as os16 from "os";
15552
+ import * as os17 from "os";
15470
15553
  function getAutoImplPid(ctx) {
15471
15554
  const proc = ctx.autoImplProcess;
15472
15555
  return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
@@ -15669,7 +15752,7 @@ async function handleAutoImplement(ctx, type, req, res) {
15669
15752
  });
15670
15753
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
15671
15754
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
15672
- const tmpDir = path17.join(os16.tmpdir(), "adhdev-autoimpl");
15755
+ const tmpDir = path17.join(os17.tmpdir(), "adhdev-autoimpl");
15673
15756
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
15674
15757
  const promptFile = path17.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
15675
15758
  fs13.writeFileSync(promptFile, prompt, "utf-8");
@@ -15823,7 +15906,7 @@ async function handleAutoImplement(ctx, type, req, res) {
15823
15906
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
15824
15907
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
15825
15908
  let shellCmd;
15826
- const isWin = os16.platform() === "win32";
15909
+ const isWin = os17.platform() === "win32";
15827
15910
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
15828
15911
  if (command === "claude") {
15829
15912
  const args = [...baseArgs, "--dangerously-skip-permissions"];
@@ -15867,7 +15950,7 @@ async function handleAutoImplement(ctx, type, req, res) {
15867
15950
  try {
15868
15951
  const pty3 = __require("node-pty");
15869
15952
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
15870
- const isWin2 = os16.platform() === "win32";
15953
+ const isWin2 = os17.platform() === "win32";
15871
15954
  child = pty3.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
15872
15955
  name: "xterm-256color",
15873
15956
  cols: 120,
@@ -16905,15 +16988,15 @@ var DevServer = class _DevServer {
16905
16988
  this.json(res, 500, { error: e.message });
16906
16989
  }
16907
16990
  });
16908
- return new Promise((resolve10, reject) => {
16991
+ return new Promise((resolve9, reject) => {
16909
16992
  this.server.listen(port, "127.0.0.1", () => {
16910
16993
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
16911
- resolve10();
16994
+ resolve9();
16912
16995
  });
16913
16996
  this.server.on("error", (e) => {
16914
16997
  if (e.code === "EADDRINUSE") {
16915
16998
  this.log(`Port ${port} in use, skipping dev server`);
16916
- resolve10();
16999
+ resolve9();
16917
17000
  } else {
16918
17001
  reject(e);
16919
17002
  }
@@ -16996,20 +17079,20 @@ var DevServer = class _DevServer {
16996
17079
  child.stderr?.on("data", (d) => {
16997
17080
  stderr += d.toString().slice(0, 2e3);
16998
17081
  });
16999
- await new Promise((resolve10) => {
17082
+ await new Promise((resolve9) => {
17000
17083
  const timer = setTimeout(() => {
17001
17084
  child.kill();
17002
- resolve10();
17085
+ resolve9();
17003
17086
  }, 3e3);
17004
17087
  child.on("exit", () => {
17005
17088
  clearTimeout(timer);
17006
- resolve10();
17089
+ resolve9();
17007
17090
  });
17008
17091
  child.stdout?.once("data", () => {
17009
17092
  setTimeout(() => {
17010
17093
  child.kill();
17011
17094
  clearTimeout(timer);
17012
- resolve10();
17095
+ resolve9();
17013
17096
  }, 500);
17014
17097
  });
17015
17098
  });
@@ -17518,14 +17601,14 @@ var DevServer = class _DevServer {
17518
17601
  child.stderr?.on("data", (d) => {
17519
17602
  stderr += d.toString();
17520
17603
  });
17521
- await new Promise((resolve10) => {
17604
+ await new Promise((resolve9) => {
17522
17605
  const timer = setTimeout(() => {
17523
17606
  child.kill();
17524
- resolve10();
17607
+ resolve9();
17525
17608
  }, timeout);
17526
17609
  child.on("exit", () => {
17527
17610
  clearTimeout(timer);
17528
- resolve10();
17611
+ resolve9();
17529
17612
  });
17530
17613
  });
17531
17614
  const elapsed = Date.now() - start;
@@ -18200,14 +18283,14 @@ data: ${JSON.stringify(msg.data)}
18200
18283
  res.end(JSON.stringify(data, null, 2));
18201
18284
  }
18202
18285
  async readBody(req) {
18203
- return new Promise((resolve10) => {
18286
+ return new Promise((resolve9) => {
18204
18287
  let body = "";
18205
18288
  req.on("data", (chunk) => body += chunk);
18206
18289
  req.on("end", () => {
18207
18290
  try {
18208
- resolve10(JSON.parse(body));
18291
+ resolve9(JSON.parse(body));
18209
18292
  } catch {
18210
- resolve10({});
18293
+ resolve9({});
18211
18294
  }
18212
18295
  });
18213
18296
  });
@@ -18676,7 +18759,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
18676
18759
  const deadline = Date.now() + timeoutMs;
18677
18760
  while (Date.now() < deadline) {
18678
18761
  if (await canConnect(endpoint)) return;
18679
- await new Promise((resolve10) => setTimeout(resolve10, STARTUP_POLL_MS));
18762
+ await new Promise((resolve9) => setTimeout(resolve9, STARTUP_POLL_MS));
18680
18763
  }
18681
18764
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
18682
18765
  }
@@ -18832,10 +18915,10 @@ async function installExtension(ide, extension) {
18832
18915
  const buffer = Buffer.from(await res.arrayBuffer());
18833
18916
  const fs15 = await import("fs");
18834
18917
  fs15.writeFileSync(vsixPath, buffer);
18835
- return new Promise((resolve10) => {
18918
+ return new Promise((resolve9) => {
18836
18919
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
18837
18920
  exec2(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
18838
- resolve10({
18921
+ resolve9({
18839
18922
  extensionId: extension.id,
18840
18923
  marketplaceId: extension.marketplaceId,
18841
18924
  success: !error,
@@ -18848,11 +18931,11 @@ async function installExtension(ide, extension) {
18848
18931
  } catch (e) {
18849
18932
  }
18850
18933
  }
18851
- return new Promise((resolve10) => {
18934
+ return new Promise((resolve9) => {
18852
18935
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
18853
18936
  exec2(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
18854
18937
  if (error) {
18855
- resolve10({
18938
+ resolve9({
18856
18939
  extensionId: extension.id,
18857
18940
  marketplaceId: extension.marketplaceId,
18858
18941
  success: false,
@@ -18860,7 +18943,7 @@ async function installExtension(ide, extension) {
18860
18943
  error: stderr || error.message
18861
18944
  });
18862
18945
  } else {
18863
- resolve10({
18946
+ resolve9({
18864
18947
  extensionId: extension.id,
18865
18948
  marketplaceId: extension.marketplaceId,
18866
18949
  success: true,