adhdev 0.1.47 → 0.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -262,7 +262,8 @@ var init_config = __esm({
262
262
  recentCliWorkspaces: [],
263
263
  machineNickname: null,
264
264
  cliHistory: [],
265
- providerSettings: {}
265
+ providerSettings: {},
266
+ ideSettings: {}
266
267
  };
267
268
  }
268
269
  });
@@ -336,6 +337,54 @@ var init_provider_loader = __esm({
336
337
  getAll() {
337
338
  return [...this.providers.values()];
338
339
  }
340
+ /**
341
+ * Provider가 활성화되어 있는지 확인 (per-IDE)
342
+ * ideSettings[ideType].extensions[type].enabled를 참조.
343
+ * 설정이 없으면 기본 false (비활성) — 사용자가 명시적으로 켜야 활성화.
344
+ * ideType 없이 호출하면 항상 true.
345
+ */
346
+ isEnabled(type, ideType) {
347
+ if (!ideType) return true;
348
+ try {
349
+ const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(config_exports));
350
+ const config = loadConfig2();
351
+ const val = config.ideSettings?.[ideType]?.extensions?.[type]?.enabled;
352
+ return val === true;
353
+ } catch {
354
+ return false;
355
+ }
356
+ }
357
+ /**
358
+ * IDE별 extension enabled 설정 저장
359
+ */
360
+ setIdeExtensionEnabled(ideType, extensionType, enabled) {
361
+ try {
362
+ const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = (init_config(), __toCommonJS(config_exports));
363
+ const config = loadConfig2();
364
+ if (!config.ideSettings) config.ideSettings = {};
365
+ if (!config.ideSettings[ideType]) config.ideSettings[ideType] = {};
366
+ if (!config.ideSettings[ideType].extensions) config.ideSettings[ideType].extensions = {};
367
+ config.ideSettings[ideType].extensions[extensionType] = { enabled };
368
+ saveConfig2(config);
369
+ this.log(`IDE extension setting: ${ideType}.${extensionType}.enabled = ${enabled}`);
370
+ return true;
371
+ } catch (e) {
372
+ this.log(`Failed to save IDE extension setting: ${e.message}`);
373
+ return false;
374
+ }
375
+ }
376
+ /**
377
+ * 카테고리별 활성화된 프로바이더만 반환 (per-IDE)
378
+ */
379
+ getEnabledByCategory(cat, ideType) {
380
+ return this.getByCategory(cat).filter((p) => this.isEnabled(p.type, ideType));
381
+ }
382
+ /**
383
+ * Extension 카테고리 중 활성화되고 extensionIdPattern이 있는 것만 (per-IDE)
384
+ */
385
+ getEnabledExtensionProviders(ideType) {
386
+ return this.getExtensionProviders().filter((p) => this.isEnabled(p.type, ideType));
387
+ }
339
388
  /**
340
389
  * IDE 카테고리의 CDP 포트 맵 반환
341
390
  * launch.ts, adhdev-daemon.ts에서 사용
@@ -857,7 +906,7 @@ var init_local_server = __esm({
857
906
  * 로컬 WS 서버 시작
858
907
  */
859
908
  async start() {
860
- return new Promise((resolve5, reject) => {
909
+ return new Promise((resolve6, reject) => {
861
910
  try {
862
911
  this.wss = new import_ws2.WebSocketServer({
863
912
  port: this.port,
@@ -867,7 +916,7 @@ var init_local_server = __esm({
867
916
  });
868
917
  this.wss.on("listening", () => {
869
918
  console.log(`[LocalServer] Listening on ws://127.0.0.1:${this.port}${DAEMON_WS_PATH}`);
870
- resolve5();
919
+ resolve6();
871
920
  });
872
921
  this.wss.on("connection", (ws) => {
873
922
  this.handleConnection(ws);
@@ -1046,14 +1095,14 @@ var init_local_server = __esm({
1046
1095
  return { success: false, error: "No extension connected" };
1047
1096
  }
1048
1097
  const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1049
- return new Promise((resolve5) => {
1098
+ return new Promise((resolve6) => {
1050
1099
  const timeout = setTimeout(() => {
1051
1100
  this.commandCallbacks.delete(requestId);
1052
- resolve5({ success: false, error: "Command execution timeout (10s)" });
1101
+ resolve6({ success: false, error: "Command execution timeout (10s)" });
1053
1102
  }, 1e4);
1054
1103
  this.commandCallbacks.set(requestId, (result) => {
1055
1104
  clearTimeout(timeout);
1056
- resolve5(result);
1105
+ resolve6(result);
1057
1106
  });
1058
1107
  this.sendToExtension(targetWs, {
1059
1108
  type: "daemon:execute_vscode",
@@ -1177,17 +1226,17 @@ async function findFreePort(ports) {
1177
1226
  throw new Error("No free port found");
1178
1227
  }
1179
1228
  function checkPortFree(port) {
1180
- return new Promise((resolve5) => {
1229
+ return new Promise((resolve6) => {
1181
1230
  const server = net.createServer();
1182
1231
  server.unref();
1183
- server.on("error", () => resolve5(false));
1232
+ server.on("error", () => resolve6(false));
1184
1233
  server.listen(port, "127.0.0.1", () => {
1185
- server.close(() => resolve5(true));
1234
+ server.close(() => resolve6(true));
1186
1235
  });
1187
1236
  });
1188
1237
  }
1189
1238
  async function isCdpActive(port) {
1190
- return new Promise((resolve5) => {
1239
+ return new Promise((resolve6) => {
1191
1240
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
1192
1241
  timeout: 2e3
1193
1242
  }, (res) => {
@@ -1196,16 +1245,16 @@ async function isCdpActive(port) {
1196
1245
  res.on("end", () => {
1197
1246
  try {
1198
1247
  const info = JSON.parse(data);
1199
- resolve5(!!info["WebKit-Version"] || !!info["Browser"]);
1248
+ resolve6(!!info["WebKit-Version"] || !!info["Browser"]);
1200
1249
  } catch {
1201
- resolve5(false);
1250
+ resolve6(false);
1202
1251
  }
1203
1252
  });
1204
1253
  });
1205
- req.on("error", () => resolve5(false));
1254
+ req.on("error", () => resolve6(false));
1206
1255
  req.on("timeout", () => {
1207
1256
  req.destroy();
1208
- resolve5(false);
1257
+ resolve6(false);
1209
1258
  });
1210
1259
  });
1211
1260
  }
@@ -1530,12 +1579,53 @@ var init_daemon_cdp = __esm({
1530
1579
  logFn;
1531
1580
  extensionProviders = [];
1532
1581
  _lastDiscoverSig = "";
1533
- constructor(port = 9333, logFn) {
1582
+ _targetId = null;
1583
+ // 특정 targetId로 연결 (multi-window 지원)
1584
+ _pageTitle = "";
1585
+ // 연결된 페이지 제목
1586
+ constructor(port = 9333, logFn, targetId) {
1534
1587
  this.port = port;
1588
+ this._targetId = targetId || null;
1535
1589
  this.logFn = logFn || ((msg) => {
1536
1590
  console.log(msg);
1537
1591
  });
1538
1592
  }
1593
+ /** 연결된 페이지의 제목 (workspace 이름 포함) */
1594
+ get pageTitle() {
1595
+ return this._pageTitle;
1596
+ }
1597
+ /**
1598
+ * 포트에 있는 모든 workbench 페이지 목록 조회 (static)
1599
+ * 같은 포트에 여러 IDE 창이 열려 있으면 여러 개 반환
1600
+ */
1601
+ static listAllTargets(port) {
1602
+ return new Promise((resolve6) => {
1603
+ const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
1604
+ let data = "";
1605
+ res.on("data", (chunk) => data += chunk.toString());
1606
+ res.on("end", () => {
1607
+ try {
1608
+ const targets = JSON.parse(data);
1609
+ const pages = targets.filter(
1610
+ (t) => t.type === "page" && t.webSocketDebuggerUrl
1611
+ );
1612
+ const isNonMain = (title) => !title || /extension-output|ADHDev CDP|Debug Console|Output\s*$|Launchpad/i.test(title);
1613
+ const mainPages = pages.filter(
1614
+ (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
1615
+ );
1616
+ resolve6(mainPages.length > 0 ? mainPages : pages.filter((t) => !isNonMain(t.title || "")));
1617
+ } catch {
1618
+ resolve6([]);
1619
+ }
1620
+ });
1621
+ });
1622
+ req.on("error", () => resolve6([]));
1623
+ req.setTimeout(2e3, () => {
1624
+ req.destroy();
1625
+ resolve6([]);
1626
+ });
1627
+ });
1628
+ }
1539
1629
  setPort(port) {
1540
1630
  this.port = port;
1541
1631
  this.log(`[CDP] Port changed to ${port}`);
@@ -1572,7 +1662,7 @@ var init_daemon_cdp = __esm({
1572
1662
  }
1573
1663
  }
1574
1664
  findTargetOnPort(port) {
1575
- return new Promise((resolve5) => {
1665
+ return new Promise((resolve6) => {
1576
1666
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
1577
1667
  let data = "";
1578
1668
  res.on("data", (chunk) => data += chunk.toString());
@@ -1583,23 +1673,35 @@ var init_daemon_cdp = __esm({
1583
1673
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
1584
1674
  );
1585
1675
  if (pages.length === 0) {
1586
- resolve5(targets.find((t) => t.webSocketDebuggerUrl) || null);
1676
+ resolve6(targets.find((t) => t.webSocketDebuggerUrl) || null);
1587
1677
  return;
1588
1678
  }
1589
1679
  const isNonMain = (title) => !title || /extension-output|ADHDev CDP|Debug Console|Output\s*$|Launchpad/i.test(title);
1590
1680
  const mainPages = pages.filter((t) => !isNonMain(t.title || ""));
1591
1681
  const list = mainPages.length > 0 ? mainPages : pages;
1592
1682
  this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
1593
- resolve5(list[0]);
1683
+ if (this._targetId) {
1684
+ const specific = list.find((t) => t.id === this._targetId);
1685
+ if (specific) {
1686
+ this._pageTitle = specific.title || "";
1687
+ resolve6(specific);
1688
+ } else {
1689
+ this.log(`[CDP] Target ${this._targetId} not found in page list`);
1690
+ resolve6(null);
1691
+ }
1692
+ return;
1693
+ }
1694
+ this._pageTitle = list[0]?.title || "";
1695
+ resolve6(list[0]);
1594
1696
  } catch {
1595
- resolve5(null);
1697
+ resolve6(null);
1596
1698
  }
1597
1699
  });
1598
1700
  });
1599
- req.on("error", () => resolve5(null));
1701
+ req.on("error", () => resolve6(null));
1600
1702
  req.setTimeout(2e3, () => {
1601
1703
  req.destroy();
1602
- resolve5(null);
1704
+ resolve6(null);
1603
1705
  });
1604
1706
  });
1605
1707
  }
@@ -1610,7 +1712,7 @@ var init_daemon_cdp = __esm({
1610
1712
  this.extensionProviders = providers;
1611
1713
  }
1612
1714
  connectToTarget(wsUrl) {
1613
- return new Promise((resolve5) => {
1715
+ return new Promise((resolve6) => {
1614
1716
  this.ws = new import_ws3.default(wsUrl);
1615
1717
  this.ws.on("open", async () => {
1616
1718
  this._connected = true;
@@ -1620,17 +1722,17 @@ var init_daemon_cdp = __esm({
1620
1722
  }
1621
1723
  this.connectBrowserWs().catch(() => {
1622
1724
  });
1623
- resolve5(true);
1725
+ resolve6(true);
1624
1726
  });
1625
1727
  this.ws.on("message", (data) => {
1626
1728
  try {
1627
1729
  const msg = JSON.parse(data.toString());
1628
1730
  if (msg.id && this.pending.has(msg.id)) {
1629
- const { resolve: resolve6, reject } = this.pending.get(msg.id);
1731
+ const { resolve: resolve7, reject } = this.pending.get(msg.id);
1630
1732
  this.pending.delete(msg.id);
1631
1733
  this.failureCount = 0;
1632
1734
  if (msg.error) reject(new Error(msg.error.message));
1633
- else resolve6(msg.result);
1735
+ else resolve7(msg.result);
1634
1736
  } else if (msg.method === "Runtime.executionContextCreated") {
1635
1737
  this.contexts.add(msg.params.context.id);
1636
1738
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -1653,7 +1755,7 @@ var init_daemon_cdp = __esm({
1653
1755
  this.ws.on("error", (err) => {
1654
1756
  this.log(`[CDP] WebSocket error: ${err.message}`);
1655
1757
  this._connected = false;
1656
- resolve5(false);
1758
+ resolve6(false);
1657
1759
  });
1658
1760
  });
1659
1761
  }
@@ -1667,7 +1769,7 @@ var init_daemon_cdp = __esm({
1667
1769
  return;
1668
1770
  }
1669
1771
  this.log(`[CDP] Connecting browser WS for target discovery...`);
1670
- await new Promise((resolve5, reject) => {
1772
+ await new Promise((resolve6, reject) => {
1671
1773
  this.browserWs = new import_ws3.default(browserWsUrl);
1672
1774
  this.browserWs.on("open", async () => {
1673
1775
  this._browserConnected = true;
@@ -1677,16 +1779,16 @@ var init_daemon_cdp = __esm({
1677
1779
  } catch (e) {
1678
1780
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
1679
1781
  }
1680
- resolve5();
1782
+ resolve6();
1681
1783
  });
1682
1784
  this.browserWs.on("message", (data) => {
1683
1785
  try {
1684
1786
  const msg = JSON.parse(data.toString());
1685
1787
  if (msg.id && this.browserPending.has(msg.id)) {
1686
- const { resolve: resolve6, reject: reject2 } = this.browserPending.get(msg.id);
1788
+ const { resolve: resolve7, reject: reject2 } = this.browserPending.get(msg.id);
1687
1789
  this.browserPending.delete(msg.id);
1688
1790
  if (msg.error) reject2(new Error(msg.error.message));
1689
- else resolve6(msg.result);
1791
+ else resolve7(msg.result);
1690
1792
  }
1691
1793
  } catch {
1692
1794
  }
@@ -1706,31 +1808,31 @@ var init_daemon_cdp = __esm({
1706
1808
  }
1707
1809
  }
1708
1810
  getBrowserWsUrl() {
1709
- return new Promise((resolve5) => {
1811
+ return new Promise((resolve6) => {
1710
1812
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
1711
1813
  let data = "";
1712
1814
  res.on("data", (chunk) => data += chunk.toString());
1713
1815
  res.on("end", () => {
1714
1816
  try {
1715
1817
  const info = JSON.parse(data);
1716
- resolve5(info.webSocketDebuggerUrl || null);
1818
+ resolve6(info.webSocketDebuggerUrl || null);
1717
1819
  } catch {
1718
- resolve5(null);
1820
+ resolve6(null);
1719
1821
  }
1720
1822
  });
1721
1823
  });
1722
- req.on("error", () => resolve5(null));
1824
+ req.on("error", () => resolve6(null));
1723
1825
  req.setTimeout(3e3, () => {
1724
1826
  req.destroy();
1725
- resolve5(null);
1827
+ resolve6(null);
1726
1828
  });
1727
1829
  });
1728
1830
  }
1729
1831
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
1730
- return new Promise((resolve5, reject) => {
1832
+ return new Promise((resolve6, reject) => {
1731
1833
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
1732
1834
  const id = this.browserMsgId++;
1733
- this.browserPending.set(id, { resolve: resolve5, reject });
1835
+ this.browserPending.set(id, { resolve: resolve6, reject });
1734
1836
  this.browserWs.send(JSON.stringify({ id, method, params }));
1735
1837
  setTimeout(() => {
1736
1838
  if (this.browserPending.has(id)) {
@@ -1770,11 +1872,11 @@ var init_daemon_cdp = __esm({
1770
1872
  }
1771
1873
  // ─── CDP Protocol ────────────────────────────────────────
1772
1874
  sendInternal(method, params = {}, timeoutMs = 15e3) {
1773
- return new Promise((resolve5, reject) => {
1875
+ return new Promise((resolve6, reject) => {
1774
1876
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
1775
1877
  if (this.ws.readyState !== import_ws3.default.OPEN) return reject(new Error("WebSocket not open"));
1776
1878
  const id = this.msgId++;
1777
- this.pending.set(id, { resolve: resolve5, reject });
1879
+ this.pending.set(id, { resolve: resolve6, reject });
1778
1880
  this.ws.send(JSON.stringify({ id, method, params }));
1779
1881
  setTimeout(() => {
1780
1882
  if (this.pending.has(id)) {
@@ -1978,14 +2080,14 @@ var init_daemon_cdp = __esm({
1978
2080
  if (!ws || ws.readyState !== import_ws3.default.OPEN) {
1979
2081
  throw new Error("CDP not connected");
1980
2082
  }
1981
- return new Promise((resolve5, reject) => {
2083
+ return new Promise((resolve6, reject) => {
1982
2084
  const id = getNextId();
1983
2085
  pendingMap.set(id, {
1984
2086
  resolve: (result) => {
1985
2087
  if (result?.result?.subtype === "error") {
1986
2088
  reject(new Error(result.result.description));
1987
2089
  } else {
1988
- resolve5(result?.result?.value);
2090
+ resolve6(result?.result?.value);
1989
2091
  }
1990
2092
  },
1991
2093
  reject
@@ -2462,13 +2564,13 @@ var init_daemon_p2p = __esm({
2462
2564
  } catch {
2463
2565
  }
2464
2566
  const http3 = require("https");
2465
- const data = await new Promise((resolve5, reject) => {
2567
+ const data = await new Promise((resolve6, reject) => {
2466
2568
  const req = http3.get(`${serverUrl}/api/v1/turn/credentials`, {
2467
2569
  headers: { "Authorization": `Bearer ${token}` }
2468
2570
  }, (res) => {
2469
2571
  let d = "";
2470
2572
  res.on("data", (c) => d += c);
2471
- res.on("end", () => resolve5(d));
2573
+ res.on("end", () => resolve6(d));
2472
2574
  });
2473
2575
  req.on("error", reject);
2474
2576
  req.setTimeout(5e3, () => {
@@ -2841,7 +2943,11 @@ var init_daemon_p2p = __esm({
2841
2943
  return;
2842
2944
  }
2843
2945
  if (type === "p2p_answer") {
2844
- const peer = peerId ? this.peers.get(peerId) : this.getFirstPeer();
2946
+ if (!peerId) {
2947
+ log("p2p_answer without peerId \u2014 ignoring (multi-peer requires explicit peerId)");
2948
+ return;
2949
+ }
2950
+ const peer = this.peers.get(peerId);
2845
2951
  if (peer?.pc) {
2846
2952
  log(`Received SDP answer for peer ${peer.peerId}`);
2847
2953
  peer.pc.setRemoteDescription(payload.sdp, payload.type);
@@ -2849,16 +2955,18 @@ var init_daemon_p2p = __esm({
2849
2955
  return;
2850
2956
  }
2851
2957
  if (type === "p2p_ice") {
2852
- const peer = peerId ? this.peers.get(peerId) : this.getFirstPeer();
2958
+ if (!peerId) {
2959
+ log("p2p_ice without peerId \u2014 ignoring (multi-peer requires explicit peerId)");
2960
+ return;
2961
+ }
2962
+ const peer = this.peers.get(peerId);
2853
2963
  if (peer?.pc && payload.candidate) {
2854
2964
  peer.pc.addRemoteCandidate(payload.candidate, payload.mid || payload.sdpMid || "0");
2855
2965
  }
2856
2966
  return;
2857
2967
  }
2858
2968
  }
2859
- getFirstPeer() {
2860
- return this.peers.values().next().value;
2861
- }
2969
+ // getFirstPeer removed — multi-peer requires explicit peerId routing
2862
2970
  // ─── 연결 관리 ──────────────────────────────
2863
2971
  disconnectPeer(peerId) {
2864
2972
  const peer = this.peers.get(peerId);
@@ -3143,15 +3251,15 @@ var init_dev_server = __esm({
3143
3251
  this.json(res, 500, { error: e.message });
3144
3252
  }
3145
3253
  });
3146
- return new Promise((resolve5, reject) => {
3254
+ return new Promise((resolve6, reject) => {
3147
3255
  this.server.listen(port, "127.0.0.1", () => {
3148
3256
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
3149
- resolve5();
3257
+ resolve6();
3150
3258
  });
3151
3259
  this.server.on("error", (e) => {
3152
3260
  if (e.code === "EADDRINUSE") {
3153
3261
  this.log(`Port ${port} in use, skipping dev server`);
3154
- resolve5();
3262
+ resolve6();
3155
3263
  } else {
3156
3264
  reject(e);
3157
3265
  }
@@ -3818,14 +3926,14 @@ var init_dev_server = __esm({
3818
3926
  res.end(JSON.stringify(data, null, 2));
3819
3927
  }
3820
3928
  async readBody(req) {
3821
- return new Promise((resolve5) => {
3929
+ return new Promise((resolve6) => {
3822
3930
  let body = "";
3823
3931
  req.on("data", (chunk) => body += chunk);
3824
3932
  req.on("end", () => {
3825
3933
  try {
3826
- resolve5(JSON.parse(body));
3934
+ resolve6(JSON.parse(body));
3827
3935
  } catch {
3828
- resolve5({});
3936
+ resolve6({});
3829
3937
  }
3830
3938
  });
3831
3939
  });
@@ -4198,7 +4306,11 @@ var init_daemon_commands = __esm({
4198
4306
  getProvider(overrideType) {
4199
4307
  const key = overrideType || this._currentProviderType || this._currentIdeType;
4200
4308
  if (!key || !this.ctx.providerLoader) return void 0;
4201
- return this.ctx.providerLoader.resolve(key);
4309
+ const result = this.ctx.providerLoader.resolve(key);
4310
+ if (result) return result;
4311
+ const baseType = key.split("_")[0];
4312
+ if (baseType !== key) return this.ctx.providerLoader.resolve(baseType);
4313
+ return void 0;
4202
4314
  }
4203
4315
  /** Get a provider script by name from ProviderLoader.
4204
4316
  * Returns the script string or null. */
@@ -4376,6 +4488,20 @@ var init_daemon_commands = __esm({
4376
4488
  return this.handleGetProviderSettings(args);
4377
4489
  case "set_provider_setting":
4378
4490
  return this.handleSetProviderSetting(args);
4491
+ // ─── IDE Extension Settings (per-IDE on/off) ──────────────
4492
+ case "get_ide_extensions":
4493
+ return this.handleGetIdeExtensions(args);
4494
+ case "set_ide_extension":
4495
+ return this.handleSetIdeExtension(args);
4496
+ // ─── Extension Model / Mode Control ──────────────
4497
+ case "list_extension_models":
4498
+ return await this.handleExtensionScript(args, "listModels");
4499
+ case "set_extension_model":
4500
+ return await this.handleExtensionScript(args, "setModel");
4501
+ case "list_extension_modes":
4502
+ return await this.handleExtensionScript(args, "listModes");
4503
+ case "set_extension_mode":
4504
+ return await this.handleExtensionScript(args, "setMode");
4379
4505
  default:
4380
4506
  return { success: false, error: `Unknown command: ${cmd}` };
4381
4507
  }
@@ -4686,6 +4812,7 @@ var init_daemon_commands = __esm({
4686
4812
  const provider2 = this.getProvider();
4687
4813
  const action = args?.action || "approve";
4688
4814
  const button = args?.button || args?.buttonText || (action === "approve" ? "Accept" : action === "reject" ? "Reject" : "Accept");
4815
+ console.log(`[resolveAction] action=${action} button="${button}" provider=${provider2?.type}`);
4689
4816
  if (provider2?.category === "extension" && this.agentStream && this.getCdp()) {
4690
4817
  const ok = await this.agentStream.resolveAgentAction(
4691
4818
  this.getCdp(),
@@ -4695,14 +4822,50 @@ var init_daemon_commands = __esm({
4695
4822
  );
4696
4823
  return { success: ok };
4697
4824
  }
4698
- try {
4699
- const evalResult = await this.evaluateProviderScript("resolveAction", {
4700
- ACTION: action,
4701
- BUTTON: button
4702
- });
4703
- if (evalResult) return { success: true };
4704
- } catch (e) {
4705
- return { success: false, error: `resolveAction failed: ${e.message}` };
4825
+ if (provider2?.scripts?.resolveAction) {
4826
+ const script = provider2.scripts.resolveAction({ action, button, buttonText: button });
4827
+ if (script) {
4828
+ const cdp2 = this.getCdp();
4829
+ if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
4830
+ try {
4831
+ const raw = await cdp2.evaluate(script, 3e4);
4832
+ let result = raw;
4833
+ if (typeof raw === "string") {
4834
+ try {
4835
+ result = JSON.parse(raw);
4836
+ } catch {
4837
+ }
4838
+ }
4839
+ console.log(`[resolveAction] script result:`, JSON.stringify(result));
4840
+ if (result?.resolved) {
4841
+ console.log(`[resolveAction] script-click resolved \u2014 "${result.clicked}"`);
4842
+ return { success: true, clicked: result.clicked };
4843
+ }
4844
+ if (result?.found && result.x != null && result.y != null) {
4845
+ const x = result.x;
4846
+ const y = result.y;
4847
+ await cdp2.send("Input.dispatchMouseEvent", {
4848
+ type: "mousePressed",
4849
+ x,
4850
+ y,
4851
+ button: "left",
4852
+ clickCount: 1
4853
+ });
4854
+ await cdp2.send("Input.dispatchMouseEvent", {
4855
+ type: "mouseReleased",
4856
+ x,
4857
+ y,
4858
+ button: "left",
4859
+ clickCount: 1
4860
+ });
4861
+ console.log(`[resolveAction] CDP click at (${x}, ${y}) \u2014 "${result.text}"`);
4862
+ return { success: true, clicked: result.text };
4863
+ }
4864
+ return { success: false, error: result?.found === false ? `Button not found: ${button}` : "No coordinates" };
4865
+ } catch (e) {
4866
+ return { success: false, error: `resolveAction failed: ${e.message}` };
4867
+ }
4868
+ }
4706
4869
  }
4707
4870
  return { success: false, error: "resolveAction script not available for this provider" };
4708
4871
  }
@@ -5097,6 +5260,103 @@ var init_daemon_commands = __esm({
5097
5260
  }
5098
5261
  return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
5099
5262
  }
5263
+ // ─── Extension Script Execution (Model/Mode) ─────
5264
+ /**
5265
+ * Extension provider의 CDP 스크립트를 실행하는 범용 핸들러.
5266
+ * args: { agentType, ideType?, model?, mode?, ... }
5267
+ * scriptName: 'listModels' | 'setModel' | 'listModes' | 'setMode'
5268
+ */
5269
+ async handleExtensionScript(args, scriptName) {
5270
+ const { agentType, ideType } = args || {};
5271
+ console.log(`[ExtScript] ${scriptName} agentType=${agentType} ideType=${ideType} _currentIdeType=${this._currentIdeType}`);
5272
+ if (!agentType) return { success: false, error: "agentType is required" };
5273
+ const loader = this.ctx.providerLoader;
5274
+ if (!loader) return { success: false, error: "ProviderLoader not initialized" };
5275
+ const provider2 = loader.get(agentType);
5276
+ if (!provider2) return { success: false, error: `Provider not found: ${agentType}` };
5277
+ if (!provider2.scripts?.[scriptName]) {
5278
+ return { success: false, error: `Script '${scriptName}' not available for ${agentType}` };
5279
+ }
5280
+ const script = provider2.scripts[scriptName](args);
5281
+ if (!script) return { success: false, error: `Script '${scriptName}' returned null` };
5282
+ const cdpKey = provider2.category === "ide" ? this._currentIdeType || agentType : this._currentIdeType || ideType;
5283
+ console.log(`[ExtScript] provider=${provider2.type} category=${provider2.category} cdpKey=${cdpKey}`);
5284
+ const cdp2 = this.getCdp(cdpKey);
5285
+ if (!cdp2?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
5286
+ try {
5287
+ let result;
5288
+ if (provider2.category === "extension") {
5289
+ const sessions = cdp2.getAgentSessions();
5290
+ let targetSessionId = null;
5291
+ for (const [sessionId, target] of sessions) {
5292
+ if (target.agentType === agentType) {
5293
+ targetSessionId = sessionId;
5294
+ break;
5295
+ }
5296
+ }
5297
+ if (!targetSessionId) {
5298
+ return { success: false, error: `No active session found for ${agentType}` };
5299
+ }
5300
+ result = await cdp2.evaluateInSession(targetSessionId, script);
5301
+ } else {
5302
+ result = await cdp2.evaluate(script, 3e4);
5303
+ }
5304
+ if (typeof result === "string") {
5305
+ try {
5306
+ const parsed = JSON.parse(result);
5307
+ return { success: true, ...parsed };
5308
+ } catch {
5309
+ return { success: true, result };
5310
+ }
5311
+ }
5312
+ return { success: true, result };
5313
+ } catch (e) {
5314
+ return { success: false, error: `Script execution failed: ${e.message}` };
5315
+ }
5316
+ }
5317
+ // ─── IDE Extension Settings (per-IDE on/off) ─────
5318
+ handleGetIdeExtensions(args) {
5319
+ const { ideType } = args || {};
5320
+ const loader = this.ctx.providerLoader;
5321
+ if (!loader) return { success: false, error: "ProviderLoader not initialized" };
5322
+ const allExtProviders = loader.getByCategory?.("extension") || [];
5323
+ const config = loadConfig();
5324
+ if (ideType) {
5325
+ const extensions = allExtProviders.map((p) => ({
5326
+ type: p.type,
5327
+ name: p.name,
5328
+ extensionId: p.extensionId,
5329
+ enabled: config.ideSettings?.[ideType]?.extensions?.[p.type]?.enabled === true
5330
+ }));
5331
+ return { success: true, ideType, extensions };
5332
+ }
5333
+ const connectedIdes = [...this.ctx.cdpManagers?.keys?.() || []];
5334
+ const result = {};
5335
+ for (const ide of connectedIdes) {
5336
+ result[ide] = allExtProviders.map((p) => ({
5337
+ type: p.type,
5338
+ name: p.name,
5339
+ extensionId: p.extensionId,
5340
+ enabled: config.ideSettings?.[ide]?.extensions?.[p.type]?.enabled === true
5341
+ }));
5342
+ }
5343
+ return { success: true, ides: result };
5344
+ }
5345
+ handleSetIdeExtension(args) {
5346
+ const { ideType, extensionType, enabled } = args || {};
5347
+ if (!ideType || !extensionType || enabled === void 0) {
5348
+ return { success: false, error: "ideType, extensionType, and enabled are required" };
5349
+ }
5350
+ const loader = this.ctx.providerLoader;
5351
+ if (!loader?.setIdeExtensionEnabled) {
5352
+ return { success: false, error: "ProviderLoader not initialized" };
5353
+ }
5354
+ const ok = loader.setIdeExtensionEnabled(ideType, extensionType, !!enabled);
5355
+ if (ok) {
5356
+ return { success: true, ideType, extensionType, enabled: !!enabled };
5357
+ }
5358
+ return { success: false, error: "Failed to save setting" };
5359
+ }
5100
5360
  };
5101
5361
  }
5102
5362
  });
@@ -5239,12 +5499,12 @@ var init_manager = __esm({
5239
5499
  constructor(logFn, providerLoader) {
5240
5500
  this.logFn = logFn || console.log;
5241
5501
  if (providerLoader) {
5242
- const extensionProviders = providerLoader.getByCategory("extension");
5243
- this.allAdapters = extensionProviders.map((p) => {
5502
+ const allExtProviders = providerLoader.getByCategory("extension");
5503
+ for (const p of allExtProviders) {
5244
5504
  const adapter = new ProviderStreamAdapter(p);
5505
+ this.allAdapters.push(adapter);
5245
5506
  this.logFn(`[AgentStream] Adapter created: ${p.type} (${p.name})`);
5246
- return adapter;
5247
- });
5507
+ }
5248
5508
  }
5249
5509
  }
5250
5510
  setLocalServer(server) {
@@ -5498,14 +5758,238 @@ var init_agent_stream = __esm({
5498
5758
  }
5499
5759
  });
5500
5760
 
5761
+ // src/daemon-logger.ts
5762
+ var daemon_logger_exports = {};
5763
+ __export(daemon_logger_exports, {
5764
+ LOG: () => LOG,
5765
+ LOG_DIR_PATH: () => LOG_DIR_PATH,
5766
+ LOG_PATH: () => LOG_PATH,
5767
+ cdpLogFn: () => cdpLogFn,
5768
+ daemonLog: () => daemonLog,
5769
+ getLogBufferSize: () => getLogBufferSize,
5770
+ getLogLevel: () => getLogLevel,
5771
+ getLogPath: () => getLogPath,
5772
+ getRecentLogs: () => getRecentLogs,
5773
+ installGlobalInterceptor: () => installGlobalInterceptor,
5774
+ setLogLevel: () => setLogLevel
5775
+ });
5776
+ function setLogLevel(level) {
5777
+ currentLevel = level;
5778
+ daemonLog("Logger", `Log level set to: ${level}`, "info");
5779
+ }
5780
+ function getLogLevel() {
5781
+ return currentLevel;
5782
+ }
5783
+ function getDateStr() {
5784
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5785
+ }
5786
+ function checkDateRotation() {
5787
+ const today = getDateStr();
5788
+ if (today !== currentDate) {
5789
+ currentDate = today;
5790
+ currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
5791
+ cleanOldLogs();
5792
+ }
5793
+ }
5794
+ function cleanOldLogs() {
5795
+ try {
5796
+ const files = fs5.readdirSync(LOG_DIR).filter((f) => f.startsWith("daemon-") && f.endsWith(".log"));
5797
+ const cutoff = /* @__PURE__ */ new Date();
5798
+ cutoff.setDate(cutoff.getDate() - MAX_LOG_DAYS);
5799
+ const cutoffStr = cutoff.toISOString().slice(0, 10);
5800
+ for (const file of files) {
5801
+ const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
5802
+ if (dateMatch && dateMatch[1] < cutoffStr) {
5803
+ try {
5804
+ fs5.unlinkSync(path6.join(LOG_DIR, file));
5805
+ } catch {
5806
+ }
5807
+ }
5808
+ }
5809
+ } catch {
5810
+ }
5811
+ }
5812
+ function rotateSizeIfNeeded() {
5813
+ try {
5814
+ const stat = fs5.statSync(currentLogFile);
5815
+ if (stat.size > MAX_LOG_SIZE) {
5816
+ const backup = currentLogFile.replace(".log", ".1.log");
5817
+ try {
5818
+ fs5.unlinkSync(backup);
5819
+ } catch {
5820
+ }
5821
+ fs5.renameSync(currentLogFile, backup);
5822
+ }
5823
+ } catch {
5824
+ }
5825
+ }
5826
+ function writeToFile(line) {
5827
+ try {
5828
+ if (++writeCount % 1e3 === 0) {
5829
+ checkDateRotation();
5830
+ rotateSizeIfNeeded();
5831
+ }
5832
+ fs5.appendFileSync(currentLogFile, line + "\n");
5833
+ } catch {
5834
+ }
5835
+ }
5836
+ function getRecentLogs(count = 50, minLevel = "info") {
5837
+ const minNum = LEVEL_NUM[minLevel];
5838
+ const filtered = ringBuffer.filter((e) => LEVEL_NUM[e.level] >= minNum);
5839
+ return filtered.slice(-count);
5840
+ }
5841
+ function getLogBufferSize() {
5842
+ return ringBuffer.length;
5843
+ }
5844
+ function ts() {
5845
+ return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
5846
+ }
5847
+ function fullTs() {
5848
+ return (/* @__PURE__ */ new Date()).toISOString();
5849
+ }
5850
+ function daemonLog(category, msg, level = "info") {
5851
+ const shouldOutput = LEVEL_NUM[level] >= LEVEL_NUM[currentLevel];
5852
+ const label = LEVEL_LABEL[level];
5853
+ const line = `[${ts()}] [${label}] [${category}] ${msg}`;
5854
+ writeToFile(line);
5855
+ ringBuffer.push({ ts: Date.now(), level, category, message: msg });
5856
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
5857
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
5858
+ }
5859
+ if (shouldOutput) {
5860
+ origConsoleLog(line);
5861
+ }
5862
+ }
5863
+ function cdpLogFn(ideType) {
5864
+ return (msg) => {
5865
+ const isDebug = msg.includes("discoverAgentWebviews:") && !msg.includes("Found agent") || msg.includes("[P2P] sent");
5866
+ daemonLog(`CDP:${ideType}`, msg, isDebug ? "debug" : "info");
5867
+ };
5868
+ }
5869
+ function installGlobalInterceptor() {
5870
+ if (interceptorInstalled) return;
5871
+ interceptorInstalled = true;
5872
+ const stripAnsi2 = (str) => str.replace(/\x1B\[[0-9;]*m/g, "");
5873
+ const isDaemonLogLine = (msg) => /\[(DBG|INF|WRN|ERR)\]/.test(msg);
5874
+ console.log = (...args) => {
5875
+ origConsoleLog(...args);
5876
+ try {
5877
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
5878
+ const clean = stripAnsi2(msg);
5879
+ if (isDaemonLogLine(clean)) return;
5880
+ const line = clean.startsWith("[20") ? clean : `[${fullTs()}] ${clean}`;
5881
+ writeToFile(line);
5882
+ const catMatch = clean.match(/\[([^\]]+)\]/);
5883
+ ringBuffer.push({
5884
+ ts: Date.now(),
5885
+ level: "info",
5886
+ category: catMatch?.[1] || "System",
5887
+ message: clean
5888
+ });
5889
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
5890
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
5891
+ }
5892
+ } catch {
5893
+ }
5894
+ };
5895
+ console.error = (...args) => {
5896
+ origConsoleError(...args);
5897
+ try {
5898
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
5899
+ const clean = stripAnsi2(msg);
5900
+ if (isDaemonLogLine(clean)) return;
5901
+ const line = `[${fullTs()}] [ERROR] ${clean}`;
5902
+ writeToFile(line);
5903
+ ringBuffer.push({ ts: Date.now(), level: "error", category: "System", message: clean });
5904
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
5905
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
5906
+ }
5907
+ } catch {
5908
+ }
5909
+ };
5910
+ console.warn = (...args) => {
5911
+ origConsoleWarn(...args);
5912
+ try {
5913
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
5914
+ const clean = stripAnsi2(msg);
5915
+ if (isDaemonLogLine(clean)) return;
5916
+ const line = `[${fullTs()}] [WARN] ${clean}`;
5917
+ writeToFile(line);
5918
+ ringBuffer.push({ ts: Date.now(), level: "warn", category: "System", message: clean });
5919
+ if (ringBuffer.length > RING_BUFFER_SIZE) {
5920
+ ringBuffer.splice(0, ringBuffer.length - RING_BUFFER_SIZE);
5921
+ }
5922
+ } catch {
5923
+ }
5924
+ };
5925
+ writeToFile(`
5926
+ === ADHDev Daemon started at ${fullTs()} ===`);
5927
+ writeToFile(`Log file: ${currentLogFile}`);
5928
+ writeToFile(`Log level: ${currentLevel}`);
5929
+ }
5930
+ function getLogPath() {
5931
+ return currentLogFile;
5932
+ }
5933
+ var fs5, path6, os6, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
5934
+ var init_daemon_logger = __esm({
5935
+ "src/daemon-logger.ts"() {
5936
+ "use strict";
5937
+ fs5 = __toESM(require("fs"));
5938
+ path6 = __toESM(require("path"));
5939
+ os6 = __toESM(require("os"));
5940
+ LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
5941
+ LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
5942
+ currentLevel = "info";
5943
+ LOG_DIR = process.platform === "darwin" ? path6.join(os6.homedir(), "Library", "Logs", "adhdev") : path6.join(os6.homedir(), ".local", "share", "adhdev", "logs");
5944
+ MAX_LOG_SIZE = 5 * 1024 * 1024;
5945
+ MAX_LOG_DAYS = 7;
5946
+ try {
5947
+ fs5.mkdirSync(LOG_DIR, { recursive: true });
5948
+ } catch {
5949
+ }
5950
+ currentDate = getDateStr();
5951
+ currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
5952
+ cleanOldLogs();
5953
+ try {
5954
+ const oldLog = path6.join(LOG_DIR, "daemon.log");
5955
+ if (fs5.existsSync(oldLog)) {
5956
+ const stat = fs5.statSync(oldLog);
5957
+ const oldDate = stat.mtime.toISOString().slice(0, 10);
5958
+ fs5.renameSync(oldLog, path6.join(LOG_DIR, `daemon-${oldDate}.log`));
5959
+ }
5960
+ const oldLogBackup = path6.join(LOG_DIR, "daemon.log.old");
5961
+ if (fs5.existsSync(oldLogBackup)) {
5962
+ fs5.unlinkSync(oldLogBackup);
5963
+ }
5964
+ } catch {
5965
+ }
5966
+ writeCount = 0;
5967
+ RING_BUFFER_SIZE = 200;
5968
+ ringBuffer = [];
5969
+ origConsoleLog = console.log.bind(console);
5970
+ origConsoleError = console.error.bind(console);
5971
+ origConsoleWarn = console.warn.bind(console);
5972
+ LOG = {
5973
+ debug: (category, msg) => daemonLog(category, msg, "debug"),
5974
+ info: (category, msg) => daemonLog(category, msg, "info"),
5975
+ warn: (category, msg) => daemonLog(category, msg, "warn"),
5976
+ error: (category, msg) => daemonLog(category, msg, "error")
5977
+ };
5978
+ interceptorInstalled = false;
5979
+ LOG_PATH = path6.join(LOG_DIR, `daemon-${getDateStr()}.log`);
5980
+ LOG_DIR_PATH = LOG_DIR;
5981
+ }
5982
+ });
5983
+
5501
5984
  // src/daemon-status.ts
5502
- var os6, path6, DaemonStatusReporter;
5985
+ var os7, path7, DaemonStatusReporter;
5503
5986
  var init_daemon_status = __esm({
5504
5987
  "src/daemon-status.ts"() {
5505
5988
  "use strict";
5506
- os6 = __toESM(require("os"));
5507
- path6 = __toESM(require("path"));
5989
+ os7 = __toESM(require("os"));
5990
+ path7 = __toESM(require("path"));
5508
5991
  init_config();
5992
+ init_daemon_logger();
5509
5993
  DaemonStatusReporter = class {
5510
5994
  deps;
5511
5995
  log;
@@ -5563,7 +6047,7 @@ var init_daemon_status = __esm({
5563
6047
  }
5564
6048
  }
5565
6049
  emitStatusEvent(event) {
5566
- this.log(`[${this.ts()}] [StatusEvent\u2192Server] ${event.event} (${event.providerType || event.ideType || ""})`);
6050
+ LOG.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
5567
6051
  this.deps.bridge?.sendMessage("status_event", event);
5568
6052
  }
5569
6053
  removeAgentTracking(_key) {
@@ -5584,13 +6068,15 @@ var init_daemon_status = __esm({
5584
6068
  const allStates = this.deps.instanceManager.collectAllStates();
5585
6069
  const ideStates = allStates.filter((s) => s.category === "ide");
5586
6070
  const cliStates = allStates.filter((s) => s.category === "cli");
6071
+ const acpStates = allStates.filter((s) => s.category === "acp");
5587
6072
  const ideSummary = ideStates.map((s) => {
5588
6073
  const msgs = s.activeChat?.messages?.length || 0;
5589
6074
  const exts = (s.extensions || []).length;
5590
6075
  return `${s.type}(${s.status},${msgs}msg,${exts}ext${s.currentModel ? ",model=" + s.currentModel : ""})`;
5591
6076
  }).join(", ");
5592
- const cliSummary = cliStates.map((s) => `${s.type}(${s.status})`).join(", ");
5593
- this.log(`[${this.ts()}] [StatusReport\u2192${target}] IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}]`);
6077
+ const cliSummary = [...cliStates, ...acpStates].map((s) => `${s.type}(${s.status})`).join(", ");
6078
+ const logLevel = opts?.p2pOnly ? "debug" : "info";
6079
+ LOG[logLevel]("StatusReport", `\u2192${target} IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length + acpStates.length} [${cliSummary}]`);
5594
6080
  const managedIdes = ideStates.map((s) => ({
5595
6081
  ideType: s.type,
5596
6082
  ideVersion: "",
@@ -5616,23 +6102,45 @@ var init_daemon_status = __esm({
5616
6102
  currentAutoApprove: s.currentAutoApprove
5617
6103
  }));
5618
6104
  const instanceIdeTypes = new Set(ideStates.map((s) => s.type));
6105
+ const instanceBaseTypes = /* @__PURE__ */ new Set();
6106
+ for (const t of instanceIdeTypes) {
6107
+ instanceBaseTypes.add(t);
6108
+ const base = t.split("_")[0];
6109
+ if (base) instanceBaseTypes.add(base);
6110
+ }
5619
6111
  const perExtData = localServer?.getPerExtensionData() || [];
5620
6112
  for (const ext of perExtData) {
5621
6113
  const ideKey = ext.ideType.toLowerCase();
5622
- if (instanceIdeTypes.has(ideKey)) continue;
5623
- managedIdes.push({
5624
- ideType: ext.ideType,
5625
- ideVersion: ext.ideVersion,
5626
- instanceId: ext.instanceId,
5627
- workspaceFolders: ext.workspaceFolders,
5628
- activeFile: ext.activeFile,
5629
- terminals: ext.terminals,
5630
- aiAgents: ext.aiAgents,
5631
- activeChat: ext.activeChat,
5632
- chats: ext.chats || [],
5633
- agentStreams: ext.agentStreams || [],
5634
- cdpConnected: false
5635
- });
6114
+ if (instanceBaseTypes.has(ideKey)) {
6115
+ const match = managedIdes.find(
6116
+ (m) => m.ideType === ideKey || m.ideType.split("_")[0] === ideKey
6117
+ );
6118
+ if (match) {
6119
+ if (!match.workspaceFolders?.length && ext.workspaceFolders?.length) {
6120
+ match.workspaceFolders = ext.workspaceFolders;
6121
+ }
6122
+ if (!match.activeFile && ext.activeFile) match.activeFile = ext.activeFile;
6123
+ if (!match.terminals && ext.terminals) match.terminals = ext.terminals;
6124
+ if ((!match.aiAgents || match.aiAgents.length === 0) && ext.aiAgents?.length) {
6125
+ match.aiAgents = ext.aiAgents;
6126
+ }
6127
+ if (!match.ideVersion && ext.ideVersion) match.ideVersion = ext.ideVersion;
6128
+ }
6129
+ } else {
6130
+ managedIdes.push({
6131
+ ideType: ext.ideType,
6132
+ ideVersion: ext.ideVersion,
6133
+ instanceId: ext.instanceId,
6134
+ workspaceFolders: ext.workspaceFolders,
6135
+ activeFile: ext.activeFile,
6136
+ terminals: ext.terminals,
6137
+ aiAgents: ext.aiAgents,
6138
+ activeChat: ext.activeChat,
6139
+ chats: ext.chats || [],
6140
+ agentStreams: ext.agentStreams || [],
6141
+ cdpConnected: false
6142
+ });
6143
+ }
5636
6144
  }
5637
6145
  const managedClis = cliStates.map((s) => ({
5638
6146
  id: s.instanceId,
@@ -5643,6 +6151,19 @@ var init_daemon_status = __esm({
5643
6151
  workingDir: s.workingDir || "",
5644
6152
  activeChat: s.activeChat
5645
6153
  }));
6154
+ for (const s of acpStates) {
6155
+ managedClis.push({
6156
+ id: s.instanceId,
6157
+ cliType: s.type,
6158
+ cliName: s.name,
6159
+ status: s.status,
6160
+ mode: "chat",
6161
+ workingDir: s.workingDir || "",
6162
+ activeChat: s.activeChat,
6163
+ currentModel: s.currentModel,
6164
+ isAcp: true
6165
+ });
6166
+ }
5646
6167
  const extSummary = localServer?.getLatestExtensionData() || {
5647
6168
  activeFile: null,
5648
6169
  workspaceFolders: [],
@@ -5654,15 +6175,15 @@ var init_daemon_status = __esm({
5654
6175
  daemonMode: true,
5655
6176
  machineNickname: loadConfig().machineNickname || null,
5656
6177
  machine: {
5657
- hostname: os6.hostname(),
5658
- platform: os6.platform(),
5659
- release: os6.release(),
5660
- arch: os6.arch(),
5661
- cpus: os6.cpus().length,
5662
- totalMem: os6.totalmem(),
5663
- freeMem: os6.freemem(),
5664
- loadavg: os6.loadavg(),
5665
- uptime: os6.uptime()
6178
+ hostname: os7.hostname(),
6179
+ platform: os7.platform(),
6180
+ release: os7.release(),
6181
+ arch: os7.arch(),
6182
+ cpus: os7.cpus().length,
6183
+ totalMem: os7.totalmem(),
6184
+ freeMem: os7.freemem(),
6185
+ loadavg: os7.loadavg(),
6186
+ uptime: os7.uptime()
5666
6187
  },
5667
6188
  managedIdes,
5668
6189
  managedClis,
@@ -5684,7 +6205,7 @@ var init_daemon_status = __esm({
5684
6205
  })),
5685
6206
  timestamp: now,
5686
6207
  activeFile: extSummary.activeFile,
5687
- workspaceFolders: extSummary.workspaceFolders?.length > 0 ? extSummary.workspaceFolders : Array.from(adapters.values()).map((a) => ({ name: path6.basename(a.workingDir), path: a.workingDir })),
6208
+ workspaceFolders: extSummary.workspaceFolders?.length > 0 ? extSummary.workspaceFolders : Array.from(adapters.values()).map((a) => ({ name: path7.basename(a.workingDir), path: a.workingDir })),
5688
6209
  terminals: extSummary.terminals,
5689
6210
  aiAgents: [
5690
6211
  ...managedIdes.flatMap((ide) => (ide.aiAgents || []).map((a) => ({
@@ -5692,17 +6213,17 @@ var init_daemon_status = __esm({
5692
6213
  name: a.name,
5693
6214
  status: a.status,
5694
6215
  ideType: ide.ideType
5695
- }))),
5696
- ...managedClis.map((c) => ({ id: c.cliType, name: c.cliName, status: c.status }))
6216
+ })))
6217
+ // CLIs are already in managedClis don't duplicate here
5697
6218
  ],
5698
6219
  activeChat: managedClis[0]?.activeChat || managedIdes[0]?.activeChat || null,
5699
6220
  agentStreams: managedIdes.flatMap((ide) => ide.agentStreams || []),
5700
6221
  connectedExtensions: extSummary.connectedIdes,
5701
- system: { platform: os6.platform(), hostname: os6.hostname() }
6222
+ system: { platform: os7.platform(), hostname: os7.hostname() }
5702
6223
  };
5703
6224
  const p2pSent = this.sendP2PPayload(payload);
5704
6225
  if (p2pSent) {
5705
- this.log(`[${this.ts()}] [P2P] sent (${JSON.stringify(payload).length} bytes)`);
6226
+ LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
5706
6227
  }
5707
6228
  if (opts?.p2pOnly) return;
5708
6229
  const plan = bridge.getUserPlan();
@@ -5711,11 +6232,11 @@ var init_daemon_status = __esm({
5711
6232
  daemonMode: true,
5712
6233
  machineNickname: payload.machineNickname,
5713
6234
  machine: {
5714
- hostname: os6.hostname(),
5715
- platform: os6.platform(),
5716
- arch: os6.arch(),
5717
- cpus: os6.cpus().length,
5718
- totalMem: os6.totalmem()
6235
+ hostname: os7.hostname(),
6236
+ platform: os7.platform(),
6237
+ arch: os7.arch(),
6238
+ cpus: os7.cpus().length,
6239
+ totalMem: os7.totalmem()
5719
6240
  },
5720
6241
  managedIdes: managedIdes.map((ide) => ({
5721
6242
  ideType: ide.ideType,
@@ -5739,7 +6260,7 @@ var init_daemon_status = __esm({
5739
6260
  timestamp: now
5740
6261
  };
5741
6262
  bridge.sendMessage("status_report", wsPayload);
5742
- this.log(`[${this.ts()}] [Server] sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
6263
+ LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
5743
6264
  }
5744
6265
  }
5745
6266
  // ─── P2P ─────────────────────────────────────────
@@ -5774,7 +6295,7 @@ function stripAnsi(str) {
5774
6295
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
5775
6296
  }
5776
6297
  function findBinary(name) {
5777
- const isWin = os7.platform() === "win32";
6298
+ const isWin = os8.platform() === "win32";
5778
6299
  try {
5779
6300
  const cmd = isWin ? `where ${name}` : `which ${name}`;
5780
6301
  return (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
@@ -5782,11 +6303,11 @@ function findBinary(name) {
5782
6303
  return isWin ? `${name}.cmd` : name;
5783
6304
  }
5784
6305
  }
5785
- var os7, import_child_process4, pty, ProviderCliAdapter;
6306
+ var os8, import_child_process4, pty, ProviderCliAdapter;
5786
6307
  var init_provider_cli_adapter = __esm({
5787
6308
  "src/cli-adapters/provider-cli-adapter.ts"() {
5788
6309
  "use strict";
5789
- os7 = __toESM(require("os"));
6310
+ os8 = __toESM(require("os"));
5790
6311
  import_child_process4 = require("child_process");
5791
6312
  try {
5792
6313
  pty = require("node-pty");
@@ -5799,7 +6320,7 @@ var init_provider_cli_adapter = __esm({
5799
6320
  this.provider = provider2;
5800
6321
  this.cliType = provider2.type;
5801
6322
  this.cliName = provider2.name;
5802
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os7.homedir()) : workingDir;
6323
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
5803
6324
  const t = provider2.timeouts || {};
5804
6325
  this.timeouts = {
5805
6326
  ptyFlush: t.ptyFlush ?? 50,
@@ -5857,7 +6378,7 @@ var init_provider_cli_adapter = __esm({
5857
6378
  if (!pty) throw new Error("node-pty is not installed");
5858
6379
  const { spawn: spawnConfig } = this.provider;
5859
6380
  const binaryPath = findBinary(spawnConfig.command);
5860
- const isWin = os7.platform() === "win32";
6381
+ const isWin = os8.platform() === "win32";
5861
6382
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
5862
6383
  console.log(`[${this.cliType}] Spawning in ${this.workingDir}`);
5863
6384
  let shellCmd;
@@ -6099,7 +6620,7 @@ var init_provider_cli_adapter = __esm({
6099
6620
 
6100
6621
  // src/cli-detector.ts
6101
6622
  async function detectCLIs() {
6102
- const platform7 = os8.platform();
6623
+ const platform7 = os9.platform();
6103
6624
  const whichCmd = platform7 === "win32" ? "where" : "which";
6104
6625
  const results = [];
6105
6626
  for (const cli of KNOWN_CLIS) {
@@ -6133,12 +6654,12 @@ async function detectCLI(cliId) {
6133
6654
  const all = await detectCLIs();
6134
6655
  return all.find((c) => c.id === normalizedId && c.installed) || null;
6135
6656
  }
6136
- var import_child_process5, os8, KNOWN_CLIS;
6657
+ var import_child_process5, os9, KNOWN_CLIS;
6137
6658
  var init_cli_detector = __esm({
6138
6659
  "src/cli-detector.ts"() {
6139
6660
  "use strict";
6140
6661
  import_child_process5 = require("child_process");
6141
- os8 = __toESM(require("os"));
6662
+ os9 = __toESM(require("os"));
6142
6663
  KNOWN_CLIS = [
6143
6664
  { id: "gemini-cli", displayName: "Gemini CLI", icon: "\u264A", command: "gemini" },
6144
6665
  { id: "claude-code", displayName: "Claude Code", icon: "\u{1F916}", command: "claude" },
@@ -6147,17 +6668,267 @@ var init_cli_detector = __esm({
6147
6668
  }
6148
6669
  });
6149
6670
 
6150
- // src/daemon-cli.ts
6151
- var os9, path7, import_chalk, DaemonCliManager;
6152
- var init_daemon_cli = __esm({
6153
- "src/daemon-cli.ts"() {
6671
+ // src/providers/status-monitor.ts
6672
+ var DEFAULT_MONITOR_CONFIG, StatusMonitor;
6673
+ var init_status_monitor = __esm({
6674
+ "src/providers/status-monitor.ts"() {
6154
6675
  "use strict";
6155
- os9 = __toESM(require("os"));
6156
- path7 = __toESM(require("path"));
6676
+ DEFAULT_MONITOR_CONFIG = {
6677
+ approvalAlert: true,
6678
+ longGeneratingAlert: true,
6679
+ longGeneratingThresholdSec: 180,
6680
+ // 3분
6681
+ alertCooldownSec: 60
6682
+ // 1분 쿨다운
6683
+ };
6684
+ StatusMonitor = class {
6685
+ config;
6686
+ lastAlertTime = /* @__PURE__ */ new Map();
6687
+ generatingStartTimes = /* @__PURE__ */ new Map();
6688
+ constructor(config) {
6689
+ this.config = { ...DEFAULT_MONITOR_CONFIG, ...config };
6690
+ }
6691
+ /** 설정 업데이트 (Provider Settings에서 호출) */
6692
+ updateConfig(partial) {
6693
+ Object.assign(this.config, partial);
6694
+ }
6695
+ /** 현재 설정 반환 */
6696
+ getConfig() {
6697
+ return { ...this.config };
6698
+ }
6699
+ /**
6700
+ * 상태 전이 체크 → 알림 이벤트 배열 반환
6701
+ * 각 onTick()에서 호출.
6702
+ */
6703
+ check(agentKey, status, now) {
6704
+ const events = [];
6705
+ if (this.config.approvalAlert && status === "waiting_approval") {
6706
+ if (this.shouldAlert(agentKey + ":approval", now)) {
6707
+ events.push({
6708
+ type: "monitor:approval_waiting",
6709
+ agentKey,
6710
+ timestamp: now,
6711
+ message: `${agentKey} is waiting for approval`
6712
+ });
6713
+ }
6714
+ }
6715
+ if (status === "generating" || status === "streaming") {
6716
+ if (!this.generatingStartTimes.has(agentKey)) {
6717
+ this.generatingStartTimes.set(agentKey, now);
6718
+ }
6719
+ if (this.config.longGeneratingAlert) {
6720
+ const startedAt = this.generatingStartTimes.get(agentKey);
6721
+ const elapsedSec = Math.round((now - startedAt) / 1e3);
6722
+ if (elapsedSec > this.config.longGeneratingThresholdSec) {
6723
+ if (this.shouldAlert(agentKey + ":long_gen", now)) {
6724
+ events.push({
6725
+ type: "monitor:long_generating",
6726
+ agentKey,
6727
+ elapsedSec,
6728
+ timestamp: now,
6729
+ message: `${agentKey} has been generating for ${Math.round(elapsedSec / 60)}min`
6730
+ });
6731
+ }
6732
+ }
6733
+ }
6734
+ } else {
6735
+ this.generatingStartTimes.delete(agentKey);
6736
+ }
6737
+ return events;
6738
+ }
6739
+ /** 쿨다운 체크 — 같은 알림을 너무 자주 보내지 않도록 */
6740
+ shouldAlert(key, now) {
6741
+ const last = this.lastAlertTime.get(key) || 0;
6742
+ if (now - last > this.config.alertCooldownSec * 1e3) {
6743
+ this.lastAlertTime.set(key, now);
6744
+ return true;
6745
+ }
6746
+ return false;
6747
+ }
6748
+ /** 리셋 (에이전트 종료/재시작 시) */
6749
+ reset(agentKey) {
6750
+ if (agentKey) {
6751
+ this.generatingStartTimes.delete(agentKey);
6752
+ for (const k of this.lastAlertTime.keys()) {
6753
+ if (k.startsWith(agentKey)) this.lastAlertTime.delete(k);
6754
+ }
6755
+ } else {
6756
+ this.generatingStartTimes.clear();
6757
+ this.lastAlertTime.clear();
6758
+ }
6759
+ }
6760
+ };
6761
+ }
6762
+ });
6763
+
6764
+ // src/providers/cli-provider-instance.ts
6765
+ var path8, CliProviderInstance;
6766
+ var init_cli_provider_instance = __esm({
6767
+ "src/providers/cli-provider-instance.ts"() {
6768
+ "use strict";
6769
+ path8 = __toESM(require("path"));
6770
+ init_provider_cli_adapter();
6771
+ init_status_monitor();
6772
+ CliProviderInstance = class {
6773
+ constructor(provider2, workingDir, cliArgs = []) {
6774
+ this.provider = provider2;
6775
+ this.workingDir = workingDir;
6776
+ this.cliArgs = cliArgs;
6777
+ this.type = provider2.type;
6778
+ this.adapter = new ProviderCliAdapter(provider2, workingDir, cliArgs);
6779
+ this.monitor = new StatusMonitor();
6780
+ }
6781
+ type;
6782
+ category = "cli";
6783
+ adapter;
6784
+ context = null;
6785
+ events = [];
6786
+ lastStatus = "starting";
6787
+ generatingStartedAt = 0;
6788
+ settings = {};
6789
+ monitor;
6790
+ // ─── Lifecycle ─────────────────────────────────
6791
+ async init(context) {
6792
+ this.context = context;
6793
+ this.settings = context.settings || {};
6794
+ this.monitor.updateConfig({
6795
+ approvalAlert: this.settings.approvalAlert !== false,
6796
+ longGeneratingAlert: this.settings.longGeneratingAlert !== false,
6797
+ longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
6798
+ });
6799
+ if (context.bridge) {
6800
+ this.adapter.setBridge(context.bridge);
6801
+ }
6802
+ if (context.onPtyData) {
6803
+ this.adapter.setOnPtyData(context.onPtyData);
6804
+ }
6805
+ this.adapter.setOnStatusChange(() => {
6806
+ this.detectStatusTransition();
6807
+ });
6808
+ await this.adapter.spawn();
6809
+ }
6810
+ async onTick() {
6811
+ }
6812
+ getState() {
6813
+ const adapterStatus = this.adapter.getStatus();
6814
+ const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
6815
+ const recentMessages = adapterStatus.messages.slice(-50).map((m) => ({
6816
+ role: m.role,
6817
+ content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content,
6818
+ timestamp: m.timestamp
6819
+ }));
6820
+ const partial = this.adapter.getPartialResponse();
6821
+ if (adapterStatus.status === "generating" && partial) {
6822
+ const cleaned = partial.trim();
6823
+ if (cleaned && cleaned !== "(generating...)") {
6824
+ recentMessages.push({
6825
+ role: "assistant",
6826
+ content: (cleaned.length > 2e3 ? cleaned.slice(0, 2e3) + "..." : cleaned) + "...",
6827
+ timestamp: Date.now()
6828
+ });
6829
+ }
6830
+ }
6831
+ return {
6832
+ type: this.type,
6833
+ name: this.provider.name,
6834
+ category: "cli",
6835
+ status: adapterStatus.status,
6836
+ mode: this.settings.mode || "terminal",
6837
+ activeChat: {
6838
+ id: `${this.type}_${this.workingDir}`,
6839
+ title: `${this.provider.name} \xB7 ${dirName}`,
6840
+ status: adapterStatus.status,
6841
+ messages: recentMessages,
6842
+ activeModal: adapterStatus.activeModal,
6843
+ inputContent: ""
6844
+ },
6845
+ workingDir: this.workingDir,
6846
+ instanceId: `${this.type}_${require("crypto").createHash("md5").update(path8.resolve(this.workingDir)).digest("hex").slice(0, 8)}`,
6847
+ lastUpdated: Date.now(),
6848
+ settings: this.settings,
6849
+ pendingEvents: this.flushEvents()
6850
+ };
6851
+ }
6852
+ onEvent(event, data) {
6853
+ if (event === "send_message" && data?.text) {
6854
+ this.adapter.sendMessage(data.text);
6855
+ } else if (event === "bridge_connected" && data?.bridge) {
6856
+ this.adapter.setBridge(data.bridge);
6857
+ }
6858
+ }
6859
+ dispose() {
6860
+ this.adapter.shutdown();
6861
+ this.monitor.reset();
6862
+ }
6863
+ // ─── 상태 전이 감지 (daemon-status.ts에서 이동) ──────
6864
+ detectStatusTransition() {
6865
+ const now = Date.now();
6866
+ const adapterStatus = this.adapter.getStatus();
6867
+ const newStatus = adapterStatus.status;
6868
+ const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
6869
+ const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
6870
+ if (newStatus !== this.lastStatus) {
6871
+ if (this.lastStatus === "idle" && newStatus === "generating") {
6872
+ this.generatingStartedAt = now;
6873
+ this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now });
6874
+ } else if (newStatus === "waiting_approval") {
6875
+ if (!this.generatingStartedAt) this.generatingStartedAt = now;
6876
+ this.pushEvent({
6877
+ event: "agent:waiting_approval",
6878
+ chatTitle,
6879
+ timestamp: now,
6880
+ modalMessage: adapterStatus.activeModal?.message
6881
+ });
6882
+ } else if (newStatus === "idle" && (this.lastStatus === "generating" || this.lastStatus === "waiting_approval")) {
6883
+ const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
6884
+ this.pushEvent({ event: "agent:generating_completed", chatTitle, duration, timestamp: now });
6885
+ this.generatingStartedAt = 0;
6886
+ } else if (newStatus === "stopped") {
6887
+ this.pushEvent({ event: "agent:stopped", chatTitle, timestamp: now });
6888
+ }
6889
+ this.lastStatus = newStatus;
6890
+ }
6891
+ const agentKey = `${this.type}:cli`;
6892
+ const monitorEvents = this.monitor.check(agentKey, newStatus, now);
6893
+ for (const me of monitorEvents) {
6894
+ this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
6895
+ }
6896
+ }
6897
+ pushEvent(event) {
6898
+ this.events.push(event);
6899
+ if (this.events.length > 50) this.events = this.events.slice(-50);
6900
+ }
6901
+ flushEvents() {
6902
+ const events = [...this.events];
6903
+ this.events = [];
6904
+ return events;
6905
+ }
6906
+ // ─── Adapter 접근 (하위 호환) ──────────────────
6907
+ getAdapter() {
6908
+ return this.adapter;
6909
+ }
6910
+ get cliType() {
6911
+ return this.type;
6912
+ }
6913
+ get cliName() {
6914
+ return this.provider.name;
6915
+ }
6916
+ };
6917
+ }
6918
+ });
6919
+
6920
+ // src/daemon-cli.ts
6921
+ var os10, path9, import_chalk, DaemonCliManager;
6922
+ var init_daemon_cli = __esm({
6923
+ "src/daemon-cli.ts"() {
6924
+ "use strict";
6925
+ os10 = __toESM(require("os"));
6926
+ path9 = __toESM(require("path"));
6157
6927
  import_chalk = __toESM(require("chalk"));
6158
6928
  init_provider_cli_adapter();
6159
6929
  init_cli_detector();
6160
6930
  init_config();
6931
+ init_cli_provider_instance();
6161
6932
  DaemonCliManager = class {
6162
6933
  adapters = /* @__PURE__ */ new Map();
6163
6934
  deps;
@@ -6191,8 +6962,8 @@ var init_daemon_cli = __esm({
6191
6962
  }
6192
6963
  // ─── 세션 시작/중지 ──────────────────────────────
6193
6964
  async startSession(cliType, workingDir, cliArgs) {
6194
- const trimmed = (workingDir || process.cwd()).trim();
6195
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os9.homedir()) : path7.resolve(trimmed);
6965
+ const trimmed = (workingDir || os10.homedir()).trim();
6966
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path9.resolve(trimmed);
6196
6967
  const cliInfo = await detectCLI(cliType);
6197
6968
  if (!cliInfo) throw new Error(`${cliType} not found`);
6198
6969
  const key = this.getCliKey(cliType, resolvedDir);
@@ -6200,34 +6971,57 @@ var init_daemon_cli = __esm({
6200
6971
  console.log(import_chalk.default.yellow(` \u26A1 CLI ${cliType} already running in ${resolvedDir}`));
6201
6972
  return;
6202
6973
  }
6974
+ const typeMap = {
6975
+ "claude-code": "claude-cli",
6976
+ "codex": "codex-cli"
6977
+ };
6978
+ const normalizedType = typeMap[cliType] || cliType;
6979
+ const provider2 = this.providerLoader.get(normalizedType);
6203
6980
  console.log(import_chalk.default.yellow(` \u26A1 Starting CLI ${cliType} in ${resolvedDir}...`));
6204
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
6205
- await adapter.spawn();
6206
- const bridge = this.deps.getBridge();
6207
- if (bridge && typeof adapter.setBridge === "function") {
6208
- adapter.setBridge(bridge);
6981
+ if (provider2) {
6982
+ console.log(import_chalk.default.cyan(` \u{1F4E6} Using provider: ${provider2.name} (${provider2.type})`));
6209
6983
  }
6210
- adapter.setOnStatusChange(() => {
6211
- this.deps.onStatusChange();
6212
- const status = adapter.getStatus?.();
6213
- if (status?.status === "stopped") {
6214
- setTimeout(() => {
6215
- if (this.adapters.get(key) === adapter) {
6216
- this.adapters.delete(key);
6217
- this.deps.removeAgentTracking(key);
6218
- console.log(import_chalk.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
6219
- this.deps.onStatusChange();
6220
- }
6221
- }, 3e3);
6222
- }
6223
- });
6224
- if (typeof adapter.setOnPtyData === "function") {
6225
- adapter.setOnPtyData((data) => {
6226
- this.deps.getP2p()?.broadcastPtyOutput(key, data);
6984
+ const instanceManager = this.deps.getInstanceManager();
6985
+ if (provider2 && instanceManager) {
6986
+ const cliInstance = new CliProviderInstance(provider2, resolvedDir, cliArgs);
6987
+ await instanceManager.addInstance(key, cliInstance, {
6988
+ bridge: this.deps.getBridge(),
6989
+ settings: {},
6990
+ onPtyData: (data) => {
6991
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
6992
+ }
6993
+ });
6994
+ this.adapters.set(key, cliInstance.getAdapter());
6995
+ console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6996
+ } else {
6997
+ const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
6998
+ await adapter.spawn();
6999
+ const bridge = this.deps.getBridge();
7000
+ if (bridge && typeof adapter.setBridge === "function") {
7001
+ adapter.setBridge(bridge);
7002
+ }
7003
+ adapter.setOnStatusChange(() => {
7004
+ this.deps.onStatusChange();
7005
+ const status = adapter.getStatus?.();
7006
+ if (status?.status === "stopped") {
7007
+ setTimeout(() => {
7008
+ if (this.adapters.get(key) === adapter) {
7009
+ this.adapters.delete(key);
7010
+ this.deps.removeAgentTracking(key);
7011
+ console.log(import_chalk.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
7012
+ this.deps.onStatusChange();
7013
+ }
7014
+ }, 3e3);
7015
+ }
6227
7016
  });
7017
+ if (typeof adapter.setOnPtyData === "function") {
7018
+ adapter.setOnPtyData((data) => {
7019
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
7020
+ });
7021
+ }
7022
+ this.adapters.set(key, adapter);
7023
+ console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6228
7024
  }
6229
- this.adapters.set(key, adapter);
6230
- console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6231
7025
  try {
6232
7026
  addCliHistory({ cliType, dir: resolvedDir, cliArgs });
6233
7027
  } catch (e) {
@@ -6241,6 +7035,7 @@ var init_daemon_cli = __esm({
6241
7035
  adapter.shutdown();
6242
7036
  this.adapters.delete(key);
6243
7037
  this.deps.removeAgentTracking(key);
7038
+ this.deps.getInstanceManager()?.removeInstance(key);
6244
7039
  console.log(import_chalk.default.yellow(` \u{1F6D1} CLI Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`));
6245
7040
  this.deps.onStatusChange();
6246
7041
  }
@@ -6268,7 +7063,8 @@ var init_daemon_cli = __esm({
6268
7063
  switch (cmd) {
6269
7064
  case "launch_cli": {
6270
7065
  const cliType = args?.cliType;
6271
- const dir = args?.dir || process.cwd();
7066
+ const defaultedToHome = !args?.dir;
7067
+ const dir = args?.dir || os10.homedir();
6272
7068
  if (!cliType) throw new Error("cliType required");
6273
7069
  const key = this.getCliKey(cliType, dir);
6274
7070
  if (!this.adapters.has(key)) {
@@ -6286,7 +7082,7 @@ var init_daemon_cli = __esm({
6286
7082
  console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
6287
7083
  }
6288
7084
  }
6289
- return { success: true, cliType, dir, id: key };
7085
+ return { success: true, cliType, dir, id: key, defaultedToHome };
6290
7086
  }
6291
7087
  case "stop_cli": {
6292
7088
  const cliType = args?.cliType;
@@ -6490,99 +7286,6 @@ var init_provider_instance_manager = __esm({
6490
7286
  }
6491
7287
  });
6492
7288
 
6493
- // src/providers/status-monitor.ts
6494
- var DEFAULT_MONITOR_CONFIG, StatusMonitor;
6495
- var init_status_monitor = __esm({
6496
- "src/providers/status-monitor.ts"() {
6497
- "use strict";
6498
- DEFAULT_MONITOR_CONFIG = {
6499
- approvalAlert: true,
6500
- longGeneratingAlert: true,
6501
- longGeneratingThresholdSec: 180,
6502
- // 3분
6503
- alertCooldownSec: 60
6504
- // 1분 쿨다운
6505
- };
6506
- StatusMonitor = class {
6507
- config;
6508
- lastAlertTime = /* @__PURE__ */ new Map();
6509
- generatingStartTimes = /* @__PURE__ */ new Map();
6510
- constructor(config) {
6511
- this.config = { ...DEFAULT_MONITOR_CONFIG, ...config };
6512
- }
6513
- /** 설정 업데이트 (Provider Settings에서 호출) */
6514
- updateConfig(partial) {
6515
- Object.assign(this.config, partial);
6516
- }
6517
- /** 현재 설정 반환 */
6518
- getConfig() {
6519
- return { ...this.config };
6520
- }
6521
- /**
6522
- * 상태 전이 체크 → 알림 이벤트 배열 반환
6523
- * 각 onTick()에서 호출.
6524
- */
6525
- check(agentKey, status, now) {
6526
- const events = [];
6527
- if (this.config.approvalAlert && status === "waiting_approval") {
6528
- if (this.shouldAlert(agentKey + ":approval", now)) {
6529
- events.push({
6530
- type: "monitor:approval_waiting",
6531
- agentKey,
6532
- timestamp: now,
6533
- message: `${agentKey} is waiting for approval`
6534
- });
6535
- }
6536
- }
6537
- if (status === "generating" || status === "streaming") {
6538
- if (!this.generatingStartTimes.has(agentKey)) {
6539
- this.generatingStartTimes.set(agentKey, now);
6540
- }
6541
- if (this.config.longGeneratingAlert) {
6542
- const startedAt = this.generatingStartTimes.get(agentKey);
6543
- const elapsedSec = Math.round((now - startedAt) / 1e3);
6544
- if (elapsedSec > this.config.longGeneratingThresholdSec) {
6545
- if (this.shouldAlert(agentKey + ":long_gen", now)) {
6546
- events.push({
6547
- type: "monitor:long_generating",
6548
- agentKey,
6549
- elapsedSec,
6550
- timestamp: now,
6551
- message: `${agentKey} has been generating for ${Math.round(elapsedSec / 60)}min`
6552
- });
6553
- }
6554
- }
6555
- }
6556
- } else {
6557
- this.generatingStartTimes.delete(agentKey);
6558
- }
6559
- return events;
6560
- }
6561
- /** 쿨다운 체크 — 같은 알림을 너무 자주 보내지 않도록 */
6562
- shouldAlert(key, now) {
6563
- const last = this.lastAlertTime.get(key) || 0;
6564
- if (now - last > this.config.alertCooldownSec * 1e3) {
6565
- this.lastAlertTime.set(key, now);
6566
- return true;
6567
- }
6568
- return false;
6569
- }
6570
- /** 리셋 (에이전트 종료/재시작 시) */
6571
- reset(agentKey) {
6572
- if (agentKey) {
6573
- this.generatingStartTimes.delete(agentKey);
6574
- for (const k of this.lastAlertTime.keys()) {
6575
- if (k.startsWith(agentKey)) this.lastAlertTime.delete(k);
6576
- }
6577
- } else {
6578
- this.generatingStartTimes.clear();
6579
- this.lastAlertTime.clear();
6580
- }
6581
- }
6582
- };
6583
- }
6584
- });
6585
-
6586
7289
  // src/providers/extension-provider-instance.ts
6587
7290
  var ExtensionProviderInstance;
6588
7291
  var init_extension_provider_instance = __esm({
@@ -6705,11 +7408,11 @@ var init_extension_provider_instance = __esm({
6705
7408
  });
6706
7409
 
6707
7410
  // src/providers/ide-provider-instance.ts
6708
- var os10, crypto, IdeProviderInstance;
7411
+ var os11, crypto, IdeProviderInstance;
6709
7412
  var init_ide_provider_instance = __esm({
6710
7413
  "src/providers/ide-provider-instance.ts"() {
6711
7414
  "use strict";
6712
- os10 = __toESM(require("os"));
7415
+ os11 = __toESM(require("os"));
6713
7416
  crypto = __toESM(require("crypto"));
6714
7417
  init_extension_provider_instance();
6715
7418
  init_status_monitor();
@@ -6735,10 +7438,10 @@ var init_ide_provider_instance = __esm({
6735
7438
  activeFile = null;
6736
7439
  // ─── 자식 Extension Instances ────────────────────
6737
7440
  extensions = /* @__PURE__ */ new Map();
6738
- constructor(provider2) {
7441
+ constructor(provider2, instanceKey) {
6739
7442
  this.type = provider2.type;
6740
7443
  this.provider = provider2;
6741
- this.instanceId = `${provider2.type}_${crypto.createHash("md5").update(os10.hostname() + provider2.type).digest("hex").slice(0, 8)}`;
7444
+ this.instanceId = instanceKey ? `${instanceKey}_${crypto.createHash("md5").update(os11.hostname() + instanceKey).digest("hex").slice(0, 8)}` : `${provider2.type}_${crypto.createHash("md5").update(os11.hostname() + provider2.type).digest("hex").slice(0, 8)}`;
6742
7445
  this.monitor = new StatusMonitor();
6743
7446
  }
6744
7447
  // ─── Lifecycle ─────────────────────────────────
@@ -6869,7 +7572,14 @@ var init_ide_provider_instance = __esm({
6869
7572
  const readChatScript = this.getReadChatScript();
6870
7573
  if (!readChatScript) return;
6871
7574
  try {
6872
- const raw = await cdp2.evaluate(readChatScript, 3e4);
7575
+ let raw = await cdp2.evaluate(readChatScript, 3e4);
7576
+ if (typeof raw === "string") {
7577
+ try {
7578
+ raw = JSON.parse(raw);
7579
+ } catch {
7580
+ return;
7581
+ }
7582
+ }
6873
7583
  if (!raw || typeof raw !== "object") return;
6874
7584
  let { activeModal } = raw;
6875
7585
  if (activeModal) {
@@ -6962,107 +7672,6 @@ var init_ide_provider_instance = __esm({
6962
7672
  }
6963
7673
  });
6964
7674
 
6965
- // src/daemon-logger.ts
6966
- var daemon_logger_exports = {};
6967
- __export(daemon_logger_exports, {
6968
- LOG_DIR_PATH: () => LOG_DIR_PATH,
6969
- LOG_PATH: () => LOG_PATH,
6970
- cdpLogFn: () => cdpLogFn,
6971
- daemonLog: () => daemonLog,
6972
- installGlobalInterceptor: () => installGlobalInterceptor
6973
- });
6974
- function rotateIfNeeded() {
6975
- try {
6976
- const stat = fs5.statSync(LOG_FILE);
6977
- if (stat.size > MAX_LOG_SIZE) {
6978
- const backup = LOG_FILE + ".old";
6979
- try {
6980
- fs5.unlinkSync(backup);
6981
- } catch {
6982
- }
6983
- fs5.renameSync(LOG_FILE, backup);
6984
- }
6985
- } catch {
6986
- }
6987
- }
6988
- function writeToFile(line) {
6989
- try {
6990
- fs5.appendFileSync(LOG_FILE, line + "\n");
6991
- } catch {
6992
- }
6993
- }
6994
- function daemonLog(category, msg) {
6995
- const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${category}] ${msg}`;
6996
- origConsoleLog(line);
6997
- writeToFile(line);
6998
- }
6999
- function cdpLogFn(ideType) {
7000
- return (msg) => {
7001
- const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [CDP:${ideType}] ${msg}`;
7002
- origConsoleLog(line);
7003
- writeToFile(line);
7004
- };
7005
- }
7006
- function installGlobalInterceptor() {
7007
- if (interceptorInstalled) return;
7008
- interceptorInstalled = true;
7009
- const stripAnsi2 = (str) => str.replace(/\x1B\[[0-9;]*m/g, "");
7010
- console.log = (...args) => {
7011
- origConsoleLog(...args);
7012
- try {
7013
- const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
7014
- const clean = stripAnsi2(msg);
7015
- const line = clean.startsWith("[20") ? clean : `[${(/* @__PURE__ */ new Date()).toISOString()}] ${clean}`;
7016
- writeToFile(line);
7017
- } catch {
7018
- }
7019
- };
7020
- console.error = (...args) => {
7021
- origConsoleError(...args);
7022
- try {
7023
- const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
7024
- const clean = stripAnsi2(msg);
7025
- writeToFile(`[${(/* @__PURE__ */ new Date()).toISOString()}] [ERROR] ${clean}`);
7026
- } catch {
7027
- }
7028
- };
7029
- console.warn = (...args) => {
7030
- origConsoleWarn(...args);
7031
- try {
7032
- const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
7033
- const clean = stripAnsi2(msg);
7034
- writeToFile(`[${(/* @__PURE__ */ new Date()).toISOString()}] [WARN] ${clean}`);
7035
- } catch {
7036
- }
7037
- };
7038
- writeToFile(`
7039
- === ADHDev Daemon started at ${(/* @__PURE__ */ new Date()).toISOString()} ===`);
7040
- writeToFile(`Log file: ${LOG_FILE}`);
7041
- }
7042
- var fs5, path8, os11, LOG_DIR, LOG_FILE, MAX_LOG_SIZE, origConsoleLog, origConsoleError, origConsoleWarn, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
7043
- var init_daemon_logger = __esm({
7044
- "src/daemon-logger.ts"() {
7045
- "use strict";
7046
- fs5 = __toESM(require("fs"));
7047
- path8 = __toESM(require("path"));
7048
- os11 = __toESM(require("os"));
7049
- LOG_DIR = process.platform === "darwin" ? path8.join(os11.homedir(), "Library", "Logs", "adhdev") : path8.join(os11.homedir(), ".local", "share", "adhdev", "logs");
7050
- LOG_FILE = path8.join(LOG_DIR, "daemon.log");
7051
- MAX_LOG_SIZE = 10 * 1024 * 1024;
7052
- try {
7053
- fs5.mkdirSync(LOG_DIR, { recursive: true });
7054
- } catch {
7055
- }
7056
- rotateIfNeeded();
7057
- origConsoleLog = console.log.bind(console);
7058
- origConsoleError = console.error.bind(console);
7059
- origConsoleWarn = console.warn.bind(console);
7060
- interceptorInstalled = false;
7061
- LOG_PATH = LOG_FILE;
7062
- LOG_DIR_PATH = LOG_DIR;
7063
- }
7064
- });
7065
-
7066
7675
  // src/adhdev-daemon.ts
7067
7676
  var adhdev_daemon_exports = {};
7068
7677
  __export(adhdev_daemon_exports, {
@@ -7071,9 +7680,9 @@ __export(adhdev_daemon_exports, {
7071
7680
  stopDaemon: () => stopDaemon
7072
7681
  });
7073
7682
  function getDaemonPidFile() {
7074
- const dir = path9.join(os12.homedir(), ".adhdev");
7683
+ const dir = path10.join(os12.homedir(), ".adhdev");
7075
7684
  if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
7076
- return path9.join(dir, "daemon.pid");
7685
+ return path10.join(dir, "daemon.pid");
7077
7686
  }
7078
7687
  function writeDaemonPid(pid) {
7079
7688
  fs6.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
@@ -7109,7 +7718,7 @@ function stopDaemon() {
7109
7718
  return false;
7110
7719
  }
7111
7720
  }
7112
- var os12, fs6, path9, crypto2, import_chalk2, DANGEROUS_PATTERNS, AdhdevDaemon;
7721
+ var os12, fs6, path10, crypto2, import_chalk2, DANGEROUS_PATTERNS, AdhdevDaemon;
7113
7722
  var init_adhdev_daemon = __esm({
7114
7723
  "src/adhdev-daemon.ts"() {
7115
7724
  "use strict";
@@ -7129,9 +7738,10 @@ var init_adhdev_daemon = __esm({
7129
7738
  init_provider_instance_manager();
7130
7739
  init_ide_provider_instance();
7131
7740
  init_ipc_protocol();
7741
+ init_daemon_logger();
7132
7742
  os12 = __toESM(require("os"));
7133
7743
  fs6 = __toESM(require("fs"));
7134
- path9 = __toESM(require("path"));
7744
+ path10 = __toESM(require("path"));
7135
7745
  crypto2 = __toESM(require("crypto"));
7136
7746
  import_chalk2 = __toESM(require("chalk"));
7137
7747
  DANGEROUS_PATTERNS = [
@@ -7173,7 +7783,8 @@ var init_adhdev_daemon = __esm({
7173
7783
  getBridge: () => this.bridge,
7174
7784
  getP2p: () => this.p2p,
7175
7785
  onStatusChange: () => this.statusReporter?.onStatusChange(),
7176
- removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key)
7786
+ removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
7787
+ getInstanceManager: () => this.instanceManager
7177
7788
  }, this.providerLoader);
7178
7789
  }
7179
7790
  async start(options = {}) {
@@ -7328,8 +7939,8 @@ var init_adhdev_daemon = __esm({
7328
7939
  });
7329
7940
  this.p2p.onStateChange((state) => {
7330
7941
  if (state === "connected") {
7331
- console.log("[P2P] Peer connected \u2192 sending immediate full status report");
7332
- this.statusReporter?.sendUnifiedStatusReport().catch((e) => console.warn("[P2P] Immediate status report failed:", e?.message));
7942
+ LOG.info("P2P", "Peer connected \u2192 sending immediate full status report");
7943
+ this.statusReporter?.sendUnifiedStatusReport().catch((e) => LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
7333
7944
  }
7334
7945
  });
7335
7946
  let ssDebugCount = 0;
@@ -7340,18 +7951,18 @@ var init_adhdev_daemon = __esm({
7340
7951
  if (!active || !cdp2) return;
7341
7952
  ssDebugCount++;
7342
7953
  if (ssDebugCount <= 3 || ssDebugCount % 25 === 0) {
7343
- console.log(`[SS] Capturing screenshot... (tick ${ssDebugCount}, active=${active}, cdp=true)`);
7954
+ LOG.debug("Screenshot", `Capturing... (tick ${ssDebugCount}, active=${active}, cdp=true)`);
7344
7955
  }
7345
7956
  try {
7346
7957
  const buf = await cdp2.captureScreenshot();
7347
7958
  if (buf) {
7348
7959
  const sent = this.p2p.sendScreenshot(buf.toString("base64"));
7349
- if (ssDebugCount <= 3) console.log(`[SS] Screenshot sent: ${buf.length} bytes, delivered=${sent}`);
7960
+ if (ssDebugCount <= 3) LOG.debug("Screenshot", `sent: ${buf.length} bytes, delivered=${sent}`);
7350
7961
  } else {
7351
- if (ssDebugCount <= 5) console.log(`[SS] captureScreenshot returned null`);
7962
+ if (ssDebugCount <= 5) LOG.debug("Screenshot", "captureScreenshot returned null");
7352
7963
  }
7353
7964
  } catch (e) {
7354
- if (ssDebugCount <= 5) console.log(`[SS] Screenshot error: ${e?.message}`);
7965
+ if (ssDebugCount <= 5) LOG.warn("Screenshot", `error: ${e?.message}`);
7355
7966
  }
7356
7967
  }, 200);
7357
7968
  } else {
@@ -7494,10 +8105,7 @@ var init_adhdev_daemon = __esm({
7494
8105
  }
7495
8106
  }
7496
8107
  async handleCommand(msg, cmd, args) {
7497
- console.log(import_chalk2.default.magenta(` \u2699 Command: ${cmd}`));
7498
- if (cmd.startsWith("agent_stream") && args?._targetInstance) {
7499
- console.log(import_chalk2.default.yellow(` \u{1F3AF} Target: ${args._targetType}:${args._targetInstance.split("_")[0]} agent=${args.agentType || ""}`));
7500
- }
8108
+ LOG.info("Command", `${cmd}${args?._targetInstance ? ` \u2192 ${args._targetType}:${args._targetInstance.split("_")[0]}` : ""}`);
7501
8109
  try {
7502
8110
  switch (cmd) {
7503
8111
  case "open_panel":
@@ -7569,17 +8177,22 @@ var init_adhdev_daemon = __esm({
7569
8177
  return { success: true, nickname };
7570
8178
  }
7571
8179
  case "get_daemon_logs": {
7572
- const lines = parseInt(data.lines) || 100;
8180
+ const count = parseInt(data.lines) || 100;
8181
+ const minLevel = data.minLevel || "info";
7573
8182
  try {
7574
- const logPath = require("path").join(require("os").tmpdir(), "adhdev-daemon.log");
8183
+ const { getRecentLogs: getRecentLogs2, LOG_PATH: LOG_PATH2 } = (init_daemon_logger(), __toCommonJS(daemon_logger_exports));
8184
+ const entries = getRecentLogs2(count, minLevel);
8185
+ if (entries.length > 0) {
8186
+ return { success: true, entries, totalBuffered: entries.length };
8187
+ }
7575
8188
  const logFs = require("fs");
7576
- if (logFs.existsSync(logPath)) {
7577
- const content = logFs.readFileSync(logPath, "utf-8");
8189
+ if (logFs.existsSync(LOG_PATH2)) {
8190
+ const content = logFs.readFileSync(LOG_PATH2, "utf-8");
7578
8191
  const allLines = content.split("\n");
7579
- const recent = allLines.slice(-lines).join("\n");
8192
+ const recent = allLines.slice(-count).join("\n");
7580
8193
  return { success: true, logs: recent, totalLines: allLines.length };
7581
8194
  }
7582
- return { success: true, logs: "", totalLines: 0 };
8195
+ return { success: true, entries: [], totalBuffered: 0 };
7583
8196
  } catch (e) {
7584
8197
  return { success: false, error: e.message };
7585
8198
  }
@@ -7612,7 +8225,7 @@ var init_adhdev_daemon = __esm({
7612
8225
  case "launch_ide": {
7613
8226
  const launchArgs = { ...args, ideId: args?.ideId || args?.ideType };
7614
8227
  const ideKey = launchArgs.ideId;
7615
- console.log(`[launch_ide] target=${ideKey || "auto"}`);
8228
+ LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
7616
8229
  const result = await launchWithCdp(launchArgs);
7617
8230
  if (result.success && result.port && result.ideId && !this.cdpManagers.has(result.ideId)) {
7618
8231
  console.log(import_chalk2.default.cyan(`[launch_ide] Connecting CDP for ${result.ideId} on port ${result.port}...`));
@@ -7621,6 +8234,12 @@ var init_adhdev_daemon = __esm({
7621
8234
  });
7622
8235
  const connected = await manager.connect();
7623
8236
  if (connected) {
8237
+ const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(result.ideId).map((p) => ({
8238
+ agentType: p.type,
8239
+ extensionId: p.extensionId || "",
8240
+ extensionIdPattern: p.extensionIdPattern
8241
+ }));
8242
+ manager.setExtensionProviders(enabledExtProviders);
7624
8243
  this.cdpManagers.set(result.ideId, manager);
7625
8244
  console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${result.ideId} (port ${result.port})`));
7626
8245
  console.log(import_chalk2.default.green(` \u{1F4E1} CDP: ${this.cdpManagers.size} IDE(s) connected`));
@@ -7702,6 +8321,37 @@ var init_adhdev_daemon = __esm({
7702
8321
  if (this.agentStreamTimer) return;
7703
8322
  this.agentStreamTimer = setInterval(async () => {
7704
8323
  if (!this.agentStreamManager || this.cdpManagers.size === 0) return;
8324
+ for (const [ideType, cdp2] of this.cdpManagers) {
8325
+ const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(ideType).map((p) => ({
8326
+ agentType: p.type,
8327
+ extensionId: p.extensionId || "",
8328
+ extensionIdPattern: p.extensionIdPattern
8329
+ }));
8330
+ cdp2.setExtensionProviders(enabledExtProviders);
8331
+ const ideInstance = this.instanceManager.getInstance(`ide:${ideType}`);
8332
+ if (ideInstance?.getExtensionTypes && ideInstance?.addExtension && ideInstance?.removeExtension) {
8333
+ const currentExtTypes = new Set(ideInstance.getExtensionTypes());
8334
+ const enabledExtTypes = new Set(
8335
+ this.providerLoader.getEnabledByCategory("extension", ideType).map((p) => p.type)
8336
+ );
8337
+ for (const extType of currentExtTypes) {
8338
+ if (!enabledExtTypes.has(extType)) {
8339
+ ideInstance.removeExtension(extType);
8340
+ LOG.info("AgentStream", `Extension removed: ${extType} (disabled for ${ideType})`);
8341
+ }
8342
+ }
8343
+ for (const extType of enabledExtTypes) {
8344
+ if (!currentExtTypes.has(extType)) {
8345
+ const extProvider = this.providerLoader.get(extType);
8346
+ if (extProvider) {
8347
+ const extSettings = this.providerLoader.getSettings(extType);
8348
+ ideInstance.addExtension(extProvider, extSettings);
8349
+ LOG.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
8350
+ }
8351
+ }
8352
+ }
8353
+ }
8354
+ }
7705
8355
  if (this._agentStreamCdpIdeType) {
7706
8356
  const cdp2 = this.cdpManagers.get(this._agentStreamCdpIdeType);
7707
8357
  if (cdp2?.isConnected) {
@@ -7723,7 +8373,7 @@ var init_adhdev_daemon = __esm({
7723
8373
  if (discovered.length > 0) {
7724
8374
  this._agentStreamCdpIdeType = ideType;
7725
8375
  await this.agentStreamManager.switchActiveAgent(cdp2, discovered[0].agentType);
7726
- console.log(`[AgentStream] Auto-activated: ${discovered[0].agentType} (${ideType})`);
8376
+ LOG.info("AgentStream", `Auto-activated: ${discovered[0].agentType} (${ideType})`);
7727
8377
  await this.agentStreamManager.syncAgentSessions(cdp2);
7728
8378
  const streams = await this.agentStreamManager.collectAgentStreams(cdp2);
7729
8379
  this.statusReporter?.updateAgentStreams(ideType, streams);
@@ -7735,6 +8385,39 @@ var init_adhdev_daemon = __esm({
7735
8385
  }
7736
8386
  }, 5e3);
7737
8387
  }
8388
+ /**
8389
+ * CdpManager 초기화 공통 로직 — extension provider 등록, ideType 설정, ProviderInstance 생성
8390
+ * @param ideType provider 기반 IDE 타입 (e.g., 'antigravity', 'cursor')
8391
+ * @param manager 연결된 CdpManager
8392
+ */
8393
+ setupCdpManager(ideType, manager) {
8394
+ const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(ideType).map((p) => ({
8395
+ agentType: p.type,
8396
+ extensionId: p.extensionId || "",
8397
+ extensionIdPattern: p.extensionIdPattern
8398
+ }));
8399
+ manager.setExtensionProviders(enabledExtProviders);
8400
+ if (this.ideType === "unknown") {
8401
+ this.ideType = ideType;
8402
+ }
8403
+ const ideProvider = this.providerLoader.get(ideType);
8404
+ if (ideProvider) {
8405
+ const managerKey = [...this.cdpManagers.entries()].find(([, m]) => m === manager)?.[0] || ideType;
8406
+ const ideInstance = new IdeProviderInstance(ideProvider, managerKey !== ideType ? managerKey : void 0);
8407
+ const resolvedSettings = this.providerLoader.getSettings(ideType);
8408
+ this.instanceManager.addInstance(`ide:${managerKey}`, ideInstance, {
8409
+ cdp: manager,
8410
+ bridge: this.bridge || void 0,
8411
+ settings: resolvedSettings
8412
+ }).then(async () => {
8413
+ const extensionProviders = this.providerLoader.getEnabledByCategory("extension", ideType);
8414
+ for (const extProvider of extensionProviders) {
8415
+ const extSettings = this.providerLoader.getSettings(extProvider.type);
8416
+ await ideInstance.addExtension(extProvider, extSettings);
8417
+ }
8418
+ }).catch((e) => console.warn(`[Instance] Failed to init IDE instance ${managerKey}:`, e?.message));
8419
+ }
8420
+ }
7738
8421
  async initCdp() {
7739
8422
  const providerCdpMap = this.providerLoader.getCdpPortMap();
7740
8423
  const cdpPortMap = {};
@@ -7755,49 +8438,87 @@ var init_adhdev_daemon = __esm({
7755
8438
  const enabledIdes = loadConfig().enabledIdes || [];
7756
8439
  const filteredPorts = enabledIdes.length > 0 ? portsToTry.filter((p) => enabledIdes.includes(p.ide)) : portsToTry;
7757
8440
  for (const { port, ide } of filteredPorts) {
7758
- const manager = new DaemonCdpManager(port, (msg) => {
7759
- console.log(`[CDP:${ide}] ${msg}`);
7760
- });
7761
- const connected = await manager.connect();
7762
- if (connected) {
7763
- const actualPort = manager.getPort();
7764
- const actualIde = Object.entries(cdpPortMap).find(([, p]) => p === actualPort)?.[0] || ide;
7765
- this.cdpManagers.set(actualIde, manager);
7766
- console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${actualIde} (port ${actualPort})`));
7767
- if (this.ideType === "unknown") {
7768
- this.ideType = actualIde;
8441
+ const allTargets = await DaemonCdpManager.listAllTargets(port);
8442
+ if (allTargets.length === 0) {
8443
+ const manager = new DaemonCdpManager(port, (msg) => {
8444
+ console.log(`[CDP:${ide}] ${msg}`);
8445
+ });
8446
+ const connected = await manager.connect();
8447
+ if (connected) {
8448
+ this.cdpManagers.set(ide, manager);
8449
+ console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${ide} (port ${port})`));
8450
+ this.setupCdpManager(ide, manager);
7769
8451
  }
7770
- const ideProvider = this.providerLoader.get(actualIde);
7771
- if (ideProvider) {
7772
- const ideInstance = new IdeProviderInstance(ideProvider);
7773
- const resolvedSettings = this.providerLoader.getSettings(actualIde);
7774
- this.instanceManager.addInstance(`ide:${actualIde}`, ideInstance, {
7775
- cdp: manager,
7776
- bridge: this.bridge || void 0,
7777
- settings: resolvedSettings
7778
- }).then(async () => {
7779
- const extensionProviders = this.providerLoader.getAll().filter((p) => p.category === "extension");
7780
- for (const extProvider of extensionProviders) {
7781
- const extSettings = this.providerLoader.getSettings(extProvider.type);
7782
- await ideInstance.addExtension(extProvider, extSettings);
7783
- }
7784
- }).catch((e) => console.warn(`[Instance] Failed to init IDE instance ${actualIde}:`, e?.message));
8452
+ continue;
8453
+ }
8454
+ for (let i = 0; i < allTargets.length; i++) {
8455
+ const target = allTargets[i];
8456
+ let managerKey;
8457
+ if (allTargets.length === 1) {
8458
+ managerKey = ide;
8459
+ } else {
8460
+ const workspaceName = (target.title || "").split(" \u2014 ")[0].trim() || `window_${i}`;
8461
+ managerKey = `${ide}_${workspaceName}`;
8462
+ }
8463
+ if (this.cdpManagers.has(managerKey)) continue;
8464
+ const manager = new DaemonCdpManager(port, (msg) => {
8465
+ console.log(`[CDP:${managerKey}] ${msg}`);
8466
+ }, target.id);
8467
+ const connected = await manager.connect();
8468
+ if (connected) {
8469
+ this.cdpManagers.set(managerKey, manager);
8470
+ console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${managerKey} (port ${port}, page "${target.title}")`));
8471
+ this.setupCdpManager(ide, manager);
7785
8472
  }
7786
8473
  }
7787
8474
  }
7788
8475
  if (this.cdpManagers.size > 0) {
7789
8476
  console.log(import_chalk2.default.green(` \u{1F4E1} CDP: ${this.cdpManagers.size} IDE(s) connected`));
7790
- this.cdpDiscoveryTimer = setInterval(async () => {
7791
- for (const m of this.cdpManagers.values()) {
7792
- if (m.isConnected) {
7793
- await m.discoverAgentWebviews();
7794
- }
7795
- }
7796
- }, 3e4);
7797
8477
  } else {
7798
8478
  console.log(import_chalk2.default.yellow(` \u26A0 CDP not available \u2014 tried ports: ${portsToTry.map((p) => `${p.ide}:${p.port}`).join(", ")}`));
7799
8479
  console.log(import_chalk2.default.yellow(` IDE may need relaunch with --remote-debugging-port`));
7800
8480
  }
8481
+ this.cdpDiscoveryTimer = setInterval(async () => {
8482
+ for (const m of this.cdpManagers.values()) {
8483
+ if (m.isConnected) {
8484
+ await m.discoverAgentWebviews();
8485
+ }
8486
+ }
8487
+ }, 3e4);
8488
+ setInterval(async () => {
8489
+ const portMap = this.providerLoader.getCdpPortMap();
8490
+ for (const [ide, ports] of Object.entries(portMap)) {
8491
+ const primaryPort = ports[0];
8492
+ const alreadyConnected = [...this.cdpManagers.entries()].some(
8493
+ ([key, m]) => m.isConnected && (key === ide || key.startsWith(ide + "_"))
8494
+ );
8495
+ if (alreadyConnected) continue;
8496
+ const targets = await DaemonCdpManager.listAllTargets(primaryPort);
8497
+ if (targets.length === 0) continue;
8498
+ console.log(import_chalk2.default.cyan(`[CDP-Scan] Found ${targets.length} page(s) on ${ide}:${primaryPort}`));
8499
+ for (let i = 0; i < targets.length; i++) {
8500
+ const target = targets[i];
8501
+ let managerKey;
8502
+ if (targets.length === 1) {
8503
+ managerKey = ide;
8504
+ } else {
8505
+ const workspaceName = (target.title || "").split(" \u2014 ")[0].trim() || `window_${i}`;
8506
+ managerKey = `${ide}_${workspaceName}`;
8507
+ }
8508
+ if (this.cdpManagers.has(managerKey)) continue;
8509
+ const manager = new DaemonCdpManager(primaryPort, (msg) => {
8510
+ console.log(`[CDP:${managerKey}] ${msg}`);
8511
+ }, target.id);
8512
+ const connected = await manager.connect();
8513
+ if (connected) {
8514
+ this.cdpManagers.set(managerKey, manager);
8515
+ console.log(import_chalk2.default.green(` \u{1F50D} CDP auto-connected: ${managerKey} (port ${primaryPort}, page "${target.title}")`));
8516
+ this.setupCdpManager(ide, manager);
8517
+ this.startAgentStreamPolling();
8518
+ }
8519
+ }
8520
+ }
8521
+ }, 3e4);
7801
8522
  }
7802
8523
  };
7803
8524
  }
@@ -7945,10 +8666,10 @@ async function installExtension(ide, extension) {
7945
8666
  const buffer = Buffer.from(await res.arrayBuffer());
7946
8667
  const fs7 = await import("fs");
7947
8668
  fs7.writeFileSync(vsixPath, buffer);
7948
- return new Promise((resolve5) => {
8669
+ return new Promise((resolve6) => {
7949
8670
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
7950
8671
  (0, import_child_process2.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
7951
- resolve5({
8672
+ resolve6({
7952
8673
  extensionId: extension.id,
7953
8674
  marketplaceId: extension.marketplaceId,
7954
8675
  success: !error,
@@ -7979,11 +8700,11 @@ async function installExtension(ide, extension) {
7979
8700
  }
7980
8701
  }
7981
8702
  }
7982
- return new Promise((resolve5) => {
8703
+ return new Promise((resolve6) => {
7983
8704
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
7984
8705
  (0, import_child_process2.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
7985
8706
  if (error) {
7986
- resolve5({
8707
+ resolve6({
7987
8708
  extensionId: extension.id,
7988
8709
  marketplaceId: extension.marketplaceId,
7989
8710
  success: false,
@@ -7991,7 +8712,7 @@ async function installExtension(ide, extension) {
7991
8712
  error: stderr || error.message
7992
8713
  });
7993
8714
  } else {
7994
- resolve5({
8715
+ resolve6({
7995
8716
  extensionId: extension.id,
7996
8717
  marketplaceId: extension.marketplaceId,
7997
8718
  success: true,
@@ -8167,11 +8888,12 @@ async function quickSetup() {
8167
8888
  console.log(` ${import_chalk3.default.bold("Status:")} ${import_chalk3.default.green("Ready to connect")}`);
8168
8889
  console.log();
8169
8890
  console.log(import_chalk3.default.gray(" Commands:"));
8170
- console.log(import_chalk3.default.gray(" adhdev daemon \u2014 Start daemon (IDE monitor + agent hub)"));
8171
- console.log(import_chalk3.default.gray(" adhdev launch cursor \u2014 Launch IDE with CDP"));
8172
- console.log(import_chalk3.default.gray(" adhdev launch gemini \u2014 Start CLI agent via daemon"));
8891
+ console.log(import_chalk3.default.gray(" adhdev daemon \u2014 Start the main daemon (required for all features)"));
8892
+ console.log(import_chalk3.default.gray(" adhdev launch <ide> \u2014 Launch an IDE with remote control (e.g. cursor)"));
8893
+ console.log(import_chalk3.default.gray(" adhdev launch <agent> \u2014 Start a CLI agent via daemon (e.g. gemini, claude)"));
8894
+ console.log(import_chalk3.default.gray(" adhdev cdp \u2014 Interactive CDP debug console"));
8173
8895
  console.log(import_chalk3.default.gray(" adhdev status \u2014 Check setup status"));
8174
- console.log(import_chalk3.default.gray(" adhdev setup \u2014 Reconfigure"));
8896
+ console.log(import_chalk3.default.gray(" adhdev setup \u2014 Reconfigure ADHDev"));
8175
8897
  console.log();
8176
8898
  await installCliOnly();
8177
8899
  await startDaemonFlow();
@@ -8343,16 +9065,16 @@ async function injectTokenToIDE(ide, connectionToken) {
8343
9065
  try {
8344
9066
  const os13 = await import("os");
8345
9067
  const fs7 = await import("fs");
8346
- const path10 = await import("path");
9068
+ const path11 = await import("path");
8347
9069
  const platform7 = os13.platform();
8348
9070
  const home = os13.homedir();
8349
9071
  const getSettingsPath = (appName2) => {
8350
9072
  if (platform7 === "darwin") {
8351
- return path10.join(home, "Library", "Application Support", appName2, "User", "settings.json");
9073
+ return path11.join(home, "Library", "Application Support", appName2, "User", "settings.json");
8352
9074
  } else if (platform7 === "win32") {
8353
- return path10.join(process.env.APPDATA || path10.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
9075
+ return path11.join(process.env.APPDATA || path11.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
8354
9076
  } else {
8355
- return path10.join(home, ".config", appName2, "User", "settings.json");
9077
+ return path11.join(home, ".config", appName2, "User", "settings.json");
8356
9078
  }
8357
9079
  };
8358
9080
  const loader = new ProviderLoader({ logFn: () => {
@@ -8370,7 +9092,7 @@ async function injectTokenToIDE(ide, connectionToken) {
8370
9092
  settings = {};
8371
9093
  }
8372
9094
  } else {
8373
- fs7.mkdirSync(path10.dirname(settingsPath), { recursive: true });
9095
+ fs7.mkdirSync(path11.dirname(settingsPath), { recursive: true });
8374
9096
  }
8375
9097
  settings["adhdev.connectionToken"] = connectionToken;
8376
9098
  settings["adhdev.autoConnect"] = true;
@@ -8392,7 +9114,7 @@ async function startDaemonFlow() {
8392
9114
  {
8393
9115
  type: "confirm",
8394
9116
  name: "startDaemon",
8395
- message: "Start ADHDev Daemon now? (IDE monitor + agent hub)",
9117
+ message: "Start the ADHDev Daemon now? (Required for all agent/IDE routing features)",
8396
9118
  default: true
8397
9119
  }
8398
9120
  ]);
@@ -8406,8 +9128,8 @@ async function startDaemonFlow() {
8406
9128
  const daemon = new AdhdevDaemon2();
8407
9129
  const { execSync: execSync6 } = await import("child_process");
8408
9130
  const os13 = await import("os");
8409
- const path10 = await import("path");
8410
- const logPath = path10.join(os13.homedir(), ".adhdev", "daemon.log");
9131
+ const path11 = await import("path");
9132
+ const logPath = path11.join(os13.homedir(), ".adhdev", "daemon.log");
8411
9133
  try {
8412
9134
  execSync6(`nohup adhdev daemon > "${logPath}" 2>&1 &`, {
8413
9135
  timeout: 3e3,
@@ -8449,10 +9171,11 @@ async function installCliOnly() {
8449
9171
  const isNpx = process.env.npm_execpath?.includes("npx") || process.argv[1]?.includes("npx") || process.argv[1]?.includes("_npx");
8450
9172
  console.log(import_chalk3.default.bold("\n\u{1F527} ADHDev CLI\n"));
8451
9173
  console.log(import_chalk3.default.gray(" The `adhdev` command lets you:"));
8452
- console.log(import_chalk3.default.gray(" \u2022 Start daemon \u2014 IDE monitor + agent hub (adhdev daemon)"));
8453
- console.log(import_chalk3.default.gray(" \u2022 Launch IDE with CDP (adhdev launch cursor)"));
8454
- console.log(import_chalk3.default.gray(" \u2022 Start CLI agents (adhdev launch gemini)"));
8455
- console.log(import_chalk3.default.gray(" \u2022 Check status (adhdev status)"));
9174
+ console.log(import_chalk3.default.gray(" \u2022 Start the main daemon (adhdev daemon)"));
9175
+ console.log(import_chalk3.default.gray(" \u2022 Launch IDE with CDP (adhdev launch <ide>)"));
9176
+ console.log(import_chalk3.default.gray(" \u2022 Start CLI agents (adhdev launch <agent>)"));
9177
+ console.log(import_chalk3.default.gray(" \u2022 CDP Debugging Console (adhdev cdp)"));
9178
+ console.log(import_chalk3.default.gray(" \u2022 Check setup status (adhdev status)"));
8456
9179
  console.log();
8457
9180
  if (currentVersion) {
8458
9181
  console.log(import_chalk3.default.green(` \u2713 Currently installed: v${currentVersion}`));
@@ -8834,7 +9557,7 @@ program.command("daemon:stop").description("Stop ADHDev Daemon").action(async ()
8834
9557
  async function sendDaemonCommand(cmd, args = {}, port = 19222) {
8835
9558
  const WebSocket4 = (await import("ws")).default;
8836
9559
  const { DAEMON_WS_PATH: DAEMON_WS_PATH2 } = await Promise.resolve().then(() => (init_ipc_protocol(), ipc_protocol_exports));
8837
- return new Promise((resolve5, reject) => {
9560
+ return new Promise((resolve6, reject) => {
8838
9561
  const wsUrl = `ws://127.0.0.1:${port}${DAEMON_WS_PATH2 || "/daemon"}`;
8839
9562
  const ws = new WebSocket4(wsUrl);
8840
9563
  const timeout = setTimeout(() => {
@@ -8865,7 +9588,7 @@ async function sendDaemonCommand(cmd, args = {}, port = 19222) {
8865
9588
  if (msg.type === "daemon:command_result" || msg.type === "command_result") {
8866
9589
  clearTimeout(timeout);
8867
9590
  ws.close();
8868
- resolve5(msg.payload?.result || msg.payload || msg);
9591
+ resolve6(msg.payload?.result || msg.payload || msg);
8869
9592
  }
8870
9593
  } catch {
8871
9594
  }
@@ -8882,13 +9605,13 @@ Is 'adhdev daemon' running?`));
8882
9605
  }
8883
9606
  async function directCdpEval(expression, port = 9222) {
8884
9607
  const http3 = await import("http");
8885
- const targets = await new Promise((resolve5, reject) => {
9608
+ const targets = await new Promise((resolve6, reject) => {
8886
9609
  http3.get(`http://127.0.0.1:${port}/json`, (res) => {
8887
9610
  let data = "";
8888
9611
  res.on("data", (c) => data += c);
8889
9612
  res.on("end", () => {
8890
9613
  try {
8891
- resolve5(JSON.parse(data));
9614
+ resolve6(JSON.parse(data));
8892
9615
  } catch {
8893
9616
  reject(new Error("Invalid JSON"));
8894
9617
  }
@@ -8901,7 +9624,7 @@ async function directCdpEval(expression, port = 9222) {
8901
9624
  const target = (mainPages.length > 0 ? mainPages[0] : pages[0]) || targets[0];
8902
9625
  if (!target?.webSocketDebuggerUrl) throw new Error("No CDP target found");
8903
9626
  const WebSocket4 = (await import("ws")).default;
8904
- return new Promise((resolve5, reject) => {
9627
+ return new Promise((resolve6, reject) => {
8905
9628
  const ws = new WebSocket4(target.webSocketDebuggerUrl);
8906
9629
  const timeout = setTimeout(() => {
8907
9630
  ws.close();
@@ -8923,11 +9646,11 @@ async function directCdpEval(expression, port = 9222) {
8923
9646
  clearTimeout(timeout);
8924
9647
  ws.close();
8925
9648
  if (msg.result?.result?.value !== void 0) {
8926
- resolve5(msg.result.result.value);
9649
+ resolve6(msg.result.result.value);
8927
9650
  } else if (msg.result?.exceptionDetails) {
8928
9651
  reject(new Error(msg.result.exceptionDetails.text));
8929
9652
  } else {
8930
- resolve5(msg.result);
9653
+ resolve6(msg.result);
8931
9654
  }
8932
9655
  }
8933
9656
  });
@@ -8956,11 +9679,11 @@ provider.command("list").description("List all loaded providers").option("-j, --
8956
9679
  return;
8957
9680
  }
8958
9681
  console.log(import_chalk4.default.bold("\n\u{1F50C} ADHDev Providers\n"));
8959
- const categories = ["ide", "extension", "cli"];
9682
+ const categories = ["ide", "extension", "cli", "acp"];
8960
9683
  for (const cat of categories) {
8961
9684
  const catProviders = providers.filter((p) => p.category === cat);
8962
9685
  if (catProviders.length === 0) continue;
8963
- const icons = { ide: "\u{1F4BB}", extension: "\u{1F9E9}", cli: "\u2328\uFE0F " };
9686
+ const icons = { ide: "\u{1F4BB}", extension: "\u{1F9E9}", cli: "\u2328\uFE0F ", acp: "\u{1F50C}" };
8964
9687
  console.log(` ${icons[cat] || ""} ${import_chalk4.default.bold(cat.toUpperCase())} (${catProviders.length})`);
8965
9688
  for (const p of catProviders) {
8966
9689
  const scripts = p.scripts ? Object.keys(p.scripts).filter((k) => typeof p.scripts[k] === "function") : [];
@@ -8981,7 +9704,7 @@ provider.command("list").description("List all loaded providers").option("-j, --
8981
9704
  provider.command("reload").description("Hot-reload all providers (requires daemon --dev)").action(async () => {
8982
9705
  try {
8983
9706
  const http3 = await import("http");
8984
- const result = await new Promise((resolve5, reject) => {
9707
+ const result = await new Promise((resolve6, reject) => {
8985
9708
  const req = http3.request({
8986
9709
  hostname: "127.0.0.1",
8987
9710
  port: 19280,
@@ -8993,9 +9716,9 @@ provider.command("reload").description("Hot-reload all providers (requires daemo
8993
9716
  res.on("data", (c) => data += c);
8994
9717
  res.on("end", () => {
8995
9718
  try {
8996
- resolve5(JSON.parse(data));
9719
+ resolve6(JSON.parse(data));
8997
9720
  } catch {
8998
- resolve5({ raw: data });
9721
+ resolve6({ raw: data });
8999
9722
  }
9000
9723
  });
9001
9724
  });
@@ -9029,7 +9752,7 @@ provider.command("create <type>").description("Scaffold a new provider.js from t
9029
9752
  const category = options.category;
9030
9753
  const location = options.builtin ? "builtin" : "user";
9031
9754
  const http3 = await import("http");
9032
- const result = await new Promise((resolve5, reject) => {
9755
+ const result = await new Promise((resolve6, reject) => {
9033
9756
  const postData = JSON.stringify({ type, name, category, location });
9034
9757
  const req = http3.request({
9035
9758
  hostname: "127.0.0.1",
@@ -9042,9 +9765,9 @@ provider.command("create <type>").description("Scaffold a new provider.js from t
9042
9765
  res.on("data", (c) => data += c);
9043
9766
  res.on("end", () => {
9044
9767
  try {
9045
- resolve5(JSON.parse(data));
9768
+ resolve6(JSON.parse(data));
9046
9769
  } catch {
9047
- resolve5({ raw: data });
9770
+ resolve6({ raw: data });
9048
9771
  }
9049
9772
  });
9050
9773
  });
@@ -9126,7 +9849,7 @@ provider.command("run <type> <script>").description("Run a specific provider scr
9126
9849
  script,
9127
9850
  params: options.param ? { text: options.param, sessionId: options.param, buttonText: options.param } : {}
9128
9851
  });
9129
- const result = await new Promise((resolve5, reject) => {
9852
+ const result = await new Promise((resolve6, reject) => {
9130
9853
  const req = http3.request({
9131
9854
  hostname: "127.0.0.1",
9132
9855
  port: 19280,
@@ -9138,9 +9861,9 @@ provider.command("run <type> <script>").description("Run a specific provider scr
9138
9861
  res.on("data", (c) => data += c);
9139
9862
  res.on("end", () => {
9140
9863
  try {
9141
- resolve5(JSON.parse(data));
9864
+ resolve6(JSON.parse(data));
9142
9865
  } catch {
9143
- resolve5({ raw: data });
9866
+ resolve6({ raw: data });
9144
9867
  }
9145
9868
  });
9146
9869
  });
@@ -9176,15 +9899,15 @@ provider.command("run <type> <script>").description("Run a specific provider scr
9176
9899
  provider.command("source <type>").description("View source code of a provider").action(async (type) => {
9177
9900
  try {
9178
9901
  const http3 = await import("http");
9179
- const result = await new Promise((resolve5, reject) => {
9902
+ const result = await new Promise((resolve6, reject) => {
9180
9903
  http3.get(`http://127.0.0.1:19280/api/providers/${type}/source`, (res) => {
9181
9904
  let data = "";
9182
9905
  res.on("data", (c) => data += c);
9183
9906
  res.on("end", () => {
9184
9907
  try {
9185
- resolve5(JSON.parse(data));
9908
+ resolve6(JSON.parse(data));
9186
9909
  } catch {
9187
- resolve5({ raw: data });
9910
+ resolve6({ raw: data });
9188
9911
  }
9189
9912
  });
9190
9913
  }).on("error", () => {
@@ -9388,13 +10111,13 @@ cdp.command("eval <expression>").description("Execute JavaScript expression via
9388
10111
  cdp.command("screenshot").description("Capture IDE screenshot").option("-p, --port <port>", "CDP port", "9222").option("-o, --output <file>", "Output file path", "/tmp/cdp_screenshot.jpg").action(async (options) => {
9389
10112
  try {
9390
10113
  const http3 = await import("http");
9391
- const targets = await new Promise((resolve5, reject) => {
10114
+ const targets = await new Promise((resolve6, reject) => {
9392
10115
  http3.get(`http://127.0.0.1:${options.port}/json`, (res) => {
9393
10116
  let data = "";
9394
10117
  res.on("data", (c) => data += c);
9395
10118
  res.on("end", () => {
9396
10119
  try {
9397
- resolve5(JSON.parse(data));
10120
+ resolve6(JSON.parse(data));
9398
10121
  } catch {
9399
10122
  reject(new Error("Invalid JSON"));
9400
10123
  }
@@ -9408,7 +10131,7 @@ cdp.command("screenshot").description("Capture IDE screenshot").option("-p, --po
9408
10131
  if (!target?.webSocketDebuggerUrl) throw new Error("No CDP target");
9409
10132
  const WebSocket4 = (await import("ws")).default;
9410
10133
  const ws = new WebSocket4(target.webSocketDebuggerUrl);
9411
- await new Promise((resolve5, reject) => {
10134
+ await new Promise((resolve6, reject) => {
9412
10135
  ws.on("open", () => {
9413
10136
  ws.send(JSON.stringify({ id: 1, method: "Page.captureScreenshot", params: { format: "jpeg", quality: 50 } }));
9414
10137
  });
@@ -9421,7 +10144,7 @@ cdp.command("screenshot").description("Capture IDE screenshot").option("-p, --po
9421
10144
  \u2713 Screenshot saved to ${options.output}
9422
10145
  `));
9423
10146
  ws.close();
9424
- resolve5();
10147
+ resolve6();
9425
10148
  }
9426
10149
  });
9427
10150
  ws.on("error", (e) => reject(e));
@@ -9437,10 +10160,10 @@ if (process.argv.length <= 2) {
9437
10160
  program.outputHelp();
9438
10161
  console.log();
9439
10162
  console.log(import_chalk4.default.gray(" Quick start:"));
9440
- console.log(import_chalk4.default.gray(" adhdev setup \u2014 First-time setup"));
9441
- console.log(import_chalk4.default.gray(" adhdev daemon \u2014 Start unified daemon"));
9442
- console.log(import_chalk4.default.gray(" adhdev launch claude \u2014 Launch CLI agent"));
9443
- console.log(import_chalk4.default.gray(" adhdev launch cursor \u2014 Launch Cursor with CDP"));
10163
+ console.log(import_chalk4.default.gray(" adhdev daemon \u2014 Start unified daemon (Required)"));
10164
+ console.log(import_chalk4.default.gray(" adhdev launch cursor \u2014 Launch IDE with CDP (e.g. cursor, windsurf)"));
10165
+ console.log(import_chalk4.default.gray(" adhdev launch claude \u2014 Launch CLI agent (e.g. gemini, claude)"));
10166
+ console.log(import_chalk4.default.gray(" adhdev setup \u2014 First-time setup & configuration"));
9444
10167
  console.log(import_chalk4.default.gray(" adhdev status \u2014 Check current setup"));
9445
10168
  console.log();
9446
10169
  } else {