adhdev 0.4.0 → 0.4.1

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.
Files changed (150) hide show
  1. package/dist/cli-entrypoint.js +685 -236
  2. package/dist/cli-entrypoint.js.map +1 -1
  3. package/dist/index.js +676 -226
  4. package/dist/index.js.map +1 -1
  5. package/package.json +2 -2
  6. package/providers/_builtin/COMPATIBILITY.md +0 -217
  7. package/providers/_builtin/CONTRIBUTING.md +0 -141
  8. package/providers/_builtin/README.md +0 -51
  9. package/providers/_builtin/_helpers/index.js +0 -188
  10. package/providers/_builtin/acp/agentpool/provider.json +0 -54
  11. package/providers/_builtin/acp/amp/provider.json +0 -52
  12. package/providers/_builtin/acp/auggie/provider.json +0 -57
  13. package/providers/_builtin/acp/autodev/provider.json +0 -54
  14. package/providers/_builtin/acp/autohand/provider.json +0 -52
  15. package/providers/_builtin/acp/blackbox-ai/provider.json +0 -54
  16. package/providers/_builtin/acp/claude-agent/provider.json +0 -57
  17. package/providers/_builtin/acp/cline-acp/provider.json +0 -54
  18. package/providers/_builtin/acp/codebuddy/provider.json +0 -54
  19. package/providers/_builtin/acp/codex-cli/provider.json +0 -57
  20. package/providers/_builtin/acp/corust-agent/provider.json +0 -52
  21. package/providers/_builtin/acp/crow-cli/provider.json +0 -54
  22. package/providers/_builtin/acp/cursor-acp/provider.json +0 -54
  23. package/providers/_builtin/acp/deepagents/provider.json +0 -52
  24. package/providers/_builtin/acp/dimcode/provider.json +0 -54
  25. package/providers/_builtin/acp/docker-cagent/provider.json +0 -57
  26. package/providers/_builtin/acp/factory-droid/provider.json +0 -60
  27. package/providers/_builtin/acp/fast-agent/provider.json +0 -52
  28. package/providers/_builtin/acp/gemini-cli/provider.json +0 -114
  29. package/providers/_builtin/acp/github-copilot/provider.json +0 -54
  30. package/providers/_builtin/acp/goose/provider.json +0 -57
  31. package/providers/_builtin/acp/junie/provider.json +0 -52
  32. package/providers/_builtin/acp/kilo/provider.json +0 -54
  33. package/providers/_builtin/acp/kimi-cli/provider.json +0 -57
  34. package/providers/_builtin/acp/minion-code/provider.json +0 -52
  35. package/providers/_builtin/acp/mistral-vibe/provider.json +0 -57
  36. package/providers/_builtin/acp/nova/provider.json +0 -54
  37. package/providers/_builtin/acp/openclaw/provider.json +0 -54
  38. package/providers/_builtin/acp/opencode/provider.json +0 -52
  39. package/providers/_builtin/acp/openhands/provider.json +0 -54
  40. package/providers/_builtin/acp/pi-acp/provider.json +0 -52
  41. package/providers/_builtin/acp/qoder/provider.json +0 -54
  42. package/providers/_builtin/acp/qwen-code/provider.json +0 -60
  43. package/providers/_builtin/acp/stakpak/provider.json +0 -54
  44. package/providers/_builtin/acp/vtcode/provider.json +0 -54
  45. package/providers/_builtin/cli/claude-cli/provider.json +0 -100
  46. package/providers/_builtin/cli/codex-cli/provider.json +0 -89
  47. package/providers/_builtin/cli/gemini-cli/provider.json +0 -93
  48. package/providers/_builtin/docs/CDP_SELECTOR_GUIDE.md +0 -370
  49. package/providers/_builtin/docs/PROVIDER_GUIDE.md +0 -916
  50. package/providers/_builtin/extension/cline/provider.json +0 -35
  51. package/providers/_builtin/extension/cline/scripts/focus_editor.js +0 -48
  52. package/providers/_builtin/extension/cline/scripts/list_chats.js +0 -100
  53. package/providers/_builtin/extension/cline/scripts/list_models.js +0 -43
  54. package/providers/_builtin/extension/cline/scripts/list_modes.js +0 -35
  55. package/providers/_builtin/extension/cline/scripts/new_session.js +0 -85
  56. package/providers/_builtin/extension/cline/scripts/open_panel.js +0 -25
  57. package/providers/_builtin/extension/cline/scripts/read_chat.js +0 -257
  58. package/providers/_builtin/extension/cline/scripts/resolve_action.js +0 -83
  59. package/providers/_builtin/extension/cline/scripts/send_message.js +0 -95
  60. package/providers/_builtin/extension/cline/scripts/set_mode.js +0 -36
  61. package/providers/_builtin/extension/cline/scripts/set_model.js +0 -36
  62. package/providers/_builtin/extension/cline/scripts/switch_session.js +0 -206
  63. package/providers/_builtin/extension/cline/scripts.js +0 -73
  64. package/providers/_builtin/extension/roo-code/provider.json +0 -35
  65. package/providers/_builtin/extension/roo-code/scripts.js +0 -659
  66. package/providers/_builtin/ide/antigravity/provider.json +0 -63
  67. package/providers/_builtin/ide/antigravity/scripts/focus_editor.js +0 -20
  68. package/providers/_builtin/ide/antigravity/scripts/legacy/list_models.js +0 -38
  69. package/providers/_builtin/ide/antigravity/scripts/legacy/list_modes.js +0 -48
  70. package/providers/_builtin/ide/antigravity/scripts/legacy/scripts.js +0 -64
  71. package/providers/_builtin/ide/antigravity/scripts/legacy/set_mode.js +0 -34
  72. package/providers/_builtin/ide/antigravity/scripts/legacy/set_model.js +0 -47
  73. package/providers/_builtin/ide/antigravity/scripts/list_chats.js +0 -137
  74. package/providers/_builtin/ide/antigravity/scripts/list_models.js +0 -61
  75. package/providers/_builtin/ide/antigravity/scripts/list_modes.js +0 -72
  76. package/providers/_builtin/ide/antigravity/scripts/new_session.js +0 -75
  77. package/providers/_builtin/ide/antigravity/scripts/read_chat.js +0 -262
  78. package/providers/_builtin/ide/antigravity/scripts/resolve_action.js +0 -68
  79. package/providers/_builtin/ide/antigravity/scripts/send_message.js +0 -56
  80. package/providers/_builtin/ide/antigravity/scripts/set_mode.js +0 -67
  81. package/providers/_builtin/ide/antigravity/scripts/set_model.js +0 -72
  82. package/providers/_builtin/ide/antigravity/scripts/switch_session.js +0 -114
  83. package/providers/_builtin/ide/antigravity/scripts.js +0 -67
  84. package/providers/_builtin/ide/cursor/provider.json +0 -59
  85. package/providers/_builtin/ide/cursor/scripts.js +0 -458
  86. package/providers/_builtin/ide/kiro/provider.json +0 -60
  87. package/providers/_builtin/ide/kiro/scripts/focus_editor.js +0 -20
  88. package/providers/_builtin/ide/kiro/scripts/open_panel.js +0 -47
  89. package/providers/_builtin/ide/kiro/scripts/resolve_action.js +0 -54
  90. package/providers/_builtin/ide/kiro/scripts/send_message.js +0 -29
  91. package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +0 -39
  92. package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +0 -39
  93. package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +0 -21
  94. package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +0 -34
  95. package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +0 -68
  96. package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +0 -72
  97. package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +0 -15
  98. package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +0 -15
  99. package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +0 -26
  100. package/providers/_builtin/ide/kiro/scripts.js +0 -62
  101. package/providers/_builtin/ide/pearai/provider.json +0 -60
  102. package/providers/_builtin/ide/pearai/scripts/focus_editor.js +0 -20
  103. package/providers/_builtin/ide/pearai/scripts/list_sessions.js +0 -38
  104. package/providers/_builtin/ide/pearai/scripts/new_session.js +0 -55
  105. package/providers/_builtin/ide/pearai/scripts/open_panel.js +0 -46
  106. package/providers/_builtin/ide/pearai/scripts/resolve_action.js +0 -54
  107. package/providers/_builtin/ide/pearai/scripts/send_message.js +0 -29
  108. package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +0 -43
  109. package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +0 -35
  110. package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +0 -62
  111. package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +0 -49
  112. package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +0 -92
  113. package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +0 -59
  114. package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +0 -72
  115. package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +0 -36
  116. package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +0 -36
  117. package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +0 -34
  118. package/providers/_builtin/ide/pearai/scripts.js +0 -74
  119. package/providers/_builtin/ide/trae/provider.json +0 -59
  120. package/providers/_builtin/ide/trae/scripts/focus_editor.js +0 -20
  121. package/providers/_builtin/ide/trae/scripts/list_chats.js +0 -24
  122. package/providers/_builtin/ide/trae/scripts/list_models.js +0 -39
  123. package/providers/_builtin/ide/trae/scripts/list_modes.js +0 -39
  124. package/providers/_builtin/ide/trae/scripts/new_session.js +0 -30
  125. package/providers/_builtin/ide/trae/scripts/open_panel.js +0 -44
  126. package/providers/_builtin/ide/trae/scripts/read_chat.js +0 -113
  127. package/providers/_builtin/ide/trae/scripts/resolve_action.js +0 -54
  128. package/providers/_builtin/ide/trae/scripts/send_message.js +0 -69
  129. package/providers/_builtin/ide/trae/scripts/set_mode.js +0 -15
  130. package/providers/_builtin/ide/trae/scripts/set_model.js +0 -15
  131. package/providers/_builtin/ide/trae/scripts/switch_session.js +0 -23
  132. package/providers/_builtin/ide/trae/scripts.js +0 -57
  133. package/providers/_builtin/ide/vscode/provider.json +0 -57
  134. package/providers/_builtin/ide/vscode-insiders/provider.json +0 -55
  135. package/providers/_builtin/ide/vscodium/provider.json +0 -56
  136. package/providers/_builtin/ide/windsurf/provider.json +0 -46
  137. package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +0 -30
  138. package/providers/_builtin/ide/windsurf/scripts/list_chats.js +0 -117
  139. package/providers/_builtin/ide/windsurf/scripts/list_models.js +0 -39
  140. package/providers/_builtin/ide/windsurf/scripts/list_modes.js +0 -39
  141. package/providers/_builtin/ide/windsurf/scripts/new_session.js +0 -69
  142. package/providers/_builtin/ide/windsurf/scripts/open_panel.js +0 -58
  143. package/providers/_builtin/ide/windsurf/scripts/read_chat.js +0 -297
  144. package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +0 -68
  145. package/providers/_builtin/ide/windsurf/scripts/send_message.js +0 -87
  146. package/providers/_builtin/ide/windsurf/scripts/set_mode.js +0 -15
  147. package/providers/_builtin/ide/windsurf/scripts/set_model.js +0 -15
  148. package/providers/_builtin/ide/windsurf/scripts/switch_session.js +0 -58
  149. package/providers/_builtin/ide/windsurf/scripts.js +0 -57
  150. package/providers/_builtin/validate.js +0 -156
@@ -16382,14 +16382,14 @@ var require_dist = __commonJS({
16382
16382
  updateConfig: () => updateConfig2
16383
16383
  });
16384
16384
  function getConfigDir() {
16385
- const dir = (0, import_path3.join)((0, import_os.homedir)(), ".adhdev");
16385
+ const dir = (0, import_path2.join)((0, import_os.homedir)(), ".adhdev");
16386
16386
  if (!(0, import_fs2.existsSync)(dir)) {
16387
16387
  (0, import_fs2.mkdirSync)(dir, { recursive: true });
16388
16388
  }
16389
16389
  return dir;
16390
16390
  }
16391
16391
  function getConfigPath() {
16392
- return (0, import_path3.join)(getConfigDir(), "config.json");
16392
+ return (0, import_path2.join)(getConfigDir(), "config.json");
16393
16393
  }
16394
16394
  function loadConfig4() {
16395
16395
  const configPath = getConfigPath();
@@ -16464,14 +16464,14 @@ var require_dist = __commonJS({
16464
16464
  saveConfig2(config2);
16465
16465
  }
16466
16466
  var import_os;
16467
- var import_path3;
16467
+ var import_path2;
16468
16468
  var import_fs2;
16469
16469
  var DEFAULT_CONFIG;
16470
16470
  var init_config = __esm2({
16471
16471
  "src/config/config.ts"() {
16472
16472
  "use strict";
16473
16473
  import_os = require("os");
16474
- import_path3 = require("path");
16474
+ import_path2 = require("path");
16475
16475
  import_fs2 = require("fs");
16476
16476
  DEFAULT_CONFIG = {
16477
16477
  serverUrl: "https://api.adhf.dev",
@@ -16915,13 +16915,44 @@ var require_dist = __commonJS({
16915
16915
  // Connect to specific targetId (multi-window support)
16916
16916
  _pageTitle = "";
16917
16917
  // Connected page title
16918
- constructor(port = 9333, logFn, targetId) {
16918
+ _targetFilter;
16919
+ // Provider-configurable target selection
16920
+ constructor(port = 9333, logFn, targetId, targetFilter) {
16919
16921
  this.port = port;
16920
16922
  this._targetId = targetId || null;
16923
+ this._targetFilter = targetFilter || {};
16921
16924
  this.logFn = logFn || ((msg) => {
16922
16925
  LOG4.info("CDP", msg);
16923
16926
  });
16924
16927
  }
16928
+ /** Set target filter (can be updated after construction) */
16929
+ setTargetFilter(filter) {
16930
+ this._targetFilter = filter;
16931
+ }
16932
+ /**
16933
+ * Check if a page title should be excluded (non-main page).
16934
+ * Uses provider-configured titleExcludes, falls back to default pattern.
16935
+ */
16936
+ isNonMainTitle(title) {
16937
+ if (!title) return true;
16938
+ const pattern = this._targetFilter.titleExcludes || "extension-output|ADHDev CDP|Debug Console|Output\\s*$|Launchpad";
16939
+ return new RegExp(pattern, "i").test(title);
16940
+ }
16941
+ /**
16942
+ * Check if a page URL matches the main window criteria.
16943
+ * Uses provider-configured urlIncludes/urlExcludes.
16944
+ */
16945
+ isMainPageUrl(url2) {
16946
+ if (!url2) return true;
16947
+ const { urlIncludes, urlExcludes } = this._targetFilter;
16948
+ if (urlIncludes && !url2.includes(urlIncludes)) return false;
16949
+ if (urlExcludes) {
16950
+ for (const exc of urlExcludes) {
16951
+ if (url2.includes(exc)) return false;
16952
+ }
16953
+ }
16954
+ return true;
16955
+ }
16925
16956
  /** Connected page title (includes workspace name) */
16926
16957
  get pageTitle() {
16927
16958
  return this._pageTitle;
@@ -16941,7 +16972,8 @@ var require_dist = __commonJS({
16941
16972
  const pages = targets.filter(
16942
16973
  (t) => t.type === "page" && t.webSocketDebuggerUrl
16943
16974
  );
16944
- const isNonMain = (title) => !title || /extension-output|ADHDev CDP|Debug Console|Output\s*$|Launchpad/i.test(title);
16975
+ const defaultExclude = /extension-output|ADHDev CDP|Debug Console|Output\s*$|Launchpad/i;
16976
+ const isNonMain = (title) => !title || defaultExclude.test(title);
16945
16977
  const mainPages = pages.filter(
16946
16978
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
16947
16979
  );
@@ -17009,8 +17041,7 @@ var require_dist = __commonJS({
17009
17041
  resolve5(targets.find((t) => t.webSocketDebuggerUrl) || null);
17010
17042
  return;
17011
17043
  }
17012
- const isNonMain = (title) => !title || /extension-output|ADHDev CDP|Debug Console|Output\s*$|Launchpad/i.test(title);
17013
- const mainPages = pages.filter((t) => !isNonMain(t.title || ""));
17044
+ const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
17014
17045
  const list = mainPages.length > 0 ? mainPages : pages;
17015
17046
  this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
17016
17047
  if (this._targetId) {
@@ -21577,7 +21608,7 @@ ${installInfo}`
21577
21608
  var os9 = __toESM2(require("os"));
21578
21609
  var ProviderLoader4 = class _ProviderLoader {
21579
21610
  providers = /* @__PURE__ */ new Map();
21580
- builtinDir;
21611
+ builtinDirs;
21581
21612
  userDir;
21582
21613
  upstreamDir;
21583
21614
  watchers = [];
@@ -21590,7 +21621,11 @@ ${installInfo}`
21590
21621
  static GITHUB_TARBALL_URL = "https://github.com/vilmire/adhdev-providers/archive/refs/heads/main.tar.gz";
21591
21622
  static META_FILE = ".meta.json";
21592
21623
  constructor(options) {
21593
- this.builtinDir = options?.builtinDir || path6.resolve(__dirname, "../providers/_builtin");
21624
+ if (options?.builtinDir) {
21625
+ this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
21626
+ } else {
21627
+ this.builtinDirs = [path6.resolve(__dirname, "../providers/_builtin")];
21628
+ }
21594
21629
  this.userDir = options?.userDir || path6.join(os9.homedir(), ".adhdev", "providers");
21595
21630
  this.upstreamDir = path6.join(this.userDir, ".upstream");
21596
21631
  this.logFn = options?.logFn || LOG4.forComponent("Provider").asLogFn();
@@ -21601,14 +21636,19 @@ ${installInfo}`
21601
21636
  // ─── Public API ────────────────────────────────
21602
21637
  /**
21603
21638
  * Load all providers (3-tier priority)
21604
- * 1. _builtin/ (bundled fallback)
21639
+ * 1. _builtin/ (bundled fallback, or multiple array dirs)
21605
21640
  * 2. .upstream/ (GitHub auto-download)
21606
21641
  * 3. User custom (~/.adhdev/providers/ excluding _upstream)
21607
21642
  * Later loads override earlier ones, so user custom always wins.
21608
21643
  */
21609
21644
  loadAll() {
21610
21645
  this.providers.clear();
21611
- const builtinCount = this.loadDir(this.builtinDir);
21646
+ let builtinCount = 0;
21647
+ for (const dir of this.builtinDirs) {
21648
+ if (fs5.existsSync(dir)) {
21649
+ builtinCount += this.loadDir(dir);
21650
+ }
21651
+ }
21612
21652
  this.log(`Loaded ${builtinCount} builtin providers`);
21613
21653
  let upstreamCount = 0;
21614
21654
  if (fs5.existsSync(this.upstreamDir)) {
@@ -21628,7 +21668,7 @@ ${installInfo}`
21628
21668
  this.log(`\u26A0 Using bundled providers only (upstream not available). Run 'adhdev daemon' with internet to auto-update.`);
21629
21669
  }
21630
21670
  if (this.providers.size === 0) {
21631
- this.log(`\u274C No providers loaded! Check builtinDir: ${this.builtinDir}`);
21671
+ this.log(`\u274C No providers loaded! Check builtinDirs.`);
21632
21672
  }
21633
21673
  }
21634
21674
  /**
@@ -21812,14 +21852,15 @@ ${installInfo}`
21812
21852
  /**
21813
21853
  * Return final provider with OS/version overrides applied.
21814
21854
  *
21815
- * Version resolution order:
21816
- * 1. context.version (explicit)
21817
- * 2. VersionArchive latest (auto-detected at daemon startup)
21818
- * 3. No version override applied
21855
+ * Script resolution order:
21856
+ * 1. compatibility array (new format — preferred)
21857
+ * Provider.json defines: "compatibility": [{ "ideVersion": ">=1.107.0", "scriptDir": "scripts/1.107" }]
21858
+ * First matching range wins. Fallback: defaultScriptDir.
21859
+ * 2. versions field (legacy format — backward compat)
21860
+ * "versions": { "< 1.107.0": { "__dir": "scripts/legacy" } }
21861
+ * 3. Root scripts.js (original format — no versioning)
21819
21862
  *
21820
- * versions override in provider.json:
21821
- * "versions": { "< 1.107.0": { "__dir": "scripts/legacy" } }
21822
- * When __dir is set, the scripts.js is re-required from that subdirectory.
21863
+ * Version source: context.version → VersionArchive → undefined
21823
21864
  */
21824
21865
  resolve(type, context) {
21825
21866
  const base = this.providers.get(type);
@@ -21842,36 +21883,51 @@ ${installInfo}`
21842
21883
  if (osOverride.inputSelector) resolved.inputSelector = osOverride.inputSelector;
21843
21884
  resolved._resolvedOs = currentOs;
21844
21885
  }
21845
- if (currentVersion && base.versions) {
21846
- for (const [range, override] of Object.entries(base.versions)) {
21847
- if (!this.matchesVersion(currentVersion, range)) continue;
21848
- resolved._resolvedVersion = currentVersion;
21849
- const dirOverride = override.__dir;
21850
- if (dirOverride) {
21851
- const providerDir = this.findProviderDir(type);
21852
- if (providerDir) {
21853
- const altScriptsPath = path6.join(providerDir, dirOverride, "scripts.js");
21854
- if (fs5.existsSync(altScriptsPath)) {
21855
- try {
21856
- delete require.cache[require.resolve(altScriptsPath)];
21857
- resolved.scripts = require(altScriptsPath);
21858
- this.log(` [version override] ${type} ${range} \u2192 scripts from ${dirOverride}/scripts.js`);
21859
- } catch (e) {
21860
- this.log(` \u26A0 version override scripts load failed: ${altScriptsPath}: ${e.message}`);
21861
- }
21862
- } else {
21863
- const altDir = path6.join(providerDir, dirOverride);
21864
- if (fs5.existsSync(altDir)) {
21865
- const wrappers = this.buildScriptWrappersFromDir(altDir);
21866
- resolved.scripts = { ...resolved.scripts, ...wrappers };
21867
- this.log(` [version override] ${type} ${range} \u2192 individual scripts from ${dirOverride}/`);
21868
- }
21886
+ if (currentVersion) {
21887
+ resolved._resolvedVersion = currentVersion;
21888
+ if (Array.isArray(base.compatibility)) {
21889
+ const compat = base.compatibility;
21890
+ let matched = false;
21891
+ for (const entry of compat) {
21892
+ if (this.matchesVersion(currentVersion, entry.ideVersion)) {
21893
+ const loaded = this.loadScriptsFromDir(type, entry.scriptDir);
21894
+ if (loaded) {
21895
+ resolved.scripts = loaded;
21896
+ this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
21897
+ matched = true;
21869
21898
  }
21899
+ break;
21900
+ }
21901
+ }
21902
+ if (!matched && base.defaultScriptDir) {
21903
+ const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
21904
+ if (loaded) {
21905
+ resolved.scripts = loaded;
21906
+ this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
21907
+ }
21908
+ resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
21909
+ }
21910
+ } else if (base.versions) {
21911
+ for (const [range, override] of Object.entries(base.versions)) {
21912
+ if (!this.matchesVersion(currentVersion, range)) continue;
21913
+ const dirOverride = override.__dir;
21914
+ if (dirOverride) {
21915
+ const loaded = this.loadScriptsFromDir(type, dirOverride);
21916
+ if (loaded) {
21917
+ resolved.scripts = loaded;
21918
+ this.log(` [version override] ${type} ${range} \u2192 ${dirOverride}`);
21919
+ }
21920
+ } else if (override.scripts) {
21921
+ resolved.scripts = { ...resolved.scripts, ...override.scripts };
21870
21922
  }
21871
- } else if (override.scripts) {
21872
- resolved.scripts = { ...resolved.scripts, ...override.scripts };
21873
21923
  }
21874
21924
  }
21925
+ } else if (Array.isArray(base.compatibility) && base.defaultScriptDir) {
21926
+ const loaded = this.loadScriptsFromDir(type, base.defaultScriptDir);
21927
+ if (loaded) {
21928
+ resolved.scripts = loaded;
21929
+ this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
21930
+ }
21875
21931
  }
21876
21932
  if (base.overrides) {
21877
21933
  for (const override of base.overrides) {
@@ -21884,6 +21940,36 @@ ${installInfo}`
21884
21940
  }
21885
21941
  return resolved;
21886
21942
  }
21943
+ /**
21944
+ * Load scripts from a scriptDir within a provider directory.
21945
+ * Tries scripts.js first, then individual .js files.
21946
+ */
21947
+ loadScriptsFromDir(type, scriptDir) {
21948
+ const providerDir = this.findProviderDir(type);
21949
+ if (!providerDir) {
21950
+ this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
21951
+ return null;
21952
+ }
21953
+ const dir = path6.join(providerDir, scriptDir);
21954
+ if (!fs5.existsSync(dir)) {
21955
+ this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
21956
+ return null;
21957
+ }
21958
+ const scriptsJs = path6.join(dir, "scripts.js");
21959
+ if (fs5.existsSync(scriptsJs)) {
21960
+ try {
21961
+ delete require.cache[require.resolve(scriptsJs)];
21962
+ const loaded = require(scriptsJs);
21963
+ this.log(` [loadScriptsFromDir] ${type}: loaded scripts.js from ${dir} (${Object.keys(loaded).length} exports)`);
21964
+ return loaded;
21965
+ } catch (e) {
21966
+ this.log(` \u26A0 scripts.js load failed: ${scriptsJs}: ${e.message}`);
21967
+ }
21968
+ }
21969
+ const result = this.buildScriptWrappersFromDir(dir);
21970
+ this.log(` [loadScriptsFromDir] ${type}: built wrappers from ${dir} (${Object.keys(result).length} scripts)`);
21971
+ return result;
21972
+ }
21887
21973
  /**
21888
21974
  * Hot-reload: start watching for file changes
21889
21975
  */
@@ -21909,7 +21995,7 @@ ${installInfo}`
21909
21995
  this.log(`Watch failed for ${dir}: ${e.message}`);
21910
21996
  }
21911
21997
  };
21912
- watchDir(this.builtinDir);
21998
+ this.builtinDirs.forEach((dir) => watchDir(dir));
21913
21999
  watchDir(this.userDir);
21914
22000
  }
21915
22001
  /**
@@ -22217,7 +22303,7 @@ ${installInfo}`
22217
22303
  const provider2 = this.providers.get(type);
22218
22304
  if (!provider2) return null;
22219
22305
  const cat = provider2.category;
22220
- const searchRoots = [this.userDir, this.upstreamDir, this.builtinDir];
22306
+ const searchRoots = [this.userDir, this.upstreamDir, ...this.builtinDirs];
22221
22307
  for (const root of searchRoots) {
22222
22308
  if (!fs5.existsSync(root)) continue;
22223
22309
  for (const candidate of [path6.join(root, type), path6.join(root, cat, type)]) {
@@ -22307,8 +22393,9 @@ ${installInfo}`
22307
22393
  mod.extensionIdPattern = new RegExp(mod.extensionIdPattern, flags);
22308
22394
  delete mod.extensionIdPattern_flags;
22309
22395
  }
22396
+ const hasCompatibility = Array.isArray(mod.compatibility);
22310
22397
  const scriptsPath = path6.join(d, "scripts.js");
22311
- if (fs5.existsSync(scriptsPath)) {
22398
+ if (!hasCompatibility && fs5.existsSync(scriptsPath)) {
22312
22399
  try {
22313
22400
  delete require.cache[require.resolve(scriptsPath)];
22314
22401
  const scripts = require(scriptsPath);
@@ -23811,7 +23898,7 @@ ${installInfo}`
23811
23898
  var path9 = __toESM2(require("path"));
23812
23899
  var os12 = __toESM2(require("os"));
23813
23900
  function generateFiles(type, name, category, opts = {}) {
23814
- const { cdpPorts, cli, processName, installPath, binary, extensionId } = opts;
23901
+ const { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 = "0.1" } = opts;
23815
23902
  if (category === "cli" || category === "acp") {
23816
23903
  const bin = binary || type;
23817
23904
  const meta22 = {
@@ -23835,6 +23922,7 @@ ${installInfo}`
23835
23922
  return { "provider.json": JSON.stringify(meta22, null, 2) + "\n" };
23836
23923
  }
23837
23924
  const isExtension = category === "extension";
23925
+ const scriptDir = `scripts/${version2}`;
23838
23926
  const meta3 = {
23839
23927
  type,
23840
23928
  name,
@@ -23853,159 +23941,284 @@ ${installInfo}`
23853
23941
  } else {
23854
23942
  meta3.inputMethod = "cdp-type-and-send";
23855
23943
  meta3.inputSelector = '[contenteditable="true"][role="textbox"]';
23944
+ meta3.providerVersion = "1.0.0";
23945
+ meta3.compatibility = [
23946
+ { ideVersion: `>=${version2}.0`, scriptDir }
23947
+ ];
23948
+ meta3.defaultScriptDir = scriptDir;
23856
23949
  }
23857
- const scripts = `/**
23858
- * CDP Scripts for ${name}
23859
- *
23860
- * Each exported function receives a params object and returns
23861
- * a JavaScript expression string to be evaluated in the IDE's DOM.
23950
+ const files = {};
23951
+ files[`${scriptDir}/scripts.js`] = `/**
23952
+ * ${name} CDP Scripts \u2014 Router
23862
23953
  *
23863
- * Use the DevServer Wizard (http://127.0.0.1:19280) to discover
23864
- * selectors and test scripts against the running IDE.
23954
+ * Loads individual .js files and invokes with params.
23955
+ * Pattern:
23956
+ * - No-params scripts: loaded as-is (IIFE)
23957
+ * - With-params scripts: \`(\${script})(\${JSON.stringify(params)})\`
23865
23958
  */
23866
23959
 
23867
- module.exports.readChat = function readChat(params) {
23868
- return \`(() => {
23869
- try {
23870
- const messages = [];
23871
- let status = 'idle';
23872
- let activeModal = null;
23960
+ 'use strict';
23873
23961
 
23874
- // TODO: Query chat container and extract messages
23875
- // Example for VS Code-based IDEs:
23876
- // document.querySelectorAll('.chat-message').forEach(el => {
23877
- // const role = el.classList.contains('user') ? 'user' : 'assistant';
23878
- // messages.push({ role, content: el.innerText.trim(), index: messages.length });
23879
- // });
23962
+ const fs = require('fs');
23963
+ const path = require('path');
23880
23964
 
23881
- // TODO: Detect approval dialogs -> status = 'waiting_approval'
23882
- // const approvalBtns = [...document.querySelectorAll('button')].filter(b =>
23883
- // b.offsetWidth > 0 && /accept|approve|run/i.test(b.textContent)
23884
- // );
23885
- // if (approvalBtns.length > 0) {
23886
- // status = 'waiting_approval';
23887
- // activeModal = { message: 'Action required', buttons: approvalBtns.map(b => b.textContent.trim()) };
23888
- // }
23965
+ function load(name) {
23966
+ try { return fs.readFileSync(path.join(__dirname, name), 'utf-8'); }
23967
+ catch { return null; }
23968
+ }
23889
23969
 
23890
- const inputEl = document.querySelector('[contenteditable="true"]');
23891
- const inputContent = inputEl?.innerText?.trim() || '';
23892
- return JSON.stringify({ id: 'active', status, title: document.title, messages, inputContent, activeModal });
23893
- } catch(e) {
23894
- return JSON.stringify({ id: '', status: 'error', messages: [], error: e.message });
23895
- }
23896
- })()\`;
23897
- };
23970
+ function withParams(name, params) {
23971
+ const script = load(name);
23972
+ if (!script) return null;
23973
+ return \`(\${script})(\${JSON.stringify(params)})\`;
23974
+ }
23898
23975
 
23899
- module.exports.sendMessage = function sendMessage(params) {
23900
- const text = typeof params === 'string' ? params : params?.text;
23901
- return \`(() => {
23902
- try {
23903
- // Most VS Code-based IDEs use needsTypeAndSend for reliable input
23904
- return JSON.stringify({
23905
- sent: false,
23906
- needsTypeAndSend: true,
23907
- selector: '[contenteditable="true"]',
23908
- });
23909
- } catch(e) {
23910
- return JSON.stringify({ sent: false, error: e.message });
23911
- }
23912
- })()\`;
23913
- };
23976
+ // \u2500\u2500\u2500 Core (no params \u2014 IIFE) \u2500\u2500\u2500
23914
23977
 
23915
- module.exports.listSessions = function listSessions(params) {
23916
- return \`(() => {
23917
- try {
23918
- const sessions = [];
23919
- // TODO: Query session/chat list sidebar
23920
- return JSON.stringify({ sessions });
23921
- } catch(e) {
23922
- return JSON.stringify({ sessions: [], error: e.message });
23923
- }
23924
- })()\`;
23925
- };
23978
+ module.exports.readChat = () => load('read_chat.js');
23979
+ module.exports.sendMessage = () => load('send_message.js');
23980
+ module.exports.listSessions = () => load('list_sessions.js');
23981
+ module.exports.newSession = () => load('new_session.js');
23982
+ module.exports.focusEditor = () => load('focus_editor.js');
23983
+ module.exports.openPanel = () => load('open_panel.js');
23984
+ module.exports.listModels = () => load('list_models.js');
23985
+ module.exports.listModes = () => load('list_modes.js');
23926
23986
 
23927
- module.exports.newSession = function newSession(params) {
23928
- return \`(() => {
23929
- try {
23930
- // TODO: Click "New Chat" button
23931
- // const btn = document.querySelector('[aria-label*="New Chat"]');
23932
- // if (btn) { btn.click(); return JSON.stringify({ created: true }); }
23933
- return JSON.stringify({ created: false, error: 'New Chat button not found' });
23934
- } catch(e) {
23935
- return JSON.stringify({ created: false, error: e.message });
23936
- }
23937
- })()\`;
23938
- };
23987
+ // \u2500\u2500\u2500 With params (function expression) \u2500\u2500\u2500
23939
23988
 
23940
- module.exports.openPanel = function openPanel(params) {
23941
- return \`(() => {
23942
- try {
23943
- // TODO: Open the chat/AI panel
23944
- return 'not_found';
23945
- } catch(e) { return 'error'; }
23946
- })()\`;
23989
+ module.exports.switchSession = (params) => {
23990
+ const index = typeof params === 'number' ? params : params?.index ?? 0;
23991
+ const title = typeof params === 'string' ? params : params?.title || null;
23992
+ return withParams('switch_session.js', { index, title });
23947
23993
  };
23948
23994
 
23949
- module.exports.focusEditor = function focusEditor(params) {
23950
- return \`(() => {
23951
- try {
23952
- const input = document.querySelector('[contenteditable="true"]');
23953
- if (input) { input.focus(); return 'focused'; }
23954
- return 'not_found';
23955
- } catch(e) { return 'error'; }
23956
- })()\`;
23995
+ module.exports.resolveAction = (params) => {
23996
+ const action = typeof params === 'string' ? params : params?.action || 'approve';
23997
+ const buttonText = params?.button || params?.buttonText
23998
+ || (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : action);
23999
+ return withParams('resolve_action.js', { buttonText });
23957
24000
  };
23958
24001
 
23959
- module.exports.resolveAction = function resolveAction(params) {
23960
- const action = typeof params === 'string' ? params : params?.action || 'approve';
23961
- const buttonText = params?.button || params?.buttonText
23962
- || (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : action);
23963
- return \`(() => {
23964
- try {
23965
- const btns = [...document.querySelectorAll('button, [role="button"]')].filter(b => b.offsetWidth > 0);
23966
- const target = btns.find(b => (b.textContent||'').trim().toLowerCase().includes(\${JSON.stringify((buttonText||'').toLowerCase())}));
23967
- if (target) { target.click(); return JSON.stringify({ resolved: true, clicked: target.textContent.trim() }); }
23968
- return JSON.stringify({ resolved: false, available: btns.map(b => b.textContent.trim()).filter(Boolean).slice(0, 10) });
23969
- } catch(e) { return JSON.stringify({ resolved: false, error: e.message }); }
23970
- })()\`;
24002
+ module.exports.setModel = (params) => {
24003
+ const model = typeof params === 'string' ? params : params?.model;
24004
+ return withParams('set_model.js', { model });
23971
24005
  };
23972
24006
 
23973
- module.exports.listNotifications = function listNotifications(params) {
23974
- return \`(() => {
23975
- try {
23976
- const toasts = [...document.querySelectorAll('.notifications-toasts .notification-toast, .notification-list-item')];
23977
- return JSON.stringify(toasts.filter(t => t.offsetWidth > 0).map((t, i) => ({
23978
- index: i,
23979
- message: t.querySelector('.notification-list-item-message')?.textContent?.trim() || t.textContent?.trim().substring(0, 200),
23980
- severity: t.querySelector('.codicon-error') ? 'error' : t.querySelector('.codicon-warning') ? 'warning' : 'info',
23981
- buttons: [...t.querySelectorAll('.notification-list-item-buttons-container button')].map(b => b.textContent?.trim()).filter(Boolean),
23982
- })));
23983
- } catch(e) { return JSON.stringify([]); }
23984
- })()\`;
24007
+ module.exports.setMode = (params) => {
24008
+ const mode = typeof params === 'string' ? params : params?.mode;
24009
+ return withParams('set_mode.js', { mode });
23985
24010
  };
24011
+ `;
24012
+ files[`${scriptDir}/read_chat.js`] = `/**
24013
+ * ${name} \u2014 read_chat
24014
+ *
24015
+ * Extract chat messages, status, and approval state from DOM.
24016
+ *
24017
+ * TODO: Identify via CDP/DevConsole:
24018
+ * 1. Chat container selector
24019
+ * 2. User message selector + class pattern
24020
+ * 3. Assistant message selector + class pattern
24021
+ * 4. Status detection (generating/idle/waiting_approval)
24022
+ * 5. Approval dialog detection (buttons, modal)
24023
+ * 6. Input field selector
24024
+ *
24025
+ * \u2192 { id, status, title, messages[], inputContent, activeModal }
24026
+ */
24027
+ (() => {
24028
+ try {
24029
+ const messages = [];
24030
+ let status = 'idle';
24031
+ let activeModal = null;
23986
24032
 
23987
- module.exports.dismissNotification = function dismissNotification(params) {
23988
- const idx = typeof params === 'number' ? params : params?.index ?? 0;
23989
- const button = typeof params === 'string' ? params : params?.button;
23990
- return \`(() => {
23991
- try {
23992
- const toasts = [...document.querySelectorAll('.notifications-toasts .notification-toast, .notification-list-item')].filter(t => t.offsetWidth > 0);
23993
- const toast = toasts[\${idx}];
23994
- if (!toast) return JSON.stringify({ dismissed: false, count: toasts.length });
23995
- if (\${JSON.stringify(button)}) {
23996
- const btn = [...toast.querySelectorAll('button')].find(b => b.textContent?.trim().toLowerCase().includes(\${JSON.stringify((button||'').toLowerCase())}));
23997
- if (btn) { btn.click(); return JSON.stringify({ dismissed: true, clicked: btn.textContent.trim() }); }
23998
- }
23999
- const closeBtn = toast.querySelector('.codicon-notifications-clear, .codicon-close');
24000
- if (closeBtn) { closeBtn.click(); return JSON.stringify({ dismissed: true }); }
24001
- return JSON.stringify({ dismissed: false, error: 'Close button not found' });
24002
- } catch(e) { return JSON.stringify({ dismissed: false, error: e.message }); }
24003
- })()\`;
24004
- };
24033
+ // TODO: Query chat container and extract messages
24034
+ // Example:
24035
+ // document.querySelectorAll('.chat-message').forEach(el => {
24036
+ // const role = el.classList.contains('user') ? 'user' : 'assistant';
24037
+ // messages.push({ role, content: el.innerText.trim(), index: messages.length });
24038
+ // });
24039
+
24040
+ // TODO: Detect generating state
24041
+ // TODO: Detect approval dialogs -> status = 'waiting_approval'
24042
+
24043
+ const inputEl = document.querySelector('[contenteditable="true"]');
24044
+ const inputContent = inputEl?.innerText?.trim() || '';
24045
+
24046
+ return JSON.stringify({
24047
+ id: 'active',
24048
+ status,
24049
+ title: document.title,
24050
+ messages,
24051
+ inputContent,
24052
+ activeModal,
24053
+ });
24054
+ } catch(e) {
24055
+ return JSON.stringify({ id: '', status: 'error', messages: [], error: e.message });
24056
+ }
24057
+ })()
24058
+ `;
24059
+ files[`${scriptDir}/send_message.js`] = `/**
24060
+ * ${name} \u2014 send_message
24061
+ *
24062
+ * For cdp-type-and-send IDEs: returns selector for daemon to type into.
24063
+ * \u2192 { sent: false, needsTypeAndSend: true, selector }
24064
+ */
24065
+ (() => {
24066
+ try {
24067
+ const input = document.querySelector('${meta3.inputSelector || '[contenteditable="true"]'}');
24068
+ if (!input) return JSON.stringify({ sent: false, error: 'Input not found' });
24069
+ return JSON.stringify({
24070
+ sent: false,
24071
+ needsTypeAndSend: true,
24072
+ selector: '${meta3.inputSelector || '[contenteditable="true"]'}',
24073
+ });
24074
+ } catch(e) {
24075
+ return JSON.stringify({ sent: false, error: e.message });
24076
+ }
24077
+ })()
24078
+ `;
24079
+ files[`${scriptDir}/list_sessions.js`] = `/**
24080
+ * ${name} \u2014 list_sessions
24081
+ *
24082
+ * TODO: Query session/chat list from sidebar.
24083
+ * \u2192 { sessions: [{ id, title, active, index }] }
24084
+ */
24085
+ (() => {
24086
+ try {
24087
+ const sessions = [];
24088
+ // TODO: Find session list container and parse items
24089
+ return JSON.stringify({ sessions });
24090
+ } catch(e) {
24091
+ return JSON.stringify({ sessions: [], error: e.message });
24092
+ }
24093
+ })()
24094
+ `;
24095
+ files[`${scriptDir}/switch_session.js`] = `/**
24096
+ * ${name} \u2014 switch_session
24097
+ *
24098
+ * params.index: number, params.title: string|null
24099
+ * TODO: Click on session in sidebar by title or index.
24100
+ * \u2192 { switched: true/false }
24101
+ */
24102
+ (params) => {
24103
+ try {
24104
+ // TODO: Find session list and click target
24105
+ return JSON.stringify({ switched: false, error: 'Not implemented' });
24106
+ } catch(e) {
24107
+ return JSON.stringify({ switched: false, error: e.message });
24108
+ }
24109
+ }
24110
+ `;
24111
+ files[`${scriptDir}/new_session.js`] = `/**
24112
+ * ${name} \u2014 new_session
24113
+ *
24114
+ * TODO: Click "New Chat" button.
24115
+ * \u2192 { created: true/false }
24116
+ */
24117
+ (() => {
24118
+ try {
24119
+ const btn = document.querySelector('[aria-label*="New Chat"], [aria-label*="New Composer"]');
24120
+ if (btn) { btn.click(); return JSON.stringify({ created: true }); }
24121
+ return JSON.stringify({ created: false, error: 'New Chat button not found' });
24122
+ } catch(e) {
24123
+ return JSON.stringify({ created: false, error: e.message });
24124
+ }
24125
+ })()
24126
+ `;
24127
+ files[`${scriptDir}/focus_editor.js`] = `/**
24128
+ * ${name} \u2014 focus_editor
24129
+ */
24130
+ (() => {
24131
+ try {
24132
+ const input = document.querySelector('${meta3.inputSelector || '[contenteditable="true"]'}');
24133
+ if (input) { input.focus(); return 'focused'; }
24134
+ return 'not_found';
24135
+ } catch(e) { return 'error'; }
24136
+ })()
24137
+ `;
24138
+ files[`${scriptDir}/open_panel.js`] = `/**
24139
+ * ${name} \u2014 open_panel
24140
+ *
24141
+ * TODO: Open chat/AI panel if not visible.
24142
+ */
24143
+ (() => {
24144
+ try {
24145
+ // TODO: Check if panel visible, if not find toggle button
24146
+ return 'not_found';
24147
+ } catch(e) { return 'error'; }
24148
+ })()
24149
+ `;
24150
+ files[`${scriptDir}/resolve_action.js`] = `/**
24151
+ * ${name} \u2014 resolve_action
24152
+ *
24153
+ * params.buttonText: string \u2014 button text to find and click.
24154
+ * \u2192 { resolved: true/false, clicked? }
24155
+ */
24156
+ (params) => {
24157
+ try {
24158
+ const btns = [...document.querySelectorAll('button, [role="button"]')].filter(b => b.offsetWidth > 0);
24159
+ const searchText = (params.buttonText || '').toLowerCase();
24160
+ const target = btns.find(b => (b.textContent||'').trim().toLowerCase().includes(searchText));
24161
+ if (target) {
24162
+ target.click();
24163
+ return JSON.stringify({ resolved: true, clicked: target.textContent.trim() });
24164
+ }
24165
+ return JSON.stringify({ resolved: false, available: btns.map(b => b.textContent.trim()).filter(Boolean).slice(0, 10) });
24166
+ } catch(e) { return JSON.stringify({ resolved: false, error: e.message }); }
24167
+ }
24168
+ `;
24169
+ files[`${scriptDir}/list_models.js`] = `/**
24170
+ * ${name} \u2014 list_models
24171
+ *
24172
+ * TODO: Open model dropdown and extract model list.
24173
+ * \u2192 { models[], current }
24174
+ */
24175
+ (() => {
24176
+ try {
24177
+ return JSON.stringify({ models: [], current: '' });
24178
+ } catch(e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
24179
+ })()
24180
+ `;
24181
+ files[`${scriptDir}/list_modes.js`] = `/**
24182
+ * ${name} \u2014 list_modes
24183
+ *
24184
+ * TODO: Open mode dropdown and extract mode list.
24185
+ * \u2192 { modes[], current }
24186
+ */
24187
+ (() => {
24188
+ try {
24189
+ return JSON.stringify({ modes: [], current: '' });
24190
+ } catch(e) { return JSON.stringify({ modes: [], current: '', error: e.message }); }
24191
+ })()
24192
+ `;
24193
+ files[`${scriptDir}/set_model.js`] = `/**
24194
+ * ${name} \u2014 set_model
24195
+ *
24196
+ * params.model: string
24197
+ * TODO: Open model dropdown and select target model.
24198
+ * \u2192 { success: true/false }
24199
+ */
24200
+ async (params) => {
24201
+ try {
24202
+ return JSON.stringify({ success: false, error: 'Not implemented' });
24203
+ } catch(e) { return JSON.stringify({ success: false, error: e.message }); }
24204
+ }
24205
+ `;
24206
+ files[`${scriptDir}/set_mode.js`] = `/**
24207
+ * ${name} \u2014 set_mode
24208
+ *
24209
+ * params.mode: string
24210
+ * TODO: Open mode dropdown and select target mode.
24211
+ * \u2192 { success: true/false }
24212
+ */
24213
+ async (params) => {
24214
+ try {
24215
+ return JSON.stringify({ success: false, error: 'Not implemented' });
24216
+ } catch(e) { return JSON.stringify({ success: false, error: e.message }); }
24217
+ }
24005
24218
  `;
24006
24219
  return {
24007
24220
  "provider.json": JSON.stringify(meta3, null, 2) + "\n",
24008
- "scripts.js": scripts
24221
+ files
24009
24222
  };
24010
24223
  }
24011
24224
  var DEV_SERVER_PORT = 19280;
@@ -24099,6 +24312,15 @@ module.exports.dismissNotification = function dismissNotification(params) {
24099
24312
  } else if (pathname.match(/^\/api\/providers\/([^/]+)\/spawn-test$/) && req.method === "POST") {
24100
24313
  const type = pathname.match(/^\/api\/providers\/([^/]+)\/spawn-test$/)[1];
24101
24314
  await this.handleSpawnTest(type, req, res);
24315
+ } else if (pathname.match(/^\/api\/providers\/([^/]+)\/validate$/) && req.method === "POST") {
24316
+ const type = pathname.match(/^\/api\/providers\/([^/]+)\/validate$/)[1];
24317
+ await this.handleValidate(type, req, res);
24318
+ } else if (pathname.match(/^\/api\/providers\/([^/]+)\/acp-chat$/) && req.method === "POST") {
24319
+ const type = pathname.match(/^\/api\/providers\/([^/]+)\/acp-chat$/)[1];
24320
+ await this.handleAcpChat(type, req, res);
24321
+ } else if (pathname.match(/^\/api\/providers\/([^/]+)\/script-hints$/) && req.method === "GET") {
24322
+ const type = pathname.match(/^\/api\/providers\/([^/]+)\/script-hints$/)[1];
24323
+ await this.handleScriptHints(type, req, res);
24102
24324
  } else if (pathname.startsWith("/assets/") || pathname === "/favicon.ico") {
24103
24325
  await this.serveStaticAsset(pathname, res);
24104
24326
  } else if (pathname === "/" || pathname === "/console" || !pathname.startsWith("/api")) {
@@ -24179,7 +24401,7 @@ module.exports.dismissNotification = function dismissNotification(params) {
24179
24401
  this.json(res, 200, { providers, count: providers.length });
24180
24402
  }
24181
24403
  async handleProviderConfig(type, _req, res) {
24182
- const provider2 = this.providerLoader.get(type);
24404
+ const provider2 = this.providerLoader.resolve(type);
24183
24405
  if (!provider2) {
24184
24406
  this.json(res, 404, { error: `Provider not found: ${type}` });
24185
24407
  return;
@@ -24192,7 +24414,7 @@ module.exports.dismissNotification = function dismissNotification(params) {
24192
24414
  this.json(res, 200, { type, config: config2 });
24193
24415
  }
24194
24416
  async handleSpawnTest(type, req, res) {
24195
- const provider2 = this.providerLoader.get(type);
24417
+ const provider2 = this.providerLoader.resolve(type);
24196
24418
  if (!provider2) {
24197
24419
  this.json(res, 404, { error: `Provider not found: ${type}` });
24198
24420
  return;
@@ -24739,6 +24961,208 @@ module.exports.dismissNotification = function dismissNotification(params) {
24739
24961
  this.json(res, 500, { error: `Save failed: ${e.message}` });
24740
24962
  }
24741
24963
  }
24964
+ async handleScriptHints(type, _req, res) {
24965
+ const dir = this.findProviderDir(type);
24966
+ if (!dir) {
24967
+ this.json(res, 404, { error: `Provider not found: ${type}` });
24968
+ return;
24969
+ }
24970
+ let scriptsPath = "";
24971
+ const directScripts = path9.join(dir, "scripts.js");
24972
+ if (fs7.existsSync(directScripts)) {
24973
+ scriptsPath = directScripts;
24974
+ } else {
24975
+ const scriptsDir = path9.join(dir, "scripts");
24976
+ if (fs7.existsSync(scriptsDir)) {
24977
+ const versions = fs7.readdirSync(scriptsDir).filter((d) => {
24978
+ return fs7.statSync(path9.join(scriptsDir, d)).isDirectory();
24979
+ }).sort().reverse();
24980
+ for (const ver of versions) {
24981
+ const p = path9.join(scriptsDir, ver, "scripts.js");
24982
+ if (fs7.existsSync(p)) {
24983
+ scriptsPath = p;
24984
+ break;
24985
+ }
24986
+ }
24987
+ }
24988
+ }
24989
+ if (!scriptsPath) {
24990
+ this.json(res, 200, { hints: {} });
24991
+ return;
24992
+ }
24993
+ try {
24994
+ const source = fs7.readFileSync(scriptsPath, "utf-8");
24995
+ const hints = {};
24996
+ const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
24997
+ let match;
24998
+ while ((match = funcRegex.exec(source)) !== null) {
24999
+ const name = match[1];
25000
+ const startIdx = match.index;
25001
+ const nextFunc = source.indexOf("module.exports.", startIdx + 1);
25002
+ const funcBody = source.substring(startIdx, nextFunc > 0 ? nextFunc : source.length);
25003
+ const paramFields = {};
25004
+ const dotRegex = /params\?\.([a-zA-Z_]+)|params\.([a-zA-Z_]+)/g;
25005
+ let dm;
25006
+ while ((dm = dotRegex.exec(funcBody)) !== null) {
25007
+ const field = dm[1] || dm[2];
25008
+ if (field === "length") continue;
25009
+ if (!(field in paramFields)) {
25010
+ if (/index|count|port|timeout/i.test(field)) paramFields[field] = 0;
25011
+ else if (/action|text|title|message|model|mode|button|name|filter/i.test(field)) paramFields[field] = "";
25012
+ else paramFields[field] = "";
25013
+ }
25014
+ }
25015
+ const typeofRegex = /typeof params === 'string' \? params : params\?\.([a-zA-Z_]+)/g;
25016
+ let tm;
25017
+ while ((tm = typeofRegex.exec(funcBody)) !== null) {
25018
+ const field = tm[1];
25019
+ if (!(field in paramFields)) paramFields[field] = "";
25020
+ }
25021
+ const numRegex = /typeof params === 'number' \? params : params\?\.([a-zA-Z_]+)/g;
25022
+ let nm;
25023
+ while ((nm = numRegex.exec(funcBody)) !== null) {
25024
+ const field = nm[1];
25025
+ if (!(field in paramFields)) paramFields[field] = 0;
25026
+ }
25027
+ const descriptions = {
25028
+ readChat: "No params required",
25029
+ sendMessage: "Text to send to the chat",
25030
+ listSessions: "No params required",
25031
+ switchSession: "Switch by index or title",
25032
+ newSession: "No params required",
25033
+ focusEditor: "No params required",
25034
+ openPanel: "No params required",
25035
+ resolveAction: "Approve/reject action buttons",
25036
+ listNotifications: "Optional message filter",
25037
+ dismissNotification: "Dismiss by index, message, or button",
25038
+ listModels: "No params required",
25039
+ setModel: "Model name to select",
25040
+ listModes: "No params required",
25041
+ setMode: "Mode name to select"
25042
+ };
25043
+ hints[name] = {
25044
+ template: Object.keys(paramFields).length > 0 ? paramFields : {},
25045
+ description: descriptions[name] || (Object.keys(paramFields).length > 0 ? "Params: " + Object.keys(paramFields).join(", ") : "No params")
25046
+ };
25047
+ }
25048
+ this.json(res, 200, { hints });
25049
+ } catch (e) {
25050
+ this.json(res, 500, { error: e.message });
25051
+ }
25052
+ }
25053
+ // ─── Validate provider.json ───
25054
+ async handleValidate(type, req, res) {
25055
+ const body = await this.readBody(req);
25056
+ const { content } = body;
25057
+ const errors = [];
25058
+ const warnings = [];
25059
+ try {
25060
+ const config2 = typeof content === "string" ? JSON.parse(content) : content;
25061
+ if (!config2.type) errors.push("Missing required field: type");
25062
+ if (!config2.name) errors.push("Missing required field: name");
25063
+ if (!config2.category) errors.push("Missing required field: category");
25064
+ else if (!["ide", "extension", "cli", "acp"].includes(config2.category)) errors.push(`Invalid category: ${config2.category}`);
25065
+ if (config2.category === "ide" || config2.category === "extension") {
25066
+ if (!config2.cdpPorts || !Array.isArray(config2.cdpPorts) || config2.cdpPorts.length === 0)
25067
+ warnings.push("IDE/Extension providers should have cdpPorts");
25068
+ if (config2.category === "extension" && !config2.extensionId)
25069
+ warnings.push("Extension providers should have extensionId");
25070
+ }
25071
+ if (config2.category === "acp" || config2.category === "cli") {
25072
+ if (!config2.spawn) errors.push("ACP/CLI providers must have spawn config");
25073
+ else {
25074
+ if (!config2.spawn.command) errors.push("spawn.command is required");
25075
+ }
25076
+ }
25077
+ if (config2.settings) {
25078
+ for (const [key, val] of Object.entries(config2.settings)) {
25079
+ const s = val;
25080
+ if (!s.type) errors.push(`settings.${key}: missing type`);
25081
+ else if (!["boolean", "number", "string", "select"].includes(s.type))
25082
+ errors.push(`settings.${key}: invalid type '${s.type}'`);
25083
+ if (s.default === void 0) warnings.push(`settings.${key}: no default value`);
25084
+ if (s.type === "number" && s.min !== void 0 && s.max !== void 0 && s.min > s.max)
25085
+ errors.push(`settings.${key}: min (${s.min}) > max (${s.max})`);
25086
+ if (s.type === "select" && (!s.options || !Array.isArray(s.options) || s.options.length === 0))
25087
+ errors.push(`settings.${key}: select type requires options[]`);
25088
+ }
25089
+ }
25090
+ if (config2.cdpPorts && Array.isArray(config2.cdpPorts)) {
25091
+ const allProviders = this.providerLoader.getAll();
25092
+ for (const port of config2.cdpPorts) {
25093
+ const conflict = allProviders.find((p) => p.type !== type && p.cdpPorts?.includes(port));
25094
+ if (conflict) warnings.push(`CDP port ${port} conflicts with provider '${conflict.type}'`);
25095
+ }
25096
+ }
25097
+ this.json(res, 200, { valid: errors.length === 0, errors, warnings });
25098
+ } catch (e) {
25099
+ this.json(res, 200, { valid: false, errors: [`Invalid JSON: ${e.message}`], warnings: [] });
25100
+ }
25101
+ }
25102
+ // ─── ACP Chat Test ───
25103
+ async handleAcpChat(type, req, res) {
25104
+ const body = await this.readBody(req);
25105
+ const { message, timeout = 3e4 } = body;
25106
+ if (!message) {
25107
+ this.json(res, 400, { error: "message required" });
25108
+ return;
25109
+ }
25110
+ const provider2 = this.providerLoader.get(type);
25111
+ if (!provider2) {
25112
+ this.json(res, 404, { error: `Provider not found: ${type}` });
25113
+ return;
25114
+ }
25115
+ const spawn3 = provider2.spawn;
25116
+ if (!spawn3) {
25117
+ this.json(res, 400, { error: `Provider ${type} has no spawn config` });
25118
+ return;
25119
+ }
25120
+ const { spawn: spawnFn } = await import("child_process");
25121
+ const start = Date.now();
25122
+ try {
25123
+ const args = [...spawn3.args || [], message];
25124
+ const child = spawnFn(spawn3.command, args, {
25125
+ shell: spawn3.shell ?? false,
25126
+ timeout,
25127
+ stdio: ["pipe", "pipe", "pipe"],
25128
+ env: { ...process.env, ...spawn3.env || {} }
25129
+ });
25130
+ let stdout = "";
25131
+ let stderr = "";
25132
+ child.stdout?.on("data", (d) => {
25133
+ stdout += d.toString();
25134
+ });
25135
+ child.stderr?.on("data", (d) => {
25136
+ stderr += d.toString();
25137
+ });
25138
+ await new Promise((resolve5) => {
25139
+ const timer = setTimeout(() => {
25140
+ child.kill();
25141
+ resolve5();
25142
+ }, timeout);
25143
+ child.on("exit", () => {
25144
+ clearTimeout(timer);
25145
+ resolve5();
25146
+ });
25147
+ });
25148
+ const elapsed = Date.now() - start;
25149
+ this.json(res, 200, {
25150
+ success: true,
25151
+ message,
25152
+ response: stdout.trim(),
25153
+ stderr: stderr.trim(),
25154
+ exitCode: child.exitCode,
25155
+ elapsed
25156
+ });
25157
+ } catch (e) {
25158
+ this.json(res, 200, {
25159
+ success: false,
25160
+ message,
25161
+ error: e.message,
25162
+ elapsed: Date.now() - start
25163
+ });
25164
+ }
25165
+ }
24742
25166
  async handleCdpTargets(_req, res) {
24743
25167
  const targets = [];
24744
25168
  for (const [ide, cdp2] of this.cdpManagers.entries()) {
@@ -24759,7 +25183,8 @@ module.exports.dismissNotification = function dismissNotification(params) {
24759
25183
  processName,
24760
25184
  installPath,
24761
25185
  binary,
24762
- extensionId
25186
+ extensionId,
25187
+ version: version2
24763
25188
  } = body;
24764
25189
  if (!type || !name) {
24765
25190
  this.json(res, 400, { error: "type and name required" });
@@ -24778,15 +25203,19 @@ module.exports.dismissNotification = function dismissNotification(params) {
24778
25203
  return;
24779
25204
  }
24780
25205
  try {
24781
- const files = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId });
25206
+ const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 });
24782
25207
  fs7.mkdirSync(targetDir, { recursive: true });
24783
- fs7.writeFileSync(jsonPath, files["provider.json"], "utf-8");
25208
+ fs7.writeFileSync(jsonPath, result["provider.json"], "utf-8");
24784
25209
  const createdFiles = ["provider.json"];
24785
- if (files["scripts.js"]) {
24786
- fs7.writeFileSync(path9.join(targetDir, "scripts.js"), files["scripts.js"], "utf-8");
24787
- createdFiles.push("scripts.js");
25210
+ if (result.files) {
25211
+ for (const [relPath, content] of Object.entries(result.files)) {
25212
+ const fullPath = path9.join(targetDir, relPath);
25213
+ fs7.mkdirSync(path9.dirname(fullPath), { recursive: true });
25214
+ fs7.writeFileSync(fullPath, content, "utf-8");
25215
+ createdFiles.push(relPath);
25216
+ }
24788
25217
  }
24789
- this.log(`Scaffolded provider: ${targetDir} (${createdFiles.join(", ")})`);
25218
+ this.log(`Scaffolded provider: ${targetDir} (${createdFiles.length} files)`);
24790
25219
  this.json(res, 201, { created: true, path: targetDir, files: createdFiles, type, name, category });
24791
25220
  } catch (e) {
24792
25221
  this.json(res, 500, { error: e.message });
@@ -25980,7 +26409,7 @@ var init_daemon_p2p = __esm({
25980
26409
  /** Fetch TURN credentials */
25981
26410
  async fetchTurnCredentials() {
25982
26411
  try {
25983
- const serverUrl = "https://api.adhf.dev";
26412
+ const serverUrl = process.env.ADHDEV_SERVER_URL || "https://api.adhf.dev";
25984
26413
  const configPath = path.join(os.homedir(), ".adhdev", "config.json");
25985
26414
  let token = "";
25986
26415
  try {
@@ -26612,7 +27041,7 @@ function stopDaemon() {
26612
27041
  return false;
26613
27042
  }
26614
27043
  }
26615
- var import_daemon_core3, os2, fs2, path2, crypto2, import_chalk, DANGEROUS_PATTERNS, AdhdevDaemon;
27044
+ var import_daemon_core3, os2, fs2, path2, crypto2, import_chalk, pkgVersion, DANGEROUS_PATTERNS, AdhdevDaemon;
26616
27045
  var init_adhdev_daemon = __esm({
26617
27046
  "src/adhdev-daemon.ts"() {
26618
27047
  "use strict";
@@ -26624,6 +27053,24 @@ var init_adhdev_daemon = __esm({
26624
27053
  path2 = __toESM(require("path"));
26625
27054
  crypto2 = __toESM(require("crypto"));
26626
27055
  import_chalk = __toESM(require("chalk"));
27056
+ pkgVersion = "unknown";
27057
+ try {
27058
+ const possiblePaths = [
27059
+ path2.join(__dirname, "..", "package.json"),
27060
+ path2.join(__dirname, "package.json")
27061
+ ];
27062
+ for (const p of possiblePaths) {
27063
+ try {
27064
+ const data = JSON.parse(fs2.readFileSync(p, "utf-8"));
27065
+ if (data.version) {
27066
+ pkgVersion = data.version;
27067
+ break;
27068
+ }
27069
+ } catch {
27070
+ }
27071
+ }
27072
+ } catch {
27073
+ }
26627
27074
  DANGEROUS_PATTERNS = [
26628
27075
  /\brm\s+(-[a-z]*f|-[a-z]*r|--force|--recursive)/i,
26629
27076
  /\bsudo\b/i,
@@ -26658,7 +27105,6 @@ var init_adhdev_daemon = __esm({
26658
27105
  constructor() {
26659
27106
  this.localPort = 19222;
26660
27107
  this.providerLoader = new import_daemon_core3.ProviderLoader({
26661
- builtinDir: path2.join(__dirname, "..", "providers", "_builtin"),
26662
27108
  logFn: import_daemon_core3.LOG.forComponent("Provider").asLogFn()
26663
27109
  });
26664
27110
  this.providerLoader.loadAll();
@@ -26734,7 +27180,7 @@ var init_adhdev_daemon = __esm({
26734
27180
  token: config2.connectionToken,
26735
27181
  cliInfo: {
26736
27182
  type: "adhdev-daemon",
26737
- version: "0.2.0",
27183
+ version: pkgVersion,
26738
27184
  platform: os2.platform(),
26739
27185
  instanceId
26740
27186
  }
@@ -27080,29 +27526,6 @@ var init_adhdev_daemon = __esm({
27080
27526
  const history = getRecentCommands(count);
27081
27527
  return { success: true, history };
27082
27528
  }
27083
- // get_acp_auth / set_acp_auth removed — ADHDev does not manage API keys.
27084
- // Each CLI/ACP tool handles its own auth. ADHDev focuses on install detection + error reporting.
27085
- case "get_daemon_logs": {
27086
- const count = parseInt(data.lines) || 100;
27087
- const minLevel = data.minLevel || "info";
27088
- try {
27089
- const { getRecentLogs, LOG_PATH } = require("./logging/logger");
27090
- const entries = getRecentLogs(count, minLevel);
27091
- if (entries.length > 0) {
27092
- return { success: true, entries, totalBuffered: entries.length };
27093
- }
27094
- const logFs = require("fs");
27095
- if (logFs.existsSync(LOG_PATH)) {
27096
- const content = logFs.readFileSync(LOG_PATH, "utf-8");
27097
- const allLines = content.split("\n");
27098
- const recent = allLines.slice(-count).join("\n");
27099
- return { success: true, logs: recent, totalLines: allLines.length };
27100
- }
27101
- return { success: true, entries: [], totalBuffered: 0 };
27102
- } catch (e) {
27103
- return { success: false, error: e.message };
27104
- }
27105
- }
27106
27529
  }
27107
27530
  const result = await this.executeDaemonCommand(cmdType, data);
27108
27531
  if (result) {
@@ -27134,6 +27557,31 @@ var init_adhdev_daemon = __esm({
27134
27557
  case "agent_command": {
27135
27558
  return this.cliManager.handleCliCommand(cmd, args);
27136
27559
  }
27560
+ case "get_logs": {
27561
+ const count = parseInt(args?.count) || parseInt(args?.lines) || 100;
27562
+ const minLevel = args?.minLevel || "info";
27563
+ const sinceTs = args?.since || 0;
27564
+ try {
27565
+ const { getRecentLogs, LOG_PATH } = require("./logging/logger");
27566
+ let logs = getRecentLogs(count, minLevel);
27567
+ if (sinceTs > 0) {
27568
+ logs = logs.filter((l) => l.ts > sinceTs);
27569
+ }
27570
+ if (logs.length > 0) {
27571
+ return { success: true, logs, totalBuffered: logs.length };
27572
+ }
27573
+ const logFs = require("fs");
27574
+ if (logFs.existsSync(LOG_PATH)) {
27575
+ const content = logFs.readFileSync(LOG_PATH, "utf-8");
27576
+ const allLines = content.split("\n");
27577
+ const recent = allLines.slice(-count).join("\n");
27578
+ return { success: true, logs: recent, totalLines: allLines.length };
27579
+ }
27580
+ return { success: true, logs: [], totalBuffered: 0 };
27581
+ } catch (e) {
27582
+ return { success: false, error: e.message };
27583
+ }
27584
+ }
27137
27585
  // ─── restart_session: IDE / CLI / ACP unified ───
27138
27586
  case "restart_session": {
27139
27587
  const targetType = args?.cliType || args?.agentType || args?.ideType;
@@ -27169,7 +27617,8 @@ var init_adhdev_daemon = __esm({
27169
27617
  if (result.success && result.port && result.ideId && !this.cdpManagers.has(result.ideId)) {
27170
27618
  const cdpLog = import_daemon_core3.LOG.forComponent(`CDP:${result.ideId}`);
27171
27619
  console.log(import_chalk.default.cyan(`[launch_ide] Connecting CDP for ${result.ideId} on port ${result.port}...`));
27172
- const manager = new import_daemon_core3.DaemonCdpManager(result.port, cdpLog.asLogFn());
27620
+ const provider2 = this.providerLoader.get(result.ideId);
27621
+ const manager = new import_daemon_core3.DaemonCdpManager(result.port, cdpLog.asLogFn(), void 0, provider2?.targetFilter);
27173
27622
  const connected = await manager.connect();
27174
27623
  if (connected) {
27175
27624
  const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(result.ideId).map((p) => ({
@@ -27442,7 +27891,8 @@ var init_adhdev_daemon = __esm({
27442
27891
  for (const { port, ide } of filteredPorts) {
27443
27892
  const allTargets = await import_daemon_core3.DaemonCdpManager.listAllTargets(port);
27444
27893
  if (allTargets.length === 0) {
27445
- const manager = new import_daemon_core3.DaemonCdpManager(port, import_daemon_core3.LOG.forComponent(`CDP:${ide}`).asLogFn());
27894
+ const provider2 = this.providerLoader.get(ide);
27895
+ const manager = new import_daemon_core3.DaemonCdpManager(port, import_daemon_core3.LOG.forComponent(`CDP:${ide}`).asLogFn(), void 0, provider2?.targetFilter);
27446
27896
  const connected = await manager.connect();
27447
27897
  if (connected) {
27448
27898
  this.cdpManagers.set(ide, manager);
@@ -27461,7 +27911,8 @@ var init_adhdev_daemon = __esm({
27461
27911
  managerKey = `${ide}_${workspaceName}`;
27462
27912
  }
27463
27913
  if (this.cdpManagers.has(managerKey)) continue;
27464
- const manager = new import_daemon_core3.DaemonCdpManager(port, import_daemon_core3.LOG.forComponent(`CDP:${managerKey}`).asLogFn(), target.id);
27914
+ const provider2 = this.providerLoader.get(ide);
27915
+ const manager = new import_daemon_core3.DaemonCdpManager(port, import_daemon_core3.LOG.forComponent(`CDP:${managerKey}`).asLogFn(), target.id, provider2?.targetFilter);
27465
27916
  const connected = await manager.connect();
27466
27917
  if (connected) {
27467
27918
  this.cdpManagers.set(managerKey, manager);
@@ -27504,7 +27955,8 @@ var init_adhdev_daemon = __esm({
27504
27955
  managerKey = `${ide}_${workspaceName}`;
27505
27956
  }
27506
27957
  if (this.cdpManagers.has(managerKey)) continue;
27507
- const manager = new import_daemon_core3.DaemonCdpManager(primaryPort, import_daemon_core3.LOG.forComponent(`CDP:${managerKey}`).asLogFn(), target.id);
27958
+ const provider2 = this.providerLoader.get(ide);
27959
+ const manager = new import_daemon_core3.DaemonCdpManager(primaryPort, import_daemon_core3.LOG.forComponent(`CDP:${managerKey}`).asLogFn(), target.id, provider2?.targetFilter);
27508
27960
  const connected = await manager.connect();
27509
27961
  if (connected) {
27510
27962
  this.cdpManagers.set(managerKey, manager);
@@ -27530,9 +27982,7 @@ var import_inquirer = __toESM(require("inquirer"));
27530
27982
  var import_ora = __toESM(require("ora"));
27531
27983
  var import_open = __toESM(require("open"));
27532
27984
  var import_daemon_core4 = __toESM(require_dist());
27533
- var import_path = require("path");
27534
- var BUILTIN_PROVIDERS_DIR = (0, import_path.join)(__dirname, "..", "providers", "_builtin");
27535
- var SERVER_URL = "https://api.adhf.dev";
27985
+ var SERVER_URL = process.env.ADHDEV_SERVER_URL || "https://api.adhf.dev";
27536
27986
  var LOGO = `
27537
27987
  ${import_chalk2.default.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}
27538
27988
  ${import_chalk2.default.cyan("\u2551")} ${import_chalk2.default.bold.white("\u{1F9A6} ADHDev Setup Wizard")} ${import_chalk2.default.cyan("\u2551")}
@@ -27541,7 +27991,7 @@ ${import_chalk2.default.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u
27541
27991
  `;
27542
27992
  var DIVIDER = import_chalk2.default.gray("\u2500".repeat(44));
27543
27993
  async function runWizard(options = {}) {
27544
- const loader = new import_daemon_core4.ProviderLoader({ builtinDir: BUILTIN_PROVIDERS_DIR, logFn: () => {
27994
+ const loader = new import_daemon_core4.ProviderLoader({ logFn: () => {
27545
27995
  } });
27546
27996
  loader.loadAll();
27547
27997
  loader.registerToDetector();
@@ -27868,7 +28318,7 @@ async function injectTokenToIDE(ide, connectionToken) {
27868
28318
  return path3.join(home, ".config", appName2, "User", "settings.json");
27869
28319
  }
27870
28320
  };
27871
- const loader = new import_daemon_core4.ProviderLoader({ builtinDir: BUILTIN_PROVIDERS_DIR, logFn: () => {
28321
+ const loader = new import_daemon_core4.ProviderLoader({ logFn: () => {
27872
28322
  } });
27873
28323
  loader.loadAll();
27874
28324
  const appNameMap = loader.getMacAppIdentifiers();
@@ -28033,18 +28483,18 @@ async function installCliOnly() {
28033
28483
  // src/cli-entrypoint.ts
28034
28484
  var import_daemon_core5 = __toESM(require_dist());
28035
28485
  var import_fs = require("fs");
28036
- var import_path2 = require("path");
28037
- var pkgVersion = "unknown";
28486
+ var import_path = require("path");
28487
+ var pkgVersion2 = "unknown";
28038
28488
  try {
28039
28489
  const possiblePaths = [
28040
- (0, import_path2.join)(__dirname, "..", "package.json"),
28041
- (0, import_path2.join)(__dirname, "package.json")
28490
+ (0, import_path.join)(__dirname, "..", "package.json"),
28491
+ (0, import_path.join)(__dirname, "package.json")
28042
28492
  ];
28043
28493
  for (const p of possiblePaths) {
28044
28494
  try {
28045
28495
  const data = JSON.parse((0, import_fs.readFileSync)(p, "utf-8"));
28046
28496
  if (data.version) {
28047
- pkgVersion = data.version;
28497
+ pkgVersion2 = data.version;
28048
28498
  break;
28049
28499
  }
28050
28500
  } catch {
@@ -28052,13 +28502,12 @@ try {
28052
28502
  }
28053
28503
  } catch {
28054
28504
  }
28055
- var BUILTIN_PROVIDERS_DIR2 = (0, import_path2.join)((0, import_path2.dirname)(__dirname), "providers", "_builtin");
28056
- var _cliProviderLoader = new import_daemon_core5.ProviderLoader({ builtinDir: BUILTIN_PROVIDERS_DIR2, logFn: () => {
28505
+ var _cliProviderLoader = new import_daemon_core5.ProviderLoader({ logFn: () => {
28057
28506
  } });
28058
28507
  _cliProviderLoader.loadAll();
28059
28508
  _cliProviderLoader.registerToDetector();
28060
28509
  var program = new import_commander.Command();
28061
- program.name("adhdev").description("\u{1F9A6} ADHDev \u2014 Agent Dashboard Hub for Dev").version(pkgVersion);
28510
+ program.name("adhdev").description("\u{1F9A6} ADHDev \u2014 Agent Dashboard Hub for Dev").version(pkgVersion2);
28062
28511
  program.command("setup").description("Run the interactive setup wizard (detect IDEs, login)").option("-f, --force", "Force re-run setup even if already configured").action(async (options) => {
28063
28512
  await runWizard({ force: options.force });
28064
28513
  });
@@ -28392,7 +28841,7 @@ program.command("daemon:upgrade").description("Upgrade ADHDev to latest version
28392
28841
  const adhdevPath = process.argv[1];
28393
28842
  const realPath = fsMod.realpathSync(adhdevPath);
28394
28843
  const isLinked = realPath.includes(".openclaw") || realPath.includes("/src/");
28395
- const currentVersion = pkgVersion;
28844
+ const currentVersion = pkgVersion2;
28396
28845
  console.log(` ${import_chalk3.default.bold("Current:")} v${currentVersion}`);
28397
28846
  console.log(` ${import_chalk3.default.bold("Install:")} ${isLinked ? "npm link (dev)" : "npm global"}`);
28398
28847
  if (isLinked) {
@@ -28571,7 +29020,7 @@ var provider = program.command("provider").description("\u{1F50C} Provider manag
28571
29020
  provider.command("list").description("List all loaded providers").option("-j, --json", "Output raw JSON").action(async (options) => {
28572
29021
  try {
28573
29022
  const { ProviderLoader: ProviderLoader4 } = await Promise.resolve().then(() => __toESM(require_dist()));
28574
- const loader = new ProviderLoader4({ builtinDir: BUILTIN_PROVIDERS_DIR2 });
29023
+ const loader = new ProviderLoader4();
28575
29024
  loader.loadAll();
28576
29025
  const providers = loader.getAll();
28577
29026
  if (options.json) {