@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.js CHANGED
@@ -637,6 +637,13 @@ function logTerminalBackendSelection(preference, ghosttyAvailable, backendKind)
637
637
  const key = `${preference}:${ghosttyAvailable}:${backendKind}`;
638
638
  if (loggedTerminalBackends.has(key)) return;
639
639
  loggedTerminalBackends.add(key);
640
+ if (backendKind === "xterm" && preference !== "xterm" && !ghosttyAvailable) {
641
+ LOG.warn(
642
+ "Terminal",
643
+ `[terminal-screen] ghostty-vt unavailable; using xterm fallback (preference=${preference})`
644
+ );
645
+ return;
646
+ }
640
647
  LOG.info(
641
648
  "Terminal",
642
649
  `[terminal-screen] backend=${backendKind} preference=${preference} ghosttyAvailable=${ghosttyAvailable}`
@@ -699,10 +706,11 @@ var init_terminal_screen = __esm({
699
706
  });
700
707
 
701
708
  // src/cli-adapters/pty-transport.ts
702
- var pty, NodePtyRuntimeTransport, NodePtyTransportFactory;
709
+ var os7, pty, NodePtyRuntimeTransport, NodePtyTransportFactory;
703
710
  var init_pty_transport = __esm({
704
711
  "src/cli-adapters/pty-transport.ts"() {
705
712
  "use strict";
713
+ os7 = __toESM(require("os"));
706
714
  try {
707
715
  pty = require("node-pty");
708
716
  } catch {
@@ -739,11 +747,21 @@ var init_pty_transport = __esm({
739
747
  NodePtyTransportFactory = class {
740
748
  spawn(command, args, options) {
741
749
  if (!pty) throw new Error("node-pty is not installed");
750
+ let cwd = options.cwd;
751
+ if (cwd) {
752
+ try {
753
+ const fs15 = require("fs");
754
+ const stat = fs15.statSync(cwd);
755
+ if (!stat.isDirectory()) cwd = os7.homedir();
756
+ } catch {
757
+ cwd = os7.homedir();
758
+ }
759
+ }
742
760
  const handle = pty.spawn(command, args, {
743
761
  name: "xterm-256color",
744
762
  cols: options.cols,
745
763
  rows: options.rows,
746
- cwd: options.cwd,
764
+ cwd,
747
765
  env: options.env
748
766
  });
749
767
  return new NodePtyRuntimeTransport(handle);
@@ -752,6 +770,15 @@ var init_pty_transport = __esm({
752
770
  }
753
771
  });
754
772
 
773
+ // src/cli-adapters/spawn-env.ts
774
+ var import_session_host_core;
775
+ var init_spawn_env = __esm({
776
+ "src/cli-adapters/spawn-env.ts"() {
777
+ "use strict";
778
+ import_session_host_core = require("@adhdev/session-host-core");
779
+ }
780
+ });
781
+
755
782
  // src/cli-adapters/provider-cli-adapter.ts
756
783
  var provider_cli_adapter_exports = {};
757
784
  __export(provider_cli_adapter_exports, {
@@ -767,32 +794,6 @@ function stripTerminalNoise(str) {
767
794
  function sanitizeTerminalText(str) {
768
795
  return stripTerminalNoise(stripAnsi(str));
769
796
  }
770
- function applyPreferredTerminalColorEnv(env) {
771
- if (env.NO_COLOR) return;
772
- if (!env.TERM || env.TERM === "xterm-color") {
773
- env.TERM = "xterm-256color";
774
- }
775
- if (!env.COLORTERM) env.COLORTERM = "truecolor";
776
- if (process.platform === "win32") {
777
- if (!env.FORCE_COLOR) env.FORCE_COLOR = "1";
778
- if (!env.CLICOLOR) env.CLICOLOR = "1";
779
- }
780
- }
781
- function buildCliSpawnEnv(baseEnv, overrides) {
782
- const env = {};
783
- const source = { ...baseEnv, ...overrides || {} };
784
- for (const [key, value] of Object.entries(source)) {
785
- if (typeof value !== "string") continue;
786
- env[key] = value;
787
- }
788
- for (const key of Object.keys(env)) {
789
- 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_")) {
790
- delete env[key];
791
- }
792
- }
793
- applyPreferredTerminalColorEnv(env);
794
- return env;
795
- }
796
797
  function computeTerminalQueryTail(buffer) {
797
798
  const prefixes = ["\x1B[6n", "\x1B[?6n"];
798
799
  const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;
@@ -806,7 +807,7 @@ function computeTerminalQueryTail(buffer) {
806
807
  return "";
807
808
  }
808
809
  function findBinary(name) {
809
- const isWin = os7.platform() === "win32";
810
+ const isWin = os8.platform() === "win32";
810
811
  try {
811
812
  const cmd = isWin ? `where ${name}` : `which ${name}`;
812
813
  return (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
@@ -854,7 +855,7 @@ function looksLikeMachOOrElf(filePath) {
854
855
  }
855
856
  function shSingleQuote(arg) {
856
857
  if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
857
- if (os7.platform() === "win32") {
858
+ if (os8.platform() === "win32") {
858
859
  return `"${arg.replace(/"/g, '""')}"`;
859
860
  }
860
861
  return `'${arg.replace(/'/g, `'\\''`)}'`;
@@ -921,37 +922,24 @@ function normalizeCliProviderForRuntime(raw) {
921
922
  }
922
923
  };
923
924
  }
924
- var os7, path7, import_child_process4, pty2, ProviderCliAdapter;
925
+ var os8, path7, import_child_process4, pty2, buildCliSpawnEnv, ProviderCliAdapter;
925
926
  var init_provider_cli_adapter = __esm({
926
927
  "src/cli-adapters/provider-cli-adapter.ts"() {
927
928
  "use strict";
928
- os7 = __toESM(require("os"));
929
+ os8 = __toESM(require("os"));
929
930
  path7 = __toESM(require("path"));
930
931
  import_child_process4 = require("child_process");
931
932
  init_logger();
932
933
  init_terminal_screen();
933
934
  init_pty_transport();
935
+ init_spawn_env();
934
936
  try {
935
937
  pty2 = require("node-pty");
936
- if (os7.platform() !== "win32") {
937
- try {
938
- const fs15 = require("fs");
939
- const ptyDir = path7.resolve(path7.dirname(require.resolve("node-pty")), "..");
940
- const platformArch = `${os7.platform()}-${os7.arch()}`;
941
- const helper = path7.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
942
- if (fs15.existsSync(helper)) {
943
- const stat = fs15.statSync(helper);
944
- if (!(stat.mode & 73)) {
945
- fs15.chmodSync(helper, stat.mode | 493);
946
- LOG.info("CLI", "[node-pty] Fixed spawn-helper permissions");
947
- }
948
- }
949
- } catch {
950
- }
951
- }
938
+ (0, import_session_host_core.ensureNodePtySpawnHelperPermissions)((msg) => LOG.info("CLI", msg));
952
939
  } catch {
953
940
  LOG.error("CLI", "[ProviderCliAdapter] node-pty not found. Terminal features disabled.");
954
941
  }
942
+ buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
955
943
  ProviderCliAdapter = class _ProviderCliAdapter {
956
944
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
957
945
  this.extraArgs = extraArgs;
@@ -959,7 +947,7 @@ var init_provider_cli_adapter = __esm({
959
947
  this.transportFactory = transportFactory;
960
948
  this.cliType = provider.type;
961
949
  this.cliName = provider.name;
962
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os7.homedir()) : workingDir;
950
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
963
951
  const t = provider.timeouts || {};
964
952
  this.timeouts = {
965
953
  ptyFlush: t.ptyFlush ?? 50,
@@ -1266,7 +1254,7 @@ var init_provider_cli_adapter = __esm({
1266
1254
  if (this.ptyProcess) return;
1267
1255
  const { spawn: spawnConfig } = this.provider;
1268
1256
  const binaryPath = findBinary(spawnConfig.command);
1269
- const isWin = os7.platform() === "win32";
1257
+ const isWin = os8.platform() === "win32";
1270
1258
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
1271
1259
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1272
1260
  this.resetTraceSession();
@@ -1318,6 +1306,12 @@ var init_provider_cli_adapter = __esm({
1318
1306
  shellArgs = ["-l", "-c", fullCmd];
1319
1307
  this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
1320
1308
  } else {
1309
+ if (isWin) {
1310
+ 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})` : "";
1311
+ if (hint) {
1312
+ throw new Error(`Failed to spawn CLI${hint}: ${msg}`);
1313
+ }
1314
+ }
1321
1315
  throw err;
1322
1316
  }
1323
1317
  }
@@ -1492,7 +1486,7 @@ var init_provider_cli_adapter = __esm({
1492
1486
  `[${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)}`
1493
1487
  );
1494
1488
  }
1495
- await new Promise((resolve10) => setTimeout(resolve10, 50));
1489
+ await new Promise((resolve9) => setTimeout(resolve9, 50));
1496
1490
  }
1497
1491
  const finalScreenText = this.terminalScreen.getText() || "";
1498
1492
  LOG.warn(
@@ -1879,7 +1873,7 @@ ${data.message || ""}`.trim();
1879
1873
  if (this.startupParseGate) {
1880
1874
  const deadline = Date.now() + 1e4;
1881
1875
  while (this.startupParseGate && Date.now() < deadline) {
1882
- await new Promise((resolve10) => setTimeout(resolve10, 50));
1876
+ await new Promise((resolve9) => setTimeout(resolve9, 50));
1883
1877
  }
1884
1878
  }
1885
1879
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
@@ -2070,7 +2064,8 @@ ${data.message || ""}`.trim();
2070
2064
  const payload = stopCommand.endsWith("\r") || stopCommand.endsWith("\n") ? stopCommand : `${stopCommand}${this.sendKey}`;
2071
2065
  this.ptyProcess.write(payload);
2072
2066
  };
2073
- if (wasProcessing) setTimeout(writeCommand, 250);
2067
+ const interruptGraceMs = typeof resume.interruptGraceMs === "number" ? Math.max(100, resume.interruptGraceMs) : 500;
2068
+ if (wasProcessing) setTimeout(writeCommand, interruptGraceMs);
2074
2069
  else writeCommand();
2075
2070
  } else {
2076
2071
  this.ptyProcess.write("");
@@ -2086,17 +2081,17 @@ ${data.message || ""}`.trim();
2086
2081
  }
2087
2082
  }
2088
2083
  waitForStopped(timeoutMs) {
2089
- return new Promise((resolve10) => {
2084
+ return new Promise((resolve9) => {
2090
2085
  const startedAt = Date.now();
2091
2086
  const timer = setInterval(() => {
2092
2087
  if (!this.ptyProcess || this.currentStatus === "stopped") {
2093
2088
  clearInterval(timer);
2094
- resolve10(true);
2089
+ resolve9(true);
2095
2090
  return;
2096
2091
  }
2097
2092
  if (Date.now() - startedAt >= timeoutMs) {
2098
2093
  clearInterval(timer);
2099
- resolve10(false);
2094
+ resolve9(false);
2100
2095
  }
2101
2096
  }, 100);
2102
2097
  });
@@ -2115,6 +2110,18 @@ ${data.message || ""}`.trim();
2115
2110
  clearTimeout(this.submitRetryTimer);
2116
2111
  this.submitRetryTimer = null;
2117
2112
  }
2113
+ if (this.responseTimeout) {
2114
+ clearTimeout(this.responseTimeout);
2115
+ this.responseTimeout = null;
2116
+ }
2117
+ if (this.idleTimeout) {
2118
+ clearTimeout(this.idleTimeout);
2119
+ this.idleTimeout = null;
2120
+ }
2121
+ if (this.pendingScriptStatusTimer) {
2122
+ clearTimeout(this.pendingScriptStatusTimer);
2123
+ this.pendingScriptStatusTimer = null;
2124
+ }
2118
2125
  if (this.pendingOutputParseTimer) {
2119
2126
  clearTimeout(this.pendingOutputParseTimer);
2120
2127
  this.pendingOutputParseTimer = null;
@@ -2156,6 +2163,18 @@ ${data.message || ""}`.trim();
2156
2163
  clearTimeout(this.submitRetryTimer);
2157
2164
  this.submitRetryTimer = null;
2158
2165
  }
2166
+ if (this.responseTimeout) {
2167
+ clearTimeout(this.responseTimeout);
2168
+ this.responseTimeout = null;
2169
+ }
2170
+ if (this.idleTimeout) {
2171
+ clearTimeout(this.idleTimeout);
2172
+ this.idleTimeout = null;
2173
+ }
2174
+ if (this.pendingScriptStatusTimer) {
2175
+ clearTimeout(this.pendingScriptStatusTimer);
2176
+ this.pendingScriptStatusTimer = null;
2177
+ }
2159
2178
  if (this.pendingOutputParseTimer) {
2160
2179
  clearTimeout(this.pendingOutputParseTimer);
2161
2180
  this.pendingOutputParseTimer = null;
@@ -2749,20 +2768,20 @@ function checkPathExists(paths) {
2749
2768
  return null;
2750
2769
  }
2751
2770
  async function detectIDEs() {
2752
- const os17 = (0, import_os2.platform)();
2771
+ const os18 = (0, import_os2.platform)();
2753
2772
  const results = [];
2754
2773
  for (const def of getMergedDefinitions()) {
2755
2774
  const cliPath = findCliCommand(def.cli);
2756
- const appPath = checkPathExists(def.paths[os17] || []);
2775
+ const appPath = checkPathExists(def.paths[os18] || []);
2757
2776
  const installed = !!(cliPath || appPath);
2758
2777
  let resolvedCli = cliPath;
2759
- if (!resolvedCli && appPath && os17 === "darwin") {
2778
+ if (!resolvedCli && appPath && os18 === "darwin") {
2760
2779
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
2761
2780
  if ((0, import_fs2.existsSync)(bundledCli)) resolvedCli = bundledCli;
2762
2781
  }
2763
- if (!resolvedCli && appPath && os17 === "win32") {
2764
- const { dirname: dirname7 } = await import("path");
2765
- const appDir = dirname7(appPath);
2782
+ if (!resolvedCli && appPath && os18 === "win32") {
2783
+ const { dirname: dirname6 } = await import("path");
2784
+ const appDir = dirname6(appPath);
2766
2785
  const candidates = [
2767
2786
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
2768
2787
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -2800,15 +2819,15 @@ function parseVersion(raw) {
2800
2819
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
2801
2820
  }
2802
2821
  function execAsync(cmd, timeoutMs = 5e3) {
2803
- return new Promise((resolve10) => {
2822
+ return new Promise((resolve9) => {
2804
2823
  const child = (0, import_child_process2.exec)(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
2805
2824
  if (err || !stdout?.trim()) {
2806
- resolve10(null);
2825
+ resolve9(null);
2807
2826
  } else {
2808
- resolve10(stdout.trim());
2827
+ resolve9(stdout.trim());
2809
2828
  }
2810
2829
  });
2811
- child.on("error", () => resolve10(null));
2830
+ child.on("error", () => resolve9(null));
2812
2831
  });
2813
2832
  }
2814
2833
  async function detectCLIs(providerLoader) {
@@ -2848,6 +2867,39 @@ async function detectCLIs(providerLoader) {
2848
2867
  }
2849
2868
  async function detectCLI(cliId, providerLoader) {
2850
2869
  const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
2870
+ if (providerLoader) {
2871
+ const cliList = providerLoader.getCliDetectionList();
2872
+ const target = cliList.find((c) => c.id === resolvedId);
2873
+ if (target) {
2874
+ const platform9 = os2.platform();
2875
+ const whichCmd = platform9 === "win32" ? "where" : "which";
2876
+ try {
2877
+ const pathResult = await execAsync(`${whichCmd} ${target.command}`);
2878
+ if (!pathResult) return null;
2879
+ const firstPath = pathResult.split("\n")[0];
2880
+ let version;
2881
+ try {
2882
+ const versionCommands = [
2883
+ target.versionCommand,
2884
+ `${target.command} --version`,
2885
+ `${target.command} -V`,
2886
+ `${target.command} -v`
2887
+ ].filter((v) => !!v);
2888
+ for (const versionCommand of versionCommands) {
2889
+ const versionResult = await execAsync(versionCommand, 3e3);
2890
+ if (versionResult) {
2891
+ version = parseVersion(versionResult);
2892
+ break;
2893
+ }
2894
+ }
2895
+ } catch {
2896
+ }
2897
+ return { ...target, installed: true, version, path: firstPath };
2898
+ } catch {
2899
+ return null;
2900
+ }
2901
+ }
2902
+ }
2851
2903
  const all = await detectCLIs(providerLoader);
2852
2904
  return all.find((c) => c.id === resolvedId && c.installed) || null;
2853
2905
  }
@@ -2975,7 +3027,7 @@ var DaemonCdpManager = class {
2975
3027
  * Returns multiple entries if multiple IDE windows are open on same port
2976
3028
  */
2977
3029
  static listAllTargets(port) {
2978
- return new Promise((resolve10) => {
3030
+ return new Promise((resolve9) => {
2979
3031
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
2980
3032
  let data = "";
2981
3033
  res.on("data", (chunk) => data += chunk.toString());
@@ -2991,16 +3043,16 @@ var DaemonCdpManager = class {
2991
3043
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
2992
3044
  );
2993
3045
  const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
2994
- resolve10(mainPages.length > 0 ? mainPages : fallbackPages);
3046
+ resolve9(mainPages.length > 0 ? mainPages : fallbackPages);
2995
3047
  } catch {
2996
- resolve10([]);
3048
+ resolve9([]);
2997
3049
  }
2998
3050
  });
2999
3051
  });
3000
- req.on("error", () => resolve10([]));
3052
+ req.on("error", () => resolve9([]));
3001
3053
  req.setTimeout(2e3, () => {
3002
3054
  req.destroy();
3003
- resolve10([]);
3055
+ resolve9([]);
3004
3056
  });
3005
3057
  });
3006
3058
  }
@@ -3040,7 +3092,7 @@ var DaemonCdpManager = class {
3040
3092
  }
3041
3093
  }
3042
3094
  findTargetOnPort(port) {
3043
- return new Promise((resolve10) => {
3095
+ return new Promise((resolve9) => {
3044
3096
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
3045
3097
  let data = "";
3046
3098
  res.on("data", (chunk) => data += chunk.toString());
@@ -3051,7 +3103,7 @@ var DaemonCdpManager = class {
3051
3103
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
3052
3104
  );
3053
3105
  if (pages.length === 0) {
3054
- resolve10(targets.find((t) => t.webSocketDebuggerUrl) || null);
3106
+ resolve9(targets.find((t) => t.webSocketDebuggerUrl) || null);
3055
3107
  return;
3056
3108
  }
3057
3109
  const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
@@ -3061,24 +3113,24 @@ var DaemonCdpManager = class {
3061
3113
  const specific = list.find((t) => t.id === this._targetId);
3062
3114
  if (specific) {
3063
3115
  this._pageTitle = specific.title || "";
3064
- resolve10(specific);
3116
+ resolve9(specific);
3065
3117
  } else {
3066
3118
  this.log(`[CDP] Target ${this._targetId} not found in page list`);
3067
- resolve10(null);
3119
+ resolve9(null);
3068
3120
  }
3069
3121
  return;
3070
3122
  }
3071
3123
  this._pageTitle = list[0]?.title || "";
3072
- resolve10(list[0]);
3124
+ resolve9(list[0]);
3073
3125
  } catch {
3074
- resolve10(null);
3126
+ resolve9(null);
3075
3127
  }
3076
3128
  });
3077
3129
  });
3078
- req.on("error", () => resolve10(null));
3130
+ req.on("error", () => resolve9(null));
3079
3131
  req.setTimeout(2e3, () => {
3080
3132
  req.destroy();
3081
- resolve10(null);
3133
+ resolve9(null);
3082
3134
  });
3083
3135
  });
3084
3136
  }
@@ -3089,7 +3141,7 @@ var DaemonCdpManager = class {
3089
3141
  this.extensionProviders = providers;
3090
3142
  }
3091
3143
  connectToTarget(wsUrl) {
3092
- return new Promise((resolve10) => {
3144
+ return new Promise((resolve9) => {
3093
3145
  this.ws = new import_ws.default(wsUrl);
3094
3146
  this.ws.on("open", async () => {
3095
3147
  this._connected = true;
@@ -3099,17 +3151,17 @@ var DaemonCdpManager = class {
3099
3151
  }
3100
3152
  this.connectBrowserWs().catch(() => {
3101
3153
  });
3102
- resolve10(true);
3154
+ resolve9(true);
3103
3155
  });
3104
3156
  this.ws.on("message", (data) => {
3105
3157
  try {
3106
3158
  const msg = JSON.parse(data.toString());
3107
3159
  if (msg.id && this.pending.has(msg.id)) {
3108
- const { resolve: resolve11, reject } = this.pending.get(msg.id);
3160
+ const { resolve: resolve10, reject } = this.pending.get(msg.id);
3109
3161
  this.pending.delete(msg.id);
3110
3162
  this.failureCount = 0;
3111
3163
  if (msg.error) reject(new Error(msg.error.message));
3112
- else resolve11(msg.result);
3164
+ else resolve10(msg.result);
3113
3165
  } else if (msg.method === "Runtime.executionContextCreated") {
3114
3166
  this.contexts.add(msg.params.context.id);
3115
3167
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -3132,7 +3184,7 @@ var DaemonCdpManager = class {
3132
3184
  this.ws.on("error", (err) => {
3133
3185
  this.log(`[CDP] WebSocket error: ${err.message}`);
3134
3186
  this._connected = false;
3135
- resolve10(false);
3187
+ resolve9(false);
3136
3188
  });
3137
3189
  });
3138
3190
  }
@@ -3146,7 +3198,7 @@ var DaemonCdpManager = class {
3146
3198
  return;
3147
3199
  }
3148
3200
  this.log(`[CDP] Connecting browser WS for target discovery...`);
3149
- await new Promise((resolve10, reject) => {
3201
+ await new Promise((resolve9, reject) => {
3150
3202
  this.browserWs = new import_ws.default(browserWsUrl);
3151
3203
  this.browserWs.on("open", async () => {
3152
3204
  this._browserConnected = true;
@@ -3156,16 +3208,16 @@ var DaemonCdpManager = class {
3156
3208
  } catch (e) {
3157
3209
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
3158
3210
  }
3159
- resolve10();
3211
+ resolve9();
3160
3212
  });
3161
3213
  this.browserWs.on("message", (data) => {
3162
3214
  try {
3163
3215
  const msg = JSON.parse(data.toString());
3164
3216
  if (msg.id && this.browserPending.has(msg.id)) {
3165
- const { resolve: resolve11, reject: reject2 } = this.browserPending.get(msg.id);
3217
+ const { resolve: resolve10, reject: reject2 } = this.browserPending.get(msg.id);
3166
3218
  this.browserPending.delete(msg.id);
3167
3219
  if (msg.error) reject2(new Error(msg.error.message));
3168
- else resolve11(msg.result);
3220
+ else resolve10(msg.result);
3169
3221
  }
3170
3222
  } catch {
3171
3223
  }
@@ -3185,31 +3237,31 @@ var DaemonCdpManager = class {
3185
3237
  }
3186
3238
  }
3187
3239
  getBrowserWsUrl() {
3188
- return new Promise((resolve10) => {
3240
+ return new Promise((resolve9) => {
3189
3241
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
3190
3242
  let data = "";
3191
3243
  res.on("data", (chunk) => data += chunk.toString());
3192
3244
  res.on("end", () => {
3193
3245
  try {
3194
3246
  const info = JSON.parse(data);
3195
- resolve10(info.webSocketDebuggerUrl || null);
3247
+ resolve9(info.webSocketDebuggerUrl || null);
3196
3248
  } catch {
3197
- resolve10(null);
3249
+ resolve9(null);
3198
3250
  }
3199
3251
  });
3200
3252
  });
3201
- req.on("error", () => resolve10(null));
3253
+ req.on("error", () => resolve9(null));
3202
3254
  req.setTimeout(3e3, () => {
3203
3255
  req.destroy();
3204
- resolve10(null);
3256
+ resolve9(null);
3205
3257
  });
3206
3258
  });
3207
3259
  }
3208
3260
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
3209
- return new Promise((resolve10, reject) => {
3261
+ return new Promise((resolve9, reject) => {
3210
3262
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
3211
3263
  const id = this.browserMsgId++;
3212
- this.browserPending.set(id, { resolve: resolve10, reject });
3264
+ this.browserPending.set(id, { resolve: resolve9, reject });
3213
3265
  this.browserWs.send(JSON.stringify({ id, method, params }));
3214
3266
  setTimeout(() => {
3215
3267
  if (this.browserPending.has(id)) {
@@ -3249,11 +3301,11 @@ var DaemonCdpManager = class {
3249
3301
  }
3250
3302
  // ─── CDP Protocol ────────────────────────────────────────
3251
3303
  sendInternal(method, params = {}, timeoutMs = 15e3) {
3252
- return new Promise((resolve10, reject) => {
3304
+ return new Promise((resolve9, reject) => {
3253
3305
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
3254
3306
  if (this.ws.readyState !== import_ws.default.OPEN) return reject(new Error("WebSocket not open"));
3255
3307
  const id = this.msgId++;
3256
- this.pending.set(id, { resolve: resolve10, reject });
3308
+ this.pending.set(id, { resolve: resolve9, reject });
3257
3309
  this.ws.send(JSON.stringify({ id, method, params }));
3258
3310
  setTimeout(() => {
3259
3311
  if (this.pending.has(id)) {
@@ -3502,7 +3554,7 @@ var DaemonCdpManager = class {
3502
3554
  const browserWs = this.browserWs;
3503
3555
  let msgId = this.browserMsgId;
3504
3556
  const sendWs = (method, params = {}, sessionId) => {
3505
- return new Promise((resolve10, reject) => {
3557
+ return new Promise((resolve9, reject) => {
3506
3558
  const mid = msgId++;
3507
3559
  this.browserMsgId = msgId;
3508
3560
  const handler = (raw) => {
@@ -3511,7 +3563,7 @@ var DaemonCdpManager = class {
3511
3563
  if (msg.id === mid) {
3512
3564
  browserWs.removeListener("message", handler);
3513
3565
  if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
3514
- else resolve10(msg.result);
3566
+ else resolve9(msg.result);
3515
3567
  }
3516
3568
  } catch {
3517
3569
  }
@@ -3702,14 +3754,14 @@ var DaemonCdpManager = class {
3702
3754
  if (!ws || ws.readyState !== import_ws.default.OPEN) {
3703
3755
  throw new Error("CDP not connected");
3704
3756
  }
3705
- return new Promise((resolve10, reject) => {
3757
+ return new Promise((resolve9, reject) => {
3706
3758
  const id = getNextId();
3707
3759
  pendingMap.set(id, {
3708
3760
  resolve: (result) => {
3709
3761
  if (result?.result?.subtype === "error") {
3710
3762
  reject(new Error(result.result.description));
3711
3763
  } else {
3712
- resolve10(result?.result?.value);
3764
+ resolve9(result?.result?.value);
3713
3765
  }
3714
3766
  },
3715
3767
  reject
@@ -3741,10 +3793,10 @@ var DaemonCdpManager = class {
3741
3793
  throw new Error("CDP not connected");
3742
3794
  }
3743
3795
  const sendViaSession = (method, params = {}) => {
3744
- return new Promise((resolve10, reject) => {
3796
+ return new Promise((resolve9, reject) => {
3745
3797
  const pendingMap = this._browserConnected ? this.browserPending : this.pending;
3746
3798
  const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
3747
- pendingMap.set(id, { resolve: resolve10, reject });
3799
+ pendingMap.set(id, { resolve: resolve9, reject });
3748
3800
  ws.send(JSON.stringify({ id, sessionId, method, params }));
3749
3801
  setTimeout(() => {
3750
3802
  if (pendingMap.has(id)) {
@@ -7745,7 +7797,7 @@ var DaemonCommandHandler = class {
7745
7797
  try {
7746
7798
  const http3 = await import("http");
7747
7799
  const postData = JSON.stringify(body);
7748
- const result = await new Promise((resolve10, reject) => {
7800
+ const result = await new Promise((resolve9, reject) => {
7749
7801
  const req = http3.request({
7750
7802
  hostname: "127.0.0.1",
7751
7803
  port: 19280,
@@ -7757,9 +7809,9 @@ var DaemonCommandHandler = class {
7757
7809
  res.on("data", (chunk) => data += chunk);
7758
7810
  res.on("end", () => {
7759
7811
  try {
7760
- resolve10(JSON.parse(data));
7812
+ resolve9(JSON.parse(data));
7761
7813
  } catch {
7762
- resolve10({ raw: data });
7814
+ resolve9({ raw: data });
7763
7815
  }
7764
7816
  });
7765
7817
  });
@@ -7777,15 +7829,15 @@ var DaemonCommandHandler = class {
7777
7829
  if (!providerType) return { success: false, error: "providerType required" };
7778
7830
  try {
7779
7831
  const http3 = await import("http");
7780
- const result = await new Promise((resolve10, reject) => {
7832
+ const result = await new Promise((resolve9, reject) => {
7781
7833
  http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
7782
7834
  let data = "";
7783
7835
  res.on("data", (chunk) => data += chunk);
7784
7836
  res.on("end", () => {
7785
7837
  try {
7786
- resolve10(JSON.parse(data));
7838
+ resolve9(JSON.parse(data));
7787
7839
  } catch {
7788
- resolve10({ raw: data });
7840
+ resolve9({ raw: data });
7789
7841
  }
7790
7842
  });
7791
7843
  }).on("error", reject);
@@ -7799,7 +7851,7 @@ var DaemonCommandHandler = class {
7799
7851
  try {
7800
7852
  const http3 = await import("http");
7801
7853
  const postData = JSON.stringify(args || {});
7802
- const result = await new Promise((resolve10, reject) => {
7854
+ const result = await new Promise((resolve9, reject) => {
7803
7855
  const req = http3.request({
7804
7856
  hostname: "127.0.0.1",
7805
7857
  port: 19280,
@@ -7811,9 +7863,9 @@ var DaemonCommandHandler = class {
7811
7863
  res.on("data", (chunk) => data += chunk);
7812
7864
  res.on("end", () => {
7813
7865
  try {
7814
- resolve10(JSON.parse(data));
7866
+ resolve9(JSON.parse(data));
7815
7867
  } catch {
7816
- resolve10({ raw: data });
7868
+ resolve9({ raw: data });
7817
7869
  }
7818
7870
  });
7819
7871
  });
@@ -7829,7 +7881,7 @@ var DaemonCommandHandler = class {
7829
7881
  };
7830
7882
 
7831
7883
  // src/commands/cli-manager.ts
7832
- var os9 = __toESM(require("os"));
7884
+ var os10 = __toESM(require("os"));
7833
7885
  var path9 = __toESM(require("path"));
7834
7886
  var crypto4 = __toESM(require("crypto"));
7835
7887
  var import_chalk = __toESM(require("chalk"));
@@ -7837,7 +7889,7 @@ init_provider_cli_adapter();
7837
7889
  init_config();
7838
7890
 
7839
7891
  // src/providers/cli-provider-instance.ts
7840
- var os8 = __toESM(require("os"));
7892
+ var os9 = __toESM(require("os"));
7841
7893
  var path8 = __toESM(require("path"));
7842
7894
  var crypto3 = __toESM(require("crypto"));
7843
7895
  var fs5 = __toESM(require("fs"));
@@ -7926,17 +7978,60 @@ var CliProviderInstance = class {
7926
7978
  async onTick() {
7927
7979
  if (this.providerSessionId) return;
7928
7980
  let probedSessionId = null;
7929
- if (this.type === "opencode-cli") {
7930
- probedSessionId = this.probeOpenCodeSessionId();
7931
- } else if (this.type === "codex-cli") {
7932
- probedSessionId = this.probeCodexSessionId();
7933
- } else if (this.type === "goose-cli") {
7934
- probedSessionId = this.probeGooseSessionId();
7981
+ const probeConfig = this.provider.sessionProbe;
7982
+ if (probeConfig) {
7983
+ probedSessionId = this.probeSessionIdFromConfig(probeConfig);
7984
+ } else {
7985
+ if (this.type === "opencode-cli") {
7986
+ probedSessionId = this.probeSessionIdFromConfig({
7987
+ dbPath: "~/.local/share/opencode/opencode.db",
7988
+ query: "select id from session where directory in ({dirs}) and time_created >= ? and time_archived is null order by time_updated desc limit 1",
7989
+ timestampFormat: "unix_ms"
7990
+ });
7991
+ } else if (this.type === "codex-cli") {
7992
+ probedSessionId = this.probeSessionIdFromConfig({
7993
+ dbPath: "~/.codex/state_5.sqlite",
7994
+ query: "select id from threads where cwd in ({dirs}) and created_at >= ? and archived = 0 order by created_at desc limit 1",
7995
+ timestampFormat: "unix_s"
7996
+ });
7997
+ } else if (this.type === "goose-cli") {
7998
+ probedSessionId = this.probeSessionIdFromConfig({
7999
+ dbPath: "~/.local/share/goose/sessions/sessions.db",
8000
+ query: "select id from sessions where working_dir in ({dirs}) and created_at >= ? order by updated_at desc limit 1",
8001
+ timestampFormat: "iso"
8002
+ });
8003
+ }
7935
8004
  }
7936
8005
  if (probedSessionId) {
7937
8006
  this.promoteProviderSessionId(probedSessionId);
7938
8007
  }
7939
8008
  }
8009
+ /**
8010
+ * Generic session ID probe using declarative ProviderSessionProbe config.
8011
+ * Replaces the previously duplicated probeOpenCode/Codex/Goose functions.
8012
+ */
8013
+ probeSessionIdFromConfig(probe) {
8014
+ const resolvedDbPath = probe.dbPath.replace(/^~/, os9.homedir());
8015
+ if (!fs5.existsSync(resolvedDbPath)) return null;
8016
+ const directories = this.getProbeDirectories();
8017
+ const minCreatedAt = Math.max(0, this.startedAt - 6e4);
8018
+ const tsFormat = probe.timestampFormat || "unix_ms";
8019
+ let timestampParam;
8020
+ if (tsFormat === "unix_s") {
8021
+ timestampParam = Math.floor(minCreatedAt / 1e3);
8022
+ } else if (tsFormat === "iso") {
8023
+ timestampParam = new Date(minCreatedAt).toISOString().slice(0, 19).replace("T", " ");
8024
+ } else {
8025
+ timestampParam = minCreatedAt;
8026
+ }
8027
+ const placeholders = this.buildSqlPlaceholderList(directories.length);
8028
+ const query = probe.query.replace("{dirs}", placeholders);
8029
+ try {
8030
+ return this.querySqliteText(resolvedDbPath, query, [...directories, timestampParam]);
8031
+ } catch {
8032
+ return null;
8033
+ }
8034
+ }
7940
8035
  getState() {
7941
8036
  const adapterStatus = this.adapter.getStatus();
7942
8037
  const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
@@ -8234,34 +8329,6 @@ var CliProviderInstance = class {
8234
8329
  });
8235
8330
  LOG.info("CLI", `[${this.type}] discovered provider session id: ${nextSessionId}`);
8236
8331
  }
8237
- probeOpenCodeSessionId() {
8238
- const dbPath = path8.join(os8.homedir(), ".local", "share", "opencode", "opencode.db");
8239
- if (!fs5.existsSync(dbPath)) return null;
8240
- const minCreatedAt = Math.max(0, this.startedAt - 6e4);
8241
- const directories = this.getProbeDirectories();
8242
- 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;`;
8243
- return this.querySqliteText(dbPath, query, [...directories, minCreatedAt]);
8244
- }
8245
- probeCodexSessionId() {
8246
- const dbPath = path8.join(os8.homedir(), ".codex", "state_5.sqlite");
8247
- if (!fs5.existsSync(dbPath)) return null;
8248
- const minCreatedAt = Math.max(0, Math.floor((this.startedAt - 6e4) / 1e3));
8249
- const directories = this.getProbeDirectories();
8250
- 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;`;
8251
- return this.querySqliteText(dbPath, query, [...directories, minCreatedAt]);
8252
- }
8253
- probeGooseSessionId() {
8254
- const dbPath = path8.join(os8.homedir(), ".local", "share", "goose", "sessions", "sessions.db");
8255
- if (!fs5.existsSync(dbPath)) return null;
8256
- const minCreatedAtIso = new Date(Math.max(0, this.startedAt - 6e4)).toISOString().slice(0, 19).replace("T", " ");
8257
- const directories = this.getProbeDirectories();
8258
- const query = `select id from sessions where working_dir in (${this.buildSqlPlaceholderList(directories.length)}) and created_at >= ? order by updated_at desc limit 1;`;
8259
- try {
8260
- return this.querySqliteText(dbPath, query, [...directories, minCreatedAtIso]);
8261
- } catch {
8262
- return null;
8263
- }
8264
- }
8265
8332
  getProbeDirectories() {
8266
8333
  const dirs = /* @__PURE__ */ new Set();
8267
8334
  const addDir = (value) => {
@@ -8733,13 +8800,13 @@ var AcpProviderInstance = class {
8733
8800
  }
8734
8801
  this.currentStatus = "waiting_approval";
8735
8802
  this.detectStatusTransition();
8736
- const approved = await new Promise((resolve10) => {
8737
- this.permissionResolvers.push(resolve10);
8803
+ const approved = await new Promise((resolve9) => {
8804
+ this.permissionResolvers.push(resolve9);
8738
8805
  setTimeout(() => {
8739
- const idx = this.permissionResolvers.indexOf(resolve10);
8806
+ const idx = this.permissionResolvers.indexOf(resolve9);
8740
8807
  if (idx >= 0) {
8741
8808
  this.permissionResolvers.splice(idx, 1);
8742
- resolve10(false);
8809
+ resolve9(false);
8743
8810
  }
8744
8811
  }, 3e5);
8745
8812
  });
@@ -9446,7 +9513,7 @@ var DaemonCliManager = class {
9446
9513
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
9447
9514
  const trimmed = (workingDir || "").trim();
9448
9515
  if (!trimmed) throw new Error("working directory required");
9449
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os9.homedir()) : path9.resolve(trimmed);
9516
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path9.resolve(trimmed);
9450
9517
  const normalizedType = this.providerLoader.resolveAlias(cliType);
9451
9518
  const provider = this.providerLoader.getByAlias(cliType);
9452
9519
  const key = crypto4.randomUUID();
@@ -9530,7 +9597,19 @@ ${installInfo}`
9530
9597
  return { runtimeSessionId: sessionId };
9531
9598
  }
9532
9599
  const cliInfo = await detectCLI(cliType, this.providerLoader);
9533
- if (!cliInfo) throw new Error(`${cliType} not found`);
9600
+ if (!cliInfo) {
9601
+ const installHint = provider?.install || "";
9602
+ const displayName = provider?.displayName || provider?.name || cliType;
9603
+ const spawnCmd = provider?.spawn?.command || cliType;
9604
+ throw new Error(
9605
+ `${displayName} is not installed.
9606
+ Command '${spawnCmd}' not found on PATH.
9607
+ ` + (installHint ? `
9608
+ ${installHint}
9609
+ ` : "") + `
9610
+ Run 'adhdev doctor' for detailed diagnostics.`
9611
+ );
9612
+ }
9534
9613
  console.log(colorize("yellow", ` \u26A1 Starting CLI ${cliType} in ${resolvedDir}...`));
9535
9614
  if (provider) {
9536
9615
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
@@ -9846,8 +9925,9 @@ ${installInfo}`
9846
9925
  const dir = rdir.path;
9847
9926
  if (!cliType) throw new Error("cliType required");
9848
9927
  const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
9928
+ const prevCliArgs = found ? found.adapter.extraArgs : void 0;
9849
9929
  if (found) await this.stopSession(found.key);
9850
- await this.startSession(cliType, dir);
9930
+ await this.startSession(cliType, dir, args?.cliArgs || prevCliArgs, args?.initialModel);
9851
9931
  return { success: true, restarted: true };
9852
9932
  }
9853
9933
  case "agent_command": {
@@ -9882,13 +9962,13 @@ ${installInfo}`
9882
9962
  // src/launch.ts
9883
9963
  var import_child_process6 = require("child_process");
9884
9964
  var net = __toESM(require("net"));
9885
- var os11 = __toESM(require("os"));
9965
+ var os12 = __toESM(require("os"));
9886
9966
  var path11 = __toESM(require("path"));
9887
9967
 
9888
9968
  // src/providers/provider-loader.ts
9889
9969
  var fs6 = __toESM(require("fs"));
9890
9970
  var path10 = __toESM(require("path"));
9891
- var os10 = __toESM(require("os"));
9971
+ var os11 = __toESM(require("os"));
9892
9972
  var chokidar = __toESM(require("chokidar"));
9893
9973
  init_logger();
9894
9974
  var ProviderLoader = class _ProviderLoader {
@@ -9908,7 +9988,7 @@ var ProviderLoader = class _ProviderLoader {
9908
9988
  static META_FILE = ".meta.json";
9909
9989
  constructor(options) {
9910
9990
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
9911
- const defaultProvidersDir = path10.join(os10.homedir(), ".adhdev", "providers");
9991
+ const defaultProvidersDir = path10.join(os11.homedir(), ".adhdev", "providers");
9912
9992
  if (options?.userDir) {
9913
9993
  this.userDir = options.userDir;
9914
9994
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -10465,7 +10545,7 @@ var ProviderLoader = class _ProviderLoader {
10465
10545
  return { updated: false };
10466
10546
  }
10467
10547
  try {
10468
- const etag = await new Promise((resolve10, reject) => {
10548
+ const etag = await new Promise((resolve9, reject) => {
10469
10549
  const options = {
10470
10550
  method: "HEAD",
10471
10551
  hostname: "github.com",
@@ -10483,7 +10563,7 @@ var ProviderLoader = class _ProviderLoader {
10483
10563
  headers: { "User-Agent": "adhdev-launcher" },
10484
10564
  timeout: 1e4
10485
10565
  }, (res2) => {
10486
- resolve10(res2.headers.etag || res2.headers["last-modified"] || "");
10566
+ resolve9(res2.headers.etag || res2.headers["last-modified"] || "");
10487
10567
  });
10488
10568
  req2.on("error", reject);
10489
10569
  req2.on("timeout", () => {
@@ -10492,7 +10572,7 @@ var ProviderLoader = class _ProviderLoader {
10492
10572
  });
10493
10573
  req2.end();
10494
10574
  } else {
10495
- resolve10(res.headers.etag || res.headers["last-modified"] || "");
10575
+ resolve9(res.headers.etag || res.headers["last-modified"] || "");
10496
10576
  }
10497
10577
  });
10498
10578
  req.on("error", reject);
@@ -10508,8 +10588,8 @@ var ProviderLoader = class _ProviderLoader {
10508
10588
  return { updated: false };
10509
10589
  }
10510
10590
  this.log("Downloading latest providers from GitHub...");
10511
- const tmpTar = path10.join(os10.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
10512
- const tmpExtract = path10.join(os10.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
10591
+ const tmpTar = path10.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
10592
+ const tmpExtract = path10.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
10513
10593
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
10514
10594
  fs6.mkdirSync(tmpExtract, { recursive: true });
10515
10595
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
@@ -10556,7 +10636,7 @@ var ProviderLoader = class _ProviderLoader {
10556
10636
  downloadFile(url, destPath) {
10557
10637
  const https = require("https");
10558
10638
  const http3 = require("http");
10559
- return new Promise((resolve10, reject) => {
10639
+ return new Promise((resolve9, reject) => {
10560
10640
  const doRequest = (reqUrl, redirectCount = 0) => {
10561
10641
  if (redirectCount > 5) {
10562
10642
  reject(new Error("Too many redirects"));
@@ -10576,7 +10656,7 @@ var ProviderLoader = class _ProviderLoader {
10576
10656
  res.pipe(ws);
10577
10657
  ws.on("finish", () => {
10578
10658
  ws.close();
10579
- resolve10();
10659
+ resolve9();
10580
10660
  });
10581
10661
  ws.on("error", reject);
10582
10662
  });
@@ -10941,17 +11021,17 @@ async function findFreePort(ports) {
10941
11021
  throw new Error("No free port found");
10942
11022
  }
10943
11023
  function checkPortFree(port) {
10944
- return new Promise((resolve10) => {
11024
+ return new Promise((resolve9) => {
10945
11025
  const server = net.createServer();
10946
11026
  server.unref();
10947
- server.on("error", () => resolve10(false));
11027
+ server.on("error", () => resolve9(false));
10948
11028
  server.listen(port, "127.0.0.1", () => {
10949
- server.close(() => resolve10(true));
11029
+ server.close(() => resolve9(true));
10950
11030
  });
10951
11031
  });
10952
11032
  }
10953
11033
  async function isCdpActive(port) {
10954
- return new Promise((resolve10) => {
11034
+ return new Promise((resolve9) => {
10955
11035
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
10956
11036
  timeout: 2e3
10957
11037
  }, (res) => {
@@ -10960,21 +11040,21 @@ async function isCdpActive(port) {
10960
11040
  res.on("end", () => {
10961
11041
  try {
10962
11042
  const info = JSON.parse(data);
10963
- resolve10(!!info["WebKit-Version"] || !!info["Browser"]);
11043
+ resolve9(!!info["WebKit-Version"] || !!info["Browser"]);
10964
11044
  } catch {
10965
- resolve10(false);
11045
+ resolve9(false);
10966
11046
  }
10967
11047
  });
10968
11048
  });
10969
- req.on("error", () => resolve10(false));
11049
+ req.on("error", () => resolve9(false));
10970
11050
  req.on("timeout", () => {
10971
11051
  req.destroy();
10972
- resolve10(false);
11052
+ resolve9(false);
10973
11053
  });
10974
11054
  });
10975
11055
  }
10976
11056
  async function killIdeProcess(ideId) {
10977
- const plat = os11.platform();
11057
+ const plat = os12.platform();
10978
11058
  const appName = getMacAppIdentifiers()[ideId];
10979
11059
  const winProcesses = getWinProcessNames()[ideId];
10980
11060
  try {
@@ -11033,7 +11113,7 @@ async function killIdeProcess(ideId) {
11033
11113
  }
11034
11114
  }
11035
11115
  function isIdeRunning(ideId) {
11036
- const plat = os11.platform();
11116
+ const plat = os12.platform();
11037
11117
  try {
11038
11118
  if (plat === "darwin") {
11039
11119
  const appName = getMacAppIdentifiers()[ideId];
@@ -11069,7 +11149,7 @@ function isIdeRunning(ideId) {
11069
11149
  }
11070
11150
  }
11071
11151
  function detectCurrentWorkspace(ideId) {
11072
- const plat = os11.platform();
11152
+ const plat = os12.platform();
11073
11153
  if (plat === "darwin") {
11074
11154
  try {
11075
11155
  const appName = getMacAppIdentifiers()[ideId];
@@ -11089,7 +11169,7 @@ function detectCurrentWorkspace(ideId) {
11089
11169
  const appName = appNameMap[ideId];
11090
11170
  if (appName) {
11091
11171
  const storagePath = path11.join(
11092
- process.env.APPDATA || path11.join(os11.homedir(), "AppData", "Roaming"),
11172
+ process.env.APPDATA || path11.join(os12.homedir(), "AppData", "Roaming"),
11093
11173
  appName,
11094
11174
  "storage.json"
11095
11175
  );
@@ -11111,7 +11191,7 @@ function detectCurrentWorkspace(ideId) {
11111
11191
  return void 0;
11112
11192
  }
11113
11193
  async function launchWithCdp(options = {}) {
11114
- const platform9 = os11.platform();
11194
+ const platform9 = os12.platform();
11115
11195
  let targetIde;
11116
11196
  const ides = await detectIDEs();
11117
11197
  if (options.ideId) {
@@ -11263,8 +11343,8 @@ init_logger();
11263
11343
  // src/logging/command-log.ts
11264
11344
  var fs7 = __toESM(require("fs"));
11265
11345
  var path12 = __toESM(require("path"));
11266
- var os12 = __toESM(require("os"));
11267
- 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");
11346
+ var os13 = __toESM(require("os"));
11347
+ 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");
11268
11348
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
11269
11349
  var MAX_DAYS = 7;
11270
11350
  try {
@@ -11399,7 +11479,7 @@ cleanOldFiles();
11399
11479
  init_logger();
11400
11480
 
11401
11481
  // src/status/snapshot.ts
11402
- var os13 = __toESM(require("os"));
11482
+ var os14 = __toESM(require("os"));
11403
11483
  init_config();
11404
11484
  init_terminal_screen();
11405
11485
  init_logger();
@@ -11515,16 +11595,16 @@ function buildStatusSnapshot(options) {
11515
11595
  version: options.version,
11516
11596
  daemonMode: options.daemonMode,
11517
11597
  machine: {
11518
- hostname: os13.hostname(),
11519
- platform: os13.platform(),
11520
- arch: os13.arch(),
11521
- cpus: os13.cpus().length,
11598
+ hostname: os14.hostname(),
11599
+ platform: os14.platform(),
11600
+ arch: os14.arch(),
11601
+ cpus: os14.cpus().length,
11522
11602
  totalMem: memSnap.totalMem,
11523
11603
  freeMem: memSnap.freeMem,
11524
11604
  availableMem: memSnap.availableMem,
11525
- loadavg: os13.loadavg(),
11526
- uptime: os13.uptime(),
11527
- release: os13.release()
11605
+ loadavg: os14.loadavg(),
11606
+ uptime: os14.uptime(),
11607
+ release: os14.release()
11528
11608
  },
11529
11609
  machineNickname: options.machineNickname ?? cfg.machineNickname ?? null,
11530
11610
  timestamp: options.timestamp ?? Date.now(),
@@ -11544,11 +11624,11 @@ function buildStatusSnapshot(options) {
11544
11624
  var import_child_process7 = require("child_process");
11545
11625
  var import_child_process8 = require("child_process");
11546
11626
  var fs8 = __toESM(require("fs"));
11547
- var os14 = __toESM(require("os"));
11627
+ var os15 = __toESM(require("os"));
11548
11628
  var path13 = __toESM(require("path"));
11549
11629
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
11550
11630
  function getUpgradeLogPath() {
11551
- const home = os14.homedir();
11631
+ const home = os15.homedir();
11552
11632
  const dir = path13.join(home, ".adhdev");
11553
11633
  fs8.mkdirSync(dir, { recursive: true });
11554
11634
  return path13.join(dir, "daemon-upgrade.log");
@@ -11581,14 +11661,14 @@ async function waitForPidExit(pid, timeoutMs) {
11581
11661
  while (Date.now() - start < timeoutMs) {
11582
11662
  try {
11583
11663
  process.kill(pid, 0);
11584
- await new Promise((resolve10) => setTimeout(resolve10, 250));
11664
+ await new Promise((resolve9) => setTimeout(resolve9, 250));
11585
11665
  } catch {
11586
11666
  return;
11587
11667
  }
11588
11668
  }
11589
11669
  }
11590
11670
  function stopSessionHostProcesses(appName) {
11591
- const pidFile = path13.join(os14.homedir(), ".adhdev", `${appName}-session-host.pid`);
11671
+ const pidFile = path13.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
11592
11672
  try {
11593
11673
  if (fs8.existsSync(pidFile)) {
11594
11674
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -11617,7 +11697,7 @@ function stopSessionHostProcesses(appName) {
11617
11697
  }
11618
11698
  }
11619
11699
  function removeDaemonPidFile() {
11620
- const pidFile = path13.join(os14.homedir(), ".adhdev", "daemon.pid");
11700
+ const pidFile = path13.join(os15.homedir(), ".adhdev", "daemon.pid");
11621
11701
  try {
11622
11702
  fs8.unlinkSync(pidFile);
11623
11703
  } catch {
@@ -13127,10 +13207,10 @@ var ProviderInstanceManager = class {
13127
13207
  // src/providers/version-archive.ts
13128
13208
  var fs10 = __toESM(require("fs"));
13129
13209
  var path14 = __toESM(require("path"));
13130
- var os15 = __toESM(require("os"));
13210
+ var os16 = __toESM(require("os"));
13131
13211
  var import_child_process9 = require("child_process");
13132
13212
  var import_os3 = require("os");
13133
- var ARCHIVE_PATH = path14.join(os15.homedir(), ".adhdev", "version-history.json");
13213
+ var ARCHIVE_PATH = path14.join(os16.homedir(), ".adhdev", "version-history.json");
13134
13214
  var MAX_ENTRIES_PER_PROVIDER = 20;
13135
13215
  var VersionArchive = class {
13136
13216
  history = {};
@@ -13217,7 +13297,7 @@ function getVersion(binary, versionCommand) {
13217
13297
  function checkPathExists2(paths) {
13218
13298
  for (const p of paths) {
13219
13299
  if (p.includes("*")) {
13220
- const home = os15.homedir();
13300
+ const home = os16.homedir();
13221
13301
  const resolved = p.replace(/\*/g, home.split(path14.sep).pop() || "");
13222
13302
  if (fs10.existsSync(resolved)) return resolved;
13223
13303
  } else {
@@ -14814,7 +14894,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
14814
14894
  return { target, instance, adapter };
14815
14895
  }
14816
14896
  function sleep(ms) {
14817
- return new Promise((resolve10) => setTimeout(resolve10, ms));
14897
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
14818
14898
  }
14819
14899
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
14820
14900
  const startedAt = Date.now();
@@ -15545,7 +15625,7 @@ async function handleCliRaw(ctx, req, res) {
15545
15625
  // src/daemon/dev-auto-implement.ts
15546
15626
  var fs13 = __toESM(require("fs"));
15547
15627
  var path17 = __toESM(require("path"));
15548
- var os16 = __toESM(require("os"));
15628
+ var os17 = __toESM(require("os"));
15549
15629
  function getAutoImplPid(ctx) {
15550
15630
  const proc = ctx.autoImplProcess;
15551
15631
  return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
@@ -15748,7 +15828,7 @@ async function handleAutoImplement(ctx, type, req, res) {
15748
15828
  });
15749
15829
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
15750
15830
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
15751
- const tmpDir = path17.join(os16.tmpdir(), "adhdev-autoimpl");
15831
+ const tmpDir = path17.join(os17.tmpdir(), "adhdev-autoimpl");
15752
15832
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
15753
15833
  const promptFile = path17.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
15754
15834
  fs13.writeFileSync(promptFile, prompt, "utf-8");
@@ -15902,7 +15982,7 @@ async function handleAutoImplement(ctx, type, req, res) {
15902
15982
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
15903
15983
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
15904
15984
  let shellCmd;
15905
- const isWin = os16.platform() === "win32";
15985
+ const isWin = os17.platform() === "win32";
15906
15986
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
15907
15987
  if (command === "claude") {
15908
15988
  const args = [...baseArgs, "--dangerously-skip-permissions"];
@@ -15946,7 +16026,7 @@ async function handleAutoImplement(ctx, type, req, res) {
15946
16026
  try {
15947
16027
  const pty3 = require("node-pty");
15948
16028
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
15949
- const isWin2 = os16.platform() === "win32";
16029
+ const isWin2 = os17.platform() === "win32";
15950
16030
  child = pty3.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
15951
16031
  name: "xterm-256color",
15952
16032
  cols: 120,
@@ -16984,15 +17064,15 @@ var DevServer = class _DevServer {
16984
17064
  this.json(res, 500, { error: e.message });
16985
17065
  }
16986
17066
  });
16987
- return new Promise((resolve10, reject) => {
17067
+ return new Promise((resolve9, reject) => {
16988
17068
  this.server.listen(port, "127.0.0.1", () => {
16989
17069
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
16990
- resolve10();
17070
+ resolve9();
16991
17071
  });
16992
17072
  this.server.on("error", (e) => {
16993
17073
  if (e.code === "EADDRINUSE") {
16994
17074
  this.log(`Port ${port} in use, skipping dev server`);
16995
- resolve10();
17075
+ resolve9();
16996
17076
  } else {
16997
17077
  reject(e);
16998
17078
  }
@@ -17075,20 +17155,20 @@ var DevServer = class _DevServer {
17075
17155
  child.stderr?.on("data", (d) => {
17076
17156
  stderr += d.toString().slice(0, 2e3);
17077
17157
  });
17078
- await new Promise((resolve10) => {
17158
+ await new Promise((resolve9) => {
17079
17159
  const timer = setTimeout(() => {
17080
17160
  child.kill();
17081
- resolve10();
17161
+ resolve9();
17082
17162
  }, 3e3);
17083
17163
  child.on("exit", () => {
17084
17164
  clearTimeout(timer);
17085
- resolve10();
17165
+ resolve9();
17086
17166
  });
17087
17167
  child.stdout?.once("data", () => {
17088
17168
  setTimeout(() => {
17089
17169
  child.kill();
17090
17170
  clearTimeout(timer);
17091
- resolve10();
17171
+ resolve9();
17092
17172
  }, 500);
17093
17173
  });
17094
17174
  });
@@ -17597,14 +17677,14 @@ var DevServer = class _DevServer {
17597
17677
  child.stderr?.on("data", (d) => {
17598
17678
  stderr += d.toString();
17599
17679
  });
17600
- await new Promise((resolve10) => {
17680
+ await new Promise((resolve9) => {
17601
17681
  const timer = setTimeout(() => {
17602
17682
  child.kill();
17603
- resolve10();
17683
+ resolve9();
17604
17684
  }, timeout);
17605
17685
  child.on("exit", () => {
17606
17686
  clearTimeout(timer);
17607
- resolve10();
17687
+ resolve9();
17608
17688
  });
17609
17689
  });
17610
17690
  const elapsed = Date.now() - start;
@@ -18279,14 +18359,14 @@ data: ${JSON.stringify(msg.data)}
18279
18359
  res.end(JSON.stringify(data, null, 2));
18280
18360
  }
18281
18361
  async readBody(req) {
18282
- return new Promise((resolve10) => {
18362
+ return new Promise((resolve9) => {
18283
18363
  let body = "";
18284
18364
  req.on("data", (chunk) => body += chunk);
18285
18365
  req.on("end", () => {
18286
18366
  try {
18287
- resolve10(JSON.parse(body));
18367
+ resolve9(JSON.parse(body));
18288
18368
  } catch {
18289
- resolve10({});
18369
+ resolve9({});
18290
18370
  }
18291
18371
  });
18292
18372
  });
@@ -18359,12 +18439,12 @@ init_provider_cli_adapter();
18359
18439
  init_pty_transport();
18360
18440
 
18361
18441
  // src/cli-adapters/session-host-transport.ts
18362
- var import_session_host_core = require("@adhdev/session-host-core");
18442
+ var import_session_host_core2 = require("@adhdev/session-host-core");
18363
18443
  init_logger();
18364
18444
  var SessionHostRuntimeTransport = class {
18365
18445
  constructor(options) {
18366
18446
  this.options = options;
18367
- this.client = new import_session_host_core.SessionHostClient({
18447
+ this.client = new import_session_host_core2.SessionHostClient({
18368
18448
  endpoint: options.endpoint,
18369
18449
  appName: options.appName
18370
18450
  });
@@ -18733,11 +18813,11 @@ var SessionHostPtyTransportFactory = class {
18733
18813
  };
18734
18814
 
18735
18815
  // src/session-host/runtime-support.ts
18736
- var import_session_host_core2 = require("@adhdev/session-host-core");
18816
+ var import_session_host_core3 = require("@adhdev/session-host-core");
18737
18817
  var STARTUP_TIMEOUT_MS = 8e3;
18738
18818
  var STARTUP_POLL_MS = 200;
18739
18819
  async function canConnect(endpoint) {
18740
- const client = new import_session_host_core2.SessionHostClient({ endpoint });
18820
+ const client = new import_session_host_core3.SessionHostClient({ endpoint });
18741
18821
  try {
18742
18822
  await client.connect();
18743
18823
  await client.close();
@@ -18750,19 +18830,19 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
18750
18830
  const deadline = Date.now() + timeoutMs;
18751
18831
  while (Date.now() < deadline) {
18752
18832
  if (await canConnect(endpoint)) return;
18753
- await new Promise((resolve10) => setTimeout(resolve10, STARTUP_POLL_MS));
18833
+ await new Promise((resolve9) => setTimeout(resolve9, STARTUP_POLL_MS));
18754
18834
  }
18755
18835
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
18756
18836
  }
18757
18837
  async function ensureSessionHostReady(options) {
18758
- const endpoint = (0, import_session_host_core2.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
18838
+ const endpoint = (0, import_session_host_core3.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
18759
18839
  if (await canConnect(endpoint)) return endpoint;
18760
18840
  options.spawnHost();
18761
18841
  await waitForReady(endpoint, options.timeoutMs);
18762
18842
  return endpoint;
18763
18843
  }
18764
18844
  async function listHostedCliRuntimes(endpoint) {
18765
- const client = new import_session_host_core2.SessionHostClient({ endpoint });
18845
+ const client = new import_session_host_core3.SessionHostClient({ endpoint });
18766
18846
  try {
18767
18847
  const response = await client.request({
18768
18848
  type: "list_sessions",
@@ -18906,10 +18986,10 @@ async function installExtension(ide, extension) {
18906
18986
  const buffer = Buffer.from(await res.arrayBuffer());
18907
18987
  const fs15 = await import("fs");
18908
18988
  fs15.writeFileSync(vsixPath, buffer);
18909
- return new Promise((resolve10) => {
18989
+ return new Promise((resolve9) => {
18910
18990
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
18911
18991
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
18912
- resolve10({
18992
+ resolve9({
18913
18993
  extensionId: extension.id,
18914
18994
  marketplaceId: extension.marketplaceId,
18915
18995
  success: !error,
@@ -18922,11 +19002,11 @@ async function installExtension(ide, extension) {
18922
19002
  } catch (e) {
18923
19003
  }
18924
19004
  }
18925
- return new Promise((resolve10) => {
19005
+ return new Promise((resolve9) => {
18926
19006
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
18927
19007
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
18928
19008
  if (error) {
18929
- resolve10({
19009
+ resolve9({
18930
19010
  extensionId: extension.id,
18931
19011
  marketplaceId: extension.marketplaceId,
18932
19012
  success: false,
@@ -18934,7 +19014,7 @@ async function installExtension(ide, extension) {
18934
19014
  error: stderr || error.message
18935
19015
  });
18936
19016
  } else {
18937
- resolve10({
19017
+ resolve9({
18938
19018
  extensionId: extension.id,
18939
19019
  marketplaceId: extension.marketplaceId,
18940
19020
  success: true,