adhdev 0.1.22 → 0.1.23

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 (2) hide show
  1. package/dist/index.js +383 -174
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -325,11 +325,61 @@ var init_config = __esm({
325
325
  userName: null,
326
326
  setupCompleted: false,
327
327
  setupDate: null,
328
- configuredCLIs: []
328
+ configuredCLIs: [],
329
+ enabledIdes: []
329
330
  };
330
331
  }
331
332
  });
332
333
 
334
+ // src/cli-detector.ts
335
+ async function detectCLIs() {
336
+ const platform9 = os.platform();
337
+ const whichCmd = platform9 === "win32" ? "where" : "which";
338
+ const results = [];
339
+ for (const cli of KNOWN_CLIS) {
340
+ try {
341
+ const pathResult = (0, import_child_process3.execSync)(`${whichCmd} ${cli.command} 2>/dev/null`, {
342
+ encoding: "utf-8",
343
+ timeout: 5e3,
344
+ stdio: ["pipe", "pipe", "pipe"]
345
+ }).trim().split("\n")[0];
346
+ if (!pathResult) throw new Error("Not found");
347
+ let version;
348
+ try {
349
+ const versionResult = (0, import_child_process3.execSync)(`${cli.command} --version 2>/dev/null`, {
350
+ encoding: "utf-8",
351
+ timeout: 5e3,
352
+ stdio: ["pipe", "pipe", "pipe"]
353
+ }).trim();
354
+ const match = versionResult.match(/(\d+\.\d+[\.\d]*)/);
355
+ version = match ? match[1] : versionResult.split("\n")[0].slice(0, 30);
356
+ } catch {
357
+ }
358
+ results.push({ ...cli, installed: true, version, path: pathResult });
359
+ } catch {
360
+ results.push({ ...cli, installed: false });
361
+ }
362
+ }
363
+ return results;
364
+ }
365
+ async function detectCLI(cliId) {
366
+ const all = await detectCLIs();
367
+ return all.find((c) => c.id === cliId && c.installed) || null;
368
+ }
369
+ var import_child_process3, os, KNOWN_CLIS;
370
+ var init_cli_detector = __esm({
371
+ "src/cli-detector.ts"() {
372
+ "use strict";
373
+ import_child_process3 = require("child_process");
374
+ os = __toESM(require("os"));
375
+ KNOWN_CLIS = [
376
+ { id: "gemini-cli", displayName: "Gemini CLI", icon: "\u264A", command: "gemini" },
377
+ { id: "claude-code", displayName: "Claude Code", icon: "\u{1F916}", command: "claude" },
378
+ { id: "codex-cli", displayName: "Codex CLI", icon: "\u{1F9E0}", command: "codex" }
379
+ ];
380
+ }
381
+ });
382
+
333
383
  // src/launch.ts
334
384
  async function findFreePort(ports) {
335
385
  for (const port2 of ports) {
@@ -377,38 +427,38 @@ async function isCdpActive(port) {
377
427
  });
378
428
  }
379
429
  async function killIdeProcess(ideId) {
380
- const plat = os.platform();
430
+ const plat = os2.platform();
381
431
  const appName = MAC_APP_IDENTIFIERS[ideId];
382
432
  const winProcesses = WIN_PROCESS_NAMES[ideId];
383
433
  try {
384
434
  if (plat === "darwin" && appName) {
385
435
  try {
386
- (0, import_child_process3.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
436
+ (0, import_child_process4.execSync)(`osascript -e 'tell application "${appName}" to quit' 2>/dev/null`, {
387
437
  timeout: 5e3
388
438
  });
389
439
  } catch {
390
440
  try {
391
- (0, import_child_process3.execSync)(`pkill -f "${appName}" 2>/dev/null`);
441
+ (0, import_child_process4.execSync)(`pkill -f "${appName}" 2>/dev/null`);
392
442
  } catch {
393
443
  }
394
444
  }
395
445
  } else if (plat === "win32" && winProcesses) {
396
446
  for (const proc of winProcesses) {
397
447
  try {
398
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
448
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`, { timeout: 5e3 });
399
449
  } catch {
400
450
  }
401
451
  }
402
452
  try {
403
453
  const exeName = winProcesses[0].replace(".exe", "");
404
- (0, import_child_process3.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
454
+ (0, import_child_process4.execSync)(`powershell -Command "Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue | Stop-Process -Force"`, {
405
455
  timeout: 1e4
406
456
  });
407
457
  } catch {
408
458
  }
409
459
  } else {
410
460
  try {
411
- (0, import_child_process3.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
461
+ (0, import_child_process4.execSync)(`pkill -f "${ideId}" 2>/dev/null`);
412
462
  } catch {
413
463
  }
414
464
  }
@@ -418,13 +468,13 @@ async function killIdeProcess(ideId) {
418
468
  }
419
469
  if (plat === "darwin" && appName) {
420
470
  try {
421
- (0, import_child_process3.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
471
+ (0, import_child_process4.execSync)(`pkill -9 -f "${appName}" 2>/dev/null`);
422
472
  } catch {
423
473
  }
424
474
  } else if (plat === "win32" && winProcesses) {
425
475
  for (const proc of winProcesses) {
426
476
  try {
427
- (0, import_child_process3.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
477
+ (0, import_child_process4.execSync)(`taskkill /IM "${proc}" /F 2>nul`);
428
478
  } catch {
429
479
  }
430
480
  }
@@ -436,26 +486,26 @@ async function killIdeProcess(ideId) {
436
486
  }
437
487
  }
438
488
  function isIdeRunning(ideId) {
439
- const plat = os.platform();
489
+ const plat = os2.platform();
440
490
  try {
441
491
  if (plat === "darwin") {
442
492
  const appName = MAC_APP_IDENTIFIERS[ideId];
443
493
  if (!appName) return false;
444
- const result = (0, import_child_process3.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
494
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${appName}" 2>/dev/null`, { encoding: "utf-8" });
445
495
  return result.trim().length > 0;
446
496
  } else if (plat === "win32") {
447
497
  const winProcesses = WIN_PROCESS_NAMES[ideId];
448
498
  if (!winProcesses) return false;
449
499
  for (const proc of winProcesses) {
450
500
  try {
451
- const result = (0, import_child_process3.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
501
+ const result = (0, import_child_process4.execSync)(`tasklist /FI "IMAGENAME eq ${proc}" /NH 2>nul`, { encoding: "utf-8" });
452
502
  if (result.includes(proc)) return true;
453
503
  } catch {
454
504
  }
455
505
  }
456
506
  try {
457
507
  const exeName = winProcesses[0].replace(".exe", "");
458
- const result = (0, import_child_process3.execSync)(
508
+ const result = (0, import_child_process4.execSync)(
459
509
  `powershell -Command "(Get-Process -Name '${exeName}' -ErrorAction SilentlyContinue).Count"`,
460
510
  { encoding: "utf-8", timeout: 5e3 }
461
511
  );
@@ -464,7 +514,7 @@ function isIdeRunning(ideId) {
464
514
  }
465
515
  return false;
466
516
  } else {
467
- const result = (0, import_child_process3.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
517
+ const result = (0, import_child_process4.execSync)(`pgrep -f "${ideId}" 2>/dev/null`, { encoding: "utf-8" });
468
518
  return result.trim().length > 0;
469
519
  }
470
520
  } catch {
@@ -472,12 +522,12 @@ function isIdeRunning(ideId) {
472
522
  }
473
523
  }
474
524
  function detectCurrentWorkspace(ideId) {
475
- const plat = os.platform();
525
+ const plat = os2.platform();
476
526
  if (plat === "darwin") {
477
527
  try {
478
528
  const appName = MAC_APP_IDENTIFIERS[ideId];
479
529
  if (!appName) return void 0;
480
- const result = (0, import_child_process3.execSync)(
530
+ const result = (0, import_child_process4.execSync)(
481
531
  `lsof -c "${appName}" 2>/dev/null | grep cwd | head -1 | awk '{print $NF}'`,
482
532
  { encoding: "utf-8", timeout: 3e3 }
483
533
  );
@@ -498,7 +548,7 @@ function detectCurrentWorkspace(ideId) {
498
548
  const appName = appNameMap[ideId];
499
549
  if (appName) {
500
550
  const storagePath = path.join(
501
- process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"),
551
+ process.env.APPDATA || path.join(os2.homedir(), "AppData", "Roaming"),
502
552
  appName,
503
553
  "storage.json"
504
554
  );
@@ -520,7 +570,7 @@ function detectCurrentWorkspace(ideId) {
520
570
  return void 0;
521
571
  }
522
572
  async function launchWithCdp(options = {}) {
523
- const platform9 = os.platform();
573
+ const platform9 = os2.platform();
524
574
  let targetIde;
525
575
  const ides = await detectIDEs();
526
576
  if (options.ideId) {
@@ -630,9 +680,9 @@ async function launchMacOS(ide, port, workspace, newWindow) {
630
680
  if (workspace) args.push(workspace);
631
681
  if (appName) {
632
682
  const openArgs = ["-a", appName, "--args", ...args];
633
- (0, import_child_process3.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
683
+ (0, import_child_process4.spawn)("open", openArgs, { detached: true, stdio: "ignore" }).unref();
634
684
  } else if (ide.cliCommand) {
635
- (0, import_child_process3.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
685
+ (0, import_child_process4.spawn)(ide.cliCommand, args, { detached: true, stdio: "ignore" }).unref();
636
686
  } else {
637
687
  throw new Error(`No app identifier or CLI for ${ide.displayName}`);
638
688
  }
@@ -658,15 +708,15 @@ async function launchLinux(ide, port, workspace, newWindow) {
658
708
  const args = ["--remote-debugging-port=" + port];
659
709
  if (newWindow) args.push("--new-window");
660
710
  if (workspace) args.push(workspace);
661
- (0, import_child_process3.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
711
+ (0, import_child_process4.spawn)(cli, args, { detached: true, stdio: "ignore" }).unref();
662
712
  }
663
- var import_child_process3, net, os, path, CDP_PORTS, MAC_APP_IDENTIFIERS, WIN_PROCESS_NAMES;
713
+ var import_child_process4, net, os2, path, CDP_PORTS, MAC_APP_IDENTIFIERS, WIN_PROCESS_NAMES;
664
714
  var init_launch = __esm({
665
715
  "src/launch.ts"() {
666
716
  "use strict";
667
- import_child_process3 = require("child_process");
717
+ import_child_process4 = require("child_process");
668
718
  net = __toESM(require("net"));
669
- os = __toESM(require("os"));
719
+ os2 = __toESM(require("os"));
670
720
  path = __toESM(require("path"));
671
721
  init_detector();
672
722
  init_config();
@@ -821,7 +871,7 @@ var init_cli_bridge = __esm({
821
871
  const handlers = this.messageHandlers.get(message.type);
822
872
  if (handlers) {
823
873
  handlers.forEach((h) => h(message));
824
- } else if (message.type !== "auth_ok" && message.type !== "auth_error") {
874
+ } else if (message.type !== "auth_ok") {
825
875
  console.log(`[CliBridge] Unhandled message type: ${message.type}`);
826
876
  }
827
877
  } catch (error) {
@@ -883,21 +933,21 @@ function stripAnsi(str) {
883
933
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
884
934
  }
885
935
  function findGeminiBinary() {
886
- const isWin = os2.platform() === "win32";
936
+ const isWin = os3.platform() === "win32";
887
937
  const cmd = isWin ? "where gemini" : "which gemini";
888
938
  try {
889
- const result = (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
939
+ const result = (0, import_child_process5.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
890
940
  return result.split("\n")[0].trim();
891
941
  } catch {
892
942
  return isWin ? "gemini.cmd" : "gemini";
893
943
  }
894
944
  }
895
- var os2, import_child_process4, pty, PROMPT_PATTERNS, STARTUP_DIALOG_PATTERNS, GeminiCliAdapter;
945
+ var os3, import_child_process5, pty, PROMPT_PATTERNS, STARTUP_DIALOG_PATTERNS, GeminiCliAdapter;
896
946
  var init_gemini_cli = __esm({
897
947
  "src/cli-adapters/gemini-cli.ts"() {
898
948
  "use strict";
899
- os2 = __toESM(require("os"));
900
- import_child_process4 = require("child_process");
949
+ os3 = __toESM(require("os"));
950
+ import_child_process5 = require("child_process");
901
951
  try {
902
952
  pty = require("node-pty");
903
953
  } catch {
@@ -1149,21 +1199,21 @@ function stripAnsi2(str) {
1149
1199
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
1150
1200
  }
1151
1201
  function findClaudeBinary() {
1152
- const isWin = os3.platform() === "win32";
1202
+ const isWin = os4.platform() === "win32";
1153
1203
  const cmd = isWin ? "where claude" : "which claude";
1154
1204
  try {
1155
- const result = (0, import_child_process5.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
1205
+ const result = (0, import_child_process6.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
1156
1206
  return result.split("\n")[0].trim();
1157
1207
  } catch {
1158
1208
  return isWin ? "claude.cmd" : "claude";
1159
1209
  }
1160
1210
  }
1161
- var os3, import_child_process5, pty2, ClaudeCliAdapter;
1211
+ var os4, import_child_process6, pty2, ClaudeCliAdapter;
1162
1212
  var init_claude_cli = __esm({
1163
1213
  "src/cli-adapters/claude-cli.ts"() {
1164
1214
  "use strict";
1165
- os3 = __toESM(require("os"));
1166
- import_child_process5 = require("child_process");
1215
+ os4 = __toESM(require("os"));
1216
+ import_child_process6 = require("child_process");
1167
1217
  try {
1168
1218
  pty2 = require("node-pty");
1169
1219
  } catch {
@@ -1361,21 +1411,21 @@ function stripAnsi3(str) {
1361
1411
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
1362
1412
  }
1363
1413
  function findCodexBinary() {
1364
- const isWin = os4.platform() === "win32";
1414
+ const isWin = os5.platform() === "win32";
1365
1415
  const cmd = isWin ? "where codex" : "which codex";
1366
1416
  try {
1367
- const result = (0, import_child_process6.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
1417
+ const result = (0, import_child_process7.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
1368
1418
  return result.split("\n")[0].trim();
1369
1419
  } catch {
1370
1420
  return isWin ? "codex.cmd" : "codex";
1371
1421
  }
1372
1422
  }
1373
- var os4, import_child_process6, pty3, CodexCliAdapter;
1423
+ var os5, import_child_process7, pty3, CodexCliAdapter;
1374
1424
  var init_codex_cli = __esm({
1375
1425
  "src/cli-adapters/codex-cli.ts"() {
1376
1426
  "use strict";
1377
- os4 = __toESM(require("os"));
1378
- import_child_process6 = require("child_process");
1427
+ os5 = __toESM(require("os"));
1428
+ import_child_process7 = require("child_process");
1379
1429
  try {
1380
1430
  pty3 = require("node-pty");
1381
1431
  } catch {
@@ -1828,13 +1878,16 @@ var init_local_server = __esm({
1828
1878
  /**
1829
1879
  * 가장 최근 Extension 상태 데이터 (통합)
1830
1880
  */
1831
- getLatestExtensionData() {
1881
+ getLatestExtensionData(enabledIdes) {
1832
1882
  let activeFile = null;
1833
1883
  const allWorkspaceFolders = [];
1834
1884
  let totalTerminals = 0;
1835
1885
  const allAgents = [];
1836
1886
  const connectedIdes = [];
1837
1887
  for (const ext of this.extensions.values()) {
1888
+ if (enabledIdes && enabledIdes.length > 0 && !enabledIdes.includes(ext.ideType.toLowerCase())) {
1889
+ continue;
1890
+ }
1838
1891
  connectedIdes.push({ ideType: ext.ideType, instanceId: ext.instanceId });
1839
1892
  if (ext.lastStatus) {
1840
1893
  if (!activeFile && ext.lastStatus.activeFile) {
@@ -1857,55 +1910,6 @@ var init_local_server = __esm({
1857
1910
  }
1858
1911
  });
1859
1912
 
1860
- // src/cli-detector.ts
1861
- async function detectCLIs() {
1862
- const platform9 = os5.platform();
1863
- const whichCmd = platform9 === "win32" ? "where" : "which";
1864
- const results = [];
1865
- for (const cli of KNOWN_CLIS) {
1866
- try {
1867
- const pathResult = (0, import_child_process7.execSync)(`${whichCmd} ${cli.command} 2>/dev/null`, {
1868
- encoding: "utf-8",
1869
- timeout: 5e3,
1870
- stdio: ["pipe", "pipe", "pipe"]
1871
- }).trim().split("\n")[0];
1872
- if (!pathResult) throw new Error("Not found");
1873
- let version;
1874
- try {
1875
- const versionResult = (0, import_child_process7.execSync)(`${cli.command} --version 2>/dev/null`, {
1876
- encoding: "utf-8",
1877
- timeout: 5e3,
1878
- stdio: ["pipe", "pipe", "pipe"]
1879
- }).trim();
1880
- const match = versionResult.match(/(\d+\.\d+[\.\d]*)/);
1881
- version = match ? match[1] : versionResult.split("\n")[0].slice(0, 30);
1882
- } catch {
1883
- }
1884
- results.push({ ...cli, installed: true, version, path: pathResult });
1885
- } catch {
1886
- results.push({ ...cli, installed: false });
1887
- }
1888
- }
1889
- return results;
1890
- }
1891
- async function detectCLI(cliId) {
1892
- const all = await detectCLIs();
1893
- return all.find((c) => c.id === cliId && c.installed) || null;
1894
- }
1895
- var import_child_process7, os5, KNOWN_CLIS;
1896
- var init_cli_detector = __esm({
1897
- "src/cli-detector.ts"() {
1898
- "use strict";
1899
- import_child_process7 = require("child_process");
1900
- os5 = __toESM(require("os"));
1901
- KNOWN_CLIS = [
1902
- { id: "gemini-cli", displayName: "Gemini CLI", icon: "\u264A", command: "gemini" },
1903
- { id: "claude-code", displayName: "Claude Code", icon: "\u{1F916}", command: "claude" },
1904
- { id: "codex-cli", displayName: "Codex CLI", icon: "\u{1F9E0}", command: "codex" }
1905
- ];
1906
- }
1907
- });
1908
-
1909
1913
  // src/daemon-cdp.ts
1910
1914
  var import_ws3, http, fs, KNOWN_AGENTS, DaemonCdpManager;
1911
1915
  var init_daemon_cdp = __esm({
@@ -1921,10 +1925,15 @@ var init_daemon_cdp = __esm({
1921
1925
  ];
1922
1926
  DaemonCdpManager = class {
1923
1927
  ws = null;
1928
+ browserWs = null;
1929
+ // browser-level WS for Target discovery
1930
+ browserMsgId = 1e4;
1931
+ browserPending = /* @__PURE__ */ new Map();
1924
1932
  msgId = 1;
1925
1933
  pending = /* @__PURE__ */ new Map();
1926
1934
  port;
1927
1935
  _connected = false;
1936
+ _browserConnected = false;
1928
1937
  targetUrl = "";
1929
1938
  reconnectTimer = null;
1930
1939
  contexts = /* @__PURE__ */ new Set();
@@ -2036,6 +2045,8 @@ var init_daemon_cdp = __esm({
2036
2045
  await this.sendInternal("Runtime.enable");
2037
2046
  } catch {
2038
2047
  }
2048
+ this.connectBrowserWs().catch(() => {
2049
+ });
2039
2050
  resolve3(true);
2040
2051
  });
2041
2052
  this.ws.on("message", (data) => {
@@ -2060,6 +2071,9 @@ var init_daemon_cdp = __esm({
2060
2071
  this.ws.on("close", () => {
2061
2072
  this.log("[CDP] WebSocket closed \u2014 scheduling reconnect");
2062
2073
  this._connected = false;
2074
+ this._browserConnected = false;
2075
+ this.browserWs?.close();
2076
+ this.browserWs = null;
2063
2077
  this.connectPromise = null;
2064
2078
  this.scheduleReconnect();
2065
2079
  });
@@ -2070,6 +2084,89 @@ var init_daemon_cdp = __esm({
2070
2084
  });
2071
2085
  });
2072
2086
  }
2087
+ /** Browser-level CDP 연결 — Target discovery에 필요 */
2088
+ async connectBrowserWs() {
2089
+ if (this._browserConnected && this.browserWs?.readyState === import_ws3.default.OPEN) return;
2090
+ try {
2091
+ const browserWsUrl = await this.getBrowserWsUrl();
2092
+ if (!browserWsUrl) {
2093
+ this.log("[CDP] No browser WS URL found");
2094
+ return;
2095
+ }
2096
+ this.log(`[CDP] Connecting browser WS for target discovery...`);
2097
+ await new Promise((resolve3, reject) => {
2098
+ this.browserWs = new import_ws3.default(browserWsUrl);
2099
+ this.browserWs.on("open", async () => {
2100
+ this._browserConnected = true;
2101
+ this.log("[CDP] \u2705 Browser WS connected \u2014 enabling target discovery");
2102
+ try {
2103
+ await this.sendBrowser("Target.setDiscoverTargets", { discover: true });
2104
+ } catch (e) {
2105
+ this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
2106
+ }
2107
+ resolve3();
2108
+ });
2109
+ this.browserWs.on("message", (data) => {
2110
+ try {
2111
+ const msg = JSON.parse(data.toString());
2112
+ if (msg.id && this.browserPending.has(msg.id)) {
2113
+ const { resolve: resolve4, reject: reject2 } = this.browserPending.get(msg.id);
2114
+ this.browserPending.delete(msg.id);
2115
+ if (msg.error) reject2(new Error(msg.error.message));
2116
+ else resolve4(msg.result);
2117
+ }
2118
+ } catch {
2119
+ }
2120
+ });
2121
+ this.browserWs.on("close", () => {
2122
+ this._browserConnected = false;
2123
+ this.browserWs = null;
2124
+ });
2125
+ this.browserWs.on("error", (err) => {
2126
+ this.log(`[CDP] Browser WS error: ${err.message}`);
2127
+ this._browserConnected = false;
2128
+ reject(err);
2129
+ });
2130
+ });
2131
+ } catch (e) {
2132
+ this.log(`[CDP] Browser WS connect failed: ${e.message}`);
2133
+ }
2134
+ }
2135
+ getBrowserWsUrl() {
2136
+ return new Promise((resolve3) => {
2137
+ const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
2138
+ let data = "";
2139
+ res.on("data", (chunk) => data += chunk.toString());
2140
+ res.on("end", () => {
2141
+ try {
2142
+ const info = JSON.parse(data);
2143
+ resolve3(info.webSocketDebuggerUrl || null);
2144
+ } catch {
2145
+ resolve3(null);
2146
+ }
2147
+ });
2148
+ });
2149
+ req.on("error", () => resolve3(null));
2150
+ req.setTimeout(3e3, () => {
2151
+ req.destroy();
2152
+ resolve3(null);
2153
+ });
2154
+ });
2155
+ }
2156
+ sendBrowser(method, params = {}, timeoutMs = 15e3) {
2157
+ return new Promise((resolve3, reject) => {
2158
+ if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
2159
+ const id = this.browserMsgId++;
2160
+ this.browserPending.set(id, { resolve: resolve3, reject });
2161
+ this.browserWs.send(JSON.stringify({ id, method, params }));
2162
+ setTimeout(() => {
2163
+ if (this.browserPending.has(id)) {
2164
+ this.browserPending.delete(id);
2165
+ reject(new Error(`Browser CDP timeout: ${method}`));
2166
+ }
2167
+ }, timeoutMs);
2168
+ });
2169
+ }
2073
2170
  scheduleReconnect() {
2074
2171
  if (this.reconnectTimer) return;
2075
2172
  this.reconnectTimer = setTimeout(async () => {
@@ -2090,6 +2187,9 @@ var init_daemon_cdp = __esm({
2090
2187
  this.ws?.close();
2091
2188
  this.ws = null;
2092
2189
  this._connected = false;
2190
+ this.browserWs?.close();
2191
+ this.browserWs = null;
2192
+ this._browserConnected = false;
2093
2193
  this.failureCount = 0;
2094
2194
  }
2095
2195
  get isConnected() {
@@ -2163,23 +2263,47 @@ var init_daemon_cdp = __esm({
2163
2263
  // ─── Agent Webview Multi-Session ─────────────────────────
2164
2264
  async discoverAgentWebviews() {
2165
2265
  if (!this.isConnected) return [];
2266
+ if (!this._browserConnected) {
2267
+ await this.connectBrowserWs().catch(() => {
2268
+ });
2269
+ }
2166
2270
  try {
2167
- const result = await this.sendInternal("Target.getTargets");
2168
- const allTargets = result?.targetInfos || [];
2271
+ let allTargets = [];
2272
+ if (this._browserConnected) {
2273
+ const result = await this.sendBrowser("Target.getTargets");
2274
+ allTargets = result?.targetInfos || [];
2275
+ } else {
2276
+ const result = await this.sendInternal("Target.getTargets");
2277
+ allTargets = result?.targetInfos || [];
2278
+ }
2169
2279
  const iframes = allTargets.filter((t) => t.type === "iframe");
2170
- this.log(`[CDP] discoverAgentWebviews: ${allTargets.length} total, ${iframes.length} iframes`);
2280
+ const typeMap = /* @__PURE__ */ new Map();
2281
+ for (const t of allTargets) {
2282
+ typeMap.set(t.type, (typeMap.get(t.type) || 0) + 1);
2283
+ }
2284
+ const typeSummary = [...typeMap.entries()].map(([k, v]) => `${k}:${v}`).join(",");
2285
+ this.log(`[CDP] discoverAgentWebviews: ${allTargets.length} total [${typeSummary}], ${iframes.length} iframes (browser=${this._browserConnected})`);
2286
+ for (const t of allTargets) {
2287
+ if (t.type !== "page" && t.type !== "worker" && t.type !== "service_worker") {
2288
+ this.log(`[CDP] target: type=${t.type} url=${(t.url || "").substring(0, 120)}`);
2289
+ }
2290
+ if ((t.url || "").includes("vscode-webview")) {
2291
+ this.log(`[CDP] webview: type=${t.type} url=${(t.url || "").substring(0, 150)}`);
2292
+ }
2293
+ }
2171
2294
  const agents = [];
2172
2295
  for (const target of allTargets) {
2173
2296
  if (target.type !== "iframe") continue;
2174
- const hasWebview = target.url?.includes("vscode-webview");
2297
+ const url = target.url || "";
2298
+ const hasWebview = url.includes("vscode-webview");
2175
2299
  if (!hasWebview) continue;
2176
2300
  for (const known of KNOWN_AGENTS) {
2177
- if (known.extensionIdPattern.test(target.url)) {
2301
+ if (known.extensionIdPattern.test(url)) {
2178
2302
  agents.push({
2179
2303
  targetId: target.targetId,
2180
2304
  extensionId: known.extensionId,
2181
2305
  agentType: known.agentType,
2182
- url: target.url
2306
+ url
2183
2307
  });
2184
2308
  this.log(`[CDP] Found agent: ${known.agentType} (${target.targetId})`);
2185
2309
  break;
@@ -2198,7 +2322,8 @@ var init_daemon_cdp = __esm({
2198
2322
  if (t.agentType === target.agentType) return sid;
2199
2323
  }
2200
2324
  try {
2201
- const result = await this.sendInternal("Target.attachToTarget", {
2325
+ const sendFn = this._browserConnected ? this.sendBrowser.bind(this) : this.sendInternal.bind(this);
2326
+ const result = await sendFn("Target.attachToTarget", {
2202
2327
  targetId: target.targetId,
2203
2328
  flatten: true
2204
2329
  });
@@ -2214,12 +2339,15 @@ var init_daemon_cdp = __esm({
2214
2339
  }
2215
2340
  }
2216
2341
  async evaluateInSession(sessionId, expression, timeoutMs = 15e3) {
2217
- if (!this.isConnected || !this.ws || this.ws.readyState !== import_ws3.default.OPEN) {
2342
+ const ws = this._browserConnected ? this.browserWs : this.ws;
2343
+ const pendingMap = this._browserConnected ? this.browserPending : this.pending;
2344
+ const getNextId = () => this._browserConnected ? this.browserMsgId++ : this.msgId++;
2345
+ if (!ws || ws.readyState !== import_ws3.default.OPEN) {
2218
2346
  throw new Error("CDP not connected");
2219
2347
  }
2220
2348
  return new Promise((resolve3, reject) => {
2221
- const id = this.msgId++;
2222
- this.pending.set(id, {
2349
+ const id = getNextId();
2350
+ pendingMap.set(id, {
2223
2351
  resolve: (result) => {
2224
2352
  if (result?.result?.subtype === "error") {
2225
2353
  reject(new Error(result.result.description));
@@ -2229,15 +2357,15 @@ var init_daemon_cdp = __esm({
2229
2357
  },
2230
2358
  reject
2231
2359
  });
2232
- this.ws.send(JSON.stringify({
2360
+ ws.send(JSON.stringify({
2233
2361
  id,
2234
2362
  sessionId,
2235
2363
  method: "Runtime.evaluate",
2236
2364
  params: { expression, returnByValue: true, awaitPromise: true }
2237
2365
  }));
2238
2366
  setTimeout(() => {
2239
- if (this.pending.has(id)) {
2240
- this.pending.delete(id);
2367
+ if (pendingMap.has(id)) {
2368
+ pendingMap.delete(id);
2241
2369
  reject(new Error(`CDP agent timeout: ${sessionId.substring(0, 12)}...`));
2242
2370
  }
2243
2371
  }, timeoutMs);
@@ -2245,7 +2373,8 @@ var init_daemon_cdp = __esm({
2245
2373
  }
2246
2374
  async detachAgent(sessionId) {
2247
2375
  try {
2248
- await this.sendInternal("Target.detachFromTarget", { sessionId });
2376
+ const sendFn = this._browserConnected ? this.sendBrowser.bind(this) : this.sendInternal.bind(this);
2377
+ await sendFn("Target.detachFromTarget", { sessionId });
2249
2378
  } catch {
2250
2379
  }
2251
2380
  this.agentSessions.delete(sessionId);
@@ -2611,7 +2740,8 @@ var init_daemon_p2p = __esm({
2611
2740
  tryLoadNodeDatachannel() {
2612
2741
  try {
2613
2742
  this.nodeDatachannel = require_lib();
2614
- log(`node-datachannel loaded \u2705`);
2743
+ const keys = Object.keys(this.nodeDatachannel).join(",");
2744
+ log(`node-datachannel loaded \u2705 (keys: ${keys.substring(0, 100)})`);
2615
2745
  return;
2616
2746
  } catch (e) {
2617
2747
  log(`node-datachannel not found: ${e?.message}`);
@@ -2745,7 +2875,12 @@ var init_daemon_p2p = __esm({
2745
2875
  if (existing?.state === "connected") return;
2746
2876
  if (existing?.state === "connecting") this.disconnectPeer(pid);
2747
2877
  log(`initiateConnection() for peer ${pid}...`);
2748
- const { PeerConnection } = this.nodeDatachannel;
2878
+ const mod = this.nodeDatachannel;
2879
+ const PeerConnectionCtor = mod.PeerConnection || mod.default?.PeerConnection || mod.default || mod;
2880
+ if (!PeerConnectionCtor || typeof PeerConnectionCtor !== "function") {
2881
+ log(`PeerConnection constructor not found in node-datachannel module. Keys: ${Object.keys(mod).join(",")}`);
2882
+ return;
2883
+ }
2749
2884
  let iceServers = [
2750
2885
  "stun:stun.cloudflare.com:3478",
2751
2886
  "stun:stun.l.google.com:19302"
@@ -2758,7 +2893,7 @@ var init_daemon_p2p = __esm({
2758
2893
  }
2759
2894
  } catch {
2760
2895
  }
2761
- const pc = new PeerConnection(`ADHDev-Daemon-${pid.substring(0, 8)}`, {
2896
+ const pc = new PeerConnectionCtor(`ADHDev-Daemon-${pid.substring(0, 8)}`, {
2762
2897
  iceServers
2763
2898
  });
2764
2899
  const entry = {
@@ -4352,7 +4487,7 @@ var init_adhdev_daemon = __esm({
4352
4487
  AdhdevDaemon = class {
4353
4488
  localServer = null;
4354
4489
  bridge = null;
4355
- adapter = null;
4490
+ adapters = /* @__PURE__ */ new Map();
4356
4491
  cdpManagers = /* @__PURE__ */ new Map();
4357
4492
  cdpDiscoveryTimer = null;
4358
4493
  p2p = null;
@@ -4363,8 +4498,12 @@ var init_adhdev_daemon = __esm({
4363
4498
  agentStreamTimer = null;
4364
4499
  running = false;
4365
4500
  statusTimer = null;
4366
- lastAgentStatus = "idle";
4367
- generatingStartedAt = 0;
4501
+ lastAgentStatus = /* @__PURE__ */ new Map();
4502
+ generatingStartedAt = /* @__PURE__ */ new Map();
4503
+ getCliKey(cliType, dir) {
4504
+ const hash = require("crypto").createHash("md5").update(require("path").resolve(dir)).digest("hex").slice(0, 8);
4505
+ return `${cliType}_${hash}`;
4506
+ }
4368
4507
  detectedIdes = [];
4369
4508
  localPort;
4370
4509
  ideType = "unknown";
@@ -4466,15 +4605,9 @@ var init_adhdev_daemon = __esm({
4466
4605
  this.commandHandler.setAgentStreamManager(this.agentStreamManager);
4467
4606
  this.startAgentStreamPolling();
4468
4607
  if (options.cliType) {
4469
- const cliInfo = await detectCLI(options.cliType);
4470
- if (cliInfo) {
4471
- this.adapter = this.createAdapter(options.cliType, workingDir);
4472
- await this.adapter.spawn();
4473
- this.adapter.setOnStatusChange(() => this.sendUnifiedStatusReport());
4474
- console.log(import_chalk2.default.green(` \u{1F916} CLI Agent started: ${cliInfo.displayName} v${cliInfo.version || "unknown"}`));
4475
- } else {
4476
- console.log(import_chalk2.default.yellow(` \u26A0 CLI ${options.cliType} not found \u2014 running without CLI agent`));
4477
- }
4608
+ await this.startCliSession(options.cliType, workingDir).catch((e) => {
4609
+ console.log(import_chalk2.default.yellow(` \u26A0 Failed to start CLI ${options.cliType}: ${e.message}`));
4610
+ });
4478
4611
  }
4479
4612
  const machineId = os8.hostname().replace(/[^a-zA-Z0-9]/g, "_");
4480
4613
  const machineHash = crypto2.createHash("md5").update(os8.hostname() + os8.homedir()).digest("hex").slice(0, 8);
@@ -4489,9 +4622,6 @@ var init_adhdev_daemon = __esm({
4489
4622
  instanceId
4490
4623
  }
4491
4624
  });
4492
- if (this.adapter && typeof this.adapter.setBridge === "function") {
4493
- this.adapter.setBridge(this.bridge);
4494
- }
4495
4625
  this.p2p = new DaemonP2PSender(this.bridge);
4496
4626
  if (this.p2p.isAvailable) {
4497
4627
  console.log(import_chalk2.default.green(" \u{1F517} P2P available (node-datachannel)"));
@@ -4624,9 +4754,9 @@ var init_adhdev_daemon = __esm({
4624
4754
  "launch_ide",
4625
4755
  "detect_ides",
4626
4756
  "restart_session",
4627
- "switch_cli",
4628
- "change_dir",
4629
4757
  "exec_command",
4758
+ "launch_cli",
4759
+ "stop_cli",
4630
4760
  // Extension-delegated commands (must be registered to receive WS messages)
4631
4761
  "vscode_command_exec",
4632
4762
  "execute_vscode_command",
@@ -4662,21 +4792,33 @@ var init_adhdev_daemon = __esm({
4662
4792
  console.log(import_chalk2.default.magenta(` \u2699 Command: ${cmd}`));
4663
4793
  try {
4664
4794
  switch (cmd) {
4665
- case "switch_cli": {
4666
- const newCli = args?.cli || "gemini-cli";
4667
- const newDir = args?.dir || this.adapter?.workingDir || process.cwd();
4668
- await this.switchCliSession(newCli, newDir);
4669
- this.sendResult(msg, true, { cli: newCli, dir: newDir });
4795
+ case "launch_cli": {
4796
+ const cliType = args?.cliType;
4797
+ const dir = args?.dir || process.cwd();
4798
+ if (!cliType) throw new Error("cliType required");
4799
+ const key = this.getCliKey(cliType, dir);
4800
+ if (!this.adapters.has(key)) {
4801
+ await this.startCliSession(cliType, dir);
4802
+ }
4803
+ this.sendResult(msg, true, { cliType, dir, id: key });
4670
4804
  return;
4671
4805
  }
4672
- case "change_dir": {
4673
- if (!args?.dir) throw new Error("Directory path required");
4674
- if (this.adapter) await this.switchCliSession(this.adapter.cliType, args.dir);
4675
- this.sendResult(msg, true, { dir: args.dir });
4806
+ case "stop_cli": {
4807
+ const cliType = args?.cliType;
4808
+ const dir = args?.dir || process.cwd();
4809
+ if (!cliType) throw new Error("cliType required");
4810
+ const key = this.getCliKey(cliType, dir);
4811
+ await this.stopCliSession(key);
4812
+ this.sendResult(msg, true, { cliType, dir });
4676
4813
  return;
4677
4814
  }
4678
4815
  case "restart_session": {
4679
- if (this.adapter) await this.switchCliSession(this.adapter.cliType, this.adapter.workingDir);
4816
+ const cliType = args?.cliType || args?.agentType;
4817
+ const dir = args?.dir || process.cwd();
4818
+ if (!cliType) throw new Error("cliType required");
4819
+ const key = this.getCliKey(cliType, dir);
4820
+ await this.stopCliSession(key);
4821
+ await this.startCliSession(cliType, dir);
4680
4822
  this.sendResult(msg, true, { restarted: true });
4681
4823
  return;
4682
4824
  }
@@ -4687,7 +4829,7 @@ var init_adhdev_daemon = __esm({
4687
4829
  this.sendResult(msg, false, { error: `Blocked: "${cmdStr}"` });
4688
4830
  return;
4689
4831
  }
4690
- const cwd = this.adapter?.workingDir || process.cwd();
4832
+ const cwd = args?.dir || process.cwd();
4691
4833
  const { exec: exec2 } = require("child_process");
4692
4834
  exec2(cmdStr, { cwd, timeout: 6e4 }, (err, stdout, stderr) => {
4693
4835
  if (!this.bridge) return;
@@ -4772,23 +4914,41 @@ var init_adhdev_daemon = __esm({
4772
4914
  return new GeminiCliAdapter(workingDir);
4773
4915
  }
4774
4916
  }
4775
- async switchCliSession(cliType, workingDir) {
4776
- console.log(import_chalk2.default.yellow(` \u26A1 Switching CLI to ${cliType} in ${workingDir}...`));
4777
- if (this.adapter) this.adapter.shutdown();
4917
+ async startCliSession(cliType, workingDir) {
4778
4918
  const cliInfo = await detectCLI(cliType);
4779
4919
  if (!cliInfo) throw new Error(`${cliType} not found`);
4780
- this.adapter = this.createAdapter(cliType, workingDir);
4781
- await this.adapter.spawn();
4782
- if (this.bridge && typeof this.adapter.setBridge === "function") {
4783
- this.adapter.setBridge(this.bridge);
4920
+ const key = this.getCliKey(cliType, workingDir);
4921
+ if (this.adapters.has(key)) {
4922
+ console.log(import_chalk2.default.yellow(` \u26A1 CLI ${cliType} already running in ${workingDir}`));
4923
+ return;
4924
+ }
4925
+ console.log(import_chalk2.default.yellow(` \u26A1 Starting CLI ${cliType} in ${workingDir}...`));
4926
+ const adapter = this.createAdapter(cliType, workingDir);
4927
+ await adapter.spawn();
4928
+ if (this.bridge && typeof adapter.setBridge === "function") {
4929
+ adapter.setBridge(this.bridge);
4930
+ }
4931
+ adapter.setOnStatusChange(() => this.sendUnifiedStatusReport());
4932
+ this.adapters.set(key, adapter);
4933
+ this.lastAgentStatus.set(key, "idle");
4934
+ console.log(import_chalk2.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${workingDir}`));
4935
+ this.sendUnifiedStatusReport();
4936
+ }
4937
+ async stopCliSession(key) {
4938
+ const adapter = this.adapters.get(key);
4939
+ if (adapter) {
4940
+ adapter.shutdown();
4941
+ this.adapters.delete(key);
4942
+ this.lastAgentStatus.delete(key);
4943
+ this.generatingStartedAt.delete(key);
4944
+ console.log(import_chalk2.default.yellow(` \u{1F6D1} CLI Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`));
4945
+ this.sendUnifiedStatusReport();
4784
4946
  }
4785
- this.adapter.setOnStatusChange(() => this.sendUnifiedStatusReport());
4786
- console.log(import_chalk2.default.green(` \u2713 CLI switched to ${cliType}`));
4787
4947
  }
4788
4948
  // ─── 통합 상태 보고 ─────────────────────────────
4789
4949
  startStatusReporting() {
4790
4950
  const scheduleNext = () => {
4791
- const isProcessing = this.adapter?.isProcessing();
4951
+ const isProcessing = Array.from(this.adapters.values()).some((a) => a.isProcessing());
4792
4952
  const interval = isProcessing ? 2e3 : 15e3;
4793
4953
  this.statusTimer = setTimeout(() => {
4794
4954
  this.sendUnifiedStatusReport().catch(() => {
@@ -4830,20 +4990,35 @@ var init_adhdev_daemon = __esm({
4830
4990
  }
4831
4991
  const now = Date.now();
4832
4992
  const perExtData = this.localServer?.getPerExtensionData() || [];
4833
- const extSummary = this.localServer?.getLatestExtensionData() || {
4993
+ const enabledIdesFilter = loadConfig().enabledIdes || [];
4994
+ const filteredExtData = enabledIdesFilter.length > 0 ? perExtData.filter((ext) => enabledIdesFilter.includes(ext.ideType.toLowerCase())) : perExtData;
4995
+ const extSummary = this.localServer?.getLatestExtensionData(enabledIdesFilter) || {
4834
4996
  activeFile: null,
4835
4997
  workspaceFolders: [],
4836
4998
  terminals: 0,
4837
4999
  aiAgents: [],
4838
5000
  connectedIdes: []
4839
5001
  };
4840
- const managedIdes = perExtData.map((ext) => {
5002
+ const managedIdes = filteredExtData.map((ext) => {
4841
5003
  const ideKey = ext.ideType.toLowerCase();
4842
5004
  const isMainCdpIde = this.cdpManagers.has(ideKey);
4843
5005
  const cdpStreamsForIde = this._cachedAgentStreamsMap.get(ideKey) || [];
5006
+ const extAgentsForIde = (ext.aiAgents || []).filter((a) => {
5007
+ const existsInCdp = cdpStreamsForIde.some((s) => s.agentType === a.id);
5008
+ const existsInExt = ext.agentStreams.some((s) => s.agentType === a.id);
5009
+ return !existsInCdp && !existsInExt;
5010
+ }).map((a) => ({
5011
+ agentType: a.id,
5012
+ agentName: a.name,
5013
+ extensionId: a.id,
5014
+ status: a.status === "active" || a.status === "installed" ? "connected" : "idle",
5015
+ messages: [],
5016
+ inputContent: ""
5017
+ }));
4844
5018
  const ideAgentStreams = [
4845
5019
  ...ext.agentStreams,
4846
- ...isMainCdpIde ? cdpStreamsForIde : []
5020
+ ...isMainCdpIde ? cdpStreamsForIde : [],
5021
+ ...extAgentsForIde
4847
5022
  ];
4848
5023
  return {
4849
5024
  ideType: ext.ideType,
@@ -4860,47 +5035,50 @@ var init_adhdev_daemon = __esm({
4860
5035
  };
4861
5036
  });
4862
5037
  const managedClis = [];
4863
- if (this.adapter) {
4864
- const adapterStatus = this.adapter.getStatus();
5038
+ for (const [key, adapter] of this.adapters.entries()) {
5039
+ const adapterStatus = adapter.getStatus();
4865
5040
  const cliStatus = adapterStatus.status;
4866
- if (cliStatus !== this.lastAgentStatus) {
4867
- if (this.lastAgentStatus === "idle" && cliStatus === "generating") {
4868
- this.generatingStartedAt = now;
4869
- this.bridge.sendMessage("status_event", {
5041
+ let lastStatus = this.lastAgentStatus.get(key) || "idle";
5042
+ if (cliStatus !== lastStatus) {
5043
+ if (lastStatus === "idle" && cliStatus === "generating") {
5044
+ this.generatingStartedAt.set(key, now);
5045
+ this.bridge?.sendMessage("status_event", {
4870
5046
  event: "agent:generating_started",
4871
- chatTitle: `${this.adapter.cliName} Session`,
5047
+ chatTitle: `${adapter.cliName} Session`,
4872
5048
  timestamp: now
4873
5049
  });
4874
- } else if (this.lastAgentStatus === "generating" && cliStatus === "idle") {
4875
- const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
4876
- this.bridge.sendMessage("status_event", {
5050
+ } else if (lastStatus === "generating" && cliStatus === "idle") {
5051
+ const startedAt = this.generatingStartedAt.get(key);
5052
+ const duration = startedAt ? Math.round((now - startedAt) / 1e3) : 0;
5053
+ this.bridge?.sendMessage("status_event", {
4877
5054
  event: "agent:generating_completed",
4878
- chatTitle: `${this.adapter.cliName} Session`,
5055
+ chatTitle: `${adapter.cliName} Session`,
4879
5056
  duration,
4880
5057
  timestamp: now
4881
5058
  });
4882
- this.generatingStartedAt = 0;
5059
+ this.generatingStartedAt.delete(key);
4883
5060
  }
4884
- this.lastAgentStatus = cliStatus;
5061
+ this.lastAgentStatus.set(key, cliStatus);
4885
5062
  }
4886
5063
  const recentMessages = adapterStatus.messages.slice(-50);
4887
5064
  const cliMessages = recentMessages.map((m) => ({
4888
5065
  role: m.role,
4889
5066
  content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content
4890
5067
  }));
4891
- const partial = this.adapter.getPartialResponse();
5068
+ const partial = adapter.getPartialResponse();
4892
5069
  if (cliStatus === "generating" && partial) {
4893
- cliMessages.push({ role: "assistant", content: partial.slice(0, 2e3) + "..." });
5070
+ cliMessages.push({ role: "assistant", content: partial.length > 2e3 ? partial.slice(0, 2e3) + "..." : partial + "..." });
4894
5071
  }
4895
5072
  managedClis.push({
4896
- cliType: this.adapter.cliType,
4897
- cliName: this.adapter.cliName,
4898
- workingDir: this.adapter.workingDir,
5073
+ id: key,
5074
+ cliType: adapter.cliType,
5075
+ cliName: adapter.cliName,
4899
5076
  status: cliStatus,
5077
+ workingDir: adapter.workingDir,
4900
5078
  activeChat: {
4901
- id: `cli-${this.adapter.cliType}`,
5079
+ id: key,
4902
5080
  status: cliStatus,
4903
- title: `${this.adapter.cliName} Session`,
5081
+ title: `${adapter.cliName} Session`,
4904
5082
  messages: cliMessages,
4905
5083
  inputContent: "",
4906
5084
  activeModal: adapterStatus.activeModal
@@ -4942,13 +5120,20 @@ var init_adhdev_daemon = __esm({
4942
5120
  timestamp: now,
4943
5121
  // ─── Legacy compat (서버 기존 로직용, 점진적 제거 예정) ───
4944
5122
  activeFile: extSummary.activeFile,
4945
- workspaceFolders: extSummary.workspaceFolders.length > 0 ? extSummary.workspaceFolders : this.adapter ? [{ name: path4.basename(this.adapter.workingDir), path: this.adapter.workingDir }] : [],
5123
+ workspaceFolders: extSummary.workspaceFolders.length > 0 ? extSummary.workspaceFolders : Array.from(this.adapters.values()).map((a) => ({ name: path4.basename(a.workingDir), path: a.workingDir })),
4946
5124
  terminals: extSummary.terminals,
5125
+ // Legacy aiAgents: managedIdes에서 각 IDE의 aiAgents를 통합
4947
5126
  aiAgents: [
4948
- ...extSummary.aiAgents,
4949
- ...this.adapter ? [{ id: this.adapter.cliType, name: this.adapter.cliName, status: this.lastAgentStatus }] : []
5127
+ ...managedIdes.flatMap((ide) => (ide.aiAgents || []).map((a) => ({
5128
+ id: a.id,
5129
+ name: a.name,
5130
+ status: a.status,
5131
+ ideType: ide.ideType
5132
+ }))),
5133
+ ...Array.from(this.adapters.entries()).map(([k, a]) => ({ id: a.cliType, name: a.cliName, status: this.lastAgentStatus.get(k) || "idle" }))
4950
5134
  ],
4951
5135
  activeChat: managedClis[0]?.activeChat || managedIdes[0]?.activeChat || null,
5136
+ // Legacy agentStreams: managedIdes의 agentStreams를 통합 (이미 IDE별로 올바르게 구성됨)
4952
5137
  agentStreams: [
4953
5138
  ...managedClis.map((c) => ({
4954
5139
  agentType: c.cliType,
@@ -4958,7 +5143,7 @@ var init_adhdev_daemon = __esm({
4958
5143
  messages: c.activeChat?.messages || [],
4959
5144
  inputContent: ""
4960
5145
  })),
4961
- ...[...this._cachedAgentStreamsMap.values()].flat()
5146
+ ...managedIdes.flatMap((ide) => ide.agentStreams || [])
4962
5147
  ],
4963
5148
  connectedExtensions: extSummary.connectedIdes,
4964
5149
  system: {
@@ -4990,7 +5175,8 @@ var init_adhdev_daemon = __esm({
4990
5175
  if (!this.running) return;
4991
5176
  this.running = false;
4992
5177
  console.log(import_chalk2.default.yellow("\n Shutting down ADHDev Daemon..."));
4993
- this.adapter?.cancel();
5178
+ for (const adapter of this.adapters.values()) adapter.shutdown();
5179
+ this.adapters.clear();
4994
5180
  if (this.statusTimer) clearTimeout(this.statusTimer);
4995
5181
  if (this.cdpDiscoveryTimer) clearInterval(this.cdpDiscoveryTimer);
4996
5182
  if (this.screenshotTimer) clearInterval(this.screenshotTimer);
@@ -5057,7 +5243,9 @@ var init_adhdev_daemon = __esm({
5057
5243
  portsToTry.push({ port, ide });
5058
5244
  }
5059
5245
  }
5060
- for (const { port, ide } of portsToTry) {
5246
+ const enabledIdes = loadConfig().enabledIdes || [];
5247
+ const filteredPorts = enabledIdes.length > 0 ? portsToTry.filter((p) => enabledIdes.includes(p.ide)) : portsToTry;
5248
+ for (const { port, ide } of filteredPorts) {
5061
5249
  const manager = new DaemonCdpManager(port, (msg) => {
5062
5250
  console.log(import_chalk2.default.gray(msg));
5063
5251
  }, true);
@@ -6464,6 +6652,7 @@ async function installCliOnly() {
6464
6652
 
6465
6653
  // src/index.ts
6466
6654
  init_detector();
6655
+ init_cli_detector();
6467
6656
  init_config();
6468
6657
  init_launch();
6469
6658
  var import_fs3 = require("fs");
@@ -6593,6 +6782,15 @@ program.command("status").description("Show current ADHDev setup status").action
6593
6782
  }
6594
6783
  }
6595
6784
  }
6785
+ const clis = await detectCLIs();
6786
+ const installedClis = clis.filter((c) => c.installed);
6787
+ if (installedClis.length > 0) {
6788
+ console.log(` ${import_chalk4.default.bold("CLI Agents:")}`);
6789
+ installedClis.forEach((cli) => {
6790
+ const ver = cli.version ? import_chalk4.default.gray(` v${cli.version}`) : "";
6791
+ console.log(` ${import_chalk4.default.green("\u2713")} ${cli.icon} ${cli.displayName}${ver}`);
6792
+ });
6793
+ }
6596
6794
  console.log(` ${import_chalk4.default.bold("Extensions:")} ${config.installedExtensions.length} installed`);
6597
6795
  config.installedExtensions.forEach((ext) => {
6598
6796
  console.log(import_chalk4.default.gray(` \u2022 ${ext}`));
@@ -6620,6 +6818,17 @@ program.command("detect").description("Detect installed IDEs on your system").ac
6620
6818
  console.log(` ${import_chalk4.default.gray("\u2717")} ${ide.icon} ${import_chalk4.default.gray(ide.displayName)} \u2014 not found`);
6621
6819
  }
6622
6820
  });
6821
+ console.log(import_chalk4.default.bold("\n\u{1F50D} Detecting installed CLI Agents...\n"));
6822
+ const clis = await detectCLIs();
6823
+ clis.forEach((cli) => {
6824
+ if (cli.installed) {
6825
+ const version = cli.version ? import_chalk4.default.gray(` v${cli.version}`) : "";
6826
+ console.log(` ${import_chalk4.default.green("\u2713")} ${cli.icon} ${import_chalk4.default.bold(cli.displayName)}${version}`);
6827
+ console.log(import_chalk4.default.gray(` Path: ${cli.path}`));
6828
+ } else {
6829
+ console.log(` ${import_chalk4.default.gray("\u2717")} ${cli.icon} ${import_chalk4.default.gray(cli.displayName)} \u2014 not found`);
6830
+ }
6831
+ });
6623
6832
  console.log();
6624
6833
  });
6625
6834
  program.command("reset").description("Reset ADHDev configuration").action(async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adhdev",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "ADHDev CLI — Detect, install and configure your IDE + AI agent extensions",
5
5
  "main": "dist/index.js",
6
6
  "bin": {