@adhdev/daemon-standalone 0.8.25 → 0.8.28

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
@@ -28029,13 +28029,13 @@ var require_dist2 = __commonJS({
28029
28029
  return LOG_DIR;
28030
28030
  }
28031
28031
  function getCurrentDaemonLogPath(date5 = /* @__PURE__ */ new Date()) {
28032
- return path42.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
28032
+ return path6.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
28033
28033
  }
28034
28034
  function checkDateRotation() {
28035
28035
  const today = getDateStr();
28036
28036
  if (today !== currentDate) {
28037
28037
  currentDate = today;
28038
- currentLogFile = path42.join(LOG_DIR, `daemon-${currentDate}.log`);
28038
+ currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
28039
28039
  cleanOldLogs();
28040
28040
  }
28041
28041
  }
@@ -28049,7 +28049,7 @@ var require_dist2 = __commonJS({
28049
28049
  const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
28050
28050
  if (dateMatch && dateMatch[1] < cutoffStr) {
28051
28051
  try {
28052
- fs22.unlinkSync(path42.join(LOG_DIR, file2));
28052
+ fs22.unlinkSync(path6.join(LOG_DIR, file2));
28053
28053
  } catch {
28054
28054
  }
28055
28055
  }
@@ -28167,7 +28167,7 @@ var require_dist2 = __commonJS({
28167
28167
  writeToFile(`Log level: ${currentLevel}`);
28168
28168
  }
28169
28169
  var fs22;
28170
- var path42;
28170
+ var path6;
28171
28171
  var os42;
28172
28172
  var LEVEL_NUM;
28173
28173
  var LEVEL_LABEL;
@@ -28190,12 +28190,12 @@ var require_dist2 = __commonJS({
28190
28190
  "src/logging/logger.ts"() {
28191
28191
  "use strict";
28192
28192
  fs22 = __toESM2(require("fs"));
28193
- path42 = __toESM2(require("path"));
28193
+ path6 = __toESM2(require("path"));
28194
28194
  os42 = __toESM2(require("os"));
28195
28195
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
28196
28196
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
28197
28197
  currentLevel = "info";
28198
- LOG_DIR = process.platform === "win32" ? path42.join(process.env.LOCALAPPDATA || process.env.APPDATA || path42.join(os42.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path42.join(os42.homedir(), "Library", "Logs", "adhdev") : path42.join(os42.homedir(), ".local", "share", "adhdev", "logs");
28198
+ LOG_DIR = process.platform === "win32" ? path6.join(process.env.LOCALAPPDATA || process.env.APPDATA || path6.join(os42.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path6.join(os42.homedir(), "Library", "Logs", "adhdev") : path6.join(os42.homedir(), ".local", "share", "adhdev", "logs");
28199
28199
  MAX_LOG_SIZE = 5 * 1024 * 1024;
28200
28200
  MAX_LOG_DAYS = 7;
28201
28201
  try {
@@ -28203,16 +28203,16 @@ var require_dist2 = __commonJS({
28203
28203
  } catch {
28204
28204
  }
28205
28205
  currentDate = getDateStr();
28206
- currentLogFile = path42.join(LOG_DIR, `daemon-${currentDate}.log`);
28206
+ currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
28207
28207
  cleanOldLogs();
28208
28208
  try {
28209
- const oldLog = path42.join(LOG_DIR, "daemon.log");
28209
+ const oldLog = path6.join(LOG_DIR, "daemon.log");
28210
28210
  if (fs22.existsSync(oldLog)) {
28211
28211
  const stat4 = fs22.statSync(oldLog);
28212
28212
  const oldDate = stat4.mtime.toISOString().slice(0, 10);
28213
- fs22.renameSync(oldLog, path42.join(LOG_DIR, `daemon-${oldDate}.log`));
28213
+ fs22.renameSync(oldLog, path6.join(LOG_DIR, `daemon-${oldDate}.log`));
28214
28214
  }
28215
- const oldLogBackup = path42.join(LOG_DIR, "daemon.log.old");
28215
+ const oldLogBackup = path6.join(LOG_DIR, "daemon.log.old");
28216
28216
  if (fs22.existsSync(oldLogBackup)) {
28217
28217
  fs22.unlinkSync(oldLogBackup);
28218
28218
  }
@@ -28244,7 +28244,7 @@ var require_dist2 = __commonJS({
28244
28244
  }
28245
28245
  };
28246
28246
  interceptorInstalled = false;
28247
- LOG_PATH = path42.join(LOG_DIR, `daemon-${getDateStr()}.log`);
28247
+ LOG_PATH = path6.join(LOG_DIR, `daemon-${getDateStr()}.log`);
28248
28248
  }
28249
28249
  });
28250
28250
  function isModuleNotFoundError(error48, ref) {
@@ -28512,18 +28512,18 @@ var require_dist2 = __commonJS({
28512
28512
  };
28513
28513
  }
28514
28514
  });
28515
- var import_session_host_core2;
28515
+ var import_session_host_core3;
28516
28516
  var init_spawn_env = __esm2({
28517
28517
  "src/cli-adapters/spawn-env.ts"() {
28518
28518
  "use strict";
28519
- import_session_host_core2 = require_dist();
28519
+ import_session_host_core3 = require_dist();
28520
28520
  }
28521
28521
  });
28522
28522
  function loadNodePty() {
28523
28523
  if (cachedPty !== void 0) return cachedPty;
28524
28524
  try {
28525
28525
  cachedPty = require("node-pty");
28526
- (0, import_session_host_core2.ensureNodePtySpawnHelperPermissions)();
28526
+ (0, import_session_host_core3.ensureNodePtySpawnHelperPermissions)();
28527
28527
  } catch {
28528
28528
  cachedPty = null;
28529
28529
  }
@@ -28666,16 +28666,22 @@ var require_dist2 = __commonJS({
28666
28666
  return "";
28667
28667
  }
28668
28668
  function findBinary(name) {
28669
+ const trimmed = String(name || "").trim();
28670
+ if (!trimmed) return trimmed;
28671
+ const expanded = trimmed.startsWith("~") ? path9.join(os8.homedir(), trimmed.slice(1)) : trimmed;
28672
+ if (path9.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
28673
+ return path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
28674
+ }
28669
28675
  const isWin = os8.platform() === "win32";
28670
28676
  try {
28671
- const cmd = isWin ? `where ${name}` : `which ${name}`;
28677
+ const cmd = isWin ? `where ${trimmed}` : `which ${trimmed}`;
28672
28678
  return (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
28673
28679
  } catch {
28674
- return isWin ? `${name}.cmd` : name;
28680
+ return isWin ? `${trimmed}.cmd` : trimmed;
28675
28681
  }
28676
28682
  }
28677
28683
  function isScriptBinary(binaryPath) {
28678
- if (!path7.isAbsolute(binaryPath)) return false;
28684
+ if (!path9.isAbsolute(binaryPath)) return false;
28679
28685
  try {
28680
28686
  const fs15 = require("fs");
28681
28687
  const resolved = fs15.realpathSync(binaryPath);
@@ -28691,7 +28697,7 @@ var require_dist2 = __commonJS({
28691
28697
  }
28692
28698
  }
28693
28699
  function looksLikeMachOOrElf(filePath) {
28694
- if (!path7.isAbsolute(filePath)) return false;
28700
+ if (!path9.isAbsolute(filePath)) return false;
28695
28701
  try {
28696
28702
  const fs15 = require("fs");
28697
28703
  const resolved = fs15.realpathSync(filePath);
@@ -28816,7 +28822,7 @@ var require_dist2 = __commonJS({
28816
28822
  };
28817
28823
  }
28818
28824
  var os8;
28819
- var path7;
28825
+ var path9;
28820
28826
  var import_child_process4;
28821
28827
  var buildCliSpawnEnv;
28822
28828
  var ProviderCliAdapter;
@@ -28824,13 +28830,13 @@ var require_dist2 = __commonJS({
28824
28830
  "src/cli-adapters/provider-cli-adapter.ts"() {
28825
28831
  "use strict";
28826
28832
  os8 = __toESM2(require("os"));
28827
- path7 = __toESM2(require("path"));
28833
+ path9 = __toESM2(require("path"));
28828
28834
  import_child_process4 = require("child_process");
28829
28835
  init_logger();
28830
28836
  init_terminal_screen();
28831
28837
  init_pty_transport();
28832
28838
  init_spawn_env();
28833
- buildCliSpawnEnv = import_session_host_core2.sanitizeSpawnEnv;
28839
+ buildCliSpawnEnv = import_session_host_core3.sanitizeSpawnEnv;
28834
28840
  ProviderCliAdapter = class _ProviderCliAdapter {
28835
28841
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
28836
28842
  this.extraArgs = extraArgs;
@@ -29179,16 +29185,17 @@ var require_dist2 = __commonJS({
29179
29185
  async spawn() {
29180
29186
  if (this.ptyProcess) return;
29181
29187
  const { spawn: spawnConfig } = this.provider;
29182
- const binaryPath = findBinary(spawnConfig.command);
29188
+ const configuredCommand = typeof this.runtimeSettings.executablePath === "string" && this.runtimeSettings.executablePath.trim() ? this.runtimeSettings.executablePath.trim() : spawnConfig.command;
29189
+ const binaryPath = findBinary(configuredCommand);
29183
29190
  const isWin = os8.platform() === "win32";
29184
29191
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
29185
29192
  LOG2.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
29186
29193
  this.resetTraceSession();
29187
29194
  let shellCmd;
29188
29195
  let shellArgs;
29189
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
29196
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
29190
29197
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
29191
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
29198
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path9.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
29192
29199
  const useShell = isWin ? useShellWin : useShellUnix;
29193
29200
  if (useShell) {
29194
29201
  if (!spawnConfig.shell && !isWin) {
@@ -29562,7 +29569,7 @@ var require_dist2 = __commonJS({
29562
29569
  `[${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)}`
29563
29570
  );
29564
29571
  }
29565
- await new Promise((resolve9) => setTimeout(resolve9, 50));
29572
+ await new Promise((resolve12) => setTimeout(resolve12, 50));
29566
29573
  }
29567
29574
  const finalScreenText = this.terminalScreen.getText() || "";
29568
29575
  LOG2.warn(
@@ -30073,7 +30080,7 @@ ${data.message || ""}`.trim();
30073
30080
  const deadline = Date.now() + 1e4;
30074
30081
  while (this.startupParseGate && Date.now() < deadline) {
30075
30082
  this.resolveStartupState("send_wait");
30076
- await new Promise((resolve9) => setTimeout(resolve9, 50));
30083
+ await new Promise((resolve12) => setTimeout(resolve12, 50));
30077
30084
  }
30078
30085
  }
30079
30086
  await this.waitForInteractivePrompt();
@@ -30298,17 +30305,17 @@ ${data.message || ""}`.trim();
30298
30305
  }
30299
30306
  }
30300
30307
  waitForStopped(timeoutMs) {
30301
- return new Promise((resolve9) => {
30308
+ return new Promise((resolve12) => {
30302
30309
  const startedAt = Date.now();
30303
30310
  const timer = setInterval(() => {
30304
30311
  if (!this.ptyProcess || this.currentStatus === "stopped") {
30305
30312
  clearInterval(timer);
30306
- resolve9(true);
30313
+ resolve12(true);
30307
30314
  return;
30308
30315
  }
30309
30316
  if (Date.now() - startedAt >= timeoutMs) {
30310
30317
  clearInterval(timer);
30311
- resolve9(false);
30318
+ resolve12(false);
30312
30319
  }
30313
30320
  }, 100);
30314
30321
  });
@@ -30995,6 +31002,7 @@ ${data.message || ""}`.trim();
30995
31002
  var import_child_process2 = require("child_process");
30996
31003
  var import_fs3 = require("fs");
30997
31004
  var import_os22 = require("os");
31005
+ var path42 = __toESM2(require("path"));
30998
31006
  var BUILTIN_IDE_DEFINITIONS = [];
30999
31007
  var registeredIDEs = /* @__PURE__ */ new Map();
31000
31008
  function registerIDEDefinition(def) {
@@ -31011,9 +31019,16 @@ ${data.message || ""}`.trim();
31011
31019
  return [...merged.values()];
31012
31020
  }
31013
31021
  function findCliCommand(command) {
31022
+ const trimmed = String(command || "").trim();
31023
+ if (!trimmed) return null;
31024
+ if (path42.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
31025
+ const candidate = trimmed.startsWith("~") ? path42.join((0, import_os22.homedir)(), trimmed.slice(1)) : trimmed;
31026
+ const resolved = path42.isAbsolute(candidate) ? candidate : path42.resolve(candidate);
31027
+ return (0, import_fs3.existsSync)(resolved) ? resolved : null;
31028
+ }
31014
31029
  try {
31015
31030
  const result = (0, import_child_process2.execSync)(
31016
- (0, import_os22.platform)() === "win32" ? `where ${command}` : `which ${command}`,
31031
+ (0, import_os22.platform)() === "win32" ? `where ${trimmed}` : `which ${trimmed}`,
31017
31032
  { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }
31018
31033
  ).trim();
31019
31034
  return result.split("\n")[0] || null;
@@ -31036,23 +31051,23 @@ ${data.message || ""}`.trim();
31036
31051
  function checkPathExists(paths) {
31037
31052
  const home = (0, import_os22.homedir)();
31038
31053
  for (const p of paths) {
31039
- if (p.includes("*")) {
31054
+ const normalized = p.startsWith("~") ? path42.join(home, p.slice(1)) : p;
31055
+ if (normalized.includes("*")) {
31040
31056
  const username = home.split(/[\\/]/).pop() || "";
31041
- const resolved = p.replace("*", username);
31057
+ const resolved = normalized.replace("*", username);
31042
31058
  if ((0, import_fs3.existsSync)(resolved)) return resolved;
31043
31059
  } else {
31044
- if ((0, import_fs3.existsSync)(p)) return p;
31060
+ if ((0, import_fs3.existsSync)(normalized)) return normalized;
31045
31061
  }
31046
31062
  }
31047
31063
  return null;
31048
31064
  }
31049
- async function detectIDEs() {
31065
+ async function detectIDEs(providerLoader) {
31050
31066
  const os18 = (0, import_os22.platform)();
31051
31067
  const results = [];
31052
31068
  for (const def of getMergedDefinitions()) {
31053
- const cliPath = findCliCommand(def.cli);
31054
- const appPath = checkPathExists(def.paths[os18] || []);
31055
- const installed = !!(cliPath || appPath);
31069
+ const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
31070
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os18] || []) || []);
31056
31071
  let resolvedCli = cliPath;
31057
31072
  if (!resolvedCli && appPath && os18 === "darwin") {
31058
31073
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
@@ -31075,6 +31090,7 @@ ${data.message || ""}`.trim();
31075
31090
  }
31076
31091
  }
31077
31092
  }
31093
+ const installed = os18 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
31078
31094
  const version2 = resolvedCli ? getIdeVersion(resolvedCli) : null;
31079
31095
  results.push({
31080
31096
  id: def.id,
@@ -31091,48 +31107,77 @@ ${data.message || ""}`.trim();
31091
31107
  }
31092
31108
  var import_child_process22 = require("child_process");
31093
31109
  var os22 = __toESM2(require("os"));
31110
+ var path52 = __toESM2(require("path"));
31111
+ var import_fs4 = require("fs");
31094
31112
  function parseVersion(raw) {
31095
31113
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
31096
31114
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
31097
31115
  }
31116
+ function shellQuote(value) {
31117
+ if (/^[a-zA-Z0-9_./:@%+=,-]+$/.test(value)) return value;
31118
+ return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
31119
+ }
31120
+ function expandHome(value) {
31121
+ const trimmed = value.trim();
31122
+ if (!trimmed.startsWith("~")) return trimmed;
31123
+ return path52.join(os22.homedir(), trimmed.slice(1));
31124
+ }
31125
+ function isExplicitCommandPath(command) {
31126
+ const trimmed = command.trim();
31127
+ return path52.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
31128
+ }
31129
+ function resolveCommandPath(command) {
31130
+ const trimmed = command.trim();
31131
+ if (!trimmed) return null;
31132
+ if (isExplicitCommandPath(trimmed)) {
31133
+ const expanded = expandHome(trimmed);
31134
+ const candidate = path52.isAbsolute(expanded) ? expanded : path52.resolve(expanded);
31135
+ return (0, import_fs4.existsSync)(candidate) ? candidate : null;
31136
+ }
31137
+ return null;
31138
+ }
31098
31139
  function execAsync(cmd, timeoutMs = 5e3) {
31099
- return new Promise((resolve9) => {
31140
+ return new Promise((resolve12) => {
31100
31141
  const child = (0, import_child_process22.exec)(cmd, { encoding: "utf-8", timeout: timeoutMs }, (err, stdout) => {
31101
31142
  if (err || !stdout?.trim()) {
31102
- resolve9(null);
31143
+ resolve12(null);
31103
31144
  } else {
31104
- resolve9(stdout.trim());
31145
+ resolve12(stdout.trim());
31105
31146
  }
31106
31147
  });
31107
- child.on("error", () => resolve9(null));
31148
+ child.on("error", () => resolve12(null));
31108
31149
  });
31109
31150
  }
31110
- async function detectCLIs(providerLoader) {
31151
+ async function detectCLIs(providerLoader, options) {
31111
31152
  const platform9 = os22.platform();
31112
31153
  const whichCmd = platform9 === "win32" ? "where" : "which";
31154
+ const includeVersion = options?.includeVersion !== false;
31113
31155
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
31114
31156
  const results = await Promise.all(
31115
31157
  cliList.map(async (cli) => {
31116
31158
  try {
31117
- const pathResult = await execAsync(`${whichCmd} ${cli.command}`);
31159
+ const explicitPath = resolveCommandPath(cli.command);
31160
+ const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(cli.command)}`);
31118
31161
  if (!pathResult) return { ...cli, installed: false };
31119
- const firstPath = pathResult.split("\n")[0];
31162
+ const firstPath = explicitPath || pathResult.split("\n")[0];
31120
31163
  let version2;
31121
- try {
31164
+ if (includeVersion) {
31122
31165
  const versionCommands = [
31123
- cli.versionCommand,
31124
- `${cli.command} --version`,
31125
- `${cli.command} -V`,
31126
- `${cli.command} -v`
31166
+ `"${firstPath}" --version`,
31167
+ `"${firstPath}" -V`,
31168
+ `"${firstPath}" -v`,
31169
+ cli.versionCommand
31127
31170
  ].filter((v2) => !!v2);
31128
- for (const versionCommand of versionCommands) {
31129
- const versionResult = await execAsync(versionCommand, 3e3);
31130
- if (versionResult) {
31131
- version2 = parseVersion(versionResult);
31132
- break;
31171
+ try {
31172
+ for (const versionCommand of versionCommands) {
31173
+ const versionResult = await execAsync(versionCommand, 3e3);
31174
+ if (versionResult) {
31175
+ version2 = parseVersion(versionResult);
31176
+ break;
31177
+ }
31133
31178
  }
31179
+ } catch {
31134
31180
  }
31135
- } catch {
31136
31181
  }
31137
31182
  return { ...cli, installed: true, version: version2, path: firstPath };
31138
31183
  } catch {
@@ -31142,7 +31187,7 @@ ${data.message || ""}`.trim();
31142
31187
  );
31143
31188
  return results;
31144
31189
  }
31145
- async function detectCLI(cliId, providerLoader) {
31190
+ async function detectCLI(cliId, providerLoader, options) {
31146
31191
  const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
31147
31192
  if (providerLoader) {
31148
31193
  const cliList = providerLoader.getCliDetectionList();
@@ -31151,25 +31196,28 @@ ${data.message || ""}`.trim();
31151
31196
  const platform9 = os22.platform();
31152
31197
  const whichCmd = platform9 === "win32" ? "where" : "which";
31153
31198
  try {
31154
- const pathResult = await execAsync(`${whichCmd} ${target.command}`);
31199
+ const explicitPath = resolveCommandPath(target.command);
31200
+ const pathResult = explicitPath || await execAsync(`${whichCmd} ${shellQuote(target.command)}`);
31155
31201
  if (!pathResult) return null;
31156
- const firstPath = pathResult.split("\n")[0];
31202
+ const firstPath = explicitPath || pathResult.split("\n")[0];
31157
31203
  let version2;
31158
- try {
31204
+ if (options?.includeVersion !== false) {
31159
31205
  const versionCommands = [
31160
- target.versionCommand,
31161
- `${target.command} --version`,
31162
- `${target.command} -V`,
31163
- `${target.command} -v`
31206
+ `"${firstPath}" --version`,
31207
+ `"${firstPath}" -V`,
31208
+ `"${firstPath}" -v`,
31209
+ target.versionCommand
31164
31210
  ].filter((v2) => !!v2);
31165
- for (const versionCommand of versionCommands) {
31166
- const versionResult = await execAsync(versionCommand, 3e3);
31167
- if (versionResult) {
31168
- version2 = parseVersion(versionResult);
31169
- break;
31211
+ try {
31212
+ for (const versionCommand of versionCommands) {
31213
+ const versionResult = await execAsync(versionCommand, 3e3);
31214
+ if (versionResult) {
31215
+ version2 = parseVersion(versionResult);
31216
+ break;
31217
+ }
31170
31218
  }
31219
+ } catch {
31171
31220
  }
31172
- } catch {
31173
31221
  }
31174
31222
  return { ...target, installed: true, version: version2, path: firstPath };
31175
31223
  } catch {
@@ -31177,7 +31225,7 @@ ${data.message || ""}`.trim();
31177
31225
  }
31178
31226
  }
31179
31227
  }
31180
- const all = await detectCLIs(providerLoader);
31228
+ const all = await detectCLIs(providerLoader, options);
31181
31229
  return all.find((c) => c.id === resolvedId && c.installed) || null;
31182
31230
  }
31183
31231
  var os32 = __toESM2(require("os"));
@@ -31300,7 +31348,7 @@ ${data.message || ""}`.trim();
31300
31348
  * Returns multiple entries if multiple IDE windows are open on same port
31301
31349
  */
31302
31350
  static listAllTargets(port) {
31303
- return new Promise((resolve9) => {
31351
+ return new Promise((resolve12) => {
31304
31352
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
31305
31353
  let data = "";
31306
31354
  res.on("data", (chunk) => data += chunk.toString());
@@ -31316,16 +31364,16 @@ ${data.message || ""}`.trim();
31316
31364
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
31317
31365
  );
31318
31366
  const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
31319
- resolve9(mainPages.length > 0 ? mainPages : fallbackPages);
31367
+ resolve12(mainPages.length > 0 ? mainPages : fallbackPages);
31320
31368
  } catch {
31321
- resolve9([]);
31369
+ resolve12([]);
31322
31370
  }
31323
31371
  });
31324
31372
  });
31325
- req.on("error", () => resolve9([]));
31373
+ req.on("error", () => resolve12([]));
31326
31374
  req.setTimeout(2e3, () => {
31327
31375
  req.destroy();
31328
- resolve9([]);
31376
+ resolve12([]);
31329
31377
  });
31330
31378
  });
31331
31379
  }
@@ -31365,7 +31413,7 @@ ${data.message || ""}`.trim();
31365
31413
  }
31366
31414
  }
31367
31415
  findTargetOnPort(port) {
31368
- return new Promise((resolve9) => {
31416
+ return new Promise((resolve12) => {
31369
31417
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
31370
31418
  let data = "";
31371
31419
  res.on("data", (chunk) => data += chunk.toString());
@@ -31376,7 +31424,7 @@ ${data.message || ""}`.trim();
31376
31424
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
31377
31425
  );
31378
31426
  if (pages.length === 0) {
31379
- resolve9(targets.find((t) => t.webSocketDebuggerUrl) || null);
31427
+ resolve12(targets.find((t) => t.webSocketDebuggerUrl) || null);
31380
31428
  return;
31381
31429
  }
31382
31430
  const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
@@ -31386,24 +31434,24 @@ ${data.message || ""}`.trim();
31386
31434
  const specific = list.find((t) => t.id === this._targetId);
31387
31435
  if (specific) {
31388
31436
  this._pageTitle = specific.title || "";
31389
- resolve9(specific);
31437
+ resolve12(specific);
31390
31438
  } else {
31391
31439
  this.log(`[CDP] Target ${this._targetId} not found in page list`);
31392
- resolve9(null);
31440
+ resolve12(null);
31393
31441
  }
31394
31442
  return;
31395
31443
  }
31396
31444
  this._pageTitle = list[0]?.title || "";
31397
- resolve9(list[0]);
31445
+ resolve12(list[0]);
31398
31446
  } catch {
31399
- resolve9(null);
31447
+ resolve12(null);
31400
31448
  }
31401
31449
  });
31402
31450
  });
31403
- req.on("error", () => resolve9(null));
31451
+ req.on("error", () => resolve12(null));
31404
31452
  req.setTimeout(2e3, () => {
31405
31453
  req.destroy();
31406
- resolve9(null);
31454
+ resolve12(null);
31407
31455
  });
31408
31456
  });
31409
31457
  }
@@ -31414,7 +31462,7 @@ ${data.message || ""}`.trim();
31414
31462
  this.extensionProviders = providers;
31415
31463
  }
31416
31464
  connectToTarget(wsUrl) {
31417
- return new Promise((resolve9) => {
31465
+ return new Promise((resolve12) => {
31418
31466
  this.ws = new import_ws2.default(wsUrl);
31419
31467
  this.ws.on("open", async () => {
31420
31468
  this._connected = true;
@@ -31424,17 +31472,17 @@ ${data.message || ""}`.trim();
31424
31472
  }
31425
31473
  this.connectBrowserWs().catch(() => {
31426
31474
  });
31427
- resolve9(true);
31475
+ resolve12(true);
31428
31476
  });
31429
31477
  this.ws.on("message", (data) => {
31430
31478
  try {
31431
31479
  const msg = JSON.parse(data.toString());
31432
31480
  if (msg.id && this.pending.has(msg.id)) {
31433
- const { resolve: resolve10, reject } = this.pending.get(msg.id);
31481
+ const { resolve: resolve13, reject } = this.pending.get(msg.id);
31434
31482
  this.pending.delete(msg.id);
31435
31483
  this.failureCount = 0;
31436
31484
  if (msg.error) reject(new Error(msg.error.message));
31437
- else resolve10(msg.result);
31485
+ else resolve13(msg.result);
31438
31486
  } else if (msg.method === "Runtime.executionContextCreated") {
31439
31487
  this.contexts.add(msg.params.context.id);
31440
31488
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -31457,7 +31505,7 @@ ${data.message || ""}`.trim();
31457
31505
  this.ws.on("error", (err) => {
31458
31506
  this.log(`[CDP] WebSocket error: ${err.message}`);
31459
31507
  this._connected = false;
31460
- resolve9(false);
31508
+ resolve12(false);
31461
31509
  });
31462
31510
  });
31463
31511
  }
@@ -31471,7 +31519,7 @@ ${data.message || ""}`.trim();
31471
31519
  return;
31472
31520
  }
31473
31521
  this.log(`[CDP] Connecting browser WS for target discovery...`);
31474
- await new Promise((resolve9, reject) => {
31522
+ await new Promise((resolve12, reject) => {
31475
31523
  this.browserWs = new import_ws2.default(browserWsUrl);
31476
31524
  this.browserWs.on("open", async () => {
31477
31525
  this._browserConnected = true;
@@ -31481,16 +31529,16 @@ ${data.message || ""}`.trim();
31481
31529
  } catch (e) {
31482
31530
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
31483
31531
  }
31484
- resolve9();
31532
+ resolve12();
31485
31533
  });
31486
31534
  this.browserWs.on("message", (data) => {
31487
31535
  try {
31488
31536
  const msg = JSON.parse(data.toString());
31489
31537
  if (msg.id && this.browserPending.has(msg.id)) {
31490
- const { resolve: resolve10, reject: reject2 } = this.browserPending.get(msg.id);
31538
+ const { resolve: resolve13, reject: reject2 } = this.browserPending.get(msg.id);
31491
31539
  this.browserPending.delete(msg.id);
31492
31540
  if (msg.error) reject2(new Error(msg.error.message));
31493
- else resolve10(msg.result);
31541
+ else resolve13(msg.result);
31494
31542
  }
31495
31543
  } catch {
31496
31544
  }
@@ -31510,31 +31558,31 @@ ${data.message || ""}`.trim();
31510
31558
  }
31511
31559
  }
31512
31560
  getBrowserWsUrl() {
31513
- return new Promise((resolve9) => {
31561
+ return new Promise((resolve12) => {
31514
31562
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
31515
31563
  let data = "";
31516
31564
  res.on("data", (chunk) => data += chunk.toString());
31517
31565
  res.on("end", () => {
31518
31566
  try {
31519
31567
  const info = JSON.parse(data);
31520
- resolve9(info.webSocketDebuggerUrl || null);
31568
+ resolve12(info.webSocketDebuggerUrl || null);
31521
31569
  } catch {
31522
- resolve9(null);
31570
+ resolve12(null);
31523
31571
  }
31524
31572
  });
31525
31573
  });
31526
- req.on("error", () => resolve9(null));
31574
+ req.on("error", () => resolve12(null));
31527
31575
  req.setTimeout(3e3, () => {
31528
31576
  req.destroy();
31529
- resolve9(null);
31577
+ resolve12(null);
31530
31578
  });
31531
31579
  });
31532
31580
  }
31533
31581
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
31534
- return new Promise((resolve9, reject) => {
31582
+ return new Promise((resolve12, reject) => {
31535
31583
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
31536
31584
  const id = this.browserMsgId++;
31537
- this.browserPending.set(id, { resolve: resolve9, reject });
31585
+ this.browserPending.set(id, { resolve: resolve12, reject });
31538
31586
  this.browserWs.send(JSON.stringify({ id, method, params }));
31539
31587
  setTimeout(() => {
31540
31588
  if (this.browserPending.has(id)) {
@@ -31574,11 +31622,11 @@ ${data.message || ""}`.trim();
31574
31622
  }
31575
31623
  // ─── CDP Protocol ────────────────────────────────────────
31576
31624
  sendInternal(method, params = {}, timeoutMs = 15e3) {
31577
- return new Promise((resolve9, reject) => {
31625
+ return new Promise((resolve12, reject) => {
31578
31626
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
31579
31627
  if (this.ws.readyState !== import_ws2.default.OPEN) return reject(new Error("WebSocket not open"));
31580
31628
  const id = this.msgId++;
31581
- this.pending.set(id, { resolve: resolve9, reject });
31629
+ this.pending.set(id, { resolve: resolve12, reject });
31582
31630
  this.ws.send(JSON.stringify({ id, method, params }));
31583
31631
  setTimeout(() => {
31584
31632
  if (this.pending.has(id)) {
@@ -31827,7 +31875,7 @@ ${data.message || ""}`.trim();
31827
31875
  const browserWs = this.browserWs;
31828
31876
  let msgId = this.browserMsgId;
31829
31877
  const sendWs = (method, params = {}, sessionId) => {
31830
- return new Promise((resolve9, reject) => {
31878
+ return new Promise((resolve12, reject) => {
31831
31879
  const mid = msgId++;
31832
31880
  this.browserMsgId = msgId;
31833
31881
  const handler = (raw) => {
@@ -31836,7 +31884,7 @@ ${data.message || ""}`.trim();
31836
31884
  if (msg.id === mid) {
31837
31885
  browserWs.removeListener("message", handler);
31838
31886
  if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
31839
- else resolve9(msg.result);
31887
+ else resolve12(msg.result);
31840
31888
  }
31841
31889
  } catch {
31842
31890
  }
@@ -32027,14 +32075,14 @@ ${data.message || ""}`.trim();
32027
32075
  if (!ws2 || ws2.readyState !== import_ws2.default.OPEN) {
32028
32076
  throw new Error("CDP not connected");
32029
32077
  }
32030
- return new Promise((resolve9, reject) => {
32078
+ return new Promise((resolve12, reject) => {
32031
32079
  const id = getNextId();
32032
32080
  pendingMap.set(id, {
32033
32081
  resolve: (result) => {
32034
32082
  if (result?.result?.subtype === "error") {
32035
32083
  reject(new Error(result.result.description));
32036
32084
  } else {
32037
- resolve9(result?.result?.value);
32085
+ resolve12(result?.result?.value);
32038
32086
  }
32039
32087
  },
32040
32088
  reject
@@ -32066,10 +32114,10 @@ ${data.message || ""}`.trim();
32066
32114
  throw new Error("CDP not connected");
32067
32115
  }
32068
32116
  const sendViaSession = (method, params = {}) => {
32069
- return new Promise((resolve9, reject) => {
32117
+ return new Promise((resolve12, reject) => {
32070
32118
  const pendingMap = this._browserConnected ? this.browserPending : this.pending;
32071
32119
  const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
32072
- pendingMap.set(id, { resolve: resolve9, reject });
32120
+ pendingMap.set(id, { resolve: resolve12, reject });
32073
32121
  ws2.send(JSON.stringify({ id, sessionId, method, params }));
32074
32122
  setTimeout(() => {
32075
32123
  if (pendingMap.has(id)) {
@@ -32687,9 +32735,9 @@ ${data.message || ""}`.trim();
32687
32735
  return String(value);
32688
32736
  }
32689
32737
  var fs32 = __toESM2(require("fs"));
32690
- var path52 = __toESM2(require("path"));
32738
+ var path7 = __toESM2(require("path"));
32691
32739
  var os52 = __toESM2(require("os"));
32692
- var HISTORY_DIR = path52.join(os52.homedir(), ".adhdev", "history");
32740
+ var HISTORY_DIR = path7.join(os52.homedir(), ".adhdev", "history");
32693
32741
  var RETAIN_DAYS = 30;
32694
32742
  var ChatHistoryWriter = class {
32695
32743
  /** Last seen message count per agent (deduplication) */
@@ -32734,11 +32782,11 @@ ${data.message || ""}`.trim();
32734
32782
  });
32735
32783
  }
32736
32784
  if (newMessages.length === 0) return;
32737
- const dir = path52.join(HISTORY_DIR, this.sanitize(agentType));
32785
+ const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
32738
32786
  fs32.mkdirSync(dir, { recursive: true });
32739
32787
  const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
32740
32788
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
32741
- const filePath = path52.join(dir, `${filePrefix}${date5}.jsonl`);
32789
+ const filePath = path7.join(dir, `${filePrefix}${date5}.jsonl`);
32742
32790
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
32743
32791
  fs32.appendFileSync(filePath, lines, "utf-8");
32744
32792
  const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
@@ -32792,14 +32840,14 @@ ${data.message || ""}`.trim();
32792
32840
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
32793
32841
  this.lastSeenCounts.delete(fromDedupKey);
32794
32842
  }
32795
- const dir = path52.join(HISTORY_DIR, this.sanitize(agentType));
32843
+ const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
32796
32844
  if (!fs32.existsSync(dir)) return;
32797
32845
  const fromPrefix = `${this.sanitize(fromId)}_`;
32798
32846
  const toPrefix = `${this.sanitize(toId)}_`;
32799
32847
  const files = fs32.readdirSync(dir).filter((file2) => file2.startsWith(fromPrefix) && file2.endsWith(".jsonl"));
32800
32848
  for (const file2 of files) {
32801
- const sourcePath = path52.join(dir, file2);
32802
- const targetPath = path52.join(dir, `${toPrefix}${file2.slice(fromPrefix.length)}`);
32849
+ const sourcePath = path7.join(dir, file2);
32850
+ const targetPath = path7.join(dir, `${toPrefix}${file2.slice(fromPrefix.length)}`);
32803
32851
  const sourceLines = fs32.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
32804
32852
  const rewritten = sourceLines.map((line) => {
32805
32853
  try {
@@ -32840,10 +32888,10 @@ ${data.message || ""}`.trim();
32840
32888
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
32841
32889
  const agentDirs = fs32.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
32842
32890
  for (const dir of agentDirs) {
32843
- const dirPath = path52.join(HISTORY_DIR, dir.name);
32891
+ const dirPath = path7.join(HISTORY_DIR, dir.name);
32844
32892
  const files = fs32.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
32845
32893
  for (const file2 of files) {
32846
- const filePath = path52.join(dirPath, file2);
32894
+ const filePath = path7.join(dirPath, file2);
32847
32895
  const stat4 = fs32.statSync(filePath);
32848
32896
  if (stat4.mtimeMs < cutoff) {
32849
32897
  fs32.unlinkSync(filePath);
@@ -32861,7 +32909,7 @@ ${data.message || ""}`.trim();
32861
32909
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId) {
32862
32910
  try {
32863
32911
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
32864
- const dir = path52.join(HISTORY_DIR, sanitized);
32912
+ const dir = path7.join(HISTORY_DIR, sanitized);
32865
32913
  if (!fs32.existsSync(dir)) return { messages: [], hasMore: false };
32866
32914
  const sanitizedInstance = historySessionId?.replace(/[^a-zA-Z0-9_-]/g, "_");
32867
32915
  const files = fs32.readdirSync(dir).filter((f) => {
@@ -32875,7 +32923,7 @@ ${data.message || ""}`.trim();
32875
32923
  const needed = offset + limit + 1;
32876
32924
  for (const file2 of files) {
32877
32925
  if (allMessages.length >= needed) break;
32878
- const filePath = path52.join(dir, file2);
32926
+ const filePath = path7.join(dir, file2);
32879
32927
  const content = fs32.readFileSync(filePath, "utf-8");
32880
32928
  const lines = content.trim().split("\n").filter(Boolean);
32881
32929
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -32897,7 +32945,7 @@ ${data.message || ""}`.trim();
32897
32945
  function listSavedHistorySessions(agentType, options = {}) {
32898
32946
  try {
32899
32947
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
32900
- const dir = path52.join(HISTORY_DIR, sanitized);
32948
+ const dir = path7.join(HISTORY_DIR, sanitized);
32901
32949
  if (!fs32.existsSync(dir)) return { sessions: [], hasMore: false };
32902
32950
  const groupedFiles = /* @__PURE__ */ new Map();
32903
32951
  const filePattern = /^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/;
@@ -32918,7 +32966,7 @@ ${data.message || ""}`.trim();
32918
32966
  let sessionTitle = "";
32919
32967
  let preview = "";
32920
32968
  for (const file2 of files.sort()) {
32921
- const filePath = path52.join(dir, file2);
32969
+ const filePath = path7.join(dir, file2);
32922
32970
  const content = fs32.readFileSync(filePath, "utf-8");
32923
32971
  const lines = content.split("\n").filter(Boolean);
32924
32972
  for (const line of lines) {
@@ -32969,6 +33017,7 @@ ${data.message || ""}`.trim();
32969
33017
  currentStatus = "idle";
32970
33018
  agentStreams = [];
32971
33019
  messages = [];
33020
+ prevMessageHashes = /* @__PURE__ */ new Map();
32972
33021
  activeModal = null;
32973
33022
  currentModel = "";
32974
33023
  currentMode = "";
@@ -33034,7 +33083,7 @@ ${data.message || ""}`.trim();
33034
33083
  onEvent(event, data) {
33035
33084
  if (event === "stream_update") {
33036
33085
  if (data?.streams) this.agentStreams = data.streams;
33037
- if (data?.messages) this.messages = data.messages;
33086
+ if (data?.messages) this.messages = this.assignReceivedAt(data.messages);
33038
33087
  if (data?.activeModal !== void 0) this.activeModal = data.activeModal;
33039
33088
  if (data?.model) this.currentModel = data.model;
33040
33089
  if (data?.mode) this.currentMode = data.mode;
@@ -33060,6 +33109,7 @@ ${data.message || ""}`.trim();
33060
33109
  dispose() {
33061
33110
  this.agentStreams = [];
33062
33111
  this.messages = [];
33112
+ this.prevMessageHashes.clear();
33063
33113
  this.monitor.reset();
33064
33114
  this.appliedEffectKeys.clear();
33065
33115
  this.runtimeMessages = [];
@@ -33215,6 +33265,23 @@ ${data.message || ""}`.trim();
33215
33265
  this.chatId || this.instanceId
33216
33266
  );
33217
33267
  }
33268
+ /**
33269
+ * Assign stable receivedAt to extension messages.
33270
+ * Same pattern as IdeProviderInstance.readChat() prevByHash —
33271
+ * preserves first-seen timestamp across polling cycles.
33272
+ */
33273
+ assignReceivedAt(messages) {
33274
+ const now = Date.now();
33275
+ const nextHashes = /* @__PURE__ */ new Map();
33276
+ for (const msg of messages) {
33277
+ const hash2 = `${msg.role}:${(msg.content || "").slice(0, 100)}`;
33278
+ const prevTime = this.prevMessageHashes.get(hash2);
33279
+ msg.receivedAt = prevTime || now;
33280
+ nextHashes.set(hash2, msg.receivedAt);
33281
+ }
33282
+ this.prevMessageHashes = nextHashes;
33283
+ return messages;
33284
+ }
33218
33285
  mergeConversationMessages(messages) {
33219
33286
  if (this.runtimeMessages.length === 0) return messages;
33220
33287
  return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b2) => {
@@ -33271,6 +33338,7 @@ ${effect.notification.body || ""}`.trim();
33271
33338
  }
33272
33339
  this.agentStreams = [];
33273
33340
  this.messages = [];
33341
+ this.prevMessageHashes.clear();
33274
33342
  this.activeModal = null;
33275
33343
  this.currentModel = "";
33276
33344
  this.currentMode = "";
@@ -34246,16 +34314,28 @@ ${effect.notification.body || ""}`.trim();
34246
34314
  if (!message || typeof message !== "object") return message;
34247
34315
  return trimStructuredStrings(message, stringLimit);
34248
34316
  }
34317
+ function normalizeMessageTime(message) {
34318
+ if (!message || typeof message !== "object") return message;
34319
+ const msg = message;
34320
+ if (msg.receivedAt == null) {
34321
+ const fallback = msg.timestamp ?? msg.createdAt;
34322
+ if (fallback != null) {
34323
+ const ts22 = typeof fallback === "string" ? Date.parse(fallback) : Number(fallback);
34324
+ if (Number.isFinite(ts22) && ts22 > 0) msg.receivedAt = ts22;
34325
+ }
34326
+ }
34327
+ return msg;
34328
+ }
34249
34329
  function trimMessagesForStatus(messages) {
34250
34330
  if (!Array.isArray(messages) || messages.length === 0) return [];
34251
34331
  const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
34252
34332
  const kept = [];
34253
34333
  let totalBytes = 0;
34254
34334
  for (let i = recent.length - 1; i >= 0; i -= 1) {
34255
- let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
34335
+ let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT));
34256
34336
  let size = estimateBytes(normalized);
34257
34337
  if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
34258
- normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
34338
+ normalized = normalizeMessageTime(trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT));
34259
34339
  size = estimateBytes(normalized);
34260
34340
  }
34261
34341
  if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
@@ -34870,7 +34950,7 @@ ${effect.notification.body || ""}`.trim();
34870
34950
  if (isExtensionTransport(transport)) {
34871
34951
  _log(`Extension: ${provider?.type || "unknown_extension"}`);
34872
34952
  try {
34873
- const evalResult = await h.evaluateProviderScript("sendMessage", { MESSAGE: text }, 3e4);
34953
+ const evalResult = await h.evaluateProviderScript("sendMessage", { message: text }, 3e4);
34874
34954
  if (evalResult?.result) {
34875
34955
  const parsed = parseMaybeJson(evalResult.result);
34876
34956
  if (didProviderConfirmSend(parsed)) {
@@ -34901,7 +34981,7 @@ ${effect.notification.body || ""}`.trim();
34901
34981
  return { success: false, error: `CDP for ${managerKey || "unknown"} not connected` };
34902
34982
  }
34903
34983
  _log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
34904
- const sendScript = h.getProviderScript("sendMessage", { MESSAGE: text });
34984
+ const sendScript = h.getProviderScript("sendMessage", { message: text });
34905
34985
  if (sendScript) {
34906
34986
  try {
34907
34987
  const result = await targetCdp.evaluate(sendScript, 3e4);
@@ -35041,6 +35121,14 @@ ${effect.notification.body || ""}`.trim();
35041
35121
  } catch {
35042
35122
  }
35043
35123
  }
35124
+ if (parsed?.sessions && Array.isArray(parsed.sessions)) {
35125
+ LOG2.info("Command", `[list_chats] OK: ${parsed.sessions.length} chats`);
35126
+ return { success: true, chats: parsed.sessions };
35127
+ }
35128
+ if (parsed?.chats && Array.isArray(parsed.chats)) {
35129
+ LOG2.info("Command", `[list_chats] OK: ${parsed.chats.length} chats`);
35130
+ return { success: true, chats: parsed.chats };
35131
+ }
35044
35132
  if (Array.isArray(parsed)) {
35045
35133
  LOG2.info("Command", `[list_chats] OK: ${parsed.length} chats`);
35046
35134
  return { success: true, chats: parsed };
@@ -35110,7 +35198,13 @@ ${effect.notification.body || ""}`.trim();
35110
35198
  } catch (e) {
35111
35199
  return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
35112
35200
  }
35113
- const script = h.getProviderScript("switchSession", { SESSION_ID: JSON.stringify(sessionId) }) || h.getProviderScript("switch_session", { SESSION_ID: JSON.stringify(sessionId) });
35201
+ const switchParams = {
35202
+ sessionId,
35203
+ title: sessionId,
35204
+ id: sessionId,
35205
+ SESSION_ID: JSON.stringify(sessionId)
35206
+ };
35207
+ const script = h.getProviderScript("switchSession", switchParams) || h.getProviderScript("switch_session", switchParams);
35114
35208
  if (!script) return { success: false, error: "switch_session script not available" };
35115
35209
  try {
35116
35210
  const raw = await cdp.evaluate(script, 15e3);
@@ -35189,8 +35283,8 @@ ${effect.notification.body || ""}`.trim();
35189
35283
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
35190
35284
  if (adapter) {
35191
35285
  const acpInstance = adapter._acpInstance;
35192
- if (acpInstance && typeof acpInstance.onEvent === "function") {
35193
- acpInstance.onEvent("set_mode", { mode });
35286
+ if (acpInstance && typeof acpInstance.setMode === "function") {
35287
+ await acpInstance.setMode(mode);
35194
35288
  return { success: true, mode };
35195
35289
  }
35196
35290
  }
@@ -35247,9 +35341,9 @@ ${effect.notification.body || ""}`.trim();
35247
35341
  LOG2.info("Command", `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
35248
35342
  if (adapter) {
35249
35343
  const acpInstance = adapter._acpInstance;
35250
- if (acpInstance && typeof acpInstance.onEvent === "function") {
35251
- acpInstance.onEvent("change_model", { model });
35252
- LOG2.info("Command", `[change_model] Dispatched change_model event to ACP instance`);
35344
+ if (acpInstance && typeof acpInstance.setConfigOption === "function") {
35345
+ await acpInstance.setConfigOption("model", model);
35346
+ LOG2.info("Command", `[change_model] Updated ACP model to ${model}`);
35253
35347
  return { success: true, model };
35254
35348
  }
35255
35349
  }
@@ -35369,6 +35463,18 @@ ${effect.notification.body || ""}`.trim();
35369
35463
  const ok = await h.agentStream.resolveSessionAction(h.getCdp(), h.currentSession.sessionId, action);
35370
35464
  return { success: ok };
35371
35465
  }
35466
+ if (transport === "acp") {
35467
+ const adapter = getTargetedCliAdapter(h, args, provider?.type);
35468
+ const acpInstance = adapter?._acpInstance;
35469
+ if (!acpInstance) return { success: false, error: "ACP instance not found" };
35470
+ try {
35471
+ await acpInstance.resolvePermission(action === "approve" || action === "accept" || action === "always");
35472
+ LOG2.info("Command", `[resolveAction] ACP \u2192 ${action}`);
35473
+ return { success: true, action };
35474
+ } catch (e) {
35475
+ return { success: false, error: e?.message || "ACP resolve action failed" };
35476
+ }
35477
+ }
35372
35478
  if (provider?.scripts?.webviewResolveAction || provider?.scripts?.webview_resolve_action) {
35373
35479
  const script = h.getProviderScript("webviewResolveAction", { action, button, buttonText: button }) || h.getProviderScript("webview_resolve_action", { action, button, buttonText: button });
35374
35480
  if (script) {
@@ -35445,7 +35551,7 @@ ${effect.notification.body || ""}`.trim();
35445
35551
  return { success: false, error: "resolveAction script not available for this provider" };
35446
35552
  }
35447
35553
  var fs42 = __toESM2(require("fs"));
35448
- var path6 = __toESM2(require("path"));
35554
+ var path8 = __toESM2(require("path"));
35449
35555
  var os62 = __toESM2(require("os"));
35450
35556
  var KEY_TO_VK = {
35451
35557
  Backspace: 8,
@@ -35697,25 +35803,25 @@ ${effect.notification.body || ""}`.trim();
35697
35803
  const inputPath = rawPath || ".";
35698
35804
  const home = os62.homedir();
35699
35805
  if (inputPath.startsWith("~")) {
35700
- return path6.resolve(path6.join(home, inputPath.slice(1)));
35806
+ return path8.resolve(path8.join(home, inputPath.slice(1)));
35701
35807
  }
35702
35808
  if (process.platform === "win32") {
35703
35809
  const normalized = normalizeWindowsRequestedPath(inputPath);
35704
- if (path6.win32.isAbsolute(normalized)) {
35705
- return path6.win32.normalize(normalized);
35810
+ if (path8.win32.isAbsolute(normalized)) {
35811
+ return path8.win32.normalize(normalized);
35706
35812
  }
35707
- return path6.win32.resolve(normalized);
35813
+ return path8.win32.resolve(normalized);
35708
35814
  }
35709
- if (path6.isAbsolute(inputPath)) {
35710
- return path6.normalize(inputPath);
35815
+ if (path8.isAbsolute(inputPath)) {
35816
+ return path8.normalize(inputPath);
35711
35817
  }
35712
- return path6.resolve(inputPath);
35818
+ return path8.resolve(inputPath);
35713
35819
  }
35714
35820
  function listDirectoryEntriesSafe(dirPath) {
35715
35821
  const entries = fs42.readdirSync(dirPath, { withFileTypes: true });
35716
35822
  const files = [];
35717
35823
  for (const entry of entries) {
35718
- const entryPath = path6.join(dirPath, entry.name);
35824
+ const entryPath = path8.join(dirPath, entry.name);
35719
35825
  try {
35720
35826
  if (entry.isDirectory()) {
35721
35827
  files.push({ name: entry.name, type: "directory" });
@@ -35754,7 +35860,7 @@ ${effect.notification.body || ""}`.trim();
35754
35860
  async function handleFileWrite(h, args) {
35755
35861
  try {
35756
35862
  const filePath = resolveSafePath(args?.path);
35757
- fs42.mkdirSync(path6.dirname(filePath), { recursive: true });
35863
+ fs42.mkdirSync(path8.dirname(filePath), { recursive: true });
35758
35864
  fs42.writeFileSync(filePath, args?.content || "", "utf-8");
35759
35865
  return { success: true, path: filePath };
35760
35866
  } catch (e) {
@@ -35840,7 +35946,7 @@ ${effect.notification.body || ""}`.trim();
35840
35946
  }
35841
35947
  return { success: true, settings: allSettings, values: allValues };
35842
35948
  }
35843
- function handleSetProviderSetting(h, args) {
35949
+ async function handleSetProviderSetting(h, args) {
35844
35950
  const loader = h.ctx.providerLoader;
35845
35951
  const { providerType, key, value } = args || {};
35846
35952
  if (!providerType || !key || value === void 0) {
@@ -35853,6 +35959,7 @@ ${effect.notification.body || ""}`.trim();
35853
35959
  const updated = h.ctx.instanceManager.updateInstanceSettings(providerType, allSettings);
35854
35960
  LOG2.info("Command", `[set_provider_setting] ${providerType}.${key}=${JSON.stringify(value)} \u2192 ${updated} instance(s) updated`);
35855
35961
  }
35962
+ await h.ctx.onProviderSettingChanged?.(providerType, key, value);
35856
35963
  return { success: true, providerType, key, value };
35857
35964
  }
35858
35965
  return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
@@ -35890,10 +35997,10 @@ ${effect.notification.body || ""}`.trim();
35890
35997
  }
35891
35998
  const command = payload.command;
35892
35999
  if (!command || typeof command !== "object") return null;
35893
- if (command.type !== "send_message") return null;
36000
+ if (command.type !== "send_message" && command.type !== "pty_write") return null;
35894
36001
  const text = typeof command.text === "string" ? command.text.trim() : typeof command.message === "string" ? command.message.trim() : "";
35895
36002
  if (!text) return null;
35896
- return { type: "send_message", text };
36003
+ return { type: command.type, text };
35897
36004
  }
35898
36005
  function applyProviderPatch(h, args, payload) {
35899
36006
  if (!payload || typeof payload !== "object") return;
@@ -35934,6 +36041,8 @@ ${effect.notification.body || ""}`.trim();
35934
36041
  const cliCommand = getCliScriptCommand(parsed.payload);
35935
36042
  if (cliCommand?.type === "send_message" && cliCommand.text) {
35936
36043
  await adapter.sendMessage(cliCommand.text);
36044
+ } else if (cliCommand?.type === "pty_write" && cliCommand.text && adapter.writeRaw) {
36045
+ adapter.writeRaw(cliCommand.text + "\r");
35937
36046
  }
35938
36047
  applyProviderPatch(h, args, parsed.payload);
35939
36048
  return { success: true, ...parsed.payload && typeof parsed.payload === "object" ? parsed.payload : { result: parsed.payload } };
@@ -36295,9 +36404,26 @@ ${effect.notification.body || ""}`.trim();
36295
36404
  if (provider?.scripts) {
36296
36405
  const fn2 = provider.scripts[scriptName];
36297
36406
  if (typeof fn2 === "function") {
36298
- const firstVal = params ? Object.values(params)[0] : void 0;
36299
- const script = firstVal ? fn2(firstVal) : fn2();
36300
- if (script) return script;
36407
+ if (params && Object.keys(params).length > 0) {
36408
+ const firstVal = Object.values(params)[0];
36409
+ if (scriptName === "sendMessage" && typeof firstVal === "string") {
36410
+ const legacyScript = fn2(firstVal);
36411
+ if (legacyScript) return legacyScript;
36412
+ }
36413
+ const script = fn2(params);
36414
+ if (script) {
36415
+ const likelyLegacyObjectLeak = typeof script === "string" && script.includes("[object Object]") && typeof firstVal === "string";
36416
+ if (!likelyLegacyObjectLeak) return script;
36417
+ }
36418
+ if (firstVal !== void 0) {
36419
+ const legacyScript = fn2(firstVal);
36420
+ if (legacyScript) return legacyScript;
36421
+ }
36422
+ if (script) return script;
36423
+ } else {
36424
+ const script = fn2();
36425
+ if (script) return script;
36426
+ }
36301
36427
  }
36302
36428
  }
36303
36429
  return null;
@@ -36591,7 +36717,7 @@ ${effect.notification.body || ""}`.trim();
36591
36717
  try {
36592
36718
  const http3 = await import("http");
36593
36719
  const postData = JSON.stringify(body);
36594
- const result = await new Promise((resolve9, reject) => {
36720
+ const result = await new Promise((resolve12, reject) => {
36595
36721
  const req = http3.request({
36596
36722
  hostname: "127.0.0.1",
36597
36723
  port: 19280,
@@ -36603,9 +36729,9 @@ ${effect.notification.body || ""}`.trim();
36603
36729
  res.on("data", (chunk) => data += chunk);
36604
36730
  res.on("end", () => {
36605
36731
  try {
36606
- resolve9(JSON.parse(data));
36732
+ resolve12(JSON.parse(data));
36607
36733
  } catch {
36608
- resolve9({ raw: data });
36734
+ resolve12({ raw: data });
36609
36735
  }
36610
36736
  });
36611
36737
  });
@@ -36623,15 +36749,15 @@ ${effect.notification.body || ""}`.trim();
36623
36749
  if (!providerType) return { success: false, error: "providerType required" };
36624
36750
  try {
36625
36751
  const http3 = await import("http");
36626
- const result = await new Promise((resolve9, reject) => {
36752
+ const result = await new Promise((resolve12, reject) => {
36627
36753
  http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
36628
36754
  let data = "";
36629
36755
  res.on("data", (chunk) => data += chunk);
36630
36756
  res.on("end", () => {
36631
36757
  try {
36632
- resolve9(JSON.parse(data));
36758
+ resolve12(JSON.parse(data));
36633
36759
  } catch {
36634
- resolve9({ raw: data });
36760
+ resolve12({ raw: data });
36635
36761
  }
36636
36762
  });
36637
36763
  }).on("error", reject);
@@ -36645,7 +36771,7 @@ ${effect.notification.body || ""}`.trim();
36645
36771
  try {
36646
36772
  const http3 = await import("http");
36647
36773
  const postData = JSON.stringify(args || {});
36648
- const result = await new Promise((resolve9, reject) => {
36774
+ const result = await new Promise((resolve12, reject) => {
36649
36775
  const req = http3.request({
36650
36776
  hostname: "127.0.0.1",
36651
36777
  port: 19280,
@@ -36657,9 +36783,9 @@ ${effect.notification.body || ""}`.trim();
36657
36783
  res.on("data", (chunk) => data += chunk);
36658
36784
  res.on("end", () => {
36659
36785
  try {
36660
- resolve9(JSON.parse(data));
36786
+ resolve12(JSON.parse(data));
36661
36787
  } catch {
36662
- resolve9({ raw: data });
36788
+ resolve12({ raw: data });
36663
36789
  }
36664
36790
  });
36665
36791
  });
@@ -36674,13 +36800,13 @@ ${effect.notification.body || ""}`.trim();
36674
36800
  }
36675
36801
  };
36676
36802
  var os10 = __toESM2(require("os"));
36677
- var path9 = __toESM2(require("path"));
36803
+ var path11 = __toESM2(require("path"));
36678
36804
  var crypto4 = __toESM2(require("crypto"));
36679
36805
  var import_chalk = __toESM2(require("chalk"));
36680
36806
  init_provider_cli_adapter();
36681
36807
  init_config();
36682
36808
  var os9 = __toESM2(require("os"));
36683
- var path8 = __toESM2(require("path"));
36809
+ var path10 = __toESM2(require("path"));
36684
36810
  var crypto3 = __toESM2(require("crypto"));
36685
36811
  var fs5 = __toESM2(require("fs"));
36686
36812
  var import_node_module = require("module");
@@ -36689,7 +36815,7 @@ ${effect.notification.body || ""}`.trim();
36689
36815
  var CachedDatabaseSync = null;
36690
36816
  function getDatabaseSync() {
36691
36817
  if (CachedDatabaseSync) return CachedDatabaseSync;
36692
- const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path8.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
36818
+ const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path10.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
36693
36819
  const sqliteModule = requireFn(`node:${"sqlite"}`);
36694
36820
  CachedDatabaseSync = sqliteModule.DatabaseSync;
36695
36821
  if (!CachedDatabaseSync) {
@@ -36754,6 +36880,7 @@ ${effect.notification.body || ""}`.trim();
36754
36880
  this.detectStatusTransition();
36755
36881
  });
36756
36882
  await this.adapter.spawn();
36883
+ this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
36757
36884
  if (this.providerSessionId) {
36758
36885
  const restoredHistory = readChatHistory(this.type, 0, 200, this.providerSessionId);
36759
36886
  if (restoredHistory.messages.length > 0) {
@@ -36848,6 +36975,7 @@ ${effect.notification.body || ""}`.trim();
36848
36975
  this.promoteProviderSessionId(parsedProviderSessionId);
36849
36976
  }
36850
36977
  const runtime = this.adapter.getRuntimeMetadata();
36978
+ this.maybeAppendRuntimeRecoveryMessage(runtime);
36851
36979
  const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
36852
36980
  const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
36853
36981
  if (controlValues) {
@@ -37174,6 +37302,28 @@ ${effect.notification.body || ""}`.trim();
37174
37302
  const pad = (value) => String(value).padStart(2, "0");
37175
37303
  return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
37176
37304
  }
37305
+ maybeAppendRuntimeRecoveryMessage(runtime) {
37306
+ if (!runtime?.restoredFromStorage || !runtime.runtimeId) return;
37307
+ const recoveryState = String(runtime.recoveryState || "").trim();
37308
+ if (!recoveryState) return;
37309
+ let content = "";
37310
+ if (recoveryState === "auto_resumed") {
37311
+ content = "Session host restored this CLI after restart and reattached it from a saved snapshot.";
37312
+ } else if (recoveryState === "resume_failed") {
37313
+ const errorSuffix = runtime.recoveryError ? ` Resume failed: ${runtime.recoveryError}` : "";
37314
+ content = `Session host found this CLI after restart, but automatic resume failed.${errorSuffix}`;
37315
+ } else if (recoveryState === "host_restart_interrupted") {
37316
+ content = "Session host found this CLI in interrupted state after restart and is attempting to resume it.";
37317
+ } else if (recoveryState === "orphan_snapshot") {
37318
+ content = "Session host restored the last snapshot for this CLI, but the original runtime was not resumed automatically.";
37319
+ } else {
37320
+ content = `Session host restored this CLI after restart (${recoveryState}).`;
37321
+ }
37322
+ this.appendRuntimeSystemMessage(
37323
+ content,
37324
+ `runtime_recovery:${runtime.runtimeId}:${recoveryState}`
37325
+ );
37326
+ }
37177
37327
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
37178
37328
  const normalizedContent = String(content || "").trim();
37179
37329
  if (!normalizedContent) return;
@@ -37488,8 +37638,9 @@ ${effect.notification.body || ""}`.trim();
37488
37638
  async setConfigOption(category, value) {
37489
37639
  const opt = this.configOptions.find((c) => c.category === category);
37490
37640
  if (!opt) {
37491
- this.log.warn(`[${this.type}] No config option for category: ${category}`);
37492
- return;
37641
+ const message = `[${this.type}] No config option for category: ${category}`;
37642
+ this.log.warn(message);
37643
+ throw new Error(message);
37493
37644
  }
37494
37645
  if (this.useStaticConfig) {
37495
37646
  opt.currentValue = value;
@@ -37501,8 +37652,9 @@ ${effect.notification.body || ""}`.trim();
37501
37652
  return;
37502
37653
  }
37503
37654
  if (!this.connection || !this.sessionId) {
37504
- this.log.warn(`[${this.type}] Cannot set config: no active connection/session`);
37505
- return;
37655
+ const message = `[${this.type}] Cannot set config: no active connection/session`;
37656
+ this.log.warn(message);
37657
+ throw new Error(message);
37506
37658
  }
37507
37659
  try {
37508
37660
  this.log.info(`[${this.type}] Sending session/set_config_option: configId=${opt.configId} value=${value} sessionId=${this.sessionId}`);
@@ -37516,7 +37668,9 @@ ${effect.notification.body || ""}`.trim();
37516
37668
  if (result?.configOptions) this.parseConfigOptions(result.configOptions);
37517
37669
  this.log.info(`[${this.type}] Config ${category} set to: ${value} | response: ${JSON.stringify(result)?.slice(0, 300)}`);
37518
37670
  } catch (e) {
37519
- this.log.warn(`[${this.type}] set_config_option failed: ${e?.message}`);
37671
+ const message = e?.message || "Unknown ACP config error";
37672
+ this.log.warn(`[${this.type}] set_config_option failed: ${message}`);
37673
+ throw new Error(message);
37520
37674
  }
37521
37675
  }
37522
37676
  async setMode(modeId) {
@@ -37532,8 +37686,9 @@ ${effect.notification.body || ""}`.trim();
37532
37686
  return;
37533
37687
  }
37534
37688
  if (!this.connection || !this.sessionId) {
37535
- this.log.warn(`[${this.type}] Cannot set mode: no active connection/session`);
37536
- return;
37689
+ const message = `[${this.type}] Cannot set mode: no active connection/session`;
37690
+ this.log.warn(message);
37691
+ throw new Error(message);
37537
37692
  }
37538
37693
  try {
37539
37694
  await this.connection.setSessionMode({
@@ -37543,7 +37698,9 @@ ${effect.notification.body || ""}`.trim();
37543
37698
  this.currentMode = modeId;
37544
37699
  this.log.info(`[${this.type}] Mode set to: ${modeId}`);
37545
37700
  } catch (e) {
37546
- this.log.warn(`[${this.type}] set_mode failed: ${e?.message}`);
37701
+ const message = e?.message || "Unknown ACP mode error";
37702
+ this.log.warn(`[${this.type}] set_mode failed: ${message}`);
37703
+ throw new Error(message);
37547
37704
  }
37548
37705
  }
37549
37706
  /** Static config: kill process and restart with new args */
@@ -37591,7 +37748,7 @@ ${effect.notification.body || ""}`.trim();
37591
37748
  if (!spawnConfig) {
37592
37749
  throw new Error(`[ACP:${this.type}] No spawn config defined`);
37593
37750
  }
37594
- const command = spawnConfig.command;
37751
+ const command = typeof this.settings.executablePath === "string" && this.settings.executablePath.trim() ? this.settings.executablePath.trim() : spawnConfig.command;
37595
37752
  let baseArgs = spawnConfig.args || [];
37596
37753
  if (this.provider.spawnArgBuilder && Object.keys(this.selectedConfig).length > 0) {
37597
37754
  baseArgs = this.provider.spawnArgBuilder(this.selectedConfig);
@@ -37707,13 +37864,13 @@ ${effect.notification.body || ""}`.trim();
37707
37864
  }
37708
37865
  this.currentStatus = "waiting_approval";
37709
37866
  this.detectStatusTransition();
37710
- const approved = await new Promise((resolve9) => {
37711
- this.permissionResolvers.push(resolve9);
37867
+ const approved = await new Promise((resolve12) => {
37868
+ this.permissionResolvers.push(resolve12);
37712
37869
  setTimeout(() => {
37713
- const idx = this.permissionResolvers.indexOf(resolve9);
37870
+ const idx = this.permissionResolvers.indexOf(resolve12);
37714
37871
  if (idx >= 0) {
37715
37872
  this.permissionResolvers.splice(idx, 1);
37716
- resolve9(false);
37873
+ resolve12(false);
37717
37874
  }
37718
37875
  }, 3e5);
37719
37876
  });
@@ -38418,7 +38575,7 @@ ${effect.notification.body || ""}`.trim();
38418
38575
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
38419
38576
  const trimmed = (workingDir || "").trim();
38420
38577
  if (!trimmed) throw new Error("working directory required");
38421
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path9.resolve(trimmed);
38578
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path11.resolve(trimmed);
38422
38579
  const normalizedType = this.providerLoader.resolveAlias(cliType);
38423
38580
  const provider = this.providerLoader.getByAlias(cliType);
38424
38581
  const key = crypto4.randomUUID();
@@ -38505,10 +38662,10 @@ ${installInfo}`
38505
38662
  if (!cliInfo) {
38506
38663
  const installHint = provider?.install || "";
38507
38664
  const displayName = provider?.displayName || provider?.name || cliType;
38508
- const spawnCmd = provider?.spawn?.command || cliType;
38665
+ const spawnCmd = this.providerLoader.getSpawnCommand(normalizedType, provider?.spawn?.command || cliType);
38509
38666
  throw new Error(
38510
38667
  `${displayName} is not installed.
38511
- Command '${spawnCmd}' not found on PATH.
38668
+ Command '${spawnCmd}' is not available.
38512
38669
  ` + (installHint ? `
38513
38670
  ${installHint}
38514
38671
  ` : "") + `
@@ -38866,14 +39023,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
38866
39023
  var import_child_process6 = require("child_process");
38867
39024
  var net3 = __toESM2(require("net"));
38868
39025
  var os12 = __toESM2(require("os"));
38869
- var path11 = __toESM2(require("path"));
39026
+ var path13 = __toESM2(require("path"));
38870
39027
  var fs6 = __toESM2(require("fs"));
38871
- var path10 = __toESM2(require("path"));
39028
+ var path12 = __toESM2(require("path"));
38872
39029
  var os11 = __toESM2(require("os"));
38873
39030
  var chokidar = __toESM2((init_chokidar(), __toCommonJS(chokidar_exports)));
38874
39031
  init_logger();
38875
39032
  var ProviderLoader = class _ProviderLoader {
38876
39033
  providers = /* @__PURE__ */ new Map();
39034
+ providerAvailability = /* @__PURE__ */ new Map();
38877
39035
  userDir;
38878
39036
  upstreamDir;
38879
39037
  disableUpstream;
@@ -38889,12 +39047,12 @@ Run 'adhdev doctor' for detailed diagnostics.`
38889
39047
  static META_FILE = ".meta.json";
38890
39048
  constructor(options) {
38891
39049
  this.logFn = options?.logFn || LOG2.forComponent("Provider").asLogFn();
38892
- const defaultProvidersDir = path10.join(os11.homedir(), ".adhdev", "providers");
39050
+ const defaultProvidersDir = path12.join(os11.homedir(), ".adhdev", "providers");
38893
39051
  if (options?.userDir) {
38894
39052
  this.userDir = options.userDir;
38895
39053
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
38896
39054
  } else {
38897
- const localRepoPath = path10.resolve(__dirname, "../../../../../adhdev-providers");
39055
+ const localRepoPath = path12.resolve(__dirname, "../../../../../adhdev-providers");
38898
39056
  if (fs6.existsSync(localRepoPath)) {
38899
39057
  this.userDir = localRepoPath;
38900
39058
  this.log(`Auto-detected local public repository: ${this.userDir} (Dev workspace speedup)`);
@@ -38903,7 +39061,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
38903
39061
  this.log(`Using default user providers directory: ${this.userDir}`);
38904
39062
  }
38905
39063
  }
38906
- this.upstreamDir = path10.join(defaultProvidersDir, ".upstream");
39064
+ this.upstreamDir = path12.join(defaultProvidersDir, ".upstream");
38907
39065
  this.disableUpstream = options?.disableUpstream ?? false;
38908
39066
  }
38909
39067
  log(msg) {
@@ -38933,7 +39091,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
38933
39091
  * Canonical provider directory shape for a given root.
38934
39092
  */
38935
39093
  getProviderDir(root, category, type) {
38936
- return path10.join(root, category, type);
39094
+ return path12.join(root, category, type);
38937
39095
  }
38938
39096
  /**
38939
39097
  * Canonical user override directory for a provider.
@@ -38960,7 +39118,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
38960
39118
  resolveProviderFile(type, ...segments) {
38961
39119
  const dir = this.findProviderDirInternal(type);
38962
39120
  if (!dir) return null;
38963
- return path10.join(dir, ...segments);
39121
+ return path12.join(dir, ...segments);
38964
39122
  }
38965
39123
  /**
38966
39124
  * Load all providers (3-tier priority)
@@ -38971,6 +39129,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
38971
39129
  */
38972
39130
  loadAll() {
38973
39131
  this.providers.clear();
39132
+ this.providerAvailability.clear();
38974
39133
  let upstreamCount = 0;
38975
39134
  if (!this.disableUpstream && fs6.existsSync(this.upstreamDir)) {
38976
39135
  upstreamCount = this.loadDir(this.upstreamDir);
@@ -38998,7 +39157,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
38998
39157
  if (!fs6.existsSync(this.upstreamDir)) return false;
38999
39158
  try {
39000
39159
  return fs6.readdirSync(this.upstreamDir).some(
39001
- (d) => fs6.statSync(path10.join(this.upstreamDir, d)).isDirectory()
39160
+ (d) => fs6.statSync(path12.join(this.upstreamDir, d)).isDirectory()
39002
39161
  );
39003
39162
  } catch {
39004
39163
  return false;
@@ -39041,11 +39200,12 @@ Run 'adhdev doctor' for detailed diagnostics.`
39041
39200
  if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
39042
39201
  const verCmdConfig = p.versionCommand;
39043
39202
  const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[process.platform] : verCmdConfig;
39203
+ const command = this.getSpawnCommand(p.type, p.spawn.command);
39044
39204
  result.push({
39045
39205
  id: p.type,
39046
39206
  displayName: p.displayName || p.name,
39047
39207
  icon: p.icon || "\u{1F527}",
39048
- command: p.spawn.command,
39208
+ command,
39049
39209
  category: p.category,
39050
39210
  ...typeof versionCommand === "string" && versionCommand.trim() ? { versionCommand: versionCommand.trim() } : {}
39051
39211
  });
@@ -39174,6 +39334,71 @@ Run 'adhdev doctor' for detailed diagnostics.`
39174
39334
  getAvailableIdeTypes() {
39175
39335
  return [...this.providers.values()].filter((p) => p.category === "ide" && p.cdpPorts).map((p) => p.type);
39176
39336
  }
39337
+ getSpawnCommand(type, fallback) {
39338
+ const override = this.getOptionalStringSetting(type, "executablePath");
39339
+ if (override) return override;
39340
+ return fallback || this.providers.get(type)?.spawn?.command || type;
39341
+ }
39342
+ getIdeCliCommand(type, fallback) {
39343
+ const override = this.getOptionalStringSetting(type, "cliPathOverride");
39344
+ if (override) return override;
39345
+ return fallback || this.providers.get(type)?.cli || null;
39346
+ }
39347
+ getIdePathCandidates(type, fallback) {
39348
+ const override = this.getOptionalStringSetting(type, "appPathOverride");
39349
+ if (override) return [override];
39350
+ if (fallback && fallback.length > 0) return fallback;
39351
+ const osPaths = this.providers.get(type)?.paths?.[process.platform];
39352
+ return Array.isArray(osPaths) ? [...osPaths] : [];
39353
+ }
39354
+ setProviderAvailability(type, state) {
39355
+ this.providerAvailability.set(type, {
39356
+ installed: !!state.installed,
39357
+ detectedPath: state.detectedPath ?? null
39358
+ });
39359
+ }
39360
+ setCliDetectionResults(results, replace = true) {
39361
+ if (replace) {
39362
+ for (const provider of this.providers.values()) {
39363
+ if (provider.category === "cli" || provider.category === "acp") {
39364
+ this.providerAvailability.set(provider.type, { installed: false, detectedPath: null });
39365
+ }
39366
+ }
39367
+ }
39368
+ for (const result of results) {
39369
+ this.setProviderAvailability(result.id, {
39370
+ installed: !!result.installed,
39371
+ detectedPath: result.path || null
39372
+ });
39373
+ }
39374
+ }
39375
+ setIdeDetectionResults(results, replace = true) {
39376
+ if (replace) {
39377
+ for (const provider of this.providers.values()) {
39378
+ if (provider.category === "ide") {
39379
+ this.providerAvailability.set(provider.type, { installed: false, detectedPath: null });
39380
+ }
39381
+ }
39382
+ }
39383
+ for (const result of results) {
39384
+ this.setProviderAvailability(result.id, {
39385
+ installed: !!result.installed,
39386
+ detectedPath: result.cliCommand || result.path || null
39387
+ });
39388
+ }
39389
+ }
39390
+ getAvailableProviderInfos() {
39391
+ return this.getAll().map((provider) => {
39392
+ const availability = this.providerAvailability.get(provider.type);
39393
+ return {
39394
+ ...provider,
39395
+ ...availability ? {
39396
+ installed: availability.installed,
39397
+ detectedPath: availability.detectedPath
39398
+ } : {}
39399
+ };
39400
+ });
39401
+ }
39177
39402
  /**
39178
39403
  * Register IDE providers to core/detector registry
39179
39404
  * → Enables detectIDEs() to detect provider.js-based IDEs
@@ -39248,8 +39473,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39248
39473
  resolved._resolvedScriptDir = entry.scriptDir;
39249
39474
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
39250
39475
  if (providerDir) {
39251
- const fullDir = path10.join(providerDir, entry.scriptDir);
39252
- resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
39476
+ const fullDir = path12.join(providerDir, entry.scriptDir);
39477
+ resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
39253
39478
  }
39254
39479
  matched = true;
39255
39480
  }
@@ -39264,8 +39489,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39264
39489
  resolved._resolvedScriptDir = base.defaultScriptDir;
39265
39490
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
39266
39491
  if (providerDir) {
39267
- const fullDir = path10.join(providerDir, base.defaultScriptDir);
39268
- resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
39492
+ const fullDir = path12.join(providerDir, base.defaultScriptDir);
39493
+ resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
39269
39494
  }
39270
39495
  }
39271
39496
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -39282,8 +39507,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39282
39507
  resolved._resolvedScriptDir = dirOverride;
39283
39508
  resolved._resolvedScriptsSource = `versions:${range}`;
39284
39509
  if (providerDir) {
39285
- const fullDir = path10.join(providerDir, dirOverride);
39286
- resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
39510
+ const fullDir = path12.join(providerDir, dirOverride);
39511
+ resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
39287
39512
  }
39288
39513
  }
39289
39514
  } else if (override.scripts) {
@@ -39299,8 +39524,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39299
39524
  resolved._resolvedScriptDir = base.defaultScriptDir;
39300
39525
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
39301
39526
  if (providerDir) {
39302
- const fullDir = path10.join(providerDir, base.defaultScriptDir);
39303
- resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
39527
+ const fullDir = path12.join(providerDir, base.defaultScriptDir);
39528
+ resolved._resolvedScriptsPath = fs6.existsSync(path12.join(fullDir, "scripts.js")) ? path12.join(fullDir, "scripts.js") : fullDir;
39304
39529
  }
39305
39530
  }
39306
39531
  }
@@ -39325,14 +39550,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
39325
39550
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
39326
39551
  return null;
39327
39552
  }
39328
- const dir = path10.join(providerDir, scriptDir);
39553
+ const dir = path12.join(providerDir, scriptDir);
39329
39554
  if (!fs6.existsSync(dir)) {
39330
39555
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
39331
39556
  return null;
39332
39557
  }
39333
39558
  const cached2 = this.scriptsCache.get(dir);
39334
39559
  if (cached2) return cached2;
39335
- const scriptsJs = path10.join(dir, "scripts.js");
39560
+ const scriptsJs = path12.join(dir, "scripts.js");
39336
39561
  if (fs6.existsSync(scriptsJs)) {
39337
39562
  try {
39338
39563
  delete require.cache[require.resolve(scriptsJs)];
@@ -39374,7 +39599,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39374
39599
  return;
39375
39600
  }
39376
39601
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
39377
- this.log(`File changed: ${path10.basename(filePath)}, reloading...`);
39602
+ this.log(`File changed: ${path12.basename(filePath)}, reloading...`);
39378
39603
  this.reload();
39379
39604
  }
39380
39605
  };
@@ -39429,7 +39654,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39429
39654
  }
39430
39655
  const https = require("https");
39431
39656
  const { execSync: execSync7 } = require("child_process");
39432
- const metaPath = path10.join(this.upstreamDir, _ProviderLoader.META_FILE);
39657
+ const metaPath = path12.join(this.upstreamDir, _ProviderLoader.META_FILE);
39433
39658
  let prevEtag = "";
39434
39659
  let prevTimestamp = 0;
39435
39660
  try {
@@ -39446,7 +39671,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39446
39671
  return { updated: false };
39447
39672
  }
39448
39673
  try {
39449
- const etag = await new Promise((resolve9, reject) => {
39674
+ const etag = await new Promise((resolve12, reject) => {
39450
39675
  const options = {
39451
39676
  method: "HEAD",
39452
39677
  hostname: "github.com",
@@ -39464,7 +39689,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39464
39689
  headers: { "User-Agent": "adhdev-launcher" },
39465
39690
  timeout: 1e4
39466
39691
  }, (res2) => {
39467
- resolve9(res2.headers.etag || res2.headers["last-modified"] || "");
39692
+ resolve12(res2.headers.etag || res2.headers["last-modified"] || "");
39468
39693
  });
39469
39694
  req2.on("error", reject);
39470
39695
  req2.on("timeout", () => {
@@ -39473,7 +39698,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39473
39698
  });
39474
39699
  req2.end();
39475
39700
  } else {
39476
- resolve9(res.headers.etag || res.headers["last-modified"] || "");
39701
+ resolve12(res.headers.etag || res.headers["last-modified"] || "");
39477
39702
  }
39478
39703
  });
39479
39704
  req.on("error", reject);
@@ -39489,17 +39714,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
39489
39714
  return { updated: false };
39490
39715
  }
39491
39716
  this.log("Downloading latest providers from GitHub...");
39492
- const tmpTar = path10.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
39493
- const tmpExtract = path10.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
39717
+ const tmpTar = path12.join(os11.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
39718
+ const tmpExtract = path12.join(os11.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
39494
39719
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
39495
39720
  fs6.mkdirSync(tmpExtract, { recursive: true });
39496
39721
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
39497
39722
  const extracted = fs6.readdirSync(tmpExtract);
39498
39723
  const rootDir = extracted.find(
39499
- (d) => fs6.statSync(path10.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
39724
+ (d) => fs6.statSync(path12.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
39500
39725
  );
39501
39726
  if (!rootDir) throw new Error("Unexpected tarball structure");
39502
- const sourceDir = path10.join(tmpExtract, rootDir);
39727
+ const sourceDir = path12.join(tmpExtract, rootDir);
39503
39728
  const backupDir = this.upstreamDir + ".bak";
39504
39729
  if (fs6.existsSync(this.upstreamDir)) {
39505
39730
  if (fs6.existsSync(backupDir)) fs6.rmSync(backupDir, { recursive: true, force: true });
@@ -39537,7 +39762,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39537
39762
  downloadFile(url2, destPath) {
39538
39763
  const https = require("https");
39539
39764
  const http3 = require("http");
39540
- return new Promise((resolve9, reject) => {
39765
+ return new Promise((resolve12, reject) => {
39541
39766
  const doRequest = (reqUrl, redirectCount = 0) => {
39542
39767
  if (redirectCount > 5) {
39543
39768
  reject(new Error("Too many redirects"));
@@ -39557,7 +39782,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39557
39782
  res.pipe(ws2);
39558
39783
  ws2.on("finish", () => {
39559
39784
  ws2.close();
39560
- resolve9();
39785
+ resolve12();
39561
39786
  });
39562
39787
  ws2.on("error", reject);
39563
39788
  });
@@ -39574,8 +39799,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39574
39799
  copyDirRecursive(src, dest) {
39575
39800
  fs6.mkdirSync(dest, { recursive: true });
39576
39801
  for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
39577
- const srcPath = path10.join(src, entry.name);
39578
- const destPath = path10.join(dest, entry.name);
39802
+ const srcPath = path12.join(src, entry.name);
39803
+ const destPath = path12.join(dest, entry.name);
39579
39804
  if (entry.isDirectory()) {
39580
39805
  this.copyDirRecursive(srcPath, destPath);
39581
39806
  } else {
@@ -39586,7 +39811,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39586
39811
  /** .meta.json save */
39587
39812
  writeMeta(metaPath, etag, timestamp) {
39588
39813
  try {
39589
- fs6.mkdirSync(path10.dirname(metaPath), { recursive: true });
39814
+ fs6.mkdirSync(path12.dirname(metaPath), { recursive: true });
39590
39815
  fs6.writeFileSync(metaPath, JSON.stringify({
39591
39816
  etag,
39592
39817
  timestamp,
@@ -39603,7 +39828,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39603
39828
  const scan = (d) => {
39604
39829
  try {
39605
39830
  for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
39606
- if (entry.isDirectory()) scan(path10.join(d, entry.name));
39831
+ if (entry.isDirectory()) scan(path12.join(d, entry.name));
39607
39832
  else if (entry.name === "provider.json") count++;
39608
39833
  }
39609
39834
  } catch {
@@ -39617,9 +39842,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39617
39842
  * Get public settings schema for a provider (for dashboard UI rendering)
39618
39843
  */
39619
39844
  getPublicSettings(type) {
39620
- const provider = this.providers.get(type);
39621
- if (!provider?.settings) return [];
39622
- return Object.entries(provider.settings).filter(([, def]) => def.public === true).map(([key, def]) => ({ key, ...def }));
39845
+ const settings = this.getSettingsSchema(type);
39846
+ return Object.entries(settings).filter(([, def]) => def.public === true).map(([key, def]) => ({ key, ...def }));
39623
39847
  }
39624
39848
  /**
39625
39849
  * Get public settings schema for all providers
@@ -39636,8 +39860,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39636
39860
  * Resolved setting value for a provider (default + user override)
39637
39861
  */
39638
39862
  getSettingValue(type, key) {
39639
- const provider = this.providers.get(type);
39640
- const schemaDef = provider?.settings?.[key];
39863
+ const schemaDef = this.getSettingsSchema(type)[key];
39641
39864
  const defaultVal = schemaDef ? schemaDef.default : void 0;
39642
39865
  try {
39643
39866
  const { loadConfig: loadConfig22 } = (init_config(), __toCommonJS2(config_exports));
@@ -39652,10 +39875,9 @@ Run 'adhdev doctor' for detailed diagnostics.`
39652
39875
  * All resolved settings for a provider (default + user override)
39653
39876
  */
39654
39877
  getSettings(type) {
39655
- const provider = this.providers.get(type);
39656
- if (!provider?.settings) return {};
39878
+ const settings = this.getSettingsSchema(type);
39657
39879
  const result = {};
39658
- for (const [key, def] of Object.entries(provider.settings)) {
39880
+ for (const [key] of Object.entries(settings)) {
39659
39881
  result[key] = this.getSettingValue(type, key);
39660
39882
  }
39661
39883
  return result;
@@ -39664,11 +39886,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
39664
39886
  * Save provider setting value (writes to config.json)
39665
39887
  */
39666
39888
  setSetting(type, key, value) {
39667
- const provider = this.providers.get(type);
39668
- const schemaDef = provider?.settings?.[key];
39889
+ const schemaDef = this.getSettingsSchema(type)[key];
39669
39890
  if (!schemaDef) return false;
39670
39891
  if (!schemaDef.public) return false;
39671
39892
  if (schemaDef.type === "boolean" && typeof value !== "boolean") return false;
39893
+ if (schemaDef.type === "string" && typeof value !== "string") return false;
39672
39894
  if (schemaDef.type === "number") {
39673
39895
  if (typeof value !== "number") return false;
39674
39896
  if (schemaDef.min !== void 0 && value < schemaDef.min) return false;
@@ -39689,6 +39911,53 @@ Run 'adhdev doctor' for detailed diagnostics.`
39689
39911
  return false;
39690
39912
  }
39691
39913
  }
39914
+ getOptionalStringSetting(type, key) {
39915
+ const value = this.getSettingValue(type, key);
39916
+ if (typeof value !== "string") return null;
39917
+ const trimmed = value.trim();
39918
+ return trimmed ? trimmed : null;
39919
+ }
39920
+ getSettingsSchema(type) {
39921
+ const provider = this.providers.get(type);
39922
+ if (!provider) return {};
39923
+ return {
39924
+ ...this.getSyntheticSettings(type, provider),
39925
+ ...provider.settings || {}
39926
+ };
39927
+ }
39928
+ getSyntheticSettings(type, provider) {
39929
+ const result = {};
39930
+ if ((provider.category === "cli" || provider.category === "acp") && provider.spawn?.command && !provider.settings?.executablePath) {
39931
+ result.executablePath = {
39932
+ type: "string",
39933
+ default: "",
39934
+ public: true,
39935
+ label: "Executable path",
39936
+ description: "Optional absolute path for this provider binary. Leave blank to use the default PATH lookup."
39937
+ };
39938
+ }
39939
+ if (provider.category === "ide") {
39940
+ if (provider.cli && !provider.settings?.cliPathOverride) {
39941
+ result.cliPathOverride = {
39942
+ type: "string",
39943
+ default: "",
39944
+ public: true,
39945
+ label: "CLI path override",
39946
+ description: "Optional absolute path for the IDE CLI launcher. Leave blank to use the detected default."
39947
+ };
39948
+ }
39949
+ if (provider.paths && !provider.settings?.appPathOverride) {
39950
+ result.appPathOverride = {
39951
+ type: "string",
39952
+ default: "",
39953
+ public: true,
39954
+ label: "App path override",
39955
+ description: "Optional absolute path for the IDE app bundle or executable. Leave blank to use the default install locations."
39956
+ };
39957
+ }
39958
+ }
39959
+ return result;
39960
+ }
39692
39961
  // ─── Private ───────────────────────────────────
39693
39962
  /**
39694
39963
  * Find the on-disk directory for a provider by type.
@@ -39702,17 +39971,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
39702
39971
  for (const root of searchRoots) {
39703
39972
  if (!fs6.existsSync(root)) continue;
39704
39973
  const candidate = this.getProviderDir(root, cat, type);
39705
- if (fs6.existsSync(path10.join(candidate, "provider.json"))) return candidate;
39706
- const catDir = path10.join(root, cat);
39974
+ if (fs6.existsSync(path12.join(candidate, "provider.json"))) return candidate;
39975
+ const catDir = path12.join(root, cat);
39707
39976
  if (fs6.existsSync(catDir)) {
39708
39977
  try {
39709
39978
  for (const entry of fs6.readdirSync(catDir, { withFileTypes: true })) {
39710
39979
  if (!entry.isDirectory()) continue;
39711
- const jsonPath = path10.join(catDir, entry.name, "provider.json");
39980
+ const jsonPath = path12.join(catDir, entry.name, "provider.json");
39712
39981
  if (fs6.existsSync(jsonPath)) {
39713
39982
  try {
39714
39983
  const data = JSON.parse(fs6.readFileSync(jsonPath, "utf-8"));
39715
- if (data.type === type) return path10.join(catDir, entry.name);
39984
+ if (data.type === type) return path12.join(catDir, entry.name);
39716
39985
  } catch {
39717
39986
  }
39718
39987
  }
@@ -39729,7 +39998,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39729
39998
  * (template substitution is NOT applied here — scripts.js handles that)
39730
39999
  */
39731
40000
  buildScriptWrappersFromDir(dir) {
39732
- const scriptsJs = path10.join(dir, "scripts.js");
40001
+ const scriptsJs = path12.join(dir, "scripts.js");
39733
40002
  if (fs6.existsSync(scriptsJs)) {
39734
40003
  try {
39735
40004
  delete require.cache[require.resolve(scriptsJs)];
@@ -39743,7 +40012,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39743
40012
  for (const file2 of fs6.readdirSync(dir)) {
39744
40013
  if (!file2.endsWith(".js")) continue;
39745
40014
  const scriptName = toCamel(file2.replace(".js", ""));
39746
- const filePath = path10.join(dir, file2);
40015
+ const filePath = path12.join(dir, file2);
39747
40016
  result[scriptName] = (...args) => {
39748
40017
  try {
39749
40018
  let content = fs6.readFileSync(filePath, "utf-8");
@@ -39803,7 +40072,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39803
40072
  }
39804
40073
  const hasJson = entries.some((e) => e.name === "provider.json");
39805
40074
  if (hasJson) {
39806
- const jsonPath = path10.join(d, "provider.json");
40075
+ const jsonPath = path12.join(d, "provider.json");
39807
40076
  try {
39808
40077
  const raw = fs6.readFileSync(jsonPath, "utf-8");
39809
40078
  const mod = JSON.parse(raw);
@@ -39816,7 +40085,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39816
40085
  delete mod.extensionIdPattern_flags;
39817
40086
  }
39818
40087
  const hasCompatibility = Array.isArray(mod.compatibility);
39819
- const scriptsPath = path10.join(d, "scripts.js");
40088
+ const scriptsPath = path12.join(d, "scripts.js");
39820
40089
  if (!hasCompatibility && fs6.existsSync(scriptsPath)) {
39821
40090
  try {
39822
40091
  delete require.cache[require.resolve(scriptsPath)];
@@ -39842,7 +40111,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
39842
40111
  if (!entry.isDirectory()) continue;
39843
40112
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
39844
40113
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
39845
- scan(path10.join(d, entry.name));
40114
+ scan(path12.join(d, entry.name));
39846
40115
  }
39847
40116
  }
39848
40117
  };
@@ -39936,17 +40205,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
39936
40205
  throw new Error("No free port found");
39937
40206
  }
39938
40207
  function checkPortFree(port) {
39939
- return new Promise((resolve9) => {
40208
+ return new Promise((resolve12) => {
39940
40209
  const server = net3.createServer();
39941
40210
  server.unref();
39942
- server.on("error", () => resolve9(false));
40211
+ server.on("error", () => resolve12(false));
39943
40212
  server.listen(port, "127.0.0.1", () => {
39944
- server.close(() => resolve9(true));
40213
+ server.close(() => resolve12(true));
39945
40214
  });
39946
40215
  });
39947
40216
  }
39948
40217
  async function isCdpActive(port) {
39949
- return new Promise((resolve9) => {
40218
+ return new Promise((resolve12) => {
39950
40219
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
39951
40220
  timeout: 2e3
39952
40221
  }, (res) => {
@@ -39955,16 +40224,16 @@ Run 'adhdev doctor' for detailed diagnostics.`
39955
40224
  res.on("end", () => {
39956
40225
  try {
39957
40226
  const info = JSON.parse(data);
39958
- resolve9(!!info["WebKit-Version"] || !!info["Browser"]);
40227
+ resolve12(!!info["WebKit-Version"] || !!info["Browser"]);
39959
40228
  } catch {
39960
- resolve9(false);
40229
+ resolve12(false);
39961
40230
  }
39962
40231
  });
39963
40232
  });
39964
- req.on("error", () => resolve9(false));
40233
+ req.on("error", () => resolve12(false));
39965
40234
  req.on("timeout", () => {
39966
40235
  req.destroy();
39967
- resolve9(false);
40236
+ resolve12(false);
39968
40237
  });
39969
40238
  });
39970
40239
  }
@@ -40098,8 +40367,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
40098
40367
  const appNameMap = getMacAppIdentifiers();
40099
40368
  const appName = appNameMap[ideId];
40100
40369
  if (appName) {
40101
- const storagePath = path11.join(
40102
- process.env.APPDATA || path11.join(os12.homedir(), "AppData", "Roaming"),
40370
+ const storagePath = path13.join(
40371
+ process.env.APPDATA || path13.join(os12.homedir(), "AppData", "Roaming"),
40103
40372
  appName,
40104
40373
  "storage.json"
40105
40374
  );
@@ -40123,7 +40392,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40123
40392
  async function launchWithCdp(options = {}) {
40124
40393
  const platform9 = os12.platform();
40125
40394
  let targetIde;
40126
- const ides = await detectIDEs();
40395
+ const ides = await detectIDEs(getProviderLoader());
40127
40396
  if (options.ideId) {
40128
40397
  targetIde = ides.find((i) => i.id === options.ideId && i.installed);
40129
40398
  if (!targetIde) {
@@ -40273,9 +40542,9 @@ Run 'adhdev doctor' for detailed diagnostics.`
40273
40542
  init_config();
40274
40543
  init_logger();
40275
40544
  var fs7 = __toESM2(require("fs"));
40276
- var path12 = __toESM2(require("path"));
40545
+ var path14 = __toESM2(require("path"));
40277
40546
  var os13 = __toESM2(require("os"));
40278
- 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");
40547
+ var LOG_DIR2 = process.platform === "win32" ? path14.join(process.env.LOCALAPPDATA || process.env.APPDATA || path14.join(os13.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path14.join(os13.homedir(), "Library", "Logs", "adhdev") : path14.join(os13.homedir(), ".local", "share", "adhdev", "logs");
40279
40548
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
40280
40549
  var MAX_DAYS = 7;
40281
40550
  try {
@@ -40313,13 +40582,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
40313
40582
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
40314
40583
  }
40315
40584
  var currentDate2 = getDateStr2();
40316
- var currentFile = path12.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
40585
+ var currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
40317
40586
  var writeCount2 = 0;
40318
40587
  function checkRotation() {
40319
40588
  const today = getDateStr2();
40320
40589
  if (today !== currentDate2) {
40321
40590
  currentDate2 = today;
40322
- currentFile = path12.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
40591
+ currentFile = path14.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
40323
40592
  cleanOldFiles();
40324
40593
  }
40325
40594
  }
@@ -40333,7 +40602,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40333
40602
  const dateMatch = file2.match(/commands-(\d{4}-\d{2}-\d{2})/);
40334
40603
  if (dateMatch && dateMatch[1] < cutoffStr) {
40335
40604
  try {
40336
- fs7.unlinkSync(path12.join(LOG_DIR2, file2));
40605
+ fs7.unlinkSync(path14.join(LOG_DIR2, file2));
40337
40606
  } catch {
40338
40607
  }
40339
40608
  }
@@ -40421,12 +40690,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
40421
40690
  }));
40422
40691
  }
40423
40692
  function buildAvailableProviders(providerLoader) {
40424
- return providerLoader.getAll().map((provider) => ({
40693
+ const providers = providerLoader.getAvailableProviderInfos?.() || providerLoader.getAll();
40694
+ return providers.map((provider) => ({
40425
40695
  type: provider.type,
40426
40696
  name: provider.displayName || provider.type,
40427
40697
  displayName: provider.displayName || provider.type,
40428
40698
  icon: provider.icon || "\u{1F4BB}",
40429
- category: provider.category
40699
+ category: provider.category,
40700
+ ...provider.installed !== void 0 ? { installed: provider.installed } : {},
40701
+ ...provider.detectedPath !== void 0 ? { detectedPath: provider.detectedPath } : {}
40430
40702
  }));
40431
40703
  }
40432
40704
  function parseMessageTime(value) {
@@ -40440,17 +40712,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
40440
40712
  function getSessionMessageUpdatedAt(session) {
40441
40713
  const lastMessage = session.activeChat?.messages?.at?.(-1);
40442
40714
  if (!lastMessage) return 0;
40443
- return parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt) || 0;
40715
+ return parseMessageTime(lastMessage.receivedAt) || 0;
40444
40716
  }
40445
40717
  function getSessionCompletionMarker(session) {
40446
40718
  const lastMessage = session.activeChat?.messages?.at?.(-1);
40447
40719
  if (!lastMessage) return "";
40448
40720
  const role = typeof lastMessage.role === "string" ? lastMessage.role : "";
40449
- if (role === "user" || role === "human") return "";
40721
+ if (role === "user" || role === "human" || role === "system") return "";
40450
40722
  if (typeof lastMessage._turnKey === "string" && lastMessage._turnKey) return `turn:${lastMessage._turnKey}`;
40451
40723
  if (typeof lastMessage.id === "string" && lastMessage.id) return `id:${lastMessage.id}`;
40452
40724
  if (typeof lastMessage.index === "number" && Number.isFinite(lastMessage.index)) return `idx:${lastMessage.index}`;
40453
- const timestamp = parseMessageTime(lastMessage.timestamp) || parseMessageTime(lastMessage.receivedAt) || parseMessageTime(lastMessage.createdAt);
40725
+ const timestamp = parseMessageTime(lastMessage.receivedAt);
40454
40726
  return timestamp > 0 ? `ts:${timestamp}` : "";
40455
40727
  }
40456
40728
  function getSessionLastUsedAt(session) {
@@ -40467,7 +40739,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40467
40739
  if (status === "generating" || status === "starting") {
40468
40740
  return { unread: false, inboxBucket: "working" };
40469
40741
  }
40470
- const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human";
40742
+ const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human" && lastRole !== "system";
40471
40743
  return { unread, inboxBucket: unread ? "task_complete" : "idle" };
40472
40744
  }
40473
40745
  function buildRecentLaunches(recentActivity) {
@@ -40552,13 +40824,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
40552
40824
  var import_child_process8 = require("child_process");
40553
40825
  var fs8 = __toESM2(require("fs"));
40554
40826
  var os15 = __toESM2(require("os"));
40555
- var path13 = __toESM2(require("path"));
40827
+ var path15 = __toESM2(require("path"));
40556
40828
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
40557
40829
  function getUpgradeLogPath() {
40558
40830
  const home = os15.homedir();
40559
- const dir = path13.join(home, ".adhdev");
40831
+ const dir = path15.join(home, ".adhdev");
40560
40832
  fs8.mkdirSync(dir, { recursive: true });
40561
- return path13.join(dir, "daemon-upgrade.log");
40833
+ return path15.join(dir, "daemon-upgrade.log");
40562
40834
  }
40563
40835
  function appendUpgradeLog(message) {
40564
40836
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -40591,14 +40863,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
40591
40863
  while (Date.now() - start < timeoutMs) {
40592
40864
  try {
40593
40865
  process.kill(pid, 0);
40594
- await new Promise((resolve9) => setTimeout(resolve9, 250));
40866
+ await new Promise((resolve12) => setTimeout(resolve12, 250));
40595
40867
  } catch {
40596
40868
  return;
40597
40869
  }
40598
40870
  }
40599
40871
  }
40600
40872
  function stopSessionHostProcesses(appName) {
40601
- const pidFile = path13.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
40873
+ const pidFile = path15.join(os15.homedir(), ".adhdev", `${appName}-session-host.pid`);
40602
40874
  try {
40603
40875
  if (fs8.existsSync(pidFile)) {
40604
40876
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -40627,7 +40899,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40627
40899
  }
40628
40900
  }
40629
40901
  function removeDaemonPidFile() {
40630
- const pidFile = path13.join(os15.homedir(), ".adhdev", "daemon.pid");
40902
+ const pidFile = path15.join(os15.homedir(), ".adhdev", "daemon.pid");
40631
40903
  try {
40632
40904
  fs8.unlinkSync(pidFile);
40633
40905
  } catch {
@@ -40638,7 +40910,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40638
40910
  const npmRoot = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
40639
40911
  if (!npmRoot) return;
40640
40912
  const npmPrefix = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
40641
- const binDir = process.platform === "win32" ? npmPrefix : path13.join(npmPrefix, "bin");
40913
+ const binDir = process.platform === "win32" ? npmPrefix : path15.join(npmPrefix, "bin");
40642
40914
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
40643
40915
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
40644
40916
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -40646,25 +40918,25 @@ Run 'adhdev doctor' for detailed diagnostics.`
40646
40918
  }
40647
40919
  if (pkgName.startsWith("@")) {
40648
40920
  const [scope, name] = pkgName.split("/");
40649
- const scopeDir = path13.join(npmRoot, scope);
40921
+ const scopeDir = path15.join(npmRoot, scope);
40650
40922
  if (!fs8.existsSync(scopeDir)) return;
40651
40923
  for (const entry of fs8.readdirSync(scopeDir)) {
40652
40924
  if (!entry.startsWith(`.${name}-`)) continue;
40653
- fs8.rmSync(path13.join(scopeDir, entry), { recursive: true, force: true });
40654
- appendUpgradeLog(`Removed stale scoped staging dir: ${path13.join(scopeDir, entry)}`);
40925
+ fs8.rmSync(path15.join(scopeDir, entry), { recursive: true, force: true });
40926
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path15.join(scopeDir, entry)}`);
40655
40927
  }
40656
40928
  } else {
40657
40929
  for (const entry of fs8.readdirSync(npmRoot)) {
40658
40930
  if (!entry.startsWith(`.${pkgName}-`)) continue;
40659
- fs8.rmSync(path13.join(npmRoot, entry), { recursive: true, force: true });
40660
- appendUpgradeLog(`Removed stale staging dir: ${path13.join(npmRoot, entry)}`);
40931
+ fs8.rmSync(path15.join(npmRoot, entry), { recursive: true, force: true });
40932
+ appendUpgradeLog(`Removed stale staging dir: ${path15.join(npmRoot, entry)}`);
40661
40933
  }
40662
40934
  }
40663
40935
  if (fs8.existsSync(binDir)) {
40664
40936
  for (const entry of fs8.readdirSync(binDir)) {
40665
40937
  if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
40666
- fs8.rmSync(path13.join(binDir, entry), { recursive: true, force: true });
40667
- appendUpgradeLog(`Removed stale bin staging entry: ${path13.join(binDir, entry)}`);
40938
+ fs8.rmSync(path15.join(binDir, entry), { recursive: true, force: true });
40939
+ appendUpgradeLog(`Removed stale bin staging entry: ${path15.join(binDir, entry)}`);
40668
40940
  }
40669
40941
  }
40670
40942
  }
@@ -40706,7 +40978,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
40706
40978
  appendUpgradeLog(installOutput.trim());
40707
40979
  }
40708
40980
  if (process.platform === "win32") {
40709
- await new Promise((resolve9) => setTimeout(resolve9, 500));
40981
+ await new Promise((resolve12) => setTimeout(resolve12, 500));
40710
40982
  cleanupStaleGlobalInstallDirs(payload.packageName);
40711
40983
  appendUpgradeLog("Post-install staging cleanup complete");
40712
40984
  }
@@ -40748,6 +41020,25 @@ Run 'adhdev doctor' for detailed diagnostics.`
40748
41020
  "change_model"
40749
41021
  ];
40750
41022
  var READ_DEBUG_ENABLED2 = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
41023
+ function toHostedCliRuntimeDescriptor(record2) {
41024
+ if (!record2 || typeof record2 !== "object") return null;
41025
+ const runtimeId = typeof record2.sessionId === "string" ? record2.sessionId : "";
41026
+ const cliType = typeof record2.providerType === "string" ? record2.providerType : "";
41027
+ const workspace = typeof record2.workspace === "string" ? record2.workspace : "";
41028
+ if (!runtimeId || !cliType || !workspace) return null;
41029
+ return {
41030
+ runtimeId,
41031
+ runtimeKey: typeof record2.runtimeKey === "string" ? record2.runtimeKey : void 0,
41032
+ displayName: typeof record2.displayName === "string" ? record2.displayName : void 0,
41033
+ workspaceLabel: typeof record2.workspaceLabel === "string" ? record2.workspaceLabel : void 0,
41034
+ lifecycle: typeof record2.lifecycle === "string" ? record2.lifecycle : void 0,
41035
+ recoveryState: typeof record2.meta?.runtimeRecoveryState === "string" ? String(record2.meta.runtimeRecoveryState) : null,
41036
+ cliType,
41037
+ workspace,
41038
+ cliArgs: Array.isArray(record2.meta?.cliArgs) ? record2.meta.cliArgs : [],
41039
+ providerSessionId: typeof record2.meta?.providerSessionId === "string" ? String(record2.meta.providerSessionId) : void 0
41040
+ };
41041
+ }
40751
41042
  var DaemonCommandRouter = class {
40752
41043
  deps;
40753
41044
  constructor(deps) {
@@ -40821,6 +41112,90 @@ Run 'adhdev doctor' for detailed diagnostics.`
40821
41112
  return { success: false, error: e.message };
40822
41113
  }
40823
41114
  }
41115
+ case "session_host_get_diagnostics": {
41116
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41117
+ const diagnostics = await this.deps.sessionHostControl.getDiagnostics({
41118
+ includeSessions: args?.includeSessions !== false,
41119
+ limit: Number(args?.limit) || void 0
41120
+ });
41121
+ return { success: true, diagnostics };
41122
+ }
41123
+ case "session_host_list_sessions": {
41124
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41125
+ const sessions = await this.deps.sessionHostControl.listSessions();
41126
+ return { success: true, sessions };
41127
+ }
41128
+ case "session_host_stop_session": {
41129
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41130
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41131
+ if (!sessionId) return { success: false, error: "sessionId required" };
41132
+ const record2 = await this.deps.sessionHostControl.stopSession(sessionId);
41133
+ return { success: true, record: record2 };
41134
+ }
41135
+ case "session_host_resume_session": {
41136
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41137
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41138
+ if (!sessionId) return { success: false, error: "sessionId required" };
41139
+ const record2 = await this.deps.sessionHostControl.resumeSession(sessionId);
41140
+ const hosted = toHostedCliRuntimeDescriptor(record2);
41141
+ if (hosted) {
41142
+ await this.deps.cliManager.restoreHostedSessions([hosted]);
41143
+ }
41144
+ return { success: true, record: record2 };
41145
+ }
41146
+ case "session_host_restart_session": {
41147
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41148
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41149
+ if (!sessionId) return { success: false, error: "sessionId required" };
41150
+ const record2 = await this.deps.sessionHostControl.restartSession(sessionId);
41151
+ const hosted = toHostedCliRuntimeDescriptor(record2);
41152
+ if (hosted) {
41153
+ await this.deps.cliManager.restoreHostedSessions([hosted]);
41154
+ }
41155
+ return { success: true, record: record2 };
41156
+ }
41157
+ case "session_host_send_signal": {
41158
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41159
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41160
+ const signal = typeof args?.signal === "string" ? args.signal : "";
41161
+ if (!sessionId) return { success: false, error: "sessionId required" };
41162
+ if (!signal) return { success: false, error: "signal required" };
41163
+ const record2 = await this.deps.sessionHostControl.sendSignal(sessionId, signal);
41164
+ return { success: true, record: record2 };
41165
+ }
41166
+ case "session_host_force_detach_client": {
41167
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41168
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41169
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
41170
+ if (!sessionId) return { success: false, error: "sessionId required" };
41171
+ if (!clientId) return { success: false, error: "clientId required" };
41172
+ const record2 = await this.deps.sessionHostControl.forceDetachClient(sessionId, clientId);
41173
+ return { success: true, record: record2 };
41174
+ }
41175
+ case "session_host_acquire_write": {
41176
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41177
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41178
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
41179
+ const ownerType = args?.ownerType === "agent" ? "agent" : "user";
41180
+ if (!sessionId) return { success: false, error: "sessionId required" };
41181
+ if (!clientId) return { success: false, error: "clientId required" };
41182
+ const record2 = await this.deps.sessionHostControl.acquireWrite({
41183
+ sessionId,
41184
+ clientId,
41185
+ ownerType,
41186
+ force: args?.force !== false
41187
+ });
41188
+ return { success: true, record: record2 };
41189
+ }
41190
+ case "session_host_release_write": {
41191
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
41192
+ const sessionId = typeof args?.sessionId === "string" ? args.sessionId : "";
41193
+ const clientId = typeof args?.clientId === "string" ? args.clientId : "";
41194
+ if (!sessionId) return { success: false, error: "sessionId required" };
41195
+ if (!clientId) return { success: false, error: "clientId required" };
41196
+ const record2 = await this.deps.sessionHostControl.releaseWrite({ sessionId, clientId });
41197
+ return { success: true, record: record2 };
41198
+ }
40824
41199
  case "list_saved_sessions": {
40825
41200
  const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : typeof args?.agentType === "string" ? args.agentType.trim() : "";
40826
41201
  const kind = args?.kind === "acp" ? "acp" : "cli";
@@ -40879,6 +41254,12 @@ Run 'adhdev doctor' for detailed diagnostics.`
40879
41254
  if (!ideType) throw new Error("ideType required");
40880
41255
  const killProcess = args?.killProcess !== false;
40881
41256
  await this.stopIde(ideType, killProcess);
41257
+ try {
41258
+ const results = await detectIDEs(this.deps.providerLoader);
41259
+ this.deps.detectedIdes.value = results;
41260
+ this.deps.providerLoader.setIdeDetectionResults(results, true);
41261
+ } catch {
41262
+ }
40882
41263
  return { success: true, ideType, stopped: true, processKilled: killProcess };
40883
41264
  }
40884
41265
  // ─── IDE restart ───
@@ -40921,6 +41302,12 @@ Run 'adhdev doctor' for detailed diagnostics.`
40921
41302
  }
40922
41303
  }
40923
41304
  this.deps.onIdeConnected?.();
41305
+ try {
41306
+ const results = await detectIDEs(this.deps.providerLoader);
41307
+ this.deps.detectedIdes.value = results;
41308
+ this.deps.providerLoader.setIdeDetectionResults(results, true);
41309
+ } catch {
41310
+ }
40924
41311
  if (result.success && resolvedWorkspace) {
40925
41312
  try {
40926
41313
  const next = appendRecentActivity(loadState(), {
@@ -40948,8 +41335,9 @@ Run 'adhdev doctor' for detailed diagnostics.`
40948
41335
  }
40949
41336
  // ─── Detect IDEs ───
40950
41337
  case "detect_ides": {
40951
- const results = await detectIDEs();
41338
+ const results = await detectIDEs(this.deps.providerLoader);
40952
41339
  this.deps.detectedIdes.value = results;
41340
+ this.deps.providerLoader.setIdeDetectionResults(results, true);
40953
41341
  return { success: true, detectedInfo: results };
40954
41342
  }
40955
41343
  // ─── Set User Name ───
@@ -41341,6 +41729,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
41341
41729
  hasScript(name) {
41342
41730
  return typeof this.provider.scripts?.[name] === "function";
41343
41731
  }
41732
+ parseMaybeJson(raw) {
41733
+ if (typeof raw !== "string") return raw;
41734
+ try {
41735
+ return JSON.parse(raw);
41736
+ } catch {
41737
+ return raw;
41738
+ }
41739
+ }
41344
41740
  summarizeRaw(raw) {
41345
41741
  try {
41346
41742
  if (typeof raw === "string") return raw.replace(/\s+/g, " ").trim().slice(0, 240);
@@ -41401,12 +41797,30 @@ Run 'adhdev doctor' for detailed diagnostics.`
41401
41797
  }
41402
41798
  }
41403
41799
  async sendMessage(evaluate, text) {
41404
- const script = this.callScript("sendMessage", text);
41800
+ const params = { message: text };
41801
+ const script = this.callScript("sendMessage", params) || this.callScript("sendMessage", text);
41405
41802
  if (!script) throw new Error(`[${this.agentName}] sendMessage script not available`);
41406
41803
  const result = await evaluate(script);
41407
41804
  if (result && typeof result === "string" && result.startsWith("error:")) {
41408
41805
  throw new Error(`[${this.agentName}] sendMessage failed: ${result}`);
41409
41806
  }
41807
+ const parsed = this.parseMaybeJson(result);
41808
+ if (parsed === true) return;
41809
+ if (typeof parsed === "string") {
41810
+ const normalized = parsed.trim().toLowerCase();
41811
+ if (normalized === "ok" || normalized === "sent" || normalized === "success" || normalized === "true") {
41812
+ return;
41813
+ }
41814
+ }
41815
+ if (parsed && typeof parsed === "object") {
41816
+ if (parsed.sent === true || parsed.success === true || parsed.ok === true || parsed.submitted === true || parsed.dispatched === true) {
41817
+ return;
41818
+ }
41819
+ if (typeof parsed.error === "string" && parsed.error.trim()) {
41820
+ throw new Error(`[${this.agentName}] sendMessage failed: ${parsed.error}`);
41821
+ }
41822
+ }
41823
+ throw new Error(`[${this.agentName}] sendMessage was not confirmed`);
41410
41824
  }
41411
41825
  async resolveAction(evaluate, action, button) {
41412
41826
  const script = this.callScript("resolveAction", { action, button });
@@ -41429,7 +41843,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
41429
41843
  const raw = await evaluate(script, 1e4);
41430
41844
  const data = typeof raw === "string" ? JSON.parse(raw) : raw;
41431
41845
  if (data?.error) return [];
41432
- return Array.isArray(data) ? data : [];
41846
+ if (Array.isArray(data)) return data;
41847
+ if (Array.isArray(data?.sessions)) return data.sessions;
41848
+ if (Array.isArray(data?.chats)) return data.chats;
41849
+ return [];
41433
41850
  } catch {
41434
41851
  return [];
41435
41852
  }
@@ -41437,7 +41854,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
41437
41854
  async switchSession(evaluate, sessionId) {
41438
41855
  const script = this.callScript("switchSession", sessionId);
41439
41856
  if (!script) return false;
41440
- return await evaluate(script, 1e4) === true;
41857
+ const raw = await evaluate(script, 1e4);
41858
+ const data = this.parseMaybeJson(raw);
41859
+ if (data === true) return true;
41860
+ if (typeof data === "string") {
41861
+ const normalized = data.trim().toLowerCase();
41862
+ return normalized === "true" || normalized === "ok" || normalized === "switched" || normalized === "success";
41863
+ }
41864
+ if (data && typeof data === "object") {
41865
+ return data.switched === true || data.success === true || data.ok === true;
41866
+ }
41867
+ return false;
41441
41868
  }
41442
41869
  async focusEditor(evaluate) {
41443
41870
  const script = this.callScript("focusEditor");
@@ -42117,11 +42544,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
42117
42544
  }
42118
42545
  };
42119
42546
  var fs10 = __toESM2(require("fs"));
42120
- var path14 = __toESM2(require("path"));
42547
+ var path16 = __toESM2(require("path"));
42121
42548
  var os16 = __toESM2(require("os"));
42122
42549
  var import_child_process9 = require("child_process");
42123
42550
  var import_os3 = require("os");
42124
- var ARCHIVE_PATH = path14.join(os16.homedir(), ".adhdev", "version-history.json");
42551
+ var ARCHIVE_PATH = path16.join(os16.homedir(), ".adhdev", "version-history.json");
42125
42552
  var MAX_ENTRIES_PER_PROVIDER = 20;
42126
42553
  var VersionArchive = class {
42127
42554
  history = {};
@@ -42168,7 +42595,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
42168
42595
  }
42169
42596
  save() {
42170
42597
  try {
42171
- fs10.mkdirSync(path14.dirname(ARCHIVE_PATH), { recursive: true });
42598
+ fs10.mkdirSync(path16.dirname(ARCHIVE_PATH), { recursive: true });
42172
42599
  fs10.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
42173
42600
  } catch {
42174
42601
  }
@@ -42209,7 +42636,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
42209
42636
  for (const p of paths) {
42210
42637
  if (p.includes("*")) {
42211
42638
  const home = os16.homedir();
42212
- const resolved = p.replace(/\*/g, home.split(path14.sep).pop() || "");
42639
+ const resolved = p.replace(/\*/g, home.split(path16.sep).pop() || "");
42213
42640
  if (fs10.existsSync(resolved)) return resolved;
42214
42641
  } else {
42215
42642
  if (fs10.existsSync(p)) return p;
@@ -42219,7 +42646,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
42219
42646
  }
42220
42647
  function getMacAppVersion(appPath) {
42221
42648
  if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
42222
- const plistPath = path14.join(appPath, "Contents", "Info.plist");
42649
+ const plistPath = path16.join(appPath, "Contents", "Info.plist");
42223
42650
  if (!fs10.existsSync(plistPath)) return null;
42224
42651
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
42225
42652
  return raw || null;
@@ -42246,7 +42673,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
42246
42673
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
42247
42674
  let resolvedBin = cliBin;
42248
42675
  if (!resolvedBin && appPath && currentOs === "darwin") {
42249
- const bundled = path14.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
42676
+ const bundled = path16.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
42250
42677
  if (provider.cli && fs10.existsSync(bundled)) resolvedBin = bundled;
42251
42678
  }
42252
42679
  info.installed = !!(appPath || resolvedBin);
@@ -42285,7 +42712,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
42285
42712
  }
42286
42713
  var http2 = __toESM2(require("http"));
42287
42714
  var fs14 = __toESM2(require("fs"));
42288
- var path18 = __toESM2(require("path"));
42715
+ var path20 = __toESM2(require("path"));
42289
42716
  function generateFiles(type, name, category, opts = {}) {
42290
42717
  const { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 = "0.1" } = opts;
42291
42718
  if (category === "cli" || category === "acp") {
@@ -42615,7 +43042,7 @@ async (params) => {
42615
43042
  }
42616
43043
  init_logger();
42617
43044
  var fs11 = __toESM2(require("fs"));
42618
- var path15 = __toESM2(require("path"));
43045
+ var path17 = __toESM2(require("path"));
42619
43046
  init_logger();
42620
43047
  async function handleCdpEvaluate(ctx, req, res) {
42621
43048
  const body = await ctx.readBody(req);
@@ -42794,17 +43221,17 @@ async (params) => {
42794
43221
  return;
42795
43222
  }
42796
43223
  let scriptsPath = "";
42797
- const directScripts = path15.join(dir, "scripts.js");
43224
+ const directScripts = path17.join(dir, "scripts.js");
42798
43225
  if (fs11.existsSync(directScripts)) {
42799
43226
  scriptsPath = directScripts;
42800
43227
  } else {
42801
- const scriptsDir = path15.join(dir, "scripts");
43228
+ const scriptsDir = path17.join(dir, "scripts");
42802
43229
  if (fs11.existsSync(scriptsDir)) {
42803
43230
  const versions = fs11.readdirSync(scriptsDir).filter((d) => {
42804
- return fs11.statSync(path15.join(scriptsDir, d)).isDirectory();
43231
+ return fs11.statSync(path17.join(scriptsDir, d)).isDirectory();
42805
43232
  }).sort().reverse();
42806
43233
  for (const ver of versions) {
42807
- const p = path15.join(scriptsDir, ver, "scripts.js");
43234
+ const p = path17.join(scriptsDir, ver, "scripts.js");
42808
43235
  if (fs11.existsSync(p)) {
42809
43236
  scriptsPath = p;
42810
43237
  break;
@@ -43621,7 +44048,7 @@ async (params) => {
43621
44048
  }
43622
44049
  }
43623
44050
  var fs12 = __toESM2(require("fs"));
43624
- var path16 = __toESM2(require("path"));
44051
+ var path18 = __toESM2(require("path"));
43625
44052
  function slugifyFixtureName(value) {
43626
44053
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
43627
44054
  return normalized || `fixture-${Date.now()}`;
@@ -43631,11 +44058,11 @@ async (params) => {
43631
44058
  if (!providerDir) {
43632
44059
  throw new Error(`Provider directory not found for '${type}'`);
43633
44060
  }
43634
- return path16.join(providerDir, "fixtures");
44061
+ return path18.join(providerDir, "fixtures");
43635
44062
  }
43636
44063
  function readCliFixture(ctx, type, name) {
43637
44064
  const fixtureDir = getCliFixtureDir(ctx, type);
43638
- const filePath = path16.join(fixtureDir, `${name}.json`);
44065
+ const filePath = path18.join(fixtureDir, `${name}.json`);
43639
44066
  if (!fs12.existsSync(filePath)) {
43640
44067
  throw new Error(`Fixture not found: ${filePath}`);
43641
44068
  }
@@ -43795,7 +44222,7 @@ async (params) => {
43795
44222
  return { target, instance, adapter };
43796
44223
  }
43797
44224
  function sleep(ms2) {
43798
- return new Promise((resolve9) => setTimeout(resolve9, ms2));
44225
+ return new Promise((resolve12) => setTimeout(resolve12, ms2));
43799
44226
  }
43800
44227
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
43801
44228
  const startedAt = Date.now();
@@ -44394,7 +44821,7 @@ async (params) => {
44394
44821
  },
44395
44822
  notes: typeof body?.notes === "string" ? body.notes : void 0
44396
44823
  };
44397
- const filePath = path16.join(fixtureDir, `${name}.json`);
44824
+ const filePath = path18.join(fixtureDir, `${name}.json`);
44398
44825
  fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
44399
44826
  ctx.json(res, 200, {
44400
44827
  saved: true,
@@ -44418,7 +44845,7 @@ async (params) => {
44418
44845
  return;
44419
44846
  }
44420
44847
  const fixtures = fs12.readdirSync(fixtureDir).filter((file2) => file2.endsWith(".json")).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file2) => {
44421
- const fullPath = path16.join(fixtureDir, file2);
44848
+ const fullPath = path18.join(fixtureDir, file2);
44422
44849
  try {
44423
44850
  const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
44424
44851
  return {
@@ -44552,7 +44979,7 @@ async (params) => {
44552
44979
  }
44553
44980
  }
44554
44981
  var fs13 = __toESM2(require("fs"));
44555
- var path17 = __toESM2(require("path"));
44982
+ var path19 = __toESM2(require("path"));
44556
44983
  var os17 = __toESM2(require("os"));
44557
44984
  function getAutoImplPid(ctx) {
44558
44985
  const proc = ctx.autoImplProcess;
@@ -44592,22 +45019,22 @@ async (params) => {
44592
45019
  if (!fs13.existsSync(scriptsDir)) return null;
44593
45020
  const versions = fs13.readdirSync(scriptsDir).filter((d) => {
44594
45021
  try {
44595
- return fs13.statSync(path17.join(scriptsDir, d)).isDirectory();
45022
+ return fs13.statSync(path19.join(scriptsDir, d)).isDirectory();
44596
45023
  } catch {
44597
45024
  return false;
44598
45025
  }
44599
45026
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
44600
45027
  if (versions.length === 0) return null;
44601
- return path17.join(scriptsDir, versions[0]);
45028
+ return path19.join(scriptsDir, versions[0]);
44602
45029
  }
44603
45030
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
44604
- const canonicalUserDir = path17.resolve(ctx.providerLoader.getUserProviderDir(category, type));
44605
- const desiredDir = requestedDir ? path17.resolve(requestedDir) : canonicalUserDir;
44606
- const upstreamRoot = path17.resolve(ctx.providerLoader.getUpstreamDir());
44607
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path17.sep}`)) {
45031
+ const canonicalUserDir = path19.resolve(ctx.providerLoader.getUserProviderDir(category, type));
45032
+ const desiredDir = requestedDir ? path19.resolve(requestedDir) : canonicalUserDir;
45033
+ const upstreamRoot = path19.resolve(ctx.providerLoader.getUpstreamDir());
45034
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path19.sep}`)) {
44608
45035
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
44609
45036
  }
44610
- if (path17.basename(desiredDir) !== type) {
45037
+ if (path19.basename(desiredDir) !== type) {
44611
45038
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
44612
45039
  }
44613
45040
  const sourceDir = ctx.findProviderDir(type);
@@ -44615,11 +45042,11 @@ async (params) => {
44615
45042
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
44616
45043
  }
44617
45044
  if (!fs13.existsSync(desiredDir)) {
44618
- fs13.mkdirSync(path17.dirname(desiredDir), { recursive: true });
45045
+ fs13.mkdirSync(path19.dirname(desiredDir), { recursive: true });
44619
45046
  fs13.cpSync(sourceDir, desiredDir, { recursive: true });
44620
45047
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
44621
45048
  }
44622
- const providerJson = path17.join(desiredDir, "provider.json");
45049
+ const providerJson = path19.join(desiredDir, "provider.json");
44623
45050
  if (!fs13.existsSync(providerJson)) {
44624
45051
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
44625
45052
  }
@@ -44642,13 +45069,13 @@ async (params) => {
44642
45069
  const refDir = ctx.findProviderDir(referenceType);
44643
45070
  if (!refDir || !fs13.existsSync(refDir)) return {};
44644
45071
  const referenceScripts = {};
44645
- const scriptsDir = path17.join(refDir, "scripts");
45072
+ const scriptsDir = path19.join(refDir, "scripts");
44646
45073
  const latestDir = getLatestScriptVersionDir(scriptsDir);
44647
45074
  if (!latestDir) return referenceScripts;
44648
45075
  for (const file2 of fs13.readdirSync(latestDir)) {
44649
45076
  if (!file2.endsWith(".js")) continue;
44650
45077
  try {
44651
- referenceScripts[file2] = fs13.readFileSync(path17.join(latestDir, file2), "utf-8");
45078
+ referenceScripts[file2] = fs13.readFileSync(path19.join(latestDir, file2), "utf-8");
44652
45079
  } catch {
44653
45080
  }
44654
45081
  }
@@ -44756,9 +45183,9 @@ async (params) => {
44756
45183
  });
44757
45184
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
44758
45185
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
44759
- const tmpDir = path17.join(os17.tmpdir(), "adhdev-autoimpl");
45186
+ const tmpDir = path19.join(os17.tmpdir(), "adhdev-autoimpl");
44760
45187
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
44761
- const promptFile = path17.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
45188
+ const promptFile = path19.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
44762
45189
  fs13.writeFileSync(promptFile, prompt, "utf-8");
44763
45190
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
44764
45191
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -45185,7 +45612,7 @@ async (params) => {
45185
45612
  setMode: "set_mode.js"
45186
45613
  };
45187
45614
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
45188
- const scriptsDir = path17.join(providerDir, "scripts");
45615
+ const scriptsDir = path19.join(providerDir, "scripts");
45189
45616
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
45190
45617
  if (latestScriptsDir) {
45191
45618
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -45196,7 +45623,7 @@ async (params) => {
45196
45623
  for (const file2 of fs13.readdirSync(latestScriptsDir)) {
45197
45624
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
45198
45625
  try {
45199
- const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45626
+ const content = fs13.readFileSync(path19.join(latestScriptsDir, file2), "utf-8");
45200
45627
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
45201
45628
  lines.push("```javascript");
45202
45629
  lines.push(content);
@@ -45213,7 +45640,7 @@ async (params) => {
45213
45640
  lines.push("");
45214
45641
  for (const file2 of refFiles) {
45215
45642
  try {
45216
- const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45643
+ const content = fs13.readFileSync(path19.join(latestScriptsDir, file2), "utf-8");
45217
45644
  lines.push(`### \`${file2}\` \u{1F512}`);
45218
45645
  lines.push("```javascript");
45219
45646
  lines.push(content);
@@ -45254,10 +45681,10 @@ async (params) => {
45254
45681
  lines.push("");
45255
45682
  }
45256
45683
  }
45257
- const docsDir = path17.join(providerDir, "../../docs");
45684
+ const docsDir = path19.join(providerDir, "../../docs");
45258
45685
  const loadGuide = (name) => {
45259
45686
  try {
45260
- const p = path17.join(docsDir, name);
45687
+ const p = path19.join(docsDir, name);
45261
45688
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
45262
45689
  } catch {
45263
45690
  }
@@ -45492,7 +45919,7 @@ async (params) => {
45492
45919
  parseApproval: "parse_approval.js"
45493
45920
  };
45494
45921
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
45495
- const scriptsDir = path17.join(providerDir, "scripts");
45922
+ const scriptsDir = path19.join(providerDir, "scripts");
45496
45923
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
45497
45924
  if (latestScriptsDir) {
45498
45925
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -45504,7 +45931,7 @@ async (params) => {
45504
45931
  if (!file2.endsWith(".js")) continue;
45505
45932
  if (!targetFileNames.has(file2)) continue;
45506
45933
  try {
45507
- const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45934
+ const content = fs13.readFileSync(path19.join(latestScriptsDir, file2), "utf-8");
45508
45935
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
45509
45936
  lines.push("```javascript");
45510
45937
  lines.push(content);
@@ -45520,7 +45947,7 @@ async (params) => {
45520
45947
  lines.push("");
45521
45948
  for (const file2 of refFiles) {
45522
45949
  try {
45523
- const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
45950
+ const content = fs13.readFileSync(path19.join(latestScriptsDir, file2), "utf-8");
45524
45951
  lines.push(`### \`${file2}\` \u{1F512}`);
45525
45952
  lines.push("```javascript");
45526
45953
  lines.push(content);
@@ -45553,10 +45980,10 @@ async (params) => {
45553
45980
  lines.push("");
45554
45981
  }
45555
45982
  }
45556
- const docsDir = path17.join(providerDir, "../../docs");
45983
+ const docsDir = path19.join(providerDir, "../../docs");
45557
45984
  const loadGuide = (name) => {
45558
45985
  try {
45559
- const p = path17.join(docsDir, name);
45986
+ const p = path19.join(docsDir, name);
45560
45987
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
45561
45988
  } catch {
45562
45989
  }
@@ -45965,8 +46392,8 @@ data: ${JSON.stringify(msg.data)}
45965
46392
  }
45966
46393
  getEndpointList() {
45967
46394
  return this.routes.map((r) => {
45968
- const path19 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
45969
- return `${r.method.padEnd(5)} ${path19}`;
46395
+ const path21 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
46396
+ return `${r.method.padEnd(5)} ${path21}`;
45970
46397
  });
45971
46398
  }
45972
46399
  async start(port = DEV_SERVER_PORT) {
@@ -45997,15 +46424,15 @@ data: ${JSON.stringify(msg.data)}
45997
46424
  this.json(res, 500, { error: e.message });
45998
46425
  }
45999
46426
  });
46000
- return new Promise((resolve9, reject) => {
46427
+ return new Promise((resolve12, reject) => {
46001
46428
  this.server.listen(port, "127.0.0.1", () => {
46002
46429
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
46003
- resolve9();
46430
+ resolve12();
46004
46431
  });
46005
46432
  this.server.on("error", (e) => {
46006
46433
  if (e.code === "EADDRINUSE") {
46007
46434
  this.log(`Port ${port} in use, skipping dev server`);
46008
- resolve9();
46435
+ resolve12();
46009
46436
  } else {
46010
46437
  reject(e);
46011
46438
  }
@@ -46088,20 +46515,20 @@ data: ${JSON.stringify(msg.data)}
46088
46515
  child.stderr?.on("data", (d) => {
46089
46516
  stderr += d.toString().slice(0, 2e3);
46090
46517
  });
46091
- await new Promise((resolve9) => {
46518
+ await new Promise((resolve12) => {
46092
46519
  const timer = setTimeout(() => {
46093
46520
  child.kill();
46094
- resolve9();
46521
+ resolve12();
46095
46522
  }, 3e3);
46096
46523
  child.on("exit", () => {
46097
46524
  clearTimeout(timer);
46098
- resolve9();
46525
+ resolve12();
46099
46526
  });
46100
46527
  child.stdout?.once("data", () => {
46101
46528
  setTimeout(() => {
46102
46529
  child.kill();
46103
46530
  clearTimeout(timer);
46104
- resolve9();
46531
+ resolve12();
46105
46532
  }, 500);
46106
46533
  });
46107
46534
  });
@@ -46248,12 +46675,12 @@ data: ${JSON.stringify(msg.data)}
46248
46675
  // ─── DevConsole SPA ───
46249
46676
  getConsoleDistDir() {
46250
46677
  const candidates = [
46251
- path18.resolve(__dirname, "../../web-devconsole/dist"),
46252
- path18.resolve(__dirname, "../../../web-devconsole/dist"),
46253
- path18.join(process.cwd(), "packages/web-devconsole/dist")
46678
+ path20.resolve(__dirname, "../../web-devconsole/dist"),
46679
+ path20.resolve(__dirname, "../../../web-devconsole/dist"),
46680
+ path20.join(process.cwd(), "packages/web-devconsole/dist")
46254
46681
  ];
46255
46682
  for (const dir of candidates) {
46256
- if (fs14.existsSync(path18.join(dir, "index.html"))) return dir;
46683
+ if (fs14.existsSync(path20.join(dir, "index.html"))) return dir;
46257
46684
  }
46258
46685
  return null;
46259
46686
  }
@@ -46263,7 +46690,7 @@ data: ${JSON.stringify(msg.data)}
46263
46690
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
46264
46691
  return;
46265
46692
  }
46266
- const htmlPath = path18.join(distDir, "index.html");
46693
+ const htmlPath = path20.join(distDir, "index.html");
46267
46694
  try {
46268
46695
  const html = fs14.readFileSync(htmlPath, "utf-8");
46269
46696
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -46288,15 +46715,15 @@ data: ${JSON.stringify(msg.data)}
46288
46715
  this.json(res, 404, { error: "Not found" });
46289
46716
  return;
46290
46717
  }
46291
- const safePath = path18.normalize(pathname).replace(/^\.\.\//, "");
46292
- const filePath = path18.join(distDir, safePath);
46718
+ const safePath = path20.normalize(pathname).replace(/^\.\.\//, "");
46719
+ const filePath = path20.join(distDir, safePath);
46293
46720
  if (!filePath.startsWith(distDir)) {
46294
46721
  this.json(res, 403, { error: "Forbidden" });
46295
46722
  return;
46296
46723
  }
46297
46724
  try {
46298
46725
  const content = fs14.readFileSync(filePath);
46299
- const ext = path18.extname(filePath);
46726
+ const ext = path20.extname(filePath);
46300
46727
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
46301
46728
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
46302
46729
  res.end(content);
@@ -46409,9 +46836,9 @@ data: ${JSON.stringify(msg.data)}
46409
46836
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
46410
46837
  if (entry.isDirectory()) {
46411
46838
  files.push({ path: rel, size: 0, type: "dir" });
46412
- scan(path18.join(d, entry.name), rel);
46839
+ scan(path20.join(d, entry.name), rel);
46413
46840
  } else {
46414
- const stat4 = fs14.statSync(path18.join(d, entry.name));
46841
+ const stat4 = fs14.statSync(path20.join(d, entry.name));
46415
46842
  files.push({ path: rel, size: stat4.size, type: "file" });
46416
46843
  }
46417
46844
  }
@@ -46434,7 +46861,7 @@ data: ${JSON.stringify(msg.data)}
46434
46861
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
46435
46862
  return;
46436
46863
  }
46437
- const fullPath = path18.resolve(dir, path18.normalize(filePath));
46864
+ const fullPath = path20.resolve(dir, path20.normalize(filePath));
46438
46865
  if (!fullPath.startsWith(dir)) {
46439
46866
  this.json(res, 403, { error: "Forbidden" });
46440
46867
  return;
@@ -46459,14 +46886,14 @@ data: ${JSON.stringify(msg.data)}
46459
46886
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
46460
46887
  return;
46461
46888
  }
46462
- const fullPath = path18.resolve(dir, path18.normalize(filePath));
46889
+ const fullPath = path20.resolve(dir, path20.normalize(filePath));
46463
46890
  if (!fullPath.startsWith(dir)) {
46464
46891
  this.json(res, 403, { error: "Forbidden" });
46465
46892
  return;
46466
46893
  }
46467
46894
  try {
46468
46895
  if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
46469
- fs14.mkdirSync(path18.dirname(fullPath), { recursive: true });
46896
+ fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
46470
46897
  fs14.writeFileSync(fullPath, content, "utf-8");
46471
46898
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
46472
46899
  this.providerLoader.reload();
@@ -46483,7 +46910,7 @@ data: ${JSON.stringify(msg.data)}
46483
46910
  return;
46484
46911
  }
46485
46912
  for (const name of ["scripts.js", "provider.json"]) {
46486
- const p = path18.join(dir, name);
46913
+ const p = path20.join(dir, name);
46487
46914
  if (fs14.existsSync(p)) {
46488
46915
  const source = fs14.readFileSync(p, "utf-8");
46489
46916
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -46504,8 +46931,8 @@ data: ${JSON.stringify(msg.data)}
46504
46931
  this.json(res, 404, { error: `Provider not found: ${type}` });
46505
46932
  return;
46506
46933
  }
46507
- const target = fs14.existsSync(path18.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
46508
- const targetPath = path18.join(dir, target);
46934
+ const target = fs14.existsSync(path20.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
46935
+ const targetPath = path20.join(dir, target);
46509
46936
  try {
46510
46937
  if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
46511
46938
  fs14.writeFileSync(targetPath, source, "utf-8");
@@ -46610,14 +47037,14 @@ data: ${JSON.stringify(msg.data)}
46610
47037
  child.stderr?.on("data", (d) => {
46611
47038
  stderr += d.toString();
46612
47039
  });
46613
- await new Promise((resolve9) => {
47040
+ await new Promise((resolve12) => {
46614
47041
  const timer = setTimeout(() => {
46615
47042
  child.kill();
46616
- resolve9();
47043
+ resolve12();
46617
47044
  }, timeout);
46618
47045
  child.on("exit", () => {
46619
47046
  clearTimeout(timer);
46620
- resolve9();
47047
+ resolve12();
46621
47048
  });
46622
47049
  });
46623
47050
  const elapsed = Date.now() - start;
@@ -46665,7 +47092,7 @@ data: ${JSON.stringify(msg.data)}
46665
47092
  }
46666
47093
  let targetDir;
46667
47094
  targetDir = this.providerLoader.getUserProviderDir(category, type);
46668
- const jsonPath = path18.join(targetDir, "provider.json");
47095
+ const jsonPath = path20.join(targetDir, "provider.json");
46669
47096
  if (fs14.existsSync(jsonPath)) {
46670
47097
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
46671
47098
  return;
@@ -46677,8 +47104,8 @@ data: ${JSON.stringify(msg.data)}
46677
47104
  const createdFiles = ["provider.json"];
46678
47105
  if (result.files) {
46679
47106
  for (const [relPath, content] of Object.entries(result.files)) {
46680
- const fullPath = path18.join(targetDir, relPath);
46681
- fs14.mkdirSync(path18.dirname(fullPath), { recursive: true });
47107
+ const fullPath = path20.join(targetDir, relPath);
47108
+ fs14.mkdirSync(path20.dirname(fullPath), { recursive: true });
46682
47109
  fs14.writeFileSync(fullPath, content, "utf-8");
46683
47110
  createdFiles.push(relPath);
46684
47111
  }
@@ -46731,22 +47158,22 @@ data: ${JSON.stringify(msg.data)}
46731
47158
  if (!fs14.existsSync(scriptsDir)) return null;
46732
47159
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
46733
47160
  try {
46734
- return fs14.statSync(path18.join(scriptsDir, d)).isDirectory();
47161
+ return fs14.statSync(path20.join(scriptsDir, d)).isDirectory();
46735
47162
  } catch {
46736
47163
  return false;
46737
47164
  }
46738
47165
  }).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
46739
47166
  if (versions.length === 0) return null;
46740
- return path18.join(scriptsDir, versions[0]);
47167
+ return path20.join(scriptsDir, versions[0]);
46741
47168
  }
46742
47169
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
46743
- const canonicalUserDir = path18.resolve(this.providerLoader.getUserProviderDir(category, type));
46744
- const desiredDir = requestedDir ? path18.resolve(requestedDir) : canonicalUserDir;
46745
- const upstreamRoot = path18.resolve(this.providerLoader.getUpstreamDir());
46746
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path18.sep}`)) {
47170
+ const canonicalUserDir = path20.resolve(this.providerLoader.getUserProviderDir(category, type));
47171
+ const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
47172
+ const upstreamRoot = path20.resolve(this.providerLoader.getUpstreamDir());
47173
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
46747
47174
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
46748
47175
  }
46749
- if (path18.basename(desiredDir) !== type) {
47176
+ if (path20.basename(desiredDir) !== type) {
46750
47177
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
46751
47178
  }
46752
47179
  const sourceDir = this.findProviderDir(type);
@@ -46754,11 +47181,11 @@ data: ${JSON.stringify(msg.data)}
46754
47181
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
46755
47182
  }
46756
47183
  if (!fs14.existsSync(desiredDir)) {
46757
- fs14.mkdirSync(path18.dirname(desiredDir), { recursive: true });
47184
+ fs14.mkdirSync(path20.dirname(desiredDir), { recursive: true });
46758
47185
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
46759
47186
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
46760
47187
  }
46761
- const providerJson = path18.join(desiredDir, "provider.json");
47188
+ const providerJson = path20.join(desiredDir, "provider.json");
46762
47189
  if (!fs14.existsSync(providerJson)) {
46763
47190
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
46764
47191
  }
@@ -46806,7 +47233,7 @@ data: ${JSON.stringify(msg.data)}
46806
47233
  setMode: "set_mode.js"
46807
47234
  };
46808
47235
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
46809
- const scriptsDir = path18.join(providerDir, "scripts");
47236
+ const scriptsDir = path20.join(providerDir, "scripts");
46810
47237
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
46811
47238
  if (latestScriptsDir) {
46812
47239
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -46817,7 +47244,7 @@ data: ${JSON.stringify(msg.data)}
46817
47244
  for (const file2 of fs14.readdirSync(latestScriptsDir)) {
46818
47245
  if (file2.endsWith(".js") && targetFileNames.has(file2)) {
46819
47246
  try {
46820
- const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
47247
+ const content = fs14.readFileSync(path20.join(latestScriptsDir, file2), "utf-8");
46821
47248
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
46822
47249
  lines.push("```javascript");
46823
47250
  lines.push(content);
@@ -46834,7 +47261,7 @@ data: ${JSON.stringify(msg.data)}
46834
47261
  lines.push("");
46835
47262
  for (const file2 of refFiles) {
46836
47263
  try {
46837
- const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
47264
+ const content = fs14.readFileSync(path20.join(latestScriptsDir, file2), "utf-8");
46838
47265
  lines.push(`### \`${file2}\` \u{1F512}`);
46839
47266
  lines.push("```javascript");
46840
47267
  lines.push(content);
@@ -46875,10 +47302,10 @@ data: ${JSON.stringify(msg.data)}
46875
47302
  lines.push("");
46876
47303
  }
46877
47304
  }
46878
- const docsDir = path18.join(providerDir, "../../docs");
47305
+ const docsDir = path20.join(providerDir, "../../docs");
46879
47306
  const loadGuide = (name) => {
46880
47307
  try {
46881
- const p = path18.join(docsDir, name);
47308
+ const p = path20.join(docsDir, name);
46882
47309
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
46883
47310
  } catch {
46884
47311
  }
@@ -47052,7 +47479,7 @@ data: ${JSON.stringify(msg.data)}
47052
47479
  parseApproval: "parse_approval.js"
47053
47480
  };
47054
47481
  const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
47055
- const scriptsDir = path18.join(providerDir, "scripts");
47482
+ const scriptsDir = path20.join(providerDir, "scripts");
47056
47483
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
47057
47484
  if (latestScriptsDir) {
47058
47485
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -47064,7 +47491,7 @@ data: ${JSON.stringify(msg.data)}
47064
47491
  if (!file2.endsWith(".js")) continue;
47065
47492
  if (!targetFileNames.has(file2)) continue;
47066
47493
  try {
47067
- const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
47494
+ const content = fs14.readFileSync(path20.join(latestScriptsDir, file2), "utf-8");
47068
47495
  lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
47069
47496
  lines.push("```javascript");
47070
47497
  lines.push(content);
@@ -47080,7 +47507,7 @@ data: ${JSON.stringify(msg.data)}
47080
47507
  lines.push("");
47081
47508
  for (const file2 of refFiles) {
47082
47509
  try {
47083
- const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
47510
+ const content = fs14.readFileSync(path20.join(latestScriptsDir, file2), "utf-8");
47084
47511
  lines.push(`### \`${file2}\` \u{1F512}`);
47085
47512
  lines.push("```javascript");
47086
47513
  lines.push(content);
@@ -47113,10 +47540,10 @@ data: ${JSON.stringify(msg.data)}
47113
47540
  lines.push("");
47114
47541
  }
47115
47542
  }
47116
- const docsDir = path18.join(providerDir, "../../docs");
47543
+ const docsDir = path20.join(providerDir, "../../docs");
47117
47544
  const loadGuide = (name) => {
47118
47545
  try {
47119
- const p = path18.join(docsDir, name);
47546
+ const p = path20.join(docsDir, name);
47120
47547
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
47121
47548
  } catch {
47122
47549
  }
@@ -47292,14 +47719,14 @@ data: ${JSON.stringify(msg.data)}
47292
47719
  res.end(JSON.stringify(data, null, 2));
47293
47720
  }
47294
47721
  async readBody(req) {
47295
- return new Promise((resolve9) => {
47722
+ return new Promise((resolve12) => {
47296
47723
  let body = "";
47297
47724
  req.on("data", (chunk) => body += chunk);
47298
47725
  req.on("end", () => {
47299
47726
  try {
47300
- resolve9(JSON.parse(body));
47727
+ resolve12(JSON.parse(body));
47301
47728
  } catch {
47302
- resolve9({});
47729
+ resolve12({});
47303
47730
  }
47304
47731
  });
47305
47732
  });
@@ -47629,6 +48056,7 @@ data: ${JSON.stringify(msg.data)}
47629
48056
  }
47630
48057
  }
47631
48058
  handleEvent(event) {
48059
+ if (!("sessionId" in event)) return;
47632
48060
  if (event.sessionId !== this.options.runtimeId) return;
47633
48061
  if ((event.type === "session_started" || event.type === "session_resumed") && typeof event.pid === "number") {
47634
48062
  this.currentPid = event.pid;
@@ -47704,7 +48132,10 @@ data: ${JSON.stringify(msg.data)}
47704
48132
  clientId: client.clientId,
47705
48133
  type: client.type,
47706
48134
  readOnly: client.readOnly
47707
- }))
48135
+ })),
48136
+ restoredFromStorage: record2.meta?.restoredFromStorage === true,
48137
+ recoveryState: typeof record2.meta?.runtimeRecoveryState === "string" ? String(record2.meta.runtimeRecoveryState) : null,
48138
+ recoveryError: typeof record2.meta?.runtimeRecoveryError === "string" ? String(record2.meta.runtimeRecoveryError) : null
47708
48139
  };
47709
48140
  }
47710
48141
  enqueue(action) {
@@ -47740,11 +48171,11 @@ data: ${JSON.stringify(msg.data)}
47740
48171
  });
47741
48172
  }
47742
48173
  };
47743
- var import_session_host_core3 = require_dist();
48174
+ var import_session_host_core32 = require_dist();
47744
48175
  var STARTUP_TIMEOUT_MS = 8e3;
47745
48176
  var STARTUP_POLL_MS = 200;
47746
48177
  async function canConnect(endpoint) {
47747
- const client = new import_session_host_core3.SessionHostClient({ endpoint });
48178
+ const client = new import_session_host_core32.SessionHostClient({ endpoint });
47748
48179
  try {
47749
48180
  await client.connect();
47750
48181
  await client.close();
@@ -47757,19 +48188,19 @@ data: ${JSON.stringify(msg.data)}
47757
48188
  const deadline = Date.now() + timeoutMs;
47758
48189
  while (Date.now() < deadline) {
47759
48190
  if (await canConnect(endpoint)) return;
47760
- await new Promise((resolve9) => setTimeout(resolve9, STARTUP_POLL_MS));
48191
+ await new Promise((resolve12) => setTimeout(resolve12, STARTUP_POLL_MS));
47761
48192
  }
47762
48193
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
47763
48194
  }
47764
48195
  async function ensureSessionHostReady2(options) {
47765
- const endpoint = (0, import_session_host_core3.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
48196
+ const endpoint = (0, import_session_host_core32.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
47766
48197
  if (await canConnect(endpoint)) return endpoint;
47767
48198
  options.spawnHost();
47768
48199
  await waitForReady(endpoint, options.timeoutMs);
47769
48200
  return endpoint;
47770
48201
  }
47771
48202
  async function listHostedCliRuntimes2(endpoint) {
47772
- const client = new import_session_host_core3.SessionHostClient({ endpoint });
48203
+ const client = new import_session_host_core32.SessionHostClient({ endpoint });
47773
48204
  try {
47774
48205
  const response = await client.request({
47775
48206
  type: "list_sessions",
@@ -47911,10 +48342,10 @@ data: ${JSON.stringify(msg.data)}
47911
48342
  const buffer = Buffer.from(await res.arrayBuffer());
47912
48343
  const fs15 = await import("fs");
47913
48344
  fs15.writeFileSync(vsixPath, buffer);
47914
- return new Promise((resolve9) => {
48345
+ return new Promise((resolve12) => {
47915
48346
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
47916
48347
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
47917
- resolve9({
48348
+ resolve12({
47918
48349
  extensionId: extension.id,
47919
48350
  marketplaceId: extension.marketplaceId,
47920
48351
  success: !error48,
@@ -47927,11 +48358,11 @@ data: ${JSON.stringify(msg.data)}
47927
48358
  } catch (e) {
47928
48359
  }
47929
48360
  }
47930
- return new Promise((resolve9) => {
48361
+ return new Promise((resolve12) => {
47931
48362
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
47932
48363
  (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, stdout, stderr) => {
47933
48364
  if (error48) {
47934
- resolve9({
48365
+ resolve12({
47935
48366
  extensionId: extension.id,
47936
48367
  marketplaceId: extension.marketplaceId,
47937
48368
  success: false,
@@ -47939,7 +48370,7 @@ data: ${JSON.stringify(msg.data)}
47939
48370
  error: stderr || error48.message
47940
48371
  });
47941
48372
  } else {
47942
- resolve9({
48373
+ resolve12({
47943
48374
  extensionId: extension.id,
47944
48375
  marketplaceId: extension.marketplaceId,
47945
48376
  success: true,
@@ -48071,13 +48502,32 @@ data: ${JSON.stringify(msg.data)}
48071
48502
  const detectedIdesRef = { value: [] };
48072
48503
  let agentStreamManager = null;
48073
48504
  let poller = null;
48505
+ const refreshProviderAvailability = async (providerType) => {
48506
+ const targetProvider = providerType ? providerLoader.getMeta(providerLoader.resolveAlias(providerType)) : null;
48507
+ const targetCategory = targetProvider?.category;
48508
+ if (!providerType || targetCategory === "cli" || targetCategory === "acp") {
48509
+ if (providerType && targetProvider) {
48510
+ const detected = await detectCLI(targetProvider.type, providerLoader, { includeVersion: false });
48511
+ providerLoader.setProviderAvailability(targetProvider.type, {
48512
+ installed: !!detected,
48513
+ detectedPath: detected?.path || null
48514
+ });
48515
+ } else {
48516
+ providerLoader.setCliDetectionResults(await detectCLIs(providerLoader, { includeVersion: false }), true);
48517
+ }
48518
+ }
48519
+ if (!providerType || targetCategory === "ide") {
48520
+ detectedIdesRef.value = await detectIDEs(providerLoader);
48521
+ providerLoader.setIdeDetectionResults(detectedIdesRef.value, true);
48522
+ }
48523
+ };
48074
48524
  const cliManager = new DaemonCliManager({
48075
48525
  ...config2.cliManagerDeps,
48076
48526
  getInstanceManager: () => instanceManager,
48077
48527
  getSessionRegistry: () => sessionRegistry
48078
48528
  }, providerLoader);
48079
48529
  LOG2.info("Init", "Detecting IDEs...");
48080
- detectedIdesRef.value = await detectIDEs();
48530
+ await refreshProviderAvailability();
48081
48531
  const installed = detectedIdesRef.value.filter((i) => i.installed);
48082
48532
  LOG2.info("Init", `Found ${installed.length} IDE(s): ${installed.map((i) => i.id).join(", ") || "none"}`);
48083
48533
  const cdpSetupContext = {
@@ -48117,7 +48567,11 @@ data: ${JSON.stringify(msg.data)}
48117
48567
  adapters: cliManager.adapters,
48118
48568
  providerLoader,
48119
48569
  instanceManager,
48120
- sessionRegistry
48570
+ sessionRegistry,
48571
+ onProviderSettingChanged: async (providerType) => {
48572
+ await refreshProviderAvailability(providerType);
48573
+ config2.onStatusChange?.();
48574
+ }
48121
48575
  });
48122
48576
  agentStreamManager = new DaemonAgentStreamManager(
48123
48577
  LOG2.forComponent("AgentStream").asLogFn(),
@@ -48140,6 +48594,7 @@ data: ${JSON.stringify(msg.data)}
48140
48594
  onIdeConnected: () => poller?.start(),
48141
48595
  onStatusChange: config2.onStatusChange,
48142
48596
  onPostChatCommand: config2.onPostChatCommand,
48597
+ sessionHostControl: config2.sessionHostControl,
48143
48598
  getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG2.forComponent(`CDP:${ideType}`).asLogFn())
48144
48599
  });
48145
48600
  poller = new AgentStreamPoller({
@@ -48514,6 +48969,58 @@ var SessionHostClient = class {
48514
48969
  }
48515
48970
  };
48516
48971
 
48972
+ // src/session-host-control.ts
48973
+ var StandaloneSessionHostControlPlane = class {
48974
+ constructor(getEndpoint) {
48975
+ this.getEndpoint = getEndpoint;
48976
+ }
48977
+ async getDiagnostics(payload = {}) {
48978
+ return this.request("get_host_diagnostics", payload);
48979
+ }
48980
+ async listSessions() {
48981
+ return this.request("list_sessions", {});
48982
+ }
48983
+ async stopSession(sessionId) {
48984
+ return this.request("stop_session", { sessionId });
48985
+ }
48986
+ async resumeSession(sessionId) {
48987
+ return this.request("resume_session", { sessionId });
48988
+ }
48989
+ async restartSession(sessionId) {
48990
+ return this.request("restart_session", { sessionId });
48991
+ }
48992
+ async sendSignal(sessionId, signal) {
48993
+ return this.request("send_signal", { sessionId, signal });
48994
+ }
48995
+ async forceDetachClient(sessionId, clientId) {
48996
+ return this.request("force_detach_client", { sessionId, clientId });
48997
+ }
48998
+ async acquireWrite(payload) {
48999
+ return this.request("acquire_write", payload);
49000
+ }
49001
+ async releaseWrite(payload) {
49002
+ return this.request("release_write", payload);
49003
+ }
49004
+ async request(type, payload) {
49005
+ const endpoint = await this.getEndpoint();
49006
+ const client = new SessionHostClient({ endpoint });
49007
+ try {
49008
+ await client.connect();
49009
+ const response = await client.request({
49010
+ type,
49011
+ payload
49012
+ });
49013
+ if (!response.success) {
49014
+ throw new Error(response.error || `Session host request failed: ${type}`);
49015
+ }
49016
+ return response.result ?? null;
49017
+ } finally {
49018
+ await client.close().catch(() => {
49019
+ });
49020
+ }
49021
+ }
49022
+ };
49023
+
48517
49024
  // ../terminal-mux-control/dist/chunk-7RNMRPVZ.mjs
48518
49025
  var import_os = __toESM(require("os"), 1);
48519
49026
  var import_path = __toESM(require("path"), 1);
@@ -48773,6 +49280,9 @@ var StandaloneServer = class {
48773
49280
  const host = options.host || "127.0.0.1";
48774
49281
  const sessionHostEndpoint = await ensureSessionHostReady();
48775
49282
  this.sessionHostEndpoint = sessionHostEndpoint;
49283
+ const sessionHostControl = new StandaloneSessionHostControlPlane(
49284
+ async () => this.ensureActiveSessionHostEndpoint()
49285
+ );
48776
49286
  this.authToken = options.token || process.env.ADHDEV_TOKEN || null;
48777
49287
  this.components = await (0, import_daemon_core2.initDaemonComponents)({
48778
49288
  cliManagerDeps: {
@@ -48811,6 +49321,7 @@ var StandaloneServer = class {
48811
49321
  listHostedCliRuntimes: async () => listHostedCliRuntimes(sessionHostEndpoint)
48812
49322
  },
48813
49323
  onStatusChange: () => this.scheduleBroadcastStatus(),
49324
+ sessionHostControl,
48814
49325
  onStreamsUpdated: (ideType, streams) => {
48815
49326
  if (!this.components) return;
48816
49327
  (0, import_daemon_core2.forwardAgentStreamsToIdeInstance)(this.components.instanceManager, ideType, streams);
@@ -49149,6 +49660,7 @@ var StandaloneServer = class {
49149
49660
  `);
49150
49661
  }
49151
49662
  const writeEvent = (event) => {
49663
+ if (!("sessionId" in event)) return;
49152
49664
  if (event.sessionId !== sessionId) return;
49153
49665
  if (!this.isCliSession(sessionId)) return;
49154
49666
  res.write(`event: ${event.type}
@@ -49301,7 +49813,7 @@ var StandaloneServer = class {
49301
49813
  return { success: false, error: "command type required" };
49302
49814
  }
49303
49815
  const result = await this.components.router.execute(type, args, "standalone");
49304
- if (type.startsWith("workspace_")) this.scheduleBroadcastStatus();
49816
+ if (type.startsWith("workspace_") || type.startsWith("session_host_")) this.scheduleBroadcastStatus();
49305
49817
  return result;
49306
49818
  }
49307
49819
  scheduleBroadcastStatus() {