@adhdev/daemon-standalone 0.9.27 → 0.9.29

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
@@ -27917,6 +27917,29 @@ var require_dist2 = __commonJS({
27917
27917
  function asBoolean(value, fallback) {
27918
27918
  return typeof value === "boolean" ? value : fallback;
27919
27919
  }
27920
+ function normalizeMachineProviders(value) {
27921
+ if (!isPlainObject2(value)) return {};
27922
+ const result = {};
27923
+ for (const [providerType, raw] of Object.entries(value)) {
27924
+ if (!isPlainObject2(raw)) continue;
27925
+ const entry = {};
27926
+ if (raw.enabled === true) entry.enabled = true;
27927
+ if (typeof raw.executable === "string" && raw.executable.trim()) {
27928
+ entry.executable = raw.executable.trim();
27929
+ }
27930
+ if (Array.isArray(raw.args)) {
27931
+ entry.args = raw.args.filter((arg) => typeof arg === "string");
27932
+ }
27933
+ if (isPlainObject2(raw.lastDetection)) {
27934
+ entry.lastDetection = raw.lastDetection;
27935
+ }
27936
+ if (isPlainObject2(raw.lastVerification)) {
27937
+ entry.lastVerification = raw.lastVerification;
27938
+ }
27939
+ result[providerType] = entry;
27940
+ }
27941
+ return result;
27942
+ }
27920
27943
  function normalizeConfig(raw) {
27921
27944
  const parsed = isPlainObject2(raw) ? raw : {};
27922
27945
  return {
@@ -27937,6 +27960,7 @@ var require_dist2 = __commonJS({
27937
27960
  machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
27938
27961
  registeredMachineId: asOptionalString(parsed.registeredMachineId),
27939
27962
  providerSettings: isPlainObject2(parsed.providerSettings) ? parsed.providerSettings : {},
27963
+ machineProviders: normalizeMachineProviders(parsed.machineProviders),
27940
27964
  ideSettings: isPlainObject2(parsed.ideSettings) ? parsed.ideSettings : {},
27941
27965
  providerSourceMode: resolveProviderSourceMode(parsed.providerSourceMode, parsed.disableUpstream),
27942
27966
  providerDir: asOptionalString(parsed.providerDir),
@@ -28091,6 +28115,7 @@ var require_dist2 = __commonJS({
28091
28115
  machineSecret: null,
28092
28116
  registeredMachineId: void 0,
28093
28117
  providerSettings: {},
28118
+ machineProviders: {},
28094
28119
  ideSettings: {},
28095
28120
  providerSourceMode: "normal",
28096
28121
  terminalSizingMode: "measured"
@@ -40672,6 +40697,8 @@ ${effect.notification.body || ""}`.trim();
40672
40697
  var os12 = __toESM2(require("os"));
40673
40698
  var path12 = __toESM2(require("path"));
40674
40699
  var crypto4 = __toESM2(require("crypto"));
40700
+ var import_fs5 = require("fs");
40701
+ var import_child_process6 = require("child_process");
40675
40702
  var import_chalk = __toESM2(require("chalk"));
40676
40703
  init_provider_cli_adapter();
40677
40704
  init_config();
@@ -42727,6 +42754,27 @@ ${rawInput}` : rawInput;
42727
42754
  if (!managedBy) return true;
42728
42755
  return managedBy === managerTag;
42729
42756
  }
42757
+ function isExplicitCommand(command) {
42758
+ const trimmed = command.trim();
42759
+ return path12.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
42760
+ }
42761
+ function expandExecutable(command) {
42762
+ const trimmed = command.trim();
42763
+ return trimmed.startsWith("~") ? path12.join(os12.homedir(), trimmed.slice(1)) : trimmed;
42764
+ }
42765
+ function commandExists(command) {
42766
+ const trimmed = command.trim();
42767
+ if (!trimmed) return false;
42768
+ if (isExplicitCommand(trimmed)) {
42769
+ return (0, import_fs5.existsSync)(expandExecutable(trimmed));
42770
+ }
42771
+ try {
42772
+ (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], { stdio: "ignore" });
42773
+ return true;
42774
+ } catch {
42775
+ return false;
42776
+ }
42777
+ }
42730
42778
  var chalkModule = import_chalk.default;
42731
42779
  var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
42732
42780
  function colorize(color, text) {
@@ -42992,29 +43040,33 @@ ${rawInput}` : rawInput;
42992
43040
  if (!trimmed) throw new Error("working directory required");
42993
43041
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path12.resolve(trimmed);
42994
43042
  const normalizedType = this.providerLoader.resolveAlias(cliType);
42995
- const provider = this.providerLoader.getByAlias(cliType);
43043
+ const rawProvider = this.providerLoader.getByAlias(cliType);
43044
+ const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
43045
+ if (provider && (provider.category === "cli" || provider.category === "acp") && !this.providerLoader.isMachineProviderEnabled(normalizedType)) {
43046
+ const displayName = provider.displayName || provider.name || normalizedType;
43047
+ throw new Error(
43048
+ `${displayName} is disabled on this machine.
43049
+ Enable and detect this provider from the Machine Providers page before starting a runtime.`
43050
+ );
43051
+ }
42996
43052
  const key = crypto4.randomUUID();
42997
43053
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
42998
43054
  if (provider && provider.category === "acp") {
42999
43055
  const instanceManager2 = this.deps.getInstanceManager();
43000
43056
  if (!instanceManager2) throw new Error("InstanceManager not available");
43001
- const spawnCmd = provider.spawn?.command;
43002
- if (spawnCmd) {
43003
- try {
43004
- const { execSync: execSync7 } = require("child_process");
43005
- execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
43006
- } catch {
43007
- const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
43008
- throw new Error(
43009
- `${provider.displayName || provider.name} is not installed.
43010
- Command '${spawnCmd}' not found in PATH.
43057
+ const resolvedProvider = this.providerLoader.resolve(normalizedType) || provider;
43058
+ const spawnCmd = resolvedProvider.spawn?.command;
43059
+ if (spawnCmd && !commandExists(spawnCmd)) {
43060
+ const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
43061
+ throw new Error(
43062
+ `${provider.displayName || provider.name} is not installed.
43063
+ Command '${spawnCmd}' not found.
43011
43064
 
43012
43065
  ${installInfo}`
43013
- );
43014
- }
43066
+ );
43015
43067
  }
43016
43068
  console.log(colorize("cyan", ` \u{1F50C} Starting ACP agent: ${provider.name} (${provider.type}) in ${resolvedDir}`));
43017
- const acpInstance = new AcpProviderInstance(provider, resolvedDir, cliArgs);
43069
+ const acpInstance = new AcpProviderInstance(resolvedProvider, resolvedDir, cliArgs);
43018
43070
  await instanceManager2.addInstance(key, acpInstance, {
43019
43071
  settings: this.providerLoader.getSettings(normalizedType)
43020
43072
  });
@@ -43482,7 +43534,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
43482
43534
  return null;
43483
43535
  }
43484
43536
  };
43485
- var import_child_process6 = require("child_process");
43537
+ var import_child_process7 = require("child_process");
43486
43538
  var net3 = __toESM2(require("net"));
43487
43539
  var os14 = __toESM2(require("os"));
43488
43540
  var path14 = __toESM2(require("path"));
@@ -43947,15 +43999,18 @@ Run 'adhdev doctor' for detailed diagnostics.`
43947
43999
  getCliDetectionList() {
43948
44000
  const result = [];
43949
44001
  for (const p of this.providers.values()) {
43950
- if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
44002
+ if ((p.category === "cli" || p.category === "acp") && p.spawn?.command && this.isMachineProviderEnabled(p.type)) {
43951
44003
  const versionCommand = this.getPlatformVersionCommand(p.versionCommand);
43952
44004
  const command = this.getSpawnCommand(p.type, p.spawn.command);
44005
+ const args = this.getSpawnArgs(p.type, p.spawn.args || []);
43953
44006
  result.push({
43954
44007
  id: p.type,
43955
44008
  displayName: p.displayName || p.name,
43956
44009
  icon: p.icon || "\u{1F527}",
43957
44010
  command,
44011
+ ...args.length > 0 ? { args } : {},
43958
44012
  category: p.category,
44013
+ enabled: true,
43959
44014
  ...typeof versionCommand === "string" && versionCommand.trim() ? { versionCommand: versionCommand.trim() } : {}
43960
44015
  });
43961
44016
  }
@@ -44084,9 +44139,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
44084
44139
  return [...this.providers.values()].filter((p) => p.category === "ide" && p.cdpPorts).map((p) => p.type);
44085
44140
  }
44086
44141
  getSpawnCommand(type, fallback) {
44087
- const override = this.getOptionalStringSetting(type, "executablePath");
44088
- if (override) return override;
44089
- return fallback || this.providers.get(type)?.spawn?.command || type;
44142
+ const providerType = this.resolveAlias(type);
44143
+ const machineConfig = this.getMachineProviderConfig(providerType);
44144
+ if (machineConfig.executable) return machineConfig.executable;
44145
+ return fallback || this.providers.get(providerType)?.spawn?.command || providerType;
44090
44146
  }
44091
44147
  getIdeCliCommand(type, fallback) {
44092
44148
  const override = this.getOptionalStringSetting(type, "cliPathOverride");
@@ -44100,6 +44156,131 @@ Run 'adhdev doctor' for detailed diagnostics.`
44100
44156
  const osPaths = this.providers.get(type)?.paths?.[process.platform];
44101
44157
  return Array.isArray(osPaths) ? [...osPaths] : [];
44102
44158
  }
44159
+ isMachineProviderEnabled(type) {
44160
+ const providerType = this.resolveAlias(type);
44161
+ const config2 = this.readConfig();
44162
+ return config2?.machineProviders?.[providerType]?.enabled === true;
44163
+ }
44164
+ getMachineProviderConfig(type) {
44165
+ const providerType = this.resolveAlias(type);
44166
+ const raw = this.readConfig()?.machineProviders?.[providerType];
44167
+ if (!raw || typeof raw !== "object") return {};
44168
+ const executable = typeof raw.executable === "string" && raw.executable.trim() ? raw.executable.trim() : void 0;
44169
+ return {
44170
+ ...raw.enabled === true ? { enabled: true } : {},
44171
+ ...executable ? { executable } : {},
44172
+ ...Array.isArray(raw.args) ? { args: raw.args.filter((arg) => typeof arg === "string") } : {},
44173
+ ...raw.lastDetection && typeof raw.lastDetection === "object" ? { lastDetection: raw.lastDetection } : {},
44174
+ ...raw.lastVerification && typeof raw.lastVerification === "object" ? { lastVerification: raw.lastVerification } : {}
44175
+ };
44176
+ }
44177
+ setMachineProviderConfig(type, patch) {
44178
+ const providerType = this.resolveAlias(type);
44179
+ if (!this.providers.has(providerType)) return false;
44180
+ const config2 = this.readConfig();
44181
+ if (!config2) return false;
44182
+ try {
44183
+ if (!config2.machineProviders) config2.machineProviders = {};
44184
+ const current = config2.machineProviders[providerType] || {};
44185
+ const next = { ...current };
44186
+ const enabledChanged = "enabled" in patch && current.enabled !== (patch.enabled === true);
44187
+ const executableChanged = "executable" in patch;
44188
+ const argsChanged = "args" in patch;
44189
+ if ("enabled" in patch) next.enabled = patch.enabled === true;
44190
+ if ("executable" in patch) {
44191
+ const executable = typeof patch.executable === "string" ? patch.executable.trim() : "";
44192
+ if (executable) next.executable = executable;
44193
+ else delete next.executable;
44194
+ }
44195
+ if ("args" in patch) {
44196
+ if (Array.isArray(patch.args)) next.args = patch.args.filter((arg) => typeof arg === "string");
44197
+ else delete next.args;
44198
+ }
44199
+ if (enabledChanged || executableChanged || argsChanged) {
44200
+ delete next.lastDetection;
44201
+ delete next.lastVerification;
44202
+ }
44203
+ if ("lastDetection" in patch) {
44204
+ if (patch.lastDetection) next.lastDetection = patch.lastDetection;
44205
+ else delete next.lastDetection;
44206
+ }
44207
+ if ("lastVerification" in patch) {
44208
+ if (patch.lastVerification) next.lastVerification = patch.lastVerification;
44209
+ else delete next.lastVerification;
44210
+ }
44211
+ config2.machineProviders[providerType] = next;
44212
+ if (next.enabled !== true) {
44213
+ this.providerAvailability.set(providerType, { installed: false, detectedPath: null });
44214
+ }
44215
+ this.writeConfig(config2);
44216
+ this.log(`Machine provider config updated: ${providerType}`);
44217
+ return true;
44218
+ } catch (e) {
44219
+ this.log(`Failed to save machine provider config: ${e.message}`);
44220
+ return false;
44221
+ }
44222
+ }
44223
+ setMachineProviderEnabled(type, enabled) {
44224
+ return this.setMachineProviderConfig(type, { enabled });
44225
+ }
44226
+ getMachineProviderStatus(type) {
44227
+ const providerType = this.resolveAlias(type);
44228
+ if (!this.isMachineProviderEnabled(providerType)) return "disabled";
44229
+ const availability = this.providerAvailability.get(providerType);
44230
+ if (!availability) return "enabled_unchecked";
44231
+ return availability.installed ? "detected" : "not_detected";
44232
+ }
44233
+ getSpawnArgs(type, fallback = []) {
44234
+ const machineConfig = this.getMachineProviderConfig(type);
44235
+ if (machineConfig.args) return [...machineConfig.args];
44236
+ return [...fallback];
44237
+ }
44238
+ parseArgsSetting(value) {
44239
+ const args = [];
44240
+ let current = "";
44241
+ let quote = null;
44242
+ let escaping = false;
44243
+ for (const ch of value.trim()) {
44244
+ if (escaping) {
44245
+ current += ch;
44246
+ escaping = false;
44247
+ continue;
44248
+ }
44249
+ if (ch === "\\") {
44250
+ escaping = true;
44251
+ continue;
44252
+ }
44253
+ if (quote === "single") {
44254
+ if (ch === "'") quote = null;
44255
+ else current += ch;
44256
+ continue;
44257
+ }
44258
+ if (quote === "double") {
44259
+ if (ch === '"') quote = null;
44260
+ else current += ch;
44261
+ continue;
44262
+ }
44263
+ if (ch === "'") {
44264
+ quote = "single";
44265
+ continue;
44266
+ }
44267
+ if (ch === '"') {
44268
+ quote = "double";
44269
+ continue;
44270
+ }
44271
+ if (/\s/.test(ch)) {
44272
+ if (current) {
44273
+ args.push(current);
44274
+ current = "";
44275
+ }
44276
+ continue;
44277
+ }
44278
+ current += ch;
44279
+ }
44280
+ if (escaping) current += "\\";
44281
+ if (current) args.push(current);
44282
+ return args;
44283
+ }
44103
44284
  setProviderAvailability(type, state) {
44104
44285
  this.providerAvailability.set(type, {
44105
44286
  installed: !!state.installed,
@@ -44107,18 +44288,53 @@ Run 'adhdev doctor' for detailed diagnostics.`
44107
44288
  });
44108
44289
  }
44109
44290
  setCliDetectionResults(results, replace = true) {
44291
+ const resultByType = /* @__PURE__ */ new Map();
44292
+ for (const result of results) {
44293
+ resultByType.set(this.resolveAlias(result.id), result);
44294
+ }
44110
44295
  if (replace) {
44111
44296
  for (const provider of this.providers.values()) {
44112
44297
  if (provider.category === "cli" || provider.category === "acp") {
44113
- this.providerAvailability.set(provider.type, { installed: false, detectedPath: null });
44298
+ const result = resultByType.get(provider.type);
44299
+ const installed = !!result?.installed;
44300
+ const detectedPath = result?.path || null;
44301
+ this.providerAvailability.set(provider.type, { installed, detectedPath });
44302
+ if (this.isMachineProviderEnabled(provider.type)) {
44303
+ this.setMachineProviderConfig(provider.type, {
44304
+ lastDetection: {
44305
+ ok: installed,
44306
+ stage: "detection",
44307
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
44308
+ command: this.getSpawnCommand(provider.type, provider.spawn?.command),
44309
+ path: detectedPath,
44310
+ message: installed ? "Provider command detected" : "Provider command was not detected"
44311
+ }
44312
+ });
44313
+ }
44114
44314
  }
44115
44315
  }
44316
+ return;
44116
44317
  }
44117
44318
  for (const result of results) {
44118
- this.setProviderAvailability(result.id, {
44319
+ const providerType = this.resolveAlias(result.id);
44320
+ const provider = this.providers.get(providerType);
44321
+ const detectedPath = result.path || null;
44322
+ this.setProviderAvailability(providerType, {
44119
44323
  installed: !!result.installed,
44120
- detectedPath: result.path || null
44324
+ detectedPath
44121
44325
  });
44326
+ if (provider && (provider.category === "cli" || provider.category === "acp") && this.isMachineProviderEnabled(providerType)) {
44327
+ this.setMachineProviderConfig(providerType, {
44328
+ lastDetection: {
44329
+ ok: !!result.installed,
44330
+ stage: "detection",
44331
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
44332
+ command: this.getSpawnCommand(providerType, provider.spawn?.command),
44333
+ path: detectedPath,
44334
+ message: result.installed ? "Provider command detected" : "Provider command was not detected"
44335
+ }
44336
+ });
44337
+ }
44122
44338
  }
44123
44339
  }
44124
44340
  setIdeDetectionResults(results, replace = true) {
@@ -44139,8 +44355,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
44139
44355
  getAvailableProviderInfos() {
44140
44356
  return this.getAll().map((provider) => {
44141
44357
  const availability = this.providerAvailability.get(provider.type);
44358
+ const enabled = this.isMachineProviderEnabled(provider.type);
44359
+ const machineConfig = this.getMachineProviderConfig(provider.type);
44142
44360
  return {
44143
44361
  ...provider,
44362
+ enabled,
44363
+ machineStatus: this.getMachineProviderStatus(provider.type),
44364
+ ...machineConfig.lastDetection ? { lastDetection: machineConfig.lastDetection } : {},
44365
+ ...machineConfig.lastVerification ? { lastVerification: machineConfig.lastVerification } : {},
44144
44366
  ...availability ? {
44145
44367
  installed: availability.installed,
44146
44368
  detectedPath: availability.detectedPath
@@ -44287,6 +44509,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
44287
44509
  }
44288
44510
  }
44289
44511
  }
44512
+ if ((resolved.category === "cli" || resolved.category === "acp") && resolved.spawn?.command) {
44513
+ resolved.spawn = {
44514
+ ...resolved.spawn,
44515
+ command: this.getSpawnCommand(type, resolved.spawn.command),
44516
+ args: this.getSpawnArgs(type, resolved.spawn.args || [])
44517
+ };
44518
+ }
44290
44519
  return resolved;
44291
44520
  }
44292
44521
  /**
@@ -44609,20 +44838,33 @@ Run 'adhdev doctor' for detailed diagnostics.`
44609
44838
  * Resolved setting value for a provider (default + user override)
44610
44839
  */
44611
44840
  getSettingValue(type, key) {
44612
- const schemaDef = this.getSettingsSchema(type)[key];
44841
+ const providerType = this.resolveAlias(type);
44842
+ const machineConfig = this.getMachineProviderConfig(providerType);
44843
+ if (key === "enabled") {
44844
+ return machineConfig.enabled === true;
44845
+ }
44846
+ if (key === "executablePath") {
44847
+ return machineConfig.executable || "";
44848
+ }
44849
+ if (key === "executableArgs") {
44850
+ const args = machineConfig.args;
44851
+ return args ? args.map((arg) => /\s/.test(arg) ? JSON.stringify(arg) : arg).join(" ") : "";
44852
+ }
44853
+ const schemaDef = this.getSettingsSchema(providerType)[key];
44613
44854
  const defaultVal = schemaDef ? key === "autoApprove" && schemaDef.type === "boolean" ? true : schemaDef.default : void 0;
44614
44855
  const config2 = this.readConfig();
44615
- const userVal = config2?.providerSettings?.[type]?.[key];
44856
+ const userVal = config2?.providerSettings?.[providerType]?.[key];
44616
44857
  return userVal !== void 0 ? userVal : defaultVal;
44617
44858
  }
44618
44859
  /**
44619
44860
  * All resolved settings for a provider (default + user override)
44620
44861
  */
44621
44862
  getSettings(type) {
44622
- const settings = this.getSettingsSchema(type);
44863
+ const providerType = this.resolveAlias(type);
44864
+ const settings = this.getSettingsSchema(providerType);
44623
44865
  const result = {};
44624
44866
  for (const [key] of Object.entries(settings)) {
44625
- result[key] = this.getSettingValue(type, key);
44867
+ result[key] = this.getSettingValue(providerType, key);
44626
44868
  }
44627
44869
  return result;
44628
44870
  }
@@ -44630,7 +44872,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
44630
44872
  * Save provider setting value (writes to config.json)
44631
44873
  */
44632
44874
  setSetting(type, key, value) {
44633
- const schemaDef = this.getSettingsSchema(type)[key];
44875
+ const providerType = this.resolveAlias(type);
44876
+ const schemaDef = this.getSettingsSchema(providerType)[key];
44634
44877
  if (!schemaDef) return false;
44635
44878
  if (!schemaDef.public) return false;
44636
44879
  if (schemaDef.type === "boolean" && typeof value !== "boolean") return false;
@@ -44641,14 +44884,25 @@ Run 'adhdev doctor' for detailed diagnostics.`
44641
44884
  if (schemaDef.max !== void 0 && value > schemaDef.max) return false;
44642
44885
  }
44643
44886
  if (schemaDef.type === "select" && schemaDef.options && !schemaDef.options.includes(value)) return false;
44887
+ if (key === "enabled") {
44888
+ return this.setMachineProviderEnabled(providerType, value);
44889
+ }
44890
+ if (key === "executablePath") {
44891
+ return this.setMachineProviderConfig(providerType, { executable: value });
44892
+ }
44893
+ if (key === "executableArgs") {
44894
+ return this.setMachineProviderConfig(providerType, {
44895
+ args: value.trim() ? this.parseArgsSetting(value) : void 0
44896
+ });
44897
+ }
44644
44898
  const config2 = this.readConfig();
44645
44899
  if (!config2) return false;
44646
44900
  try {
44647
44901
  if (!config2.providerSettings) config2.providerSettings = {};
44648
- if (!config2.providerSettings[type]) config2.providerSettings[type] = {};
44649
- config2.providerSettings[type][key] = value;
44902
+ if (!config2.providerSettings[providerType]) config2.providerSettings[providerType] = {};
44903
+ config2.providerSettings[providerType][key] = value;
44650
44904
  this.writeConfig(config2);
44651
- this.log(`Setting updated: ${type}.${key} = ${JSON.stringify(value)}`);
44905
+ this.log(`Setting updated: ${providerType}.${key} = ${JSON.stringify(value)}`);
44652
44906
  return true;
44653
44907
  } catch (e) {
44654
44908
  this.log(`Failed to save setting: ${e.message}`);
@@ -44709,6 +44963,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
44709
44963
  }
44710
44964
  getSyntheticSettings(type, provider) {
44711
44965
  const result = {};
44966
+ if (provider.category === "cli" || provider.category === "acp") {
44967
+ result.enabled = {
44968
+ type: "boolean",
44969
+ default: false,
44970
+ public: true,
44971
+ label: "Enabled on this machine",
44972
+ description: "Opt in before ADHDev detects, launches, or verifies this provider on this machine."
44973
+ };
44974
+ }
44712
44975
  if (!provider.settings?.autoApprove) {
44713
44976
  result.autoApprove = {
44714
44977
  type: "boolean",
@@ -44727,6 +44990,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
44727
44990
  description: "Optional absolute path for this provider binary. Leave blank to use the default PATH lookup."
44728
44991
  };
44729
44992
  }
44993
+ if ((provider.category === "cli" || provider.category === "acp") && provider.spawn?.command && !provider.settings?.executableArgs) {
44994
+ result.executableArgs = {
44995
+ type: "string",
44996
+ default: "",
44997
+ public: true,
44998
+ label: "Executable arguments",
44999
+ description: "Optional replacement for provider default command arguments. Leave blank to use the provider default."
45000
+ };
45001
+ }
44730
45002
  if (provider.category === "ide") {
44731
45003
  if (provider.cli && !provider.settings?.cliPathOverride) {
44732
45004
  result.cliPathOverride = {
@@ -45043,32 +45315,32 @@ Run 'adhdev doctor' for detailed diagnostics.`
45043
45315
  try {
45044
45316
  if (plat === "darwin" && appName) {
45045
45317
  try {
45046
- (0, import_child_process6.execSync)(`osascript -e 'tell application "${escapeForAppleScript(appName)}" to quit' 2>/dev/null`, {
45318
+ (0, import_child_process7.execSync)(`osascript -e 'tell application "${escapeForAppleScript(appName)}" to quit' 2>/dev/null`, {
45047
45319
  timeout: 5e3
45048
45320
  });
45049
45321
  } catch {
45050
45322
  try {
45051
- (0, import_child_process6.execSync)(`pkill -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
45323
+ (0, import_child_process7.execSync)(`pkill -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
45052
45324
  } catch {
45053
45325
  }
45054
45326
  }
45055
45327
  } else if (plat === "win32" && winProcesses) {
45056
45328
  for (const proc of winProcesses) {
45057
45329
  try {
45058
- (0, import_child_process6.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
45330
+ (0, import_child_process7.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
45059
45331
  } catch {
45060
45332
  }
45061
45333
  }
45062
45334
  try {
45063
45335
  const exeName = winProcesses[0].replace(".exe", "");
45064
- (0, import_child_process6.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
45336
+ (0, import_child_process7.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
45065
45337
  timeout: 1e4
45066
45338
  });
45067
45339
  } catch {
45068
45340
  }
45069
45341
  } else {
45070
45342
  try {
45071
- (0, import_child_process6.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
45343
+ (0, import_child_process7.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
45072
45344
  } catch {
45073
45345
  }
45074
45346
  }
@@ -45078,13 +45350,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
45078
45350
  }
45079
45351
  if (plat === "darwin" && appName) {
45080
45352
  try {
45081
- (0, import_child_process6.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
45353
+ (0, import_child_process7.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
45082
45354
  } catch {
45083
45355
  }
45084
45356
  } else if (plat === "win32" && winProcesses) {
45085
45357
  for (const proc of winProcesses) {
45086
45358
  try {
45087
- (0, import_child_process6.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
45359
+ (0, import_child_process7.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
45088
45360
  } catch {
45089
45361
  }
45090
45362
  }
@@ -45102,13 +45374,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
45102
45374
  const appName = getMacAppIdentifiers()[ideId];
45103
45375
  if (!appName) return false;
45104
45376
  try {
45105
- const result = (0, import_child_process6.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
45377
+ const result = (0, import_child_process7.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
45106
45378
  encoding: "utf-8",
45107
45379
  timeout: 3e3
45108
45380
  });
45109
45381
  return result.trim().length > 0;
45110
45382
  } catch {
45111
- const result = (0, import_child_process6.execSync)(
45383
+ const result = (0, import_child_process7.execSync)(
45112
45384
  `osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
45113
45385
  {
45114
45386
  encoding: "utf-8",
@@ -45123,14 +45395,14 @@ Run 'adhdev doctor' for detailed diagnostics.`
45123
45395
  if (!winProcesses) return false;
45124
45396
  for (const proc of winProcesses) {
45125
45397
  try {
45126
- const result = (0, import_child_process6.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
45398
+ const result = (0, import_child_process7.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
45127
45399
  if (result.includes(proc)) return true;
45128
45400
  } catch {
45129
45401
  }
45130
45402
  }
45131
45403
  try {
45132
45404
  const exeName = winProcesses[0].replace(".exe", "");
45133
- const result = (0, import_child_process6.execSync)(
45405
+ const result = (0, import_child_process7.execSync)(
45134
45406
  `powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
45135
45407
  { encoding: "utf-8", timeout: 5e3 }
45136
45408
  );
@@ -45139,7 +45411,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
45139
45411
  }
45140
45412
  return false;
45141
45413
  } else {
45142
- const result = (0, import_child_process6.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
45414
+ const result = (0, import_child_process7.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
45143
45415
  return result.trim().length > 0;
45144
45416
  }
45145
45417
  } catch {
@@ -45152,7 +45424,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
45152
45424
  try {
45153
45425
  const appName = getMacAppIdentifiers()[ideId];
45154
45426
  if (!appName) return void 0;
45155
- const result = (0, import_child_process6.execSync)(
45427
+ const result = (0, import_child_process7.execSync)(
45156
45428
  `lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
45157
45429
  { encoding: "utf-8", timeout: 3e3 }
45158
45430
  );
@@ -45304,10 +45576,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
45304
45576
  const canUseAppLauncher = !!appName;
45305
45577
  const useAppLauncher = preferredMethod === "app" ? canUseAppLauncher : preferredMethod === "cli" ? false : !canUseCli && canUseAppLauncher;
45306
45578
  if (!useAppLauncher && ide.cliCommand) {
45307
- (0, import_child_process6.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
45579
+ (0, import_child_process7.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
45308
45580
  } else if (appName) {
45309
45581
  const openArgs = ["-a", appName, "--args", ...args];
45310
- (0, import_child_process6.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
45582
+ (0, import_child_process7.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
45311
45583
  } else {
45312
45584
  throw new Error(`No app identifier or CLI for ${ide.displayName}`);
45313
45585
  }
@@ -45333,7 +45605,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
45333
45605
  const args = ["--remote-debugging-port=" + port];
45334
45606
  if (newWindow) args.push("--new-window");
45335
45607
  if (workspace) args.push(workspace);
45336
- (0, import_child_process6.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
45608
+ (0, import_child_process7.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
45337
45609
  }
45338
45610
  function getAvailableIdeIds() {
45339
45611
  return getProviderLoader().getAvailableIdeTypes();
@@ -45783,8 +46055,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
45783
46055
  }
45784
46056
  };
45785
46057
  }
45786
- var import_child_process7 = require("child_process");
45787
46058
  var import_child_process8 = require("child_process");
46059
+ var import_child_process9 = require("child_process");
45788
46060
  var fs8 = __toESM2(require("fs"));
45789
46061
  var os17 = __toESM2(require("os"));
45790
46062
  var path16 = __toESM2(require("path"));
@@ -45885,7 +46157,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
45885
46157
  function killPid2(pid) {
45886
46158
  try {
45887
46159
  if (process.platform === "win32") {
45888
- (0, import_child_process7.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
46160
+ (0, import_child_process8.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
45889
46161
  } else {
45890
46162
  process.kill(pid, "SIGTERM");
45891
46163
  }
@@ -45923,7 +46195,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
45923
46195
  }
45924
46196
  if (process.platform !== "win32") {
45925
46197
  try {
45926
- const raw = (0, import_child_process7.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
46198
+ const raw = (0, import_child_process8.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
45927
46199
  for (const line of raw.split("\n")) {
45928
46200
  const pid = Number.parseInt(line.trim(), 10);
45929
46201
  if (Number.isFinite(pid)) {
@@ -45944,9 +46216,9 @@ Run 'adhdev doctor' for detailed diagnostics.`
45944
46216
  function cleanupStaleGlobalInstallDirs(pkgName, surface) {
45945
46217
  const npmExecOpts = getNpmExecOptions();
45946
46218
  const prefixArgs = surface.installPrefix ? ["--prefix", surface.installPrefix] : [];
45947
- const npmRoot = (0, import_child_process7.execFileSync)(surface.npmExecutable, ["root", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
46219
+ const npmRoot = (0, import_child_process8.execFileSync)(surface.npmExecutable, ["root", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
45948
46220
  if (!npmRoot) return;
45949
- const npmPrefix = surface.installPrefix || (0, import_child_process7.execFileSync)(surface.npmExecutable, ["prefix", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
46221
+ const npmPrefix = surface.installPrefix || (0, import_child_process8.execFileSync)(surface.npmExecutable, ["prefix", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
45950
46222
  const binDir = process.platform === "win32" ? npmPrefix : path16.join(npmPrefix, "bin");
45951
46223
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
45952
46224
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
@@ -45979,7 +46251,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
45979
46251
  }
45980
46252
  function spawnDetachedDaemonUpgradeHelper(payload) {
45981
46253
  const env = { ...process.env, [UPGRADE_HELPER_ENV]: JSON.stringify(payload) };
45982
- const child = (0, import_child_process8.spawn)(process.execPath, process.argv.slice(1), {
46254
+ const child = (0, import_child_process9.spawn)(process.execPath, process.argv.slice(1), {
45983
46255
  detached: true,
45984
46256
  stdio: "ignore",
45985
46257
  windowsHide: true,
@@ -46009,7 +46281,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
46009
46281
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
46010
46282
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
46011
46283
  appendUpgradeLog(`Installing ${spec}`);
46012
- const installOutput = (0, import_child_process7.execFileSync)(
46284
+ const installOutput = (0, import_child_process8.execFileSync)(
46013
46285
  installCommand.command,
46014
46286
  installCommand.args,
46015
46287
  {
@@ -46031,7 +46303,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
46031
46303
  const env = { ...process.env };
46032
46304
  delete env[UPGRADE_HELPER_ENV];
46033
46305
  appendUpgradeLog(`Restarting daemon with args: ${restartArgv.join(" ")}`);
46034
- const child = (0, import_child_process8.spawn)(process.execPath, restartArgv, {
46306
+ const child = (0, import_child_process9.spawn)(process.execPath, restartArgv, {
46035
46307
  detached: true,
46036
46308
  stdio: "ignore",
46037
46309
  windowsHide: true,
@@ -46564,6 +46836,33 @@ Run 'adhdev doctor' for detailed diagnostics.`
46564
46836
  }
46565
46837
  return { ...result };
46566
46838
  }
46839
+ // ─── Detect providers ───
46840
+ case "detect_provider": {
46841
+ const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : "";
46842
+ if (!providerType) return { success: false, error: "providerType is required" };
46843
+ const normalizedType = this.deps.providerLoader.resolveAlias(providerType);
46844
+ const provider = this.deps.providerLoader.getByAlias(providerType);
46845
+ if (!provider) return { success: false, error: `Provider not found: ${providerType}` };
46846
+ if (provider.category !== "cli" && provider.category !== "acp") {
46847
+ return { success: false, error: `Provider detection is only supported for CLI/ACP providers: ${providerType}` };
46848
+ }
46849
+ if (!this.deps.providerLoader.isMachineProviderEnabled(normalizedType)) {
46850
+ return { success: false, error: `Provider is disabled on this machine: ${providerType}` };
46851
+ }
46852
+ const detected = await detectCLI(normalizedType, this.deps.providerLoader, { includeVersion: false });
46853
+ this.deps.providerLoader.setCliDetectionResults([{
46854
+ id: normalizedType,
46855
+ installed: !!detected,
46856
+ path: detected?.path
46857
+ }], false);
46858
+ this.deps.onStatusChange?.();
46859
+ return {
46860
+ success: true,
46861
+ providerType: normalizedType,
46862
+ detected: !!detected,
46863
+ path: detected?.path || null
46864
+ };
46865
+ }
46567
46866
  // ─── Detect IDEs ───
46568
46867
  case "detect_ides": {
46569
46868
  const results = await detectIDEs(this.deps.providerLoader);
@@ -46609,13 +46908,16 @@ Run 'adhdev doctor' for detailed diagnostics.`
46609
46908
  this.deps.cdpManagers
46610
46909
  );
46611
46910
  const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
46612
- const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
46911
+ const requestedCompletionMarker = typeof args?.completionMarker === "string" ? args.completionMarker.trim() : "";
46912
+ const completionMarker = requestedCompletionMarker || (targetSession ? getSessionCompletionMarker(targetSession) : "");
46913
+ const requestedProviderSessionId = typeof args?.providerSessionId === "string" ? args.providerSessionId.trim() : "";
46914
+ const providerSessionId = requestedProviderSessionId || targetSession?.providerSessionId;
46613
46915
  const next = markSessionSeen(
46614
46916
  currentState,
46615
46917
  sessionId,
46616
46918
  typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
46617
46919
  completionMarker,
46618
- targetSession?.providerSessionId
46920
+ providerSessionId
46619
46921
  );
46620
46922
  if (READ_DEBUG_ENABLED2) {
46621
46923
  LOG2.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
@@ -48312,7 +48614,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
48312
48614
  var fs10 = __toESM2(require("fs"));
48313
48615
  var path17 = __toESM2(require("path"));
48314
48616
  var os18 = __toESM2(require("os"));
48315
- var import_child_process9 = require("child_process");
48617
+ var import_child_process10 = require("child_process");
48316
48618
  var import_os3 = require("os");
48317
48619
  var ARCHIVE_PATH = path17.join(os18.homedir(), ".adhdev", "version-history.json");
48318
48620
  var MAX_ENTRIES_PER_PROVIDER = 20;
@@ -48369,7 +48671,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
48369
48671
  };
48370
48672
  function runCommand(cmd, timeout = 1e4) {
48371
48673
  try {
48372
- return (0, import_child_process9.execSync)(cmd, {
48674
+ return (0, import_child_process10.execSync)(cmd, {
48373
48675
  encoding: "utf-8",
48374
48676
  timeout,
48375
48677
  stdio: ["pipe", "pipe", "pipe"]
@@ -54129,7 +54431,7 @@ data: ${JSON.stringify(msg.data)}
54129
54431
  if (raw === "0" || raw === "false" || raw === "no") return false;
54130
54432
  return raw === "1" || raw === "true" || raw === "yes";
54131
54433
  }
54132
- var import_child_process10 = require("child_process");
54434
+ var import_child_process11 = require("child_process");
54133
54435
  var EXTENSION_CATALOG = [
54134
54436
  // AI Agent extensions
54135
54437
  {
@@ -54219,7 +54521,7 @@ data: ${JSON.stringify(msg.data)}
54219
54521
  function isExtensionInstalled(ide, marketplaceId) {
54220
54522
  if (!ide.cliCommand) return false;
54221
54523
  try {
54222
- const result = (0, import_child_process10.execSync)(`"${ide.cliCommand}" --list-extensions`, {
54524
+ const result = (0, import_child_process11.execSync)(`"${ide.cliCommand}" --list-extensions`, {
54223
54525
  encoding: "utf-8",
54224
54526
  timeout: 15e3,
54225
54527
  stdio: ["pipe", "pipe", "pipe"]
@@ -54260,7 +54562,7 @@ data: ${JSON.stringify(msg.data)}
54260
54562
  fs15.writeFileSync(vsixPath, buffer);
54261
54563
  return new Promise((resolve12) => {
54262
54564
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
54263
- (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
54565
+ (0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
54264
54566
  resolve12({
54265
54567
  extensionId: extension.id,
54266
54568
  marketplaceId: extension.marketplaceId,
@@ -54276,7 +54578,7 @@ data: ${JSON.stringify(msg.data)}
54276
54578
  }
54277
54579
  return new Promise((resolve12) => {
54278
54580
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
54279
- (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, stdout, stderr) => {
54581
+ (0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error48, stdout, stderr) => {
54280
54582
  if (error48) {
54281
54583
  resolve12({
54282
54584
  extensionId: extension.id,
@@ -54313,7 +54615,7 @@ data: ${JSON.stringify(msg.data)}
54313
54615
  if (!ide.cliCommand) return false;
54314
54616
  try {
54315
54617
  const args = workspacePath ? `"${workspacePath}"` : "";
54316
- (0, import_child_process10.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
54618
+ (0, import_child_process11.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
54317
54619
  return true;
54318
54620
  } catch {
54319
54621
  return false;
@@ -54425,10 +54727,11 @@ data: ${JSON.stringify(msg.data)}
54425
54727
  if (!providerType || targetCategory === "cli" || targetCategory === "acp") {
54426
54728
  if (providerType && targetProvider) {
54427
54729
  const detected = await detectCLI(targetProvider.type, providerLoader, { includeVersion: false });
54428
- providerLoader.setProviderAvailability(targetProvider.type, {
54730
+ providerLoader.setCliDetectionResults([{
54731
+ id: targetProvider.type,
54429
54732
  installed: !!detected,
54430
- detectedPath: detected?.path || null
54431
- });
54733
+ path: detected?.path
54734
+ }], false);
54432
54735
  } else {
54433
54736
  providerLoader.setCliDetectionResults(await detectCLIs(providerLoader, { includeVersion: false }), true);
54434
54737
  }
@@ -55936,9 +56239,12 @@ var StandaloneServer = class {
55936
56239
  void (async () => {
55937
56240
  const client = await this.createSessionHostClient();
55938
56241
  try {
56242
+ const sinceSeqParam = parsedUrl.searchParams.get("sinceSeq");
56243
+ const sinceSeqValue = sinceSeqParam === null ? void 0 : Number(sinceSeqParam);
56244
+ const sinceSeq = typeof sinceSeqValue === "number" && Number.isFinite(sinceSeqValue) ? sinceSeqValue : void 0;
55939
56245
  const snapshot = await client.request({
55940
56246
  type: "get_snapshot",
55941
- payload: { sessionId }
56247
+ payload: { sessionId, sinceSeq }
55942
56248
  });
55943
56249
  if (!snapshot.success || !snapshot.result) {
55944
56250
  res.writeHead(404, { "Content-Type": "application/json" });