@adhdev/daemon-core 0.9.28 → 0.9.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -66,6 +66,29 @@ function asOptionalString(value) {
66
66
  function asBoolean(value, fallback) {
67
67
  return typeof value === "boolean" ? value : fallback;
68
68
  }
69
+ function normalizeMachineProviders(value) {
70
+ if (!isPlainObject(value)) return {};
71
+ const result = {};
72
+ for (const [providerType, raw] of Object.entries(value)) {
73
+ if (!isPlainObject(raw)) continue;
74
+ const entry = {};
75
+ if (raw.enabled === true) entry.enabled = true;
76
+ if (typeof raw.executable === "string" && raw.executable.trim()) {
77
+ entry.executable = raw.executable.trim();
78
+ }
79
+ if (Array.isArray(raw.args)) {
80
+ entry.args = raw.args.filter((arg) => typeof arg === "string");
81
+ }
82
+ if (isPlainObject(raw.lastDetection)) {
83
+ entry.lastDetection = raw.lastDetection;
84
+ }
85
+ if (isPlainObject(raw.lastVerification)) {
86
+ entry.lastVerification = raw.lastVerification;
87
+ }
88
+ result[providerType] = entry;
89
+ }
90
+ return result;
91
+ }
69
92
  function normalizeConfig(raw) {
70
93
  const parsed = isPlainObject(raw) ? raw : {};
71
94
  return {
@@ -86,6 +109,7 @@ function normalizeConfig(raw) {
86
109
  machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
87
110
  registeredMachineId: asOptionalString(parsed.registeredMachineId),
88
111
  providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
112
+ machineProviders: normalizeMachineProviders(parsed.machineProviders),
89
113
  ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
90
114
  providerSourceMode: resolveProviderSourceMode(parsed.providerSourceMode, parsed.disableUpstream),
91
115
  providerDir: asOptionalString(parsed.providerDir),
@@ -235,6 +259,7 @@ var init_config = __esm({
235
259
  machineSecret: null,
236
260
  registeredMachineId: void 0,
237
261
  providerSettings: {},
262
+ machineProviders: {},
238
263
  ideSettings: {},
239
264
  providerSourceMode: "normal",
240
265
  terminalSizingMode: "measured"
@@ -12905,6 +12930,8 @@ var DaemonCommandHandler = class {
12905
12930
  var os12 = __toESM(require("os"));
12906
12931
  var path12 = __toESM(require("path"));
12907
12932
  var crypto4 = __toESM(require("crypto"));
12933
+ var import_fs5 = require("fs");
12934
+ var import_child_process6 = require("child_process");
12908
12935
  var import_chalk = __toESM(require("chalk"));
12909
12936
  init_provider_cli_adapter();
12910
12937
  init_config();
@@ -14974,6 +15001,27 @@ function shouldRestoreHostedRuntime(record, managerTag) {
14974
15001
  }
14975
15002
 
14976
15003
  // src/commands/cli-manager.ts
15004
+ function isExplicitCommand(command) {
15005
+ const trimmed = command.trim();
15006
+ return path12.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
15007
+ }
15008
+ function expandExecutable(command) {
15009
+ const trimmed = command.trim();
15010
+ return trimmed.startsWith("~") ? path12.join(os12.homedir(), trimmed.slice(1)) : trimmed;
15011
+ }
15012
+ function commandExists(command) {
15013
+ const trimmed = command.trim();
15014
+ if (!trimmed) return false;
15015
+ if (isExplicitCommand(trimmed)) {
15016
+ return (0, import_fs5.existsSync)(expandExecutable(trimmed));
15017
+ }
15018
+ try {
15019
+ (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], { stdio: "ignore" });
15020
+ return true;
15021
+ } catch {
15022
+ return false;
15023
+ }
15024
+ }
14977
15025
  var chalkModule = import_chalk.default;
14978
15026
  var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
14979
15027
  function colorize(color, text) {
@@ -15239,29 +15287,33 @@ var DaemonCliManager = class {
15239
15287
  if (!trimmed) throw new Error("working directory required");
15240
15288
  const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path12.resolve(trimmed);
15241
15289
  const normalizedType = this.providerLoader.resolveAlias(cliType);
15242
- const provider = this.providerLoader.getByAlias(cliType);
15290
+ const rawProvider = this.providerLoader.getByAlias(cliType);
15291
+ const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
15292
+ if (provider && (provider.category === "cli" || provider.category === "acp") && !this.providerLoader.isMachineProviderEnabled(normalizedType)) {
15293
+ const displayName = provider.displayName || provider.name || normalizedType;
15294
+ throw new Error(
15295
+ `${displayName} is disabled on this machine.
15296
+ Enable and detect this provider from the Machine Providers page before starting a runtime.`
15297
+ );
15298
+ }
15243
15299
  const key = crypto4.randomUUID();
15244
15300
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
15245
15301
  if (provider && provider.category === "acp") {
15246
15302
  const instanceManager2 = this.deps.getInstanceManager();
15247
15303
  if (!instanceManager2) throw new Error("InstanceManager not available");
15248
- const spawnCmd = provider.spawn?.command;
15249
- if (spawnCmd) {
15250
- try {
15251
- const { execSync: execSync7 } = require("child_process");
15252
- execSync7(`which ${spawnCmd}`, { stdio: "ignore" });
15253
- } catch {
15254
- const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
15255
- throw new Error(
15256
- `${provider.displayName || provider.name} is not installed.
15257
- Command '${spawnCmd}' not found in PATH.
15304
+ const resolvedProvider = this.providerLoader.resolve(normalizedType) || provider;
15305
+ const spawnCmd = resolvedProvider.spawn?.command;
15306
+ if (spawnCmd && !commandExists(spawnCmd)) {
15307
+ const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
15308
+ throw new Error(
15309
+ `${provider.displayName || provider.name} is not installed.
15310
+ Command '${spawnCmd}' not found.
15258
15311
 
15259
15312
  ${installInfo}`
15260
- );
15261
- }
15313
+ );
15262
15314
  }
15263
15315
  console.log(colorize("cyan", ` \u{1F50C} Starting ACP agent: ${provider.name} (${provider.type}) in ${resolvedDir}`));
15264
- const acpInstance = new AcpProviderInstance(provider, resolvedDir, cliArgs);
15316
+ const acpInstance = new AcpProviderInstance(resolvedProvider, resolvedDir, cliArgs);
15265
15317
  await instanceManager2.addInstance(key, acpInstance, {
15266
15318
  settings: this.providerLoader.getSettings(normalizedType)
15267
15319
  });
@@ -15731,7 +15783,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
15731
15783
  };
15732
15784
 
15733
15785
  // src/launch.ts
15734
- var import_child_process6 = require("child_process");
15786
+ var import_child_process7 = require("child_process");
15735
15787
  var net = __toESM(require("net"));
15736
15788
  var os14 = __toESM(require("os"));
15737
15789
  var path14 = __toESM(require("path"));
@@ -16202,15 +16254,18 @@ var ProviderLoader = class _ProviderLoader {
16202
16254
  getCliDetectionList() {
16203
16255
  const result = [];
16204
16256
  for (const p of this.providers.values()) {
16205
- if ((p.category === "cli" || p.category === "acp") && p.spawn?.command) {
16257
+ if ((p.category === "cli" || p.category === "acp") && p.spawn?.command && this.isMachineProviderEnabled(p.type)) {
16206
16258
  const versionCommand = this.getPlatformVersionCommand(p.versionCommand);
16207
16259
  const command = this.getSpawnCommand(p.type, p.spawn.command);
16260
+ const args = this.getSpawnArgs(p.type, p.spawn.args || []);
16208
16261
  result.push({
16209
16262
  id: p.type,
16210
16263
  displayName: p.displayName || p.name,
16211
16264
  icon: p.icon || "\u{1F527}",
16212
16265
  command,
16266
+ ...args.length > 0 ? { args } : {},
16213
16267
  category: p.category,
16268
+ enabled: true,
16214
16269
  ...typeof versionCommand === "string" && versionCommand.trim() ? { versionCommand: versionCommand.trim() } : {}
16215
16270
  });
16216
16271
  }
@@ -16339,9 +16394,10 @@ var ProviderLoader = class _ProviderLoader {
16339
16394
  return [...this.providers.values()].filter((p) => p.category === "ide" && p.cdpPorts).map((p) => p.type);
16340
16395
  }
16341
16396
  getSpawnCommand(type, fallback) {
16342
- const override = this.getOptionalStringSetting(type, "executablePath");
16343
- if (override) return override;
16344
- return fallback || this.providers.get(type)?.spawn?.command || type;
16397
+ const providerType = this.resolveAlias(type);
16398
+ const machineConfig = this.getMachineProviderConfig(providerType);
16399
+ if (machineConfig.executable) return machineConfig.executable;
16400
+ return fallback || this.providers.get(providerType)?.spawn?.command || providerType;
16345
16401
  }
16346
16402
  getIdeCliCommand(type, fallback) {
16347
16403
  const override = this.getOptionalStringSetting(type, "cliPathOverride");
@@ -16355,6 +16411,131 @@ var ProviderLoader = class _ProviderLoader {
16355
16411
  const osPaths = this.providers.get(type)?.paths?.[process.platform];
16356
16412
  return Array.isArray(osPaths) ? [...osPaths] : [];
16357
16413
  }
16414
+ isMachineProviderEnabled(type) {
16415
+ const providerType = this.resolveAlias(type);
16416
+ const config = this.readConfig();
16417
+ return config?.machineProviders?.[providerType]?.enabled === true;
16418
+ }
16419
+ getMachineProviderConfig(type) {
16420
+ const providerType = this.resolveAlias(type);
16421
+ const raw = this.readConfig()?.machineProviders?.[providerType];
16422
+ if (!raw || typeof raw !== "object") return {};
16423
+ const executable = typeof raw.executable === "string" && raw.executable.trim() ? raw.executable.trim() : void 0;
16424
+ return {
16425
+ ...raw.enabled === true ? { enabled: true } : {},
16426
+ ...executable ? { executable } : {},
16427
+ ...Array.isArray(raw.args) ? { args: raw.args.filter((arg) => typeof arg === "string") } : {},
16428
+ ...raw.lastDetection && typeof raw.lastDetection === "object" ? { lastDetection: raw.lastDetection } : {},
16429
+ ...raw.lastVerification && typeof raw.lastVerification === "object" ? { lastVerification: raw.lastVerification } : {}
16430
+ };
16431
+ }
16432
+ setMachineProviderConfig(type, patch) {
16433
+ const providerType = this.resolveAlias(type);
16434
+ if (!this.providers.has(providerType)) return false;
16435
+ const config = this.readConfig();
16436
+ if (!config) return false;
16437
+ try {
16438
+ if (!config.machineProviders) config.machineProviders = {};
16439
+ const current = config.machineProviders[providerType] || {};
16440
+ const next = { ...current };
16441
+ const enabledChanged = "enabled" in patch && current.enabled !== (patch.enabled === true);
16442
+ const executableChanged = "executable" in patch;
16443
+ const argsChanged = "args" in patch;
16444
+ if ("enabled" in patch) next.enabled = patch.enabled === true;
16445
+ if ("executable" in patch) {
16446
+ const executable = typeof patch.executable === "string" ? patch.executable.trim() : "";
16447
+ if (executable) next.executable = executable;
16448
+ else delete next.executable;
16449
+ }
16450
+ if ("args" in patch) {
16451
+ if (Array.isArray(patch.args)) next.args = patch.args.filter((arg) => typeof arg === "string");
16452
+ else delete next.args;
16453
+ }
16454
+ if (enabledChanged || executableChanged || argsChanged) {
16455
+ delete next.lastDetection;
16456
+ delete next.lastVerification;
16457
+ }
16458
+ if ("lastDetection" in patch) {
16459
+ if (patch.lastDetection) next.lastDetection = patch.lastDetection;
16460
+ else delete next.lastDetection;
16461
+ }
16462
+ if ("lastVerification" in patch) {
16463
+ if (patch.lastVerification) next.lastVerification = patch.lastVerification;
16464
+ else delete next.lastVerification;
16465
+ }
16466
+ config.machineProviders[providerType] = next;
16467
+ if (next.enabled !== true) {
16468
+ this.providerAvailability.set(providerType, { installed: false, detectedPath: null });
16469
+ }
16470
+ this.writeConfig(config);
16471
+ this.log(`Machine provider config updated: ${providerType}`);
16472
+ return true;
16473
+ } catch (e) {
16474
+ this.log(`Failed to save machine provider config: ${e.message}`);
16475
+ return false;
16476
+ }
16477
+ }
16478
+ setMachineProviderEnabled(type, enabled) {
16479
+ return this.setMachineProviderConfig(type, { enabled });
16480
+ }
16481
+ getMachineProviderStatus(type) {
16482
+ const providerType = this.resolveAlias(type);
16483
+ if (!this.isMachineProviderEnabled(providerType)) return "disabled";
16484
+ const availability = this.providerAvailability.get(providerType);
16485
+ if (!availability) return "enabled_unchecked";
16486
+ return availability.installed ? "detected" : "not_detected";
16487
+ }
16488
+ getSpawnArgs(type, fallback = []) {
16489
+ const machineConfig = this.getMachineProviderConfig(type);
16490
+ if (machineConfig.args) return [...machineConfig.args];
16491
+ return [...fallback];
16492
+ }
16493
+ parseArgsSetting(value) {
16494
+ const args = [];
16495
+ let current = "";
16496
+ let quote = null;
16497
+ let escaping = false;
16498
+ for (const ch of value.trim()) {
16499
+ if (escaping) {
16500
+ current += ch;
16501
+ escaping = false;
16502
+ continue;
16503
+ }
16504
+ if (ch === "\\") {
16505
+ escaping = true;
16506
+ continue;
16507
+ }
16508
+ if (quote === "single") {
16509
+ if (ch === "'") quote = null;
16510
+ else current += ch;
16511
+ continue;
16512
+ }
16513
+ if (quote === "double") {
16514
+ if (ch === '"') quote = null;
16515
+ else current += ch;
16516
+ continue;
16517
+ }
16518
+ if (ch === "'") {
16519
+ quote = "single";
16520
+ continue;
16521
+ }
16522
+ if (ch === '"') {
16523
+ quote = "double";
16524
+ continue;
16525
+ }
16526
+ if (/\s/.test(ch)) {
16527
+ if (current) {
16528
+ args.push(current);
16529
+ current = "";
16530
+ }
16531
+ continue;
16532
+ }
16533
+ current += ch;
16534
+ }
16535
+ if (escaping) current += "\\";
16536
+ if (current) args.push(current);
16537
+ return args;
16538
+ }
16358
16539
  setProviderAvailability(type, state) {
16359
16540
  this.providerAvailability.set(type, {
16360
16541
  installed: !!state.installed,
@@ -16362,18 +16543,53 @@ var ProviderLoader = class _ProviderLoader {
16362
16543
  });
16363
16544
  }
16364
16545
  setCliDetectionResults(results, replace = true) {
16546
+ const resultByType = /* @__PURE__ */ new Map();
16547
+ for (const result of results) {
16548
+ resultByType.set(this.resolveAlias(result.id), result);
16549
+ }
16365
16550
  if (replace) {
16366
16551
  for (const provider of this.providers.values()) {
16367
16552
  if (provider.category === "cli" || provider.category === "acp") {
16368
- this.providerAvailability.set(provider.type, { installed: false, detectedPath: null });
16553
+ const result = resultByType.get(provider.type);
16554
+ const installed = !!result?.installed;
16555
+ const detectedPath = result?.path || null;
16556
+ this.providerAvailability.set(provider.type, { installed, detectedPath });
16557
+ if (this.isMachineProviderEnabled(provider.type)) {
16558
+ this.setMachineProviderConfig(provider.type, {
16559
+ lastDetection: {
16560
+ ok: installed,
16561
+ stage: "detection",
16562
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
16563
+ command: this.getSpawnCommand(provider.type, provider.spawn?.command),
16564
+ path: detectedPath,
16565
+ message: installed ? "Provider command detected" : "Provider command was not detected"
16566
+ }
16567
+ });
16568
+ }
16369
16569
  }
16370
16570
  }
16571
+ return;
16371
16572
  }
16372
16573
  for (const result of results) {
16373
- this.setProviderAvailability(result.id, {
16574
+ const providerType = this.resolveAlias(result.id);
16575
+ const provider = this.providers.get(providerType);
16576
+ const detectedPath = result.path || null;
16577
+ this.setProviderAvailability(providerType, {
16374
16578
  installed: !!result.installed,
16375
- detectedPath: result.path || null
16579
+ detectedPath
16376
16580
  });
16581
+ if (provider && (provider.category === "cli" || provider.category === "acp") && this.isMachineProviderEnabled(providerType)) {
16582
+ this.setMachineProviderConfig(providerType, {
16583
+ lastDetection: {
16584
+ ok: !!result.installed,
16585
+ stage: "detection",
16586
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
16587
+ command: this.getSpawnCommand(providerType, provider.spawn?.command),
16588
+ path: detectedPath,
16589
+ message: result.installed ? "Provider command detected" : "Provider command was not detected"
16590
+ }
16591
+ });
16592
+ }
16377
16593
  }
16378
16594
  }
16379
16595
  setIdeDetectionResults(results, replace = true) {
@@ -16394,8 +16610,14 @@ var ProviderLoader = class _ProviderLoader {
16394
16610
  getAvailableProviderInfos() {
16395
16611
  return this.getAll().map((provider) => {
16396
16612
  const availability = this.providerAvailability.get(provider.type);
16613
+ const enabled = this.isMachineProviderEnabled(provider.type);
16614
+ const machineConfig = this.getMachineProviderConfig(provider.type);
16397
16615
  return {
16398
16616
  ...provider,
16617
+ enabled,
16618
+ machineStatus: this.getMachineProviderStatus(provider.type),
16619
+ ...machineConfig.lastDetection ? { lastDetection: machineConfig.lastDetection } : {},
16620
+ ...machineConfig.lastVerification ? { lastVerification: machineConfig.lastVerification } : {},
16399
16621
  ...availability ? {
16400
16622
  installed: availability.installed,
16401
16623
  detectedPath: availability.detectedPath
@@ -16542,6 +16764,13 @@ var ProviderLoader = class _ProviderLoader {
16542
16764
  }
16543
16765
  }
16544
16766
  }
16767
+ if ((resolved.category === "cli" || resolved.category === "acp") && resolved.spawn?.command) {
16768
+ resolved.spawn = {
16769
+ ...resolved.spawn,
16770
+ command: this.getSpawnCommand(type, resolved.spawn.command),
16771
+ args: this.getSpawnArgs(type, resolved.spawn.args || [])
16772
+ };
16773
+ }
16545
16774
  return resolved;
16546
16775
  }
16547
16776
  /**
@@ -16864,20 +17093,33 @@ var ProviderLoader = class _ProviderLoader {
16864
17093
  * Resolved setting value for a provider (default + user override)
16865
17094
  */
16866
17095
  getSettingValue(type, key) {
16867
- const schemaDef = this.getSettingsSchema(type)[key];
17096
+ const providerType = this.resolveAlias(type);
17097
+ const machineConfig = this.getMachineProviderConfig(providerType);
17098
+ if (key === "enabled") {
17099
+ return machineConfig.enabled === true;
17100
+ }
17101
+ if (key === "executablePath") {
17102
+ return machineConfig.executable || "";
17103
+ }
17104
+ if (key === "executableArgs") {
17105
+ const args = machineConfig.args;
17106
+ return args ? args.map((arg) => /\s/.test(arg) ? JSON.stringify(arg) : arg).join(" ") : "";
17107
+ }
17108
+ const schemaDef = this.getSettingsSchema(providerType)[key];
16868
17109
  const defaultVal = schemaDef ? key === "autoApprove" && schemaDef.type === "boolean" ? true : schemaDef.default : void 0;
16869
17110
  const config = this.readConfig();
16870
- const userVal = config?.providerSettings?.[type]?.[key];
17111
+ const userVal = config?.providerSettings?.[providerType]?.[key];
16871
17112
  return userVal !== void 0 ? userVal : defaultVal;
16872
17113
  }
16873
17114
  /**
16874
17115
  * All resolved settings for a provider (default + user override)
16875
17116
  */
16876
17117
  getSettings(type) {
16877
- const settings = this.getSettingsSchema(type);
17118
+ const providerType = this.resolveAlias(type);
17119
+ const settings = this.getSettingsSchema(providerType);
16878
17120
  const result = {};
16879
17121
  for (const [key] of Object.entries(settings)) {
16880
- result[key] = this.getSettingValue(type, key);
17122
+ result[key] = this.getSettingValue(providerType, key);
16881
17123
  }
16882
17124
  return result;
16883
17125
  }
@@ -16885,7 +17127,8 @@ var ProviderLoader = class _ProviderLoader {
16885
17127
  * Save provider setting value (writes to config.json)
16886
17128
  */
16887
17129
  setSetting(type, key, value) {
16888
- const schemaDef = this.getSettingsSchema(type)[key];
17130
+ const providerType = this.resolveAlias(type);
17131
+ const schemaDef = this.getSettingsSchema(providerType)[key];
16889
17132
  if (!schemaDef) return false;
16890
17133
  if (!schemaDef.public) return false;
16891
17134
  if (schemaDef.type === "boolean" && typeof value !== "boolean") return false;
@@ -16896,14 +17139,25 @@ var ProviderLoader = class _ProviderLoader {
16896
17139
  if (schemaDef.max !== void 0 && value > schemaDef.max) return false;
16897
17140
  }
16898
17141
  if (schemaDef.type === "select" && schemaDef.options && !schemaDef.options.includes(value)) return false;
17142
+ if (key === "enabled") {
17143
+ return this.setMachineProviderEnabled(providerType, value);
17144
+ }
17145
+ if (key === "executablePath") {
17146
+ return this.setMachineProviderConfig(providerType, { executable: value });
17147
+ }
17148
+ if (key === "executableArgs") {
17149
+ return this.setMachineProviderConfig(providerType, {
17150
+ args: value.trim() ? this.parseArgsSetting(value) : void 0
17151
+ });
17152
+ }
16899
17153
  const config = this.readConfig();
16900
17154
  if (!config) return false;
16901
17155
  try {
16902
17156
  if (!config.providerSettings) config.providerSettings = {};
16903
- if (!config.providerSettings[type]) config.providerSettings[type] = {};
16904
- config.providerSettings[type][key] = value;
17157
+ if (!config.providerSettings[providerType]) config.providerSettings[providerType] = {};
17158
+ config.providerSettings[providerType][key] = value;
16905
17159
  this.writeConfig(config);
16906
- this.log(`Setting updated: ${type}.${key} = ${JSON.stringify(value)}`);
17160
+ this.log(`Setting updated: ${providerType}.${key} = ${JSON.stringify(value)}`);
16907
17161
  return true;
16908
17162
  } catch (e) {
16909
17163
  this.log(`Failed to save setting: ${e.message}`);
@@ -16964,6 +17218,15 @@ var ProviderLoader = class _ProviderLoader {
16964
17218
  }
16965
17219
  getSyntheticSettings(type, provider) {
16966
17220
  const result = {};
17221
+ if (provider.category === "cli" || provider.category === "acp") {
17222
+ result.enabled = {
17223
+ type: "boolean",
17224
+ default: false,
17225
+ public: true,
17226
+ label: "Enabled on this machine",
17227
+ description: "Opt in before ADHDev detects, launches, or verifies this provider on this machine."
17228
+ };
17229
+ }
16967
17230
  if (!provider.settings?.autoApprove) {
16968
17231
  result.autoApprove = {
16969
17232
  type: "boolean",
@@ -16982,6 +17245,15 @@ var ProviderLoader = class _ProviderLoader {
16982
17245
  description: "Optional absolute path for this provider binary. Leave blank to use the default PATH lookup."
16983
17246
  };
16984
17247
  }
17248
+ if ((provider.category === "cli" || provider.category === "acp") && provider.spawn?.command && !provider.settings?.executableArgs) {
17249
+ result.executableArgs = {
17250
+ type: "string",
17251
+ default: "",
17252
+ public: true,
17253
+ label: "Executable arguments",
17254
+ description: "Optional replacement for provider default command arguments. Leave blank to use the provider default."
17255
+ };
17256
+ }
16985
17257
  if (provider.category === "ide") {
16986
17258
  if (provider.cli && !provider.settings?.cliPathOverride) {
16987
17259
  result.cliPathOverride = {
@@ -17300,32 +17572,32 @@ async function killIdeProcess(ideId) {
17300
17572
  try {
17301
17573
  if (plat === "darwin" && appName) {
17302
17574
  try {
17303
- (0, import_child_process6.execSync)(`osascript -e 'tell application "${escapeForAppleScript(appName)}" to quit' 2>/dev/null`, {
17575
+ (0, import_child_process7.execSync)(`osascript -e 'tell application "${escapeForAppleScript(appName)}" to quit' 2>/dev/null`, {
17304
17576
  timeout: 5e3
17305
17577
  });
17306
17578
  } catch {
17307
17579
  try {
17308
- (0, import_child_process6.execSync)(`pkill -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
17580
+ (0, import_child_process7.execSync)(`pkill -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
17309
17581
  } catch {
17310
17582
  }
17311
17583
  }
17312
17584
  } else if (plat === "win32" && winProcesses) {
17313
17585
  for (const proc of winProcesses) {
17314
17586
  try {
17315
- (0, import_child_process6.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
17587
+ (0, import_child_process7.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
17316
17588
  } catch {
17317
17589
  }
17318
17590
  }
17319
17591
  try {
17320
17592
  const exeName = winProcesses[0].replace(".exe", "");
17321
- (0, import_child_process6.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
17593
+ (0, import_child_process7.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
17322
17594
  timeout: 1e4
17323
17595
  });
17324
17596
  } catch {
17325
17597
  }
17326
17598
  } else {
17327
17599
  try {
17328
- (0, import_child_process6.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
17600
+ (0, import_child_process7.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
17329
17601
  } catch {
17330
17602
  }
17331
17603
  }
@@ -17335,13 +17607,13 @@ async function killIdeProcess(ideId) {
17335
17607
  }
17336
17608
  if (plat === "darwin" && appName) {
17337
17609
  try {
17338
- (0, import_child_process6.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
17610
+ (0, import_child_process7.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
17339
17611
  } catch {
17340
17612
  }
17341
17613
  } else if (plat === "win32" && winProcesses) {
17342
17614
  for (const proc of winProcesses) {
17343
17615
  try {
17344
- (0, import_child_process6.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
17616
+ (0, import_child_process7.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
17345
17617
  } catch {
17346
17618
  }
17347
17619
  }
@@ -17359,13 +17631,13 @@ function isIdeRunning(ideId) {
17359
17631
  const appName = getMacAppIdentifiers()[ideId];
17360
17632
  if (!appName) return false;
17361
17633
  try {
17362
- const result = (0, import_child_process6.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
17634
+ const result = (0, import_child_process7.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
17363
17635
  encoding: "utf-8",
17364
17636
  timeout: 3e3
17365
17637
  });
17366
17638
  return result.trim().length > 0;
17367
17639
  } catch {
17368
- const result = (0, import_child_process6.execSync)(
17640
+ const result = (0, import_child_process7.execSync)(
17369
17641
  `osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
17370
17642
  {
17371
17643
  encoding: "utf-8",
@@ -17380,14 +17652,14 @@ function isIdeRunning(ideId) {
17380
17652
  if (!winProcesses) return false;
17381
17653
  for (const proc of winProcesses) {
17382
17654
  try {
17383
- const result = (0, import_child_process6.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
17655
+ const result = (0, import_child_process7.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
17384
17656
  if (result.includes(proc)) return true;
17385
17657
  } catch {
17386
17658
  }
17387
17659
  }
17388
17660
  try {
17389
17661
  const exeName = winProcesses[0].replace(".exe", "");
17390
- const result = (0, import_child_process6.execSync)(
17662
+ const result = (0, import_child_process7.execSync)(
17391
17663
  `powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
17392
17664
  { encoding: "utf-8", timeout: 5e3 }
17393
17665
  );
@@ -17396,7 +17668,7 @@ function isIdeRunning(ideId) {
17396
17668
  }
17397
17669
  return false;
17398
17670
  } else {
17399
- const result = (0, import_child_process6.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
17671
+ const result = (0, import_child_process7.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
17400
17672
  return result.trim().length > 0;
17401
17673
  }
17402
17674
  } catch {
@@ -17409,7 +17681,7 @@ function detectCurrentWorkspace(ideId) {
17409
17681
  try {
17410
17682
  const appName = getMacAppIdentifiers()[ideId];
17411
17683
  if (!appName) return void 0;
17412
- const result = (0, import_child_process6.execSync)(
17684
+ const result = (0, import_child_process7.execSync)(
17413
17685
  `lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
17414
17686
  { encoding: "utf-8", timeout: 3e3 }
17415
17687
  );
@@ -17561,10 +17833,10 @@ async function launchMacOS(ide, port, workspace, newWindow) {
17561
17833
  const canUseAppLauncher = !!appName;
17562
17834
  const useAppLauncher = preferredMethod === "app" ? canUseAppLauncher : preferredMethod === "cli" ? false : !canUseCli && canUseAppLauncher;
17563
17835
  if (!useAppLauncher && ide.cliCommand) {
17564
- (0, import_child_process6.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
17836
+ (0, import_child_process7.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
17565
17837
  } else if (appName) {
17566
17838
  const openArgs = ["-a", appName, "--args", ...args];
17567
- (0, import_child_process6.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
17839
+ (0, import_child_process7.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
17568
17840
  } else {
17569
17841
  throw new Error(`No app identifier or CLI for ${ide.displayName}`);
17570
17842
  }
@@ -17590,7 +17862,7 @@ async function launchLinux(ide, port, workspace, newWindow) {
17590
17862
  const args = ["--remote-debugging-port=" + port];
17591
17863
  if (newWindow) args.push("--new-window");
17592
17864
  if (workspace) args.push(workspace);
17593
- (0, import_child_process6.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
17865
+ (0, import_child_process7.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
17594
17866
  }
17595
17867
  function getAvailableIdeIds() {
17596
17868
  return getProviderLoader().getAvailableIdeTypes();
@@ -17794,7 +18066,11 @@ function buildAvailableProviders(providerLoader) {
17794
18066
  icon: provider.icon || "\u{1F4BB}",
17795
18067
  category: provider.category,
17796
18068
  ...provider.installed !== void 0 ? { installed: provider.installed } : {},
17797
- ...provider.detectedPath !== void 0 ? { detectedPath: provider.detectedPath } : {}
18069
+ ...provider.detectedPath !== void 0 ? { detectedPath: provider.detectedPath } : {},
18070
+ ...provider.enabled !== void 0 ? { enabled: provider.enabled } : {},
18071
+ ...provider.machineStatus !== void 0 ? { machineStatus: provider.machineStatus } : {},
18072
+ ...provider.lastDetection !== void 0 ? { lastDetection: provider.lastDetection } : {},
18073
+ ...provider.lastVerification !== void 0 ? { lastVerification: provider.lastVerification } : {}
17798
18074
  }));
17799
18075
  }
17800
18076
  function buildMachineInfo(profile = "full") {
@@ -18050,8 +18326,8 @@ function buildStatusSnapshot(options) {
18050
18326
  }
18051
18327
 
18052
18328
  // src/commands/upgrade-helper.ts
18053
- var import_child_process7 = require("child_process");
18054
18329
  var import_child_process8 = require("child_process");
18330
+ var import_child_process9 = require("child_process");
18055
18331
  var fs8 = __toESM(require("fs"));
18056
18332
  var os17 = __toESM(require("os"));
18057
18333
  var path16 = __toESM(require("path"));
@@ -18152,7 +18428,7 @@ function getNpmExecOptions() {
18152
18428
  function killPid(pid) {
18153
18429
  try {
18154
18430
  if (process.platform === "win32") {
18155
- (0, import_child_process7.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
18431
+ (0, import_child_process8.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
18156
18432
  } else {
18157
18433
  process.kill(pid, "SIGTERM");
18158
18434
  }
@@ -18190,7 +18466,7 @@ function stopSessionHostProcesses(appName) {
18190
18466
  }
18191
18467
  if (process.platform !== "win32") {
18192
18468
  try {
18193
- const raw = (0, import_child_process7.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
18469
+ const raw = (0, import_child_process8.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
18194
18470
  for (const line of raw.split("\n")) {
18195
18471
  const pid = Number.parseInt(line.trim(), 10);
18196
18472
  if (Number.isFinite(pid)) {
@@ -18211,9 +18487,9 @@ function removeDaemonPidFile() {
18211
18487
  function cleanupStaleGlobalInstallDirs(pkgName, surface) {
18212
18488
  const npmExecOpts = getNpmExecOptions();
18213
18489
  const prefixArgs = surface.installPrefix ? ["--prefix", surface.installPrefix] : [];
18214
- const npmRoot = (0, import_child_process7.execFileSync)(surface.npmExecutable, ["root", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
18490
+ const npmRoot = (0, import_child_process8.execFileSync)(surface.npmExecutable, ["root", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
18215
18491
  if (!npmRoot) return;
18216
- const npmPrefix = surface.installPrefix || (0, import_child_process7.execFileSync)(surface.npmExecutable, ["prefix", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
18492
+ const npmPrefix = surface.installPrefix || (0, import_child_process8.execFileSync)(surface.npmExecutable, ["prefix", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
18217
18493
  const binDir = process.platform === "win32" ? npmPrefix : path16.join(npmPrefix, "bin");
18218
18494
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
18219
18495
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
@@ -18246,7 +18522,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
18246
18522
  }
18247
18523
  function spawnDetachedDaemonUpgradeHelper(payload) {
18248
18524
  const env = { ...process.env, [UPGRADE_HELPER_ENV]: JSON.stringify(payload) };
18249
- const child = (0, import_child_process8.spawn)(process.execPath, process.argv.slice(1), {
18525
+ const child = (0, import_child_process9.spawn)(process.execPath, process.argv.slice(1), {
18250
18526
  detached: true,
18251
18527
  stdio: "ignore",
18252
18528
  windowsHide: true,
@@ -18276,7 +18552,7 @@ async function runDaemonUpgradeHelper(payload) {
18276
18552
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
18277
18553
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
18278
18554
  appendUpgradeLog(`Installing ${spec}`);
18279
- const installOutput = (0, import_child_process7.execFileSync)(
18555
+ const installOutput = (0, import_child_process8.execFileSync)(
18280
18556
  installCommand.command,
18281
18557
  installCommand.args,
18282
18558
  {
@@ -18298,7 +18574,7 @@ async function runDaemonUpgradeHelper(payload) {
18298
18574
  const env = { ...process.env };
18299
18575
  delete env[UPGRADE_HELPER_ENV];
18300
18576
  appendUpgradeLog(`Restarting daemon with args: ${restartArgv.join(" ")}`);
18301
- const child = (0, import_child_process8.spawn)(process.execPath, restartArgv, {
18577
+ const child = (0, import_child_process9.spawn)(process.execPath, restartArgv, {
18302
18578
  detached: true,
18303
18579
  stdio: "ignore",
18304
18580
  windowsHide: true,
@@ -18833,6 +19109,33 @@ var DaemonCommandRouter = class {
18833
19109
  }
18834
19110
  return { ...result };
18835
19111
  }
19112
+ // ─── Detect providers ───
19113
+ case "detect_provider": {
19114
+ const providerType = typeof args?.providerType === "string" ? args.providerType.trim() : "";
19115
+ if (!providerType) return { success: false, error: "providerType is required" };
19116
+ const normalizedType = this.deps.providerLoader.resolveAlias(providerType);
19117
+ const provider = this.deps.providerLoader.getByAlias(providerType);
19118
+ if (!provider) return { success: false, error: `Provider not found: ${providerType}` };
19119
+ if (provider.category !== "cli" && provider.category !== "acp") {
19120
+ return { success: false, error: `Provider detection is only supported for CLI/ACP providers: ${providerType}` };
19121
+ }
19122
+ if (!this.deps.providerLoader.isMachineProviderEnabled(normalizedType)) {
19123
+ return { success: false, error: `Provider is disabled on this machine: ${providerType}` };
19124
+ }
19125
+ const detected = await detectCLI(normalizedType, this.deps.providerLoader, { includeVersion: false });
19126
+ this.deps.providerLoader.setCliDetectionResults([{
19127
+ id: normalizedType,
19128
+ installed: !!detected,
19129
+ path: detected?.path
19130
+ }], false);
19131
+ this.deps.onStatusChange?.();
19132
+ return {
19133
+ success: true,
19134
+ providerType: normalizedType,
19135
+ detected: !!detected,
19136
+ path: detected?.path || null
19137
+ };
19138
+ }
18836
19139
  // ─── Detect IDEs ───
18837
19140
  case "detect_ides": {
18838
19141
  const results = await detectIDEs(this.deps.providerLoader);
@@ -18878,13 +19181,16 @@ var DaemonCommandRouter = class {
18878
19181
  this.deps.cdpManagers
18879
19182
  );
18880
19183
  const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
18881
- const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
19184
+ const requestedCompletionMarker = typeof args?.completionMarker === "string" ? args.completionMarker.trim() : "";
19185
+ const completionMarker = requestedCompletionMarker || (targetSession ? getSessionCompletionMarker(targetSession) : "");
19186
+ const requestedProviderSessionId = typeof args?.providerSessionId === "string" ? args.providerSessionId.trim() : "";
19187
+ const providerSessionId = requestedProviderSessionId || targetSession?.providerSessionId;
18882
19188
  const next = markSessionSeen(
18883
19189
  currentState,
18884
19190
  sessionId,
18885
19191
  typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
18886
19192
  completionMarker,
18887
- targetSession?.providerSessionId
19193
+ providerSessionId
18888
19194
  );
18889
19195
  if (READ_DEBUG_ENABLED2) {
18890
19196
  LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
@@ -20605,7 +20911,7 @@ init_chat_message_normalization();
20605
20911
  var fs10 = __toESM(require("fs"));
20606
20912
  var path17 = __toESM(require("path"));
20607
20913
  var os18 = __toESM(require("os"));
20608
- var import_child_process9 = require("child_process");
20914
+ var import_child_process10 = require("child_process");
20609
20915
  var import_os3 = require("os");
20610
20916
  var ARCHIVE_PATH = path17.join(os18.homedir(), ".adhdev", "version-history.json");
20611
20917
  var MAX_ENTRIES_PER_PROVIDER = 20;
@@ -20662,7 +20968,7 @@ var VersionArchive = class {
20662
20968
  };
20663
20969
  function runCommand(cmd, timeout = 1e4) {
20664
20970
  try {
20665
- return (0, import_child_process9.execSync)(cmd, {
20971
+ return (0, import_child_process10.execSync)(cmd, {
20666
20972
  encoding: "utf-8",
20667
20973
  timeout,
20668
20974
  stdio: ["pipe", "pipe", "pipe"]
@@ -26448,7 +26754,7 @@ function shouldAutoRestoreHostedSessionsOnStartup(env = process.env) {
26448
26754
  }
26449
26755
 
26450
26756
  // src/installer.ts
26451
- var import_child_process10 = require("child_process");
26757
+ var import_child_process11 = require("child_process");
26452
26758
  var EXTENSION_CATALOG = [
26453
26759
  // AI Agent extensions
26454
26760
  {
@@ -26538,7 +26844,7 @@ var EXTENSION_CATALOG = [
26538
26844
  function isExtensionInstalled(ide, marketplaceId) {
26539
26845
  if (!ide.cliCommand) return false;
26540
26846
  try {
26541
- const result = (0, import_child_process10.execSync)(`"${ide.cliCommand}" --list-extensions`, {
26847
+ const result = (0, import_child_process11.execSync)(`"${ide.cliCommand}" --list-extensions`, {
26542
26848
  encoding: "utf-8",
26543
26849
  timeout: 15e3,
26544
26850
  stdio: ["pipe", "pipe", "pipe"]
@@ -26579,7 +26885,7 @@ async function installExtension(ide, extension) {
26579
26885
  fs15.writeFileSync(vsixPath, buffer);
26580
26886
  return new Promise((resolve12) => {
26581
26887
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
26582
- (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
26888
+ (0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
26583
26889
  resolve12({
26584
26890
  extensionId: extension.id,
26585
26891
  marketplaceId: extension.marketplaceId,
@@ -26595,7 +26901,7 @@ async function installExtension(ide, extension) {
26595
26901
  }
26596
26902
  return new Promise((resolve12) => {
26597
26903
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
26598
- (0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
26904
+ (0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
26599
26905
  if (error) {
26600
26906
  resolve12({
26601
26907
  extensionId: extension.id,
@@ -26632,7 +26938,7 @@ function launchIDE(ide, workspacePath) {
26632
26938
  if (!ide.cliCommand) return false;
26633
26939
  try {
26634
26940
  const args = workspacePath ? `"${workspacePath}"` : "";
26635
- (0, import_child_process10.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
26941
+ (0, import_child_process11.exec)(`"${ide.cliCommand}" ${args}`, { timeout: 1e4 });
26636
26942
  return true;
26637
26943
  } catch {
26638
26944
  return false;
@@ -26748,10 +27054,11 @@ async function initDaemonComponents(config) {
26748
27054
  if (!providerType || targetCategory === "cli" || targetCategory === "acp") {
26749
27055
  if (providerType && targetProvider) {
26750
27056
  const detected = await detectCLI(targetProvider.type, providerLoader, { includeVersion: false });
26751
- providerLoader.setProviderAvailability(targetProvider.type, {
27057
+ providerLoader.setCliDetectionResults([{
27058
+ id: targetProvider.type,
26752
27059
  installed: !!detected,
26753
- detectedPath: detected?.path || null
26754
- });
27060
+ path: detected?.path
27061
+ }], false);
26755
27062
  } else {
26756
27063
  providerLoader.setCliDetectionResults(await detectCLIs(providerLoader, { includeVersion: false }), true);
26757
27064
  }