adhdev 0.1.46 → 0.1.48

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
  }
@@ -1529,12 +1578,54 @@ var init_daemon_cdp = __esm({
1529
1578
  agentSessions = /* @__PURE__ */ new Map();
1530
1579
  logFn;
1531
1580
  extensionProviders = [];
1532
- constructor(port = 9333, logFn) {
1581
+ _lastDiscoverSig = "";
1582
+ _targetId = null;
1583
+ // 특정 targetId로 연결 (multi-window 지원)
1584
+ _pageTitle = "";
1585
+ // 연결된 페이지 제목
1586
+ constructor(port = 9333, logFn, targetId) {
1533
1587
  this.port = port;
1588
+ this._targetId = targetId || null;
1534
1589
  this.logFn = logFn || ((msg) => {
1535
1590
  console.log(msg);
1536
1591
  });
1537
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
+ }
1538
1629
  setPort(port) {
1539
1630
  this.port = port;
1540
1631
  this.log(`[CDP] Port changed to ${port}`);
@@ -1571,7 +1662,7 @@ var init_daemon_cdp = __esm({
1571
1662
  }
1572
1663
  }
1573
1664
  findTargetOnPort(port) {
1574
- return new Promise((resolve5) => {
1665
+ return new Promise((resolve6) => {
1575
1666
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
1576
1667
  let data = "";
1577
1668
  res.on("data", (chunk) => data += chunk.toString());
@@ -1582,23 +1673,35 @@ var init_daemon_cdp = __esm({
1582
1673
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
1583
1674
  );
1584
1675
  if (pages.length === 0) {
1585
- resolve5(targets.find((t) => t.webSocketDebuggerUrl) || null);
1676
+ resolve6(targets.find((t) => t.webSocketDebuggerUrl) || null);
1586
1677
  return;
1587
1678
  }
1588
1679
  const isNonMain = (title) => !title || /extension-output|ADHDev CDP|Debug Console|Output\s*$|Launchpad/i.test(title);
1589
1680
  const mainPages = pages.filter((t) => !isNonMain(t.title || ""));
1590
1681
  const list = mainPages.length > 0 ? mainPages : pages;
1591
1682
  this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
1592
- 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]);
1593
1696
  } catch {
1594
- resolve5(null);
1697
+ resolve6(null);
1595
1698
  }
1596
1699
  });
1597
1700
  });
1598
- req.on("error", () => resolve5(null));
1701
+ req.on("error", () => resolve6(null));
1599
1702
  req.setTimeout(2e3, () => {
1600
1703
  req.destroy();
1601
- resolve5(null);
1704
+ resolve6(null);
1602
1705
  });
1603
1706
  });
1604
1707
  }
@@ -1609,7 +1712,7 @@ var init_daemon_cdp = __esm({
1609
1712
  this.extensionProviders = providers;
1610
1713
  }
1611
1714
  connectToTarget(wsUrl) {
1612
- return new Promise((resolve5) => {
1715
+ return new Promise((resolve6) => {
1613
1716
  this.ws = new import_ws3.default(wsUrl);
1614
1717
  this.ws.on("open", async () => {
1615
1718
  this._connected = true;
@@ -1619,17 +1722,17 @@ var init_daemon_cdp = __esm({
1619
1722
  }
1620
1723
  this.connectBrowserWs().catch(() => {
1621
1724
  });
1622
- resolve5(true);
1725
+ resolve6(true);
1623
1726
  });
1624
1727
  this.ws.on("message", (data) => {
1625
1728
  try {
1626
1729
  const msg = JSON.parse(data.toString());
1627
1730
  if (msg.id && this.pending.has(msg.id)) {
1628
- const { resolve: resolve6, reject } = this.pending.get(msg.id);
1731
+ const { resolve: resolve7, reject } = this.pending.get(msg.id);
1629
1732
  this.pending.delete(msg.id);
1630
1733
  this.failureCount = 0;
1631
1734
  if (msg.error) reject(new Error(msg.error.message));
1632
- else resolve6(msg.result);
1735
+ else resolve7(msg.result);
1633
1736
  } else if (msg.method === "Runtime.executionContextCreated") {
1634
1737
  this.contexts.add(msg.params.context.id);
1635
1738
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -1652,7 +1755,7 @@ var init_daemon_cdp = __esm({
1652
1755
  this.ws.on("error", (err) => {
1653
1756
  this.log(`[CDP] WebSocket error: ${err.message}`);
1654
1757
  this._connected = false;
1655
- resolve5(false);
1758
+ resolve6(false);
1656
1759
  });
1657
1760
  });
1658
1761
  }
@@ -1666,7 +1769,7 @@ var init_daemon_cdp = __esm({
1666
1769
  return;
1667
1770
  }
1668
1771
  this.log(`[CDP] Connecting browser WS for target discovery...`);
1669
- await new Promise((resolve5, reject) => {
1772
+ await new Promise((resolve6, reject) => {
1670
1773
  this.browserWs = new import_ws3.default(browserWsUrl);
1671
1774
  this.browserWs.on("open", async () => {
1672
1775
  this._browserConnected = true;
@@ -1676,16 +1779,16 @@ var init_daemon_cdp = __esm({
1676
1779
  } catch (e) {
1677
1780
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
1678
1781
  }
1679
- resolve5();
1782
+ resolve6();
1680
1783
  });
1681
1784
  this.browserWs.on("message", (data) => {
1682
1785
  try {
1683
1786
  const msg = JSON.parse(data.toString());
1684
1787
  if (msg.id && this.browserPending.has(msg.id)) {
1685
- const { resolve: resolve6, reject: reject2 } = this.browserPending.get(msg.id);
1788
+ const { resolve: resolve7, reject: reject2 } = this.browserPending.get(msg.id);
1686
1789
  this.browserPending.delete(msg.id);
1687
1790
  if (msg.error) reject2(new Error(msg.error.message));
1688
- else resolve6(msg.result);
1791
+ else resolve7(msg.result);
1689
1792
  }
1690
1793
  } catch {
1691
1794
  }
@@ -1705,31 +1808,31 @@ var init_daemon_cdp = __esm({
1705
1808
  }
1706
1809
  }
1707
1810
  getBrowserWsUrl() {
1708
- return new Promise((resolve5) => {
1811
+ return new Promise((resolve6) => {
1709
1812
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
1710
1813
  let data = "";
1711
1814
  res.on("data", (chunk) => data += chunk.toString());
1712
1815
  res.on("end", () => {
1713
1816
  try {
1714
1817
  const info = JSON.parse(data);
1715
- resolve5(info.webSocketDebuggerUrl || null);
1818
+ resolve6(info.webSocketDebuggerUrl || null);
1716
1819
  } catch {
1717
- resolve5(null);
1820
+ resolve6(null);
1718
1821
  }
1719
1822
  });
1720
1823
  });
1721
- req.on("error", () => resolve5(null));
1824
+ req.on("error", () => resolve6(null));
1722
1825
  req.setTimeout(3e3, () => {
1723
1826
  req.destroy();
1724
- resolve5(null);
1827
+ resolve6(null);
1725
1828
  });
1726
1829
  });
1727
1830
  }
1728
1831
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
1729
- return new Promise((resolve5, reject) => {
1832
+ return new Promise((resolve6, reject) => {
1730
1833
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
1731
1834
  const id = this.browserMsgId++;
1732
- this.browserPending.set(id, { resolve: resolve5, reject });
1835
+ this.browserPending.set(id, { resolve: resolve6, reject });
1733
1836
  this.browserWs.send(JSON.stringify({ id, method, params }));
1734
1837
  setTimeout(() => {
1735
1838
  if (this.browserPending.has(id)) {
@@ -1769,11 +1872,11 @@ var init_daemon_cdp = __esm({
1769
1872
  }
1770
1873
  // ─── CDP Protocol ────────────────────────────────────────
1771
1874
  sendInternal(method, params = {}, timeoutMs = 15e3) {
1772
- return new Promise((resolve5, reject) => {
1875
+ return new Promise((resolve6, reject) => {
1773
1876
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
1774
1877
  if (this.ws.readyState !== import_ws3.default.OPEN) return reject(new Error("WebSocket not open"));
1775
1878
  const id = this.msgId++;
1776
- this.pending.set(id, { resolve: resolve5, reject });
1879
+ this.pending.set(id, { resolve: resolve6, reject });
1777
1880
  this.ws.send(JSON.stringify({ id, method, params }));
1778
1881
  setTimeout(() => {
1779
1882
  if (this.pending.has(id)) {
@@ -1910,13 +2013,17 @@ var init_daemon_cdp = __esm({
1910
2013
  typeMap.set(t.type, (typeMap.get(t.type) || 0) + 1);
1911
2014
  }
1912
2015
  const typeSummary = [...typeMap.entries()].map(([k, v]) => `${k}:${v}`).join(",");
1913
- this.log(`[CDP] discoverAgentWebviews: ${allTargets.length} total [${typeSummary}], ${iframes.length} iframes (browser=${this._browserConnected})`);
1914
- for (const t of allTargets) {
1915
- if (t.type !== "page" && t.type !== "worker" && t.type !== "service_worker") {
1916
- this.log(`[CDP] target: type=${t.type} url=${(t.url || "").substring(0, 120)}`);
1917
- }
1918
- if ((t.url || "").includes("vscode-webview")) {
1919
- this.log(`[CDP] webview: type=${t.type} url=${(t.url || "").substring(0, 150)}`);
2016
+ const sig = `${allTargets.length}:${iframes.length}:${typeSummary}`;
2017
+ if (sig !== this._lastDiscoverSig) {
2018
+ this._lastDiscoverSig = sig;
2019
+ this.log(`[CDP] discoverAgentWebviews: ${allTargets.length} total [${typeSummary}], ${iframes.length} iframes (browser=${this._browserConnected})`);
2020
+ for (const t of allTargets) {
2021
+ if (t.type !== "page" && t.type !== "worker" && t.type !== "service_worker") {
2022
+ this.log(`[CDP] target: type=${t.type} url=${(t.url || "").substring(0, 120)}`);
2023
+ }
2024
+ if ((t.url || "").includes("vscode-webview")) {
2025
+ this.log(`[CDP] webview: type=${t.type} url=${(t.url || "").substring(0, 150)}`);
2026
+ }
1920
2027
  }
1921
2028
  }
1922
2029
  const agents = [];
@@ -1973,14 +2080,14 @@ var init_daemon_cdp = __esm({
1973
2080
  if (!ws || ws.readyState !== import_ws3.default.OPEN) {
1974
2081
  throw new Error("CDP not connected");
1975
2082
  }
1976
- return new Promise((resolve5, reject) => {
2083
+ return new Promise((resolve6, reject) => {
1977
2084
  const id = getNextId();
1978
2085
  pendingMap.set(id, {
1979
2086
  resolve: (result) => {
1980
2087
  if (result?.result?.subtype === "error") {
1981
2088
  reject(new Error(result.result.description));
1982
2089
  } else {
1983
- resolve5(result?.result?.value);
2090
+ resolve6(result?.result?.value);
1984
2091
  }
1985
2092
  },
1986
2093
  reject
@@ -2457,13 +2564,13 @@ var init_daemon_p2p = __esm({
2457
2564
  } catch {
2458
2565
  }
2459
2566
  const http3 = require("https");
2460
- const data = await new Promise((resolve5, reject) => {
2567
+ const data = await new Promise((resolve6, reject) => {
2461
2568
  const req = http3.get(`${serverUrl}/api/v1/turn/credentials`, {
2462
2569
  headers: { "Authorization": `Bearer ${token}` }
2463
2570
  }, (res) => {
2464
2571
  let d = "";
2465
2572
  res.on("data", (c) => d += c);
2466
- res.on("end", () => resolve5(d));
2573
+ res.on("end", () => resolve6(d));
2467
2574
  });
2468
2575
  req.on("error", reject);
2469
2576
  req.setTimeout(5e3, () => {
@@ -2613,7 +2720,9 @@ var init_daemon_p2p = __esm({
2613
2720
  const text = typeof msg === "string" ? msg : msg.toString("utf-8");
2614
2721
  try {
2615
2722
  const parsed = JSON.parse(text);
2616
- log(`Files message from peer ${peerId}: type=${parsed.type}`);
2723
+ if (parsed.type !== "command" && parsed.type !== "pty_input" && parsed.type !== "pty_resize") {
2724
+ log(`Files message from peer ${peerId}: type=${parsed.type}`);
2725
+ }
2617
2726
  if (parsed.type === "screenshot_start") {
2618
2727
  const peer = this.peers.get(peerId);
2619
2728
  if (peer) {
@@ -2834,7 +2943,11 @@ var init_daemon_p2p = __esm({
2834
2943
  return;
2835
2944
  }
2836
2945
  if (type === "p2p_answer") {
2837
- 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);
2838
2951
  if (peer?.pc) {
2839
2952
  log(`Received SDP answer for peer ${peer.peerId}`);
2840
2953
  peer.pc.setRemoteDescription(payload.sdp, payload.type);
@@ -2842,16 +2955,18 @@ var init_daemon_p2p = __esm({
2842
2955
  return;
2843
2956
  }
2844
2957
  if (type === "p2p_ice") {
2845
- 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);
2846
2963
  if (peer?.pc && payload.candidate) {
2847
2964
  peer.pc.addRemoteCandidate(payload.candidate, payload.mid || payload.sdpMid || "0");
2848
2965
  }
2849
2966
  return;
2850
2967
  }
2851
2968
  }
2852
- getFirstPeer() {
2853
- return this.peers.values().next().value;
2854
- }
2969
+ // getFirstPeer removed — multi-peer requires explicit peerId routing
2855
2970
  // ─── 연결 관리 ──────────────────────────────
2856
2971
  disconnectPeer(peerId) {
2857
2972
  const peer = this.peers.get(peerId);
@@ -3136,15 +3251,15 @@ var init_dev_server = __esm({
3136
3251
  this.json(res, 500, { error: e.message });
3137
3252
  }
3138
3253
  });
3139
- return new Promise((resolve5, reject) => {
3254
+ return new Promise((resolve6, reject) => {
3140
3255
  this.server.listen(port, "127.0.0.1", () => {
3141
3256
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
3142
- resolve5();
3257
+ resolve6();
3143
3258
  });
3144
3259
  this.server.on("error", (e) => {
3145
3260
  if (e.code === "EADDRINUSE") {
3146
3261
  this.log(`Port ${port} in use, skipping dev server`);
3147
- resolve5();
3262
+ resolve6();
3148
3263
  } else {
3149
3264
  reject(e);
3150
3265
  }
@@ -3811,14 +3926,14 @@ var init_dev_server = __esm({
3811
3926
  res.end(JSON.stringify(data, null, 2));
3812
3927
  }
3813
3928
  async readBody(req) {
3814
- return new Promise((resolve5) => {
3929
+ return new Promise((resolve6) => {
3815
3930
  let body = "";
3816
3931
  req.on("data", (chunk) => body += chunk);
3817
3932
  req.on("end", () => {
3818
3933
  try {
3819
- resolve5(JSON.parse(body));
3934
+ resolve6(JSON.parse(body));
3820
3935
  } catch {
3821
- resolve5({});
3936
+ resolve6({});
3822
3937
  }
3823
3938
  });
3824
3939
  });
@@ -4153,12 +4268,10 @@ var init_daemon_commands = __esm({
4153
4268
  getCdp(ideType) {
4154
4269
  const key = ideType || this._currentIdeType;
4155
4270
  if (!key) {
4156
- console.log(`[getCdp] \u26A0 No ideType specified, cannot resolve CDP`);
4157
4271
  return null;
4158
4272
  }
4159
4273
  const m = this.ctx.cdpManagers.get(key.toLowerCase());
4160
4274
  if (m?.isConnected) return m;
4161
- console.log(`[getCdp] \u26A0 Target IDE "${key}" CDP not available`);
4162
4275
  return null;
4163
4276
  }
4164
4277
  /** Current IDE type extracted from command args (per-request) */
@@ -4193,7 +4306,11 @@ var init_daemon_commands = __esm({
4193
4306
  getProvider(overrideType) {
4194
4307
  const key = overrideType || this._currentProviderType || this._currentIdeType;
4195
4308
  if (!key || !this.ctx.providerLoader) return void 0;
4196
- 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;
4197
4314
  }
4198
4315
  /** Get a provider script by name from ProviderLoader.
4199
4316
  * Returns the script string or null. */
@@ -4264,7 +4381,12 @@ var init_daemon_commands = __esm({
4264
4381
  async handle(cmd, args) {
4265
4382
  this._currentIdeType = this.extractIdeType(args);
4266
4383
  this._currentProviderType = args?.agentType || args?.providerType || this._currentIdeType;
4267
- console.log(`[Cmd] ${cmd} \u2192 ideType=${this._currentIdeType || "none"} providerType=${this._currentProviderType || "none"}`);
4384
+ if (!this._currentIdeType && !this._currentProviderType) {
4385
+ const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "resolve_action"];
4386
+ if (cdpCommands.includes(cmd)) {
4387
+ return { success: false, error: "No ideType specified \u2014 cannot route command" };
4388
+ }
4389
+ }
4268
4390
  switch (cmd) {
4269
4391
  // ─── CDP 직접 처리 ───────────────────
4270
4392
  case "read_chat":
@@ -4366,6 +4488,20 @@ var init_daemon_commands = __esm({
4366
4488
  return this.handleGetProviderSettings(args);
4367
4489
  case "set_provider_setting":
4368
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");
4369
4505
  default:
4370
4506
  return { success: false, error: `Unknown command: ${cmd}` };
4371
4507
  }
@@ -4676,6 +4812,7 @@ var init_daemon_commands = __esm({
4676
4812
  const provider2 = this.getProvider();
4677
4813
  const action = args?.action || "approve";
4678
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}`);
4679
4816
  if (provider2?.category === "extension" && this.agentStream && this.getCdp()) {
4680
4817
  const ok = await this.agentStream.resolveAgentAction(
4681
4818
  this.getCdp(),
@@ -4685,14 +4822,50 @@ var init_daemon_commands = __esm({
4685
4822
  );
4686
4823
  return { success: ok };
4687
4824
  }
4688
- try {
4689
- const evalResult = await this.evaluateProviderScript("resolveAction", {
4690
- ACTION: action,
4691
- BUTTON: button
4692
- });
4693
- if (evalResult) return { success: true };
4694
- } catch (e) {
4695
- 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
+ }
4696
4869
  }
4697
4870
  return { success: false, error: "resolveAction script not available for this provider" };
4698
4871
  }
@@ -5087,6 +5260,103 @@ var init_daemon_commands = __esm({
5087
5260
  }
5088
5261
  return { success: false, error: `Failed to set ${providerType}.${key} \u2014 invalid key, value, or not a public setting` };
5089
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
+ }
5090
5360
  };
5091
5361
  }
5092
5362
  });
@@ -5229,12 +5499,12 @@ var init_manager = __esm({
5229
5499
  constructor(logFn, providerLoader) {
5230
5500
  this.logFn = logFn || console.log;
5231
5501
  if (providerLoader) {
5232
- const extensionProviders = providerLoader.getByCategory("extension");
5233
- this.allAdapters = extensionProviders.map((p) => {
5502
+ const allExtProviders = providerLoader.getByCategory("extension");
5503
+ for (const p of allExtProviders) {
5234
5504
  const adapter = new ProviderStreamAdapter(p);
5505
+ this.allAdapters.push(adapter);
5235
5506
  this.logFn(`[AgentStream] Adapter created: ${p.type} (${p.name})`);
5236
- return adapter;
5237
- });
5507
+ }
5238
5508
  }
5239
5509
  }
5240
5510
  setLocalServer(server) {
@@ -5488,14 +5758,238 @@ var init_agent_stream = __esm({
5488
5758
  }
5489
5759
  });
5490
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
+
5491
5984
  // src/daemon-status.ts
5492
- var os6, path6, DaemonStatusReporter;
5985
+ var os7, path7, DaemonStatusReporter;
5493
5986
  var init_daemon_status = __esm({
5494
5987
  "src/daemon-status.ts"() {
5495
5988
  "use strict";
5496
- os6 = __toESM(require("os"));
5497
- path6 = __toESM(require("path"));
5989
+ os7 = __toESM(require("os"));
5990
+ path7 = __toESM(require("path"));
5498
5991
  init_config();
5992
+ init_daemon_logger();
5499
5993
  DaemonStatusReporter = class {
5500
5994
  deps;
5501
5995
  log;
@@ -5553,7 +6047,7 @@ var init_daemon_status = __esm({
5553
6047
  }
5554
6048
  }
5555
6049
  emitStatusEvent(event) {
5556
- this.log(`[${this.ts()}] [StatusEvent\u2192Server] ${event.event} (${event.providerType || event.ideType || ""})`);
6050
+ LOG.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
5557
6051
  this.deps.bridge?.sendMessage("status_event", event);
5558
6052
  }
5559
6053
  removeAgentTracking(_key) {
@@ -5580,7 +6074,8 @@ var init_daemon_status = __esm({
5580
6074
  return `${s.type}(${s.status},${msgs}msg,${exts}ext${s.currentModel ? ",model=" + s.currentModel : ""})`;
5581
6075
  }).join(", ");
5582
6076
  const cliSummary = cliStates.map((s) => `${s.type}(${s.status})`).join(", ");
5583
- this.log(`[${this.ts()}] [StatusReport\u2192${target}] IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}]`);
6077
+ const logLevel = opts?.p2pOnly ? "debug" : "info";
6078
+ LOG[logLevel]("StatusReport", `\u2192${target} IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}]`);
5584
6079
  const managedIdes = ideStates.map((s) => ({
5585
6080
  ideType: s.type,
5586
6081
  ideVersion: "",
@@ -5606,23 +6101,45 @@ var init_daemon_status = __esm({
5606
6101
  currentAutoApprove: s.currentAutoApprove
5607
6102
  }));
5608
6103
  const instanceIdeTypes = new Set(ideStates.map((s) => s.type));
6104
+ const instanceBaseTypes = /* @__PURE__ */ new Set();
6105
+ for (const t of instanceIdeTypes) {
6106
+ instanceBaseTypes.add(t);
6107
+ const base = t.split("_")[0];
6108
+ if (base) instanceBaseTypes.add(base);
6109
+ }
5609
6110
  const perExtData = localServer?.getPerExtensionData() || [];
5610
6111
  for (const ext of perExtData) {
5611
6112
  const ideKey = ext.ideType.toLowerCase();
5612
- if (instanceIdeTypes.has(ideKey)) continue;
5613
- managedIdes.push({
5614
- ideType: ext.ideType,
5615
- ideVersion: ext.ideVersion,
5616
- instanceId: ext.instanceId,
5617
- workspaceFolders: ext.workspaceFolders,
5618
- activeFile: ext.activeFile,
5619
- terminals: ext.terminals,
5620
- aiAgents: ext.aiAgents,
5621
- activeChat: ext.activeChat,
5622
- chats: ext.chats || [],
5623
- agentStreams: ext.agentStreams || [],
5624
- cdpConnected: false
5625
- });
6113
+ if (instanceBaseTypes.has(ideKey)) {
6114
+ const match = managedIdes.find(
6115
+ (m) => m.ideType === ideKey || m.ideType.split("_")[0] === ideKey
6116
+ );
6117
+ if (match) {
6118
+ if (!match.workspaceFolders?.length && ext.workspaceFolders?.length) {
6119
+ match.workspaceFolders = ext.workspaceFolders;
6120
+ }
6121
+ if (!match.activeFile && ext.activeFile) match.activeFile = ext.activeFile;
6122
+ if (!match.terminals && ext.terminals) match.terminals = ext.terminals;
6123
+ if ((!match.aiAgents || match.aiAgents.length === 0) && ext.aiAgents?.length) {
6124
+ match.aiAgents = ext.aiAgents;
6125
+ }
6126
+ if (!match.ideVersion && ext.ideVersion) match.ideVersion = ext.ideVersion;
6127
+ }
6128
+ } else {
6129
+ managedIdes.push({
6130
+ ideType: ext.ideType,
6131
+ ideVersion: ext.ideVersion,
6132
+ instanceId: ext.instanceId,
6133
+ workspaceFolders: ext.workspaceFolders,
6134
+ activeFile: ext.activeFile,
6135
+ terminals: ext.terminals,
6136
+ aiAgents: ext.aiAgents,
6137
+ activeChat: ext.activeChat,
6138
+ chats: ext.chats || [],
6139
+ agentStreams: ext.agentStreams || [],
6140
+ cdpConnected: false
6141
+ });
6142
+ }
5626
6143
  }
5627
6144
  const managedClis = cliStates.map((s) => ({
5628
6145
  id: s.instanceId,
@@ -5644,15 +6161,15 @@ var init_daemon_status = __esm({
5644
6161
  daemonMode: true,
5645
6162
  machineNickname: loadConfig().machineNickname || null,
5646
6163
  machine: {
5647
- hostname: os6.hostname(),
5648
- platform: os6.platform(),
5649
- release: os6.release(),
5650
- arch: os6.arch(),
5651
- cpus: os6.cpus().length,
5652
- totalMem: os6.totalmem(),
5653
- freeMem: os6.freemem(),
5654
- loadavg: os6.loadavg(),
5655
- uptime: os6.uptime()
6164
+ hostname: os7.hostname(),
6165
+ platform: os7.platform(),
6166
+ release: os7.release(),
6167
+ arch: os7.arch(),
6168
+ cpus: os7.cpus().length,
6169
+ totalMem: os7.totalmem(),
6170
+ freeMem: os7.freemem(),
6171
+ loadavg: os7.loadavg(),
6172
+ uptime: os7.uptime()
5656
6173
  },
5657
6174
  managedIdes,
5658
6175
  managedClis,
@@ -5674,7 +6191,7 @@ var init_daemon_status = __esm({
5674
6191
  })),
5675
6192
  timestamp: now,
5676
6193
  activeFile: extSummary.activeFile,
5677
- workspaceFolders: extSummary.workspaceFolders?.length > 0 ? extSummary.workspaceFolders : Array.from(adapters.values()).map((a) => ({ name: path6.basename(a.workingDir), path: a.workingDir })),
6194
+ workspaceFolders: extSummary.workspaceFolders?.length > 0 ? extSummary.workspaceFolders : Array.from(adapters.values()).map((a) => ({ name: path7.basename(a.workingDir), path: a.workingDir })),
5678
6195
  terminals: extSummary.terminals,
5679
6196
  aiAgents: [
5680
6197
  ...managedIdes.flatMap((ide) => (ide.aiAgents || []).map((a) => ({
@@ -5682,17 +6199,17 @@ var init_daemon_status = __esm({
5682
6199
  name: a.name,
5683
6200
  status: a.status,
5684
6201
  ideType: ide.ideType
5685
- }))),
5686
- ...managedClis.map((c) => ({ id: c.cliType, name: c.cliName, status: c.status }))
6202
+ })))
6203
+ // CLIs are already in managedClis don't duplicate here
5687
6204
  ],
5688
6205
  activeChat: managedClis[0]?.activeChat || managedIdes[0]?.activeChat || null,
5689
6206
  agentStreams: managedIdes.flatMap((ide) => ide.agentStreams || []),
5690
6207
  connectedExtensions: extSummary.connectedIdes,
5691
- system: { platform: os6.platform(), hostname: os6.hostname() }
6208
+ system: { platform: os7.platform(), hostname: os7.hostname() }
5692
6209
  };
5693
6210
  const p2pSent = this.sendP2PPayload(payload);
5694
6211
  if (p2pSent) {
5695
- this.log(`[${this.ts()}] [P2P] sent (${JSON.stringify(payload).length} bytes)`);
6212
+ LOG.debug("P2P", `sent (${JSON.stringify(payload).length} bytes)`);
5696
6213
  }
5697
6214
  if (opts?.p2pOnly) return;
5698
6215
  const plan = bridge.getUserPlan();
@@ -5701,11 +6218,11 @@ var init_daemon_status = __esm({
5701
6218
  daemonMode: true,
5702
6219
  machineNickname: payload.machineNickname,
5703
6220
  machine: {
5704
- hostname: os6.hostname(),
5705
- platform: os6.platform(),
5706
- arch: os6.arch(),
5707
- cpus: os6.cpus().length,
5708
- totalMem: os6.totalmem()
6221
+ hostname: os7.hostname(),
6222
+ platform: os7.platform(),
6223
+ arch: os7.arch(),
6224
+ cpus: os7.cpus().length,
6225
+ totalMem: os7.totalmem()
5709
6226
  },
5710
6227
  managedIdes: managedIdes.map((ide) => ({
5711
6228
  ideType: ide.ideType,
@@ -5729,7 +6246,7 @@ var init_daemon_status = __esm({
5729
6246
  timestamp: now
5730
6247
  };
5731
6248
  bridge.sendMessage("status_report", wsPayload);
5732
- this.log(`[${this.ts()}] [Server] sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
6249
+ LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)`);
5733
6250
  }
5734
6251
  }
5735
6252
  // ─── P2P ─────────────────────────────────────────
@@ -5764,7 +6281,7 @@ function stripAnsi(str) {
5764
6281
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "");
5765
6282
  }
5766
6283
  function findBinary(name) {
5767
- const isWin = os7.platform() === "win32";
6284
+ const isWin = os8.platform() === "win32";
5768
6285
  try {
5769
6286
  const cmd = isWin ? `where ${name}` : `which ${name}`;
5770
6287
  return (0, import_child_process4.execSync)(cmd, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0].trim();
@@ -5772,11 +6289,11 @@ function findBinary(name) {
5772
6289
  return isWin ? `${name}.cmd` : name;
5773
6290
  }
5774
6291
  }
5775
- var os7, import_child_process4, pty, ProviderCliAdapter;
6292
+ var os8, import_child_process4, pty, ProviderCliAdapter;
5776
6293
  var init_provider_cli_adapter = __esm({
5777
6294
  "src/cli-adapters/provider-cli-adapter.ts"() {
5778
6295
  "use strict";
5779
- os7 = __toESM(require("os"));
6296
+ os8 = __toESM(require("os"));
5780
6297
  import_child_process4 = require("child_process");
5781
6298
  try {
5782
6299
  pty = require("node-pty");
@@ -5789,7 +6306,7 @@ var init_provider_cli_adapter = __esm({
5789
6306
  this.provider = provider2;
5790
6307
  this.cliType = provider2.type;
5791
6308
  this.cliName = provider2.name;
5792
- this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os7.homedir()) : workingDir;
6309
+ this.workingDir = workingDir.startsWith("~") ? workingDir.replace(/^~/, os8.homedir()) : workingDir;
5793
6310
  const t = provider2.timeouts || {};
5794
6311
  this.timeouts = {
5795
6312
  ptyFlush: t.ptyFlush ?? 50,
@@ -5847,7 +6364,7 @@ var init_provider_cli_adapter = __esm({
5847
6364
  if (!pty) throw new Error("node-pty is not installed");
5848
6365
  const { spawn: spawnConfig } = this.provider;
5849
6366
  const binaryPath = findBinary(spawnConfig.command);
5850
- const isWin = os7.platform() === "win32";
6367
+ const isWin = os8.platform() === "win32";
5851
6368
  const allArgs = [...spawnConfig.args, ...this.extraArgs];
5852
6369
  console.log(`[${this.cliType}] Spawning in ${this.workingDir}`);
5853
6370
  let shellCmd;
@@ -6089,7 +6606,7 @@ var init_provider_cli_adapter = __esm({
6089
6606
 
6090
6607
  // src/cli-detector.ts
6091
6608
  async function detectCLIs() {
6092
- const platform7 = os8.platform();
6609
+ const platform7 = os9.platform();
6093
6610
  const whichCmd = platform7 === "win32" ? "where" : "which";
6094
6611
  const results = [];
6095
6612
  for (const cli of KNOWN_CLIS) {
@@ -6123,12 +6640,12 @@ async function detectCLI(cliId) {
6123
6640
  const all = await detectCLIs();
6124
6641
  return all.find((c) => c.id === normalizedId && c.installed) || null;
6125
6642
  }
6126
- var import_child_process5, os8, KNOWN_CLIS;
6643
+ var import_child_process5, os9, KNOWN_CLIS;
6127
6644
  var init_cli_detector = __esm({
6128
6645
  "src/cli-detector.ts"() {
6129
6646
  "use strict";
6130
6647
  import_child_process5 = require("child_process");
6131
- os8 = __toESM(require("os"));
6648
+ os9 = __toESM(require("os"));
6132
6649
  KNOWN_CLIS = [
6133
6650
  { id: "gemini-cli", displayName: "Gemini CLI", icon: "\u264A", command: "gemini" },
6134
6651
  { id: "claude-code", displayName: "Claude Code", icon: "\u{1F916}", command: "claude" },
@@ -6137,17 +6654,267 @@ var init_cli_detector = __esm({
6137
6654
  }
6138
6655
  });
6139
6656
 
6657
+ // src/providers/status-monitor.ts
6658
+ var DEFAULT_MONITOR_CONFIG, StatusMonitor;
6659
+ var init_status_monitor = __esm({
6660
+ "src/providers/status-monitor.ts"() {
6661
+ "use strict";
6662
+ DEFAULT_MONITOR_CONFIG = {
6663
+ approvalAlert: true,
6664
+ longGeneratingAlert: true,
6665
+ longGeneratingThresholdSec: 180,
6666
+ // 3분
6667
+ alertCooldownSec: 60
6668
+ // 1분 쿨다운
6669
+ };
6670
+ StatusMonitor = class {
6671
+ config;
6672
+ lastAlertTime = /* @__PURE__ */ new Map();
6673
+ generatingStartTimes = /* @__PURE__ */ new Map();
6674
+ constructor(config) {
6675
+ this.config = { ...DEFAULT_MONITOR_CONFIG, ...config };
6676
+ }
6677
+ /** 설정 업데이트 (Provider Settings에서 호출) */
6678
+ updateConfig(partial) {
6679
+ Object.assign(this.config, partial);
6680
+ }
6681
+ /** 현재 설정 반환 */
6682
+ getConfig() {
6683
+ return { ...this.config };
6684
+ }
6685
+ /**
6686
+ * 상태 전이 체크 → 알림 이벤트 배열 반환
6687
+ * 각 onTick()에서 호출.
6688
+ */
6689
+ check(agentKey, status, now) {
6690
+ const events = [];
6691
+ if (this.config.approvalAlert && status === "waiting_approval") {
6692
+ if (this.shouldAlert(agentKey + ":approval", now)) {
6693
+ events.push({
6694
+ type: "monitor:approval_waiting",
6695
+ agentKey,
6696
+ timestamp: now,
6697
+ message: `${agentKey} is waiting for approval`
6698
+ });
6699
+ }
6700
+ }
6701
+ if (status === "generating" || status === "streaming") {
6702
+ if (!this.generatingStartTimes.has(agentKey)) {
6703
+ this.generatingStartTimes.set(agentKey, now);
6704
+ }
6705
+ if (this.config.longGeneratingAlert) {
6706
+ const startedAt = this.generatingStartTimes.get(agentKey);
6707
+ const elapsedSec = Math.round((now - startedAt) / 1e3);
6708
+ if (elapsedSec > this.config.longGeneratingThresholdSec) {
6709
+ if (this.shouldAlert(agentKey + ":long_gen", now)) {
6710
+ events.push({
6711
+ type: "monitor:long_generating",
6712
+ agentKey,
6713
+ elapsedSec,
6714
+ timestamp: now,
6715
+ message: `${agentKey} has been generating for ${Math.round(elapsedSec / 60)}min`
6716
+ });
6717
+ }
6718
+ }
6719
+ }
6720
+ } else {
6721
+ this.generatingStartTimes.delete(agentKey);
6722
+ }
6723
+ return events;
6724
+ }
6725
+ /** 쿨다운 체크 — 같은 알림을 너무 자주 보내지 않도록 */
6726
+ shouldAlert(key, now) {
6727
+ const last = this.lastAlertTime.get(key) || 0;
6728
+ if (now - last > this.config.alertCooldownSec * 1e3) {
6729
+ this.lastAlertTime.set(key, now);
6730
+ return true;
6731
+ }
6732
+ return false;
6733
+ }
6734
+ /** 리셋 (에이전트 종료/재시작 시) */
6735
+ reset(agentKey) {
6736
+ if (agentKey) {
6737
+ this.generatingStartTimes.delete(agentKey);
6738
+ for (const k of this.lastAlertTime.keys()) {
6739
+ if (k.startsWith(agentKey)) this.lastAlertTime.delete(k);
6740
+ }
6741
+ } else {
6742
+ this.generatingStartTimes.clear();
6743
+ this.lastAlertTime.clear();
6744
+ }
6745
+ }
6746
+ };
6747
+ }
6748
+ });
6749
+
6750
+ // src/providers/cli-provider-instance.ts
6751
+ var path8, CliProviderInstance;
6752
+ var init_cli_provider_instance = __esm({
6753
+ "src/providers/cli-provider-instance.ts"() {
6754
+ "use strict";
6755
+ path8 = __toESM(require("path"));
6756
+ init_provider_cli_adapter();
6757
+ init_status_monitor();
6758
+ CliProviderInstance = class {
6759
+ constructor(provider2, workingDir, cliArgs = []) {
6760
+ this.provider = provider2;
6761
+ this.workingDir = workingDir;
6762
+ this.cliArgs = cliArgs;
6763
+ this.type = provider2.type;
6764
+ this.adapter = new ProviderCliAdapter(provider2, workingDir, cliArgs);
6765
+ this.monitor = new StatusMonitor();
6766
+ }
6767
+ type;
6768
+ category = "cli";
6769
+ adapter;
6770
+ context = null;
6771
+ events = [];
6772
+ lastStatus = "starting";
6773
+ generatingStartedAt = 0;
6774
+ settings = {};
6775
+ monitor;
6776
+ // ─── Lifecycle ─────────────────────────────────
6777
+ async init(context) {
6778
+ this.context = context;
6779
+ this.settings = context.settings || {};
6780
+ this.monitor.updateConfig({
6781
+ approvalAlert: this.settings.approvalAlert !== false,
6782
+ longGeneratingAlert: this.settings.longGeneratingAlert !== false,
6783
+ longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
6784
+ });
6785
+ if (context.bridge) {
6786
+ this.adapter.setBridge(context.bridge);
6787
+ }
6788
+ if (context.onPtyData) {
6789
+ this.adapter.setOnPtyData(context.onPtyData);
6790
+ }
6791
+ this.adapter.setOnStatusChange(() => {
6792
+ this.detectStatusTransition();
6793
+ });
6794
+ await this.adapter.spawn();
6795
+ }
6796
+ async onTick() {
6797
+ }
6798
+ getState() {
6799
+ const adapterStatus = this.adapter.getStatus();
6800
+ const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
6801
+ const recentMessages = adapterStatus.messages.slice(-50).map((m) => ({
6802
+ role: m.role,
6803
+ content: m.content.length > 2e3 ? m.content.slice(0, 2e3) + "\n... (truncated)" : m.content,
6804
+ timestamp: m.timestamp
6805
+ }));
6806
+ const partial = this.adapter.getPartialResponse();
6807
+ if (adapterStatus.status === "generating" && partial) {
6808
+ const cleaned = partial.trim();
6809
+ if (cleaned && cleaned !== "(generating...)") {
6810
+ recentMessages.push({
6811
+ role: "assistant",
6812
+ content: (cleaned.length > 2e3 ? cleaned.slice(0, 2e3) + "..." : cleaned) + "...",
6813
+ timestamp: Date.now()
6814
+ });
6815
+ }
6816
+ }
6817
+ return {
6818
+ type: this.type,
6819
+ name: this.provider.name,
6820
+ category: "cli",
6821
+ status: adapterStatus.status,
6822
+ mode: this.settings.mode || "terminal",
6823
+ activeChat: {
6824
+ id: `${this.type}_${this.workingDir}`,
6825
+ title: `${this.provider.name} \xB7 ${dirName}`,
6826
+ status: adapterStatus.status,
6827
+ messages: recentMessages,
6828
+ activeModal: adapterStatus.activeModal,
6829
+ inputContent: ""
6830
+ },
6831
+ workingDir: this.workingDir,
6832
+ instanceId: `${this.type}_${require("crypto").createHash("md5").update(path8.resolve(this.workingDir)).digest("hex").slice(0, 8)}`,
6833
+ lastUpdated: Date.now(),
6834
+ settings: this.settings,
6835
+ pendingEvents: this.flushEvents()
6836
+ };
6837
+ }
6838
+ onEvent(event, data) {
6839
+ if (event === "send_message" && data?.text) {
6840
+ this.adapter.sendMessage(data.text);
6841
+ } else if (event === "bridge_connected" && data?.bridge) {
6842
+ this.adapter.setBridge(data.bridge);
6843
+ }
6844
+ }
6845
+ dispose() {
6846
+ this.adapter.shutdown();
6847
+ this.monitor.reset();
6848
+ }
6849
+ // ─── 상태 전이 감지 (daemon-status.ts에서 이동) ──────
6850
+ detectStatusTransition() {
6851
+ const now = Date.now();
6852
+ const adapterStatus = this.adapter.getStatus();
6853
+ const newStatus = adapterStatus.status;
6854
+ const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
6855
+ const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
6856
+ if (newStatus !== this.lastStatus) {
6857
+ if (this.lastStatus === "idle" && newStatus === "generating") {
6858
+ this.generatingStartedAt = now;
6859
+ this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now });
6860
+ } else if (newStatus === "waiting_approval") {
6861
+ if (!this.generatingStartedAt) this.generatingStartedAt = now;
6862
+ this.pushEvent({
6863
+ event: "agent:waiting_approval",
6864
+ chatTitle,
6865
+ timestamp: now,
6866
+ modalMessage: adapterStatus.activeModal?.message
6867
+ });
6868
+ } else if (newStatus === "idle" && (this.lastStatus === "generating" || this.lastStatus === "waiting_approval")) {
6869
+ const duration = this.generatingStartedAt ? Math.round((now - this.generatingStartedAt) / 1e3) : 0;
6870
+ this.pushEvent({ event: "agent:generating_completed", chatTitle, duration, timestamp: now });
6871
+ this.generatingStartedAt = 0;
6872
+ } else if (newStatus === "stopped") {
6873
+ this.pushEvent({ event: "agent:stopped", chatTitle, timestamp: now });
6874
+ }
6875
+ this.lastStatus = newStatus;
6876
+ }
6877
+ const agentKey = `${this.type}:cli`;
6878
+ const monitorEvents = this.monitor.check(agentKey, newStatus, now);
6879
+ for (const me of monitorEvents) {
6880
+ this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
6881
+ }
6882
+ }
6883
+ pushEvent(event) {
6884
+ this.events.push(event);
6885
+ if (this.events.length > 50) this.events = this.events.slice(-50);
6886
+ }
6887
+ flushEvents() {
6888
+ const events = [...this.events];
6889
+ this.events = [];
6890
+ return events;
6891
+ }
6892
+ // ─── Adapter 접근 (하위 호환) ──────────────────
6893
+ getAdapter() {
6894
+ return this.adapter;
6895
+ }
6896
+ get cliType() {
6897
+ return this.type;
6898
+ }
6899
+ get cliName() {
6900
+ return this.provider.name;
6901
+ }
6902
+ };
6903
+ }
6904
+ });
6905
+
6140
6906
  // src/daemon-cli.ts
6141
- var os9, path7, import_chalk, DaemonCliManager;
6907
+ var os10, path9, import_chalk, DaemonCliManager;
6142
6908
  var init_daemon_cli = __esm({
6143
6909
  "src/daemon-cli.ts"() {
6144
6910
  "use strict";
6145
- os9 = __toESM(require("os"));
6146
- path7 = __toESM(require("path"));
6911
+ os10 = __toESM(require("os"));
6912
+ path9 = __toESM(require("path"));
6147
6913
  import_chalk = __toESM(require("chalk"));
6148
6914
  init_provider_cli_adapter();
6149
6915
  init_cli_detector();
6150
6916
  init_config();
6917
+ init_cli_provider_instance();
6151
6918
  DaemonCliManager = class {
6152
6919
  adapters = /* @__PURE__ */ new Map();
6153
6920
  deps;
@@ -6181,8 +6948,8 @@ var init_daemon_cli = __esm({
6181
6948
  }
6182
6949
  // ─── 세션 시작/중지 ──────────────────────────────
6183
6950
  async startSession(cliType, workingDir, cliArgs) {
6184
- const trimmed = (workingDir || process.cwd()).trim();
6185
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os9.homedir()) : path7.resolve(trimmed);
6951
+ const trimmed = (workingDir || os10.homedir()).trim();
6952
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os10.homedir()) : path9.resolve(trimmed);
6186
6953
  const cliInfo = await detectCLI(cliType);
6187
6954
  if (!cliInfo) throw new Error(`${cliType} not found`);
6188
6955
  const key = this.getCliKey(cliType, resolvedDir);
@@ -6190,34 +6957,57 @@ var init_daemon_cli = __esm({
6190
6957
  console.log(import_chalk.default.yellow(` \u26A1 CLI ${cliType} already running in ${resolvedDir}`));
6191
6958
  return;
6192
6959
  }
6960
+ const typeMap = {
6961
+ "claude-code": "claude-cli",
6962
+ "codex": "codex-cli"
6963
+ };
6964
+ const normalizedType = typeMap[cliType] || cliType;
6965
+ const provider2 = this.providerLoader.get(normalizedType);
6193
6966
  console.log(import_chalk.default.yellow(` \u26A1 Starting CLI ${cliType} in ${resolvedDir}...`));
6194
- const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
6195
- await adapter.spawn();
6196
- const bridge = this.deps.getBridge();
6197
- if (bridge && typeof adapter.setBridge === "function") {
6198
- adapter.setBridge(bridge);
6967
+ if (provider2) {
6968
+ console.log(import_chalk.default.cyan(` \u{1F4E6} Using provider: ${provider2.name} (${provider2.type})`));
6199
6969
  }
6200
- adapter.setOnStatusChange(() => {
6201
- this.deps.onStatusChange();
6202
- const status = adapter.getStatus?.();
6203
- if (status?.status === "stopped") {
6204
- setTimeout(() => {
6205
- if (this.adapters.get(key) === adapter) {
6206
- this.adapters.delete(key);
6207
- this.deps.removeAgentTracking(key);
6208
- console.log(import_chalk.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
6209
- this.deps.onStatusChange();
6210
- }
6211
- }, 3e3);
6212
- }
6213
- });
6214
- if (typeof adapter.setOnPtyData === "function") {
6215
- adapter.setOnPtyData((data) => {
6216
- this.deps.getP2p()?.broadcastPtyOutput(key, data);
6970
+ const instanceManager = this.deps.getInstanceManager();
6971
+ if (provider2 && instanceManager) {
6972
+ const cliInstance = new CliProviderInstance(provider2, resolvedDir, cliArgs);
6973
+ await instanceManager.addInstance(key, cliInstance, {
6974
+ bridge: this.deps.getBridge(),
6975
+ settings: {},
6976
+ onPtyData: (data) => {
6977
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
6978
+ }
6979
+ });
6980
+ this.adapters.set(key, cliInstance.getAdapter());
6981
+ console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6982
+ } else {
6983
+ const adapter = this.createAdapter(cliType, resolvedDir, cliArgs);
6984
+ await adapter.spawn();
6985
+ const bridge = this.deps.getBridge();
6986
+ if (bridge && typeof adapter.setBridge === "function") {
6987
+ adapter.setBridge(bridge);
6988
+ }
6989
+ adapter.setOnStatusChange(() => {
6990
+ this.deps.onStatusChange();
6991
+ const status = adapter.getStatus?.();
6992
+ if (status?.status === "stopped") {
6993
+ setTimeout(() => {
6994
+ if (this.adapters.get(key) === adapter) {
6995
+ this.adapters.delete(key);
6996
+ this.deps.removeAgentTracking(key);
6997
+ console.log(import_chalk.default.yellow(` \u{1F9F9} Auto-cleaned stopped CLI: ${adapter.cliType}`));
6998
+ this.deps.onStatusChange();
6999
+ }
7000
+ }, 3e3);
7001
+ }
6217
7002
  });
7003
+ if (typeof adapter.setOnPtyData === "function") {
7004
+ adapter.setOnPtyData((data) => {
7005
+ this.deps.getP2p()?.broadcastPtyOutput(key, data);
7006
+ });
7007
+ }
7008
+ this.adapters.set(key, adapter);
7009
+ console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6218
7010
  }
6219
- this.adapters.set(key, adapter);
6220
- console.log(import_chalk.default.green(` \u2713 CLI started: ${cliInfo.displayName} v${cliInfo.version || "unknown"} in ${resolvedDir}`));
6221
7011
  try {
6222
7012
  addCliHistory({ cliType, dir: resolvedDir, cliArgs });
6223
7013
  } catch (e) {
@@ -6231,6 +7021,7 @@ var init_daemon_cli = __esm({
6231
7021
  adapter.shutdown();
6232
7022
  this.adapters.delete(key);
6233
7023
  this.deps.removeAgentTracking(key);
7024
+ this.deps.getInstanceManager()?.removeInstance(key);
6234
7025
  console.log(import_chalk.default.yellow(` \u{1F6D1} CLI Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`));
6235
7026
  this.deps.onStatusChange();
6236
7027
  }
@@ -6258,7 +7049,8 @@ var init_daemon_cli = __esm({
6258
7049
  switch (cmd) {
6259
7050
  case "launch_cli": {
6260
7051
  const cliType = args?.cliType;
6261
- const dir = args?.dir || process.cwd();
7052
+ const defaultedToHome = !args?.dir;
7053
+ const dir = args?.dir || os10.homedir();
6262
7054
  if (!cliType) throw new Error("cliType required");
6263
7055
  const key = this.getCliKey(cliType, dir);
6264
7056
  if (!this.adapters.has(key)) {
@@ -6276,7 +7068,7 @@ var init_daemon_cli = __esm({
6276
7068
  console.error(import_chalk.default.red(` \u2717 Failed to save recent workspace: ${e}`));
6277
7069
  }
6278
7070
  }
6279
- return { success: true, cliType, dir, id: key };
7071
+ return { success: true, cliType, dir, id: key, defaultedToHome };
6280
7072
  }
6281
7073
  case "stop_cli": {
6282
7074
  const cliType = args?.cliType;
@@ -6480,99 +7272,6 @@ var init_provider_instance_manager = __esm({
6480
7272
  }
6481
7273
  });
6482
7274
 
6483
- // src/providers/status-monitor.ts
6484
- var DEFAULT_MONITOR_CONFIG, StatusMonitor;
6485
- var init_status_monitor = __esm({
6486
- "src/providers/status-monitor.ts"() {
6487
- "use strict";
6488
- DEFAULT_MONITOR_CONFIG = {
6489
- approvalAlert: true,
6490
- longGeneratingAlert: true,
6491
- longGeneratingThresholdSec: 180,
6492
- // 3분
6493
- alertCooldownSec: 60
6494
- // 1분 쿨다운
6495
- };
6496
- StatusMonitor = class {
6497
- config;
6498
- lastAlertTime = /* @__PURE__ */ new Map();
6499
- generatingStartTimes = /* @__PURE__ */ new Map();
6500
- constructor(config) {
6501
- this.config = { ...DEFAULT_MONITOR_CONFIG, ...config };
6502
- }
6503
- /** 설정 업데이트 (Provider Settings에서 호출) */
6504
- updateConfig(partial) {
6505
- Object.assign(this.config, partial);
6506
- }
6507
- /** 현재 설정 반환 */
6508
- getConfig() {
6509
- return { ...this.config };
6510
- }
6511
- /**
6512
- * 상태 전이 체크 → 알림 이벤트 배열 반환
6513
- * 각 onTick()에서 호출.
6514
- */
6515
- check(agentKey, status, now) {
6516
- const events = [];
6517
- if (this.config.approvalAlert && status === "waiting_approval") {
6518
- if (this.shouldAlert(agentKey + ":approval", now)) {
6519
- events.push({
6520
- type: "monitor:approval_waiting",
6521
- agentKey,
6522
- timestamp: now,
6523
- message: `${agentKey} is waiting for approval`
6524
- });
6525
- }
6526
- }
6527
- if (status === "generating" || status === "streaming") {
6528
- if (!this.generatingStartTimes.has(agentKey)) {
6529
- this.generatingStartTimes.set(agentKey, now);
6530
- }
6531
- if (this.config.longGeneratingAlert) {
6532
- const startedAt = this.generatingStartTimes.get(agentKey);
6533
- const elapsedSec = Math.round((now - startedAt) / 1e3);
6534
- if (elapsedSec > this.config.longGeneratingThresholdSec) {
6535
- if (this.shouldAlert(agentKey + ":long_gen", now)) {
6536
- events.push({
6537
- type: "monitor:long_generating",
6538
- agentKey,
6539
- elapsedSec,
6540
- timestamp: now,
6541
- message: `${agentKey} has been generating for ${Math.round(elapsedSec / 60)}min`
6542
- });
6543
- }
6544
- }
6545
- }
6546
- } else {
6547
- this.generatingStartTimes.delete(agentKey);
6548
- }
6549
- return events;
6550
- }
6551
- /** 쿨다운 체크 — 같은 알림을 너무 자주 보내지 않도록 */
6552
- shouldAlert(key, now) {
6553
- const last = this.lastAlertTime.get(key) || 0;
6554
- if (now - last > this.config.alertCooldownSec * 1e3) {
6555
- this.lastAlertTime.set(key, now);
6556
- return true;
6557
- }
6558
- return false;
6559
- }
6560
- /** 리셋 (에이전트 종료/재시작 시) */
6561
- reset(agentKey) {
6562
- if (agentKey) {
6563
- this.generatingStartTimes.delete(agentKey);
6564
- for (const k of this.lastAlertTime.keys()) {
6565
- if (k.startsWith(agentKey)) this.lastAlertTime.delete(k);
6566
- }
6567
- } else {
6568
- this.generatingStartTimes.clear();
6569
- this.lastAlertTime.clear();
6570
- }
6571
- }
6572
- };
6573
- }
6574
- });
6575
-
6576
7275
  // src/providers/extension-provider-instance.ts
6577
7276
  var ExtensionProviderInstance;
6578
7277
  var init_extension_provider_instance = __esm({
@@ -6695,11 +7394,11 @@ var init_extension_provider_instance = __esm({
6695
7394
  });
6696
7395
 
6697
7396
  // src/providers/ide-provider-instance.ts
6698
- var os10, crypto, IdeProviderInstance;
7397
+ var os11, crypto, IdeProviderInstance;
6699
7398
  var init_ide_provider_instance = __esm({
6700
7399
  "src/providers/ide-provider-instance.ts"() {
6701
7400
  "use strict";
6702
- os10 = __toESM(require("os"));
7401
+ os11 = __toESM(require("os"));
6703
7402
  crypto = __toESM(require("crypto"));
6704
7403
  init_extension_provider_instance();
6705
7404
  init_status_monitor();
@@ -6725,10 +7424,10 @@ var init_ide_provider_instance = __esm({
6725
7424
  activeFile = null;
6726
7425
  // ─── 자식 Extension Instances ────────────────────
6727
7426
  extensions = /* @__PURE__ */ new Map();
6728
- constructor(provider2) {
7427
+ constructor(provider2, instanceKey) {
6729
7428
  this.type = provider2.type;
6730
7429
  this.provider = provider2;
6731
- this.instanceId = `${provider2.type}_${crypto.createHash("md5").update(os10.hostname() + provider2.type).digest("hex").slice(0, 8)}`;
7430
+ 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)}`;
6732
7431
  this.monitor = new StatusMonitor();
6733
7432
  }
6734
7433
  // ─── Lifecycle ─────────────────────────────────
@@ -6859,7 +7558,14 @@ var init_ide_provider_instance = __esm({
6859
7558
  const readChatScript = this.getReadChatScript();
6860
7559
  if (!readChatScript) return;
6861
7560
  try {
6862
- const raw = await cdp2.evaluate(readChatScript, 3e4);
7561
+ let raw = await cdp2.evaluate(readChatScript, 3e4);
7562
+ if (typeof raw === "string") {
7563
+ try {
7564
+ raw = JSON.parse(raw);
7565
+ } catch {
7566
+ return;
7567
+ }
7568
+ }
6863
7569
  if (!raw || typeof raw !== "object") return;
6864
7570
  let { activeModal } = raw;
6865
7571
  if (activeModal) {
@@ -6952,107 +7658,6 @@ var init_ide_provider_instance = __esm({
6952
7658
  }
6953
7659
  });
6954
7660
 
6955
- // src/daemon-logger.ts
6956
- var daemon_logger_exports = {};
6957
- __export(daemon_logger_exports, {
6958
- LOG_DIR_PATH: () => LOG_DIR_PATH,
6959
- LOG_PATH: () => LOG_PATH,
6960
- cdpLogFn: () => cdpLogFn,
6961
- daemonLog: () => daemonLog,
6962
- installGlobalInterceptor: () => installGlobalInterceptor
6963
- });
6964
- function rotateIfNeeded() {
6965
- try {
6966
- const stat = fs5.statSync(LOG_FILE);
6967
- if (stat.size > MAX_LOG_SIZE) {
6968
- const backup = LOG_FILE + ".old";
6969
- try {
6970
- fs5.unlinkSync(backup);
6971
- } catch {
6972
- }
6973
- fs5.renameSync(LOG_FILE, backup);
6974
- }
6975
- } catch {
6976
- }
6977
- }
6978
- function writeToFile(line) {
6979
- try {
6980
- fs5.appendFileSync(LOG_FILE, line + "\n");
6981
- } catch {
6982
- }
6983
- }
6984
- function daemonLog(category, msg) {
6985
- const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${category}] ${msg}`;
6986
- origConsoleLog(line);
6987
- writeToFile(line);
6988
- }
6989
- function cdpLogFn(ideType) {
6990
- return (msg) => {
6991
- const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [CDP:${ideType}] ${msg}`;
6992
- origConsoleLog(line);
6993
- writeToFile(line);
6994
- };
6995
- }
6996
- function installGlobalInterceptor() {
6997
- if (interceptorInstalled) return;
6998
- interceptorInstalled = true;
6999
- const stripAnsi2 = (str) => str.replace(/\x1B\[[0-9;]*m/g, "");
7000
- console.log = (...args) => {
7001
- origConsoleLog(...args);
7002
- try {
7003
- const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
7004
- const clean = stripAnsi2(msg);
7005
- const line = clean.startsWith("[20") ? clean : `[${(/* @__PURE__ */ new Date()).toISOString()}] ${clean}`;
7006
- writeToFile(line);
7007
- } catch {
7008
- }
7009
- };
7010
- console.error = (...args) => {
7011
- origConsoleError(...args);
7012
- try {
7013
- const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
7014
- const clean = stripAnsi2(msg);
7015
- writeToFile(`[${(/* @__PURE__ */ new Date()).toISOString()}] [ERROR] ${clean}`);
7016
- } catch {
7017
- }
7018
- };
7019
- console.warn = (...args) => {
7020
- origConsoleWarn(...args);
7021
- try {
7022
- const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
7023
- const clean = stripAnsi2(msg);
7024
- writeToFile(`[${(/* @__PURE__ */ new Date()).toISOString()}] [WARN] ${clean}`);
7025
- } catch {
7026
- }
7027
- };
7028
- writeToFile(`
7029
- === ADHDev Daemon started at ${(/* @__PURE__ */ new Date()).toISOString()} ===`);
7030
- writeToFile(`Log file: ${LOG_FILE}`);
7031
- }
7032
- var fs5, path8, os11, LOG_DIR, LOG_FILE, MAX_LOG_SIZE, origConsoleLog, origConsoleError, origConsoleWarn, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
7033
- var init_daemon_logger = __esm({
7034
- "src/daemon-logger.ts"() {
7035
- "use strict";
7036
- fs5 = __toESM(require("fs"));
7037
- path8 = __toESM(require("path"));
7038
- os11 = __toESM(require("os"));
7039
- LOG_DIR = process.platform === "darwin" ? path8.join(os11.homedir(), "Library", "Logs", "adhdev") : path8.join(os11.homedir(), ".local", "share", "adhdev", "logs");
7040
- LOG_FILE = path8.join(LOG_DIR, "daemon.log");
7041
- MAX_LOG_SIZE = 10 * 1024 * 1024;
7042
- try {
7043
- fs5.mkdirSync(LOG_DIR, { recursive: true });
7044
- } catch {
7045
- }
7046
- rotateIfNeeded();
7047
- origConsoleLog = console.log.bind(console);
7048
- origConsoleError = console.error.bind(console);
7049
- origConsoleWarn = console.warn.bind(console);
7050
- interceptorInstalled = false;
7051
- LOG_PATH = LOG_FILE;
7052
- LOG_DIR_PATH = LOG_DIR;
7053
- }
7054
- });
7055
-
7056
7661
  // src/adhdev-daemon.ts
7057
7662
  var adhdev_daemon_exports = {};
7058
7663
  __export(adhdev_daemon_exports, {
@@ -7061,9 +7666,9 @@ __export(adhdev_daemon_exports, {
7061
7666
  stopDaemon: () => stopDaemon
7062
7667
  });
7063
7668
  function getDaemonPidFile() {
7064
- const dir = path9.join(os12.homedir(), ".adhdev");
7669
+ const dir = path10.join(os12.homedir(), ".adhdev");
7065
7670
  if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
7066
- return path9.join(dir, "daemon.pid");
7671
+ return path10.join(dir, "daemon.pid");
7067
7672
  }
7068
7673
  function writeDaemonPid(pid) {
7069
7674
  fs6.writeFileSync(getDaemonPidFile(), String(pid), "utf-8");
@@ -7099,7 +7704,7 @@ function stopDaemon() {
7099
7704
  return false;
7100
7705
  }
7101
7706
  }
7102
- var os12, fs6, path9, crypto2, import_chalk2, DANGEROUS_PATTERNS, AdhdevDaemon;
7707
+ var os12, fs6, path10, crypto2, import_chalk2, DANGEROUS_PATTERNS, AdhdevDaemon;
7103
7708
  var init_adhdev_daemon = __esm({
7104
7709
  "src/adhdev-daemon.ts"() {
7105
7710
  "use strict";
@@ -7119,9 +7724,10 @@ var init_adhdev_daemon = __esm({
7119
7724
  init_provider_instance_manager();
7120
7725
  init_ide_provider_instance();
7121
7726
  init_ipc_protocol();
7727
+ init_daemon_logger();
7122
7728
  os12 = __toESM(require("os"));
7123
7729
  fs6 = __toESM(require("fs"));
7124
- path9 = __toESM(require("path"));
7730
+ path10 = __toESM(require("path"));
7125
7731
  crypto2 = __toESM(require("crypto"));
7126
7732
  import_chalk2 = __toESM(require("chalk"));
7127
7733
  DANGEROUS_PATTERNS = [
@@ -7163,7 +7769,8 @@ var init_adhdev_daemon = __esm({
7163
7769
  getBridge: () => this.bridge,
7164
7770
  getP2p: () => this.p2p,
7165
7771
  onStatusChange: () => this.statusReporter?.onStatusChange(),
7166
- removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key)
7772
+ removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
7773
+ getInstanceManager: () => this.instanceManager
7167
7774
  }, this.providerLoader);
7168
7775
  }
7169
7776
  async start(options = {}) {
@@ -7318,8 +7925,8 @@ var init_adhdev_daemon = __esm({
7318
7925
  });
7319
7926
  this.p2p.onStateChange((state) => {
7320
7927
  if (state === "connected") {
7321
- console.log("[P2P] Peer connected \u2192 sending immediate full status report");
7322
- this.statusReporter?.sendUnifiedStatusReport().catch((e) => console.warn("[P2P] Immediate status report failed:", e?.message));
7928
+ LOG.info("P2P", "Peer connected \u2192 sending immediate full status report");
7929
+ this.statusReporter?.sendUnifiedStatusReport().catch((e) => LOG.warn("P2P", `Immediate status report failed: ${e?.message}`));
7323
7930
  }
7324
7931
  });
7325
7932
  let ssDebugCount = 0;
@@ -7330,18 +7937,18 @@ var init_adhdev_daemon = __esm({
7330
7937
  if (!active || !cdp2) return;
7331
7938
  ssDebugCount++;
7332
7939
  if (ssDebugCount <= 3 || ssDebugCount % 25 === 0) {
7333
- console.log(`[SS] Capturing screenshot... (tick ${ssDebugCount}, active=${active}, cdp=true)`);
7940
+ LOG.debug("Screenshot", `Capturing... (tick ${ssDebugCount}, active=${active}, cdp=true)`);
7334
7941
  }
7335
7942
  try {
7336
7943
  const buf = await cdp2.captureScreenshot();
7337
7944
  if (buf) {
7338
7945
  const sent = this.p2p.sendScreenshot(buf.toString("base64"));
7339
- if (ssDebugCount <= 3) console.log(`[SS] Screenshot sent: ${buf.length} bytes, delivered=${sent}`);
7946
+ if (ssDebugCount <= 3) LOG.debug("Screenshot", `sent: ${buf.length} bytes, delivered=${sent}`);
7340
7947
  } else {
7341
- if (ssDebugCount <= 5) console.log(`[SS] captureScreenshot returned null`);
7948
+ if (ssDebugCount <= 5) LOG.debug("Screenshot", "captureScreenshot returned null");
7342
7949
  }
7343
7950
  } catch (e) {
7344
- if (ssDebugCount <= 5) console.log(`[SS] Screenshot error: ${e?.message}`);
7951
+ if (ssDebugCount <= 5) LOG.warn("Screenshot", `error: ${e?.message}`);
7345
7952
  }
7346
7953
  }, 200);
7347
7954
  } else {
@@ -7484,10 +8091,7 @@ var init_adhdev_daemon = __esm({
7484
8091
  }
7485
8092
  }
7486
8093
  async handleCommand(msg, cmd, args) {
7487
- console.log(import_chalk2.default.magenta(` \u2699 Command: ${cmd}`));
7488
- if (cmd.startsWith("agent_stream") && args?._targetInstance) {
7489
- console.log(import_chalk2.default.yellow(` \u{1F3AF} Target: ${args._targetType}:${args._targetInstance.split("_")[0]} agent=${args.agentType || ""}`));
7490
- }
8094
+ LOG.info("Command", `${cmd}${args?._targetInstance ? ` \u2192 ${args._targetType}:${args._targetInstance.split("_")[0]}` : ""}`);
7491
8095
  try {
7492
8096
  switch (cmd) {
7493
8097
  case "open_panel":
@@ -7559,17 +8163,22 @@ var init_adhdev_daemon = __esm({
7559
8163
  return { success: true, nickname };
7560
8164
  }
7561
8165
  case "get_daemon_logs": {
7562
- const lines = parseInt(data.lines) || 100;
8166
+ const count = parseInt(data.lines) || 100;
8167
+ const minLevel = data.minLevel || "info";
7563
8168
  try {
7564
- const logPath = require("path").join(require("os").tmpdir(), "adhdev-daemon.log");
8169
+ const { getRecentLogs: getRecentLogs2, LOG_PATH: LOG_PATH2 } = (init_daemon_logger(), __toCommonJS(daemon_logger_exports));
8170
+ const entries = getRecentLogs2(count, minLevel);
8171
+ if (entries.length > 0) {
8172
+ return { success: true, entries, totalBuffered: entries.length };
8173
+ }
7565
8174
  const logFs = require("fs");
7566
- if (logFs.existsSync(logPath)) {
7567
- const content = logFs.readFileSync(logPath, "utf-8");
8175
+ if (logFs.existsSync(LOG_PATH2)) {
8176
+ const content = logFs.readFileSync(LOG_PATH2, "utf-8");
7568
8177
  const allLines = content.split("\n");
7569
- const recent = allLines.slice(-lines).join("\n");
8178
+ const recent = allLines.slice(-count).join("\n");
7570
8179
  return { success: true, logs: recent, totalLines: allLines.length };
7571
8180
  }
7572
- return { success: true, logs: "", totalLines: 0 };
8181
+ return { success: true, entries: [], totalBuffered: 0 };
7573
8182
  } catch (e) {
7574
8183
  return { success: false, error: e.message };
7575
8184
  }
@@ -7602,7 +8211,7 @@ var init_adhdev_daemon = __esm({
7602
8211
  case "launch_ide": {
7603
8212
  const launchArgs = { ...args, ideId: args?.ideId || args?.ideType };
7604
8213
  const ideKey = launchArgs.ideId;
7605
- console.log(`[launch_ide] target=${ideKey || "auto"}`);
8214
+ LOG.info("LaunchIDE", `target=${ideKey || "auto"}`);
7606
8215
  const result = await launchWithCdp(launchArgs);
7607
8216
  if (result.success && result.port && result.ideId && !this.cdpManagers.has(result.ideId)) {
7608
8217
  console.log(import_chalk2.default.cyan(`[launch_ide] Connecting CDP for ${result.ideId} on port ${result.port}...`));
@@ -7611,6 +8220,12 @@ var init_adhdev_daemon = __esm({
7611
8220
  });
7612
8221
  const connected = await manager.connect();
7613
8222
  if (connected) {
8223
+ const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(result.ideId).map((p) => ({
8224
+ agentType: p.type,
8225
+ extensionId: p.extensionId || "",
8226
+ extensionIdPattern: p.extensionIdPattern
8227
+ }));
8228
+ manager.setExtensionProviders(enabledExtProviders);
7614
8229
  this.cdpManagers.set(result.ideId, manager);
7615
8230
  console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${result.ideId} (port ${result.port})`));
7616
8231
  console.log(import_chalk2.default.green(` \u{1F4E1} CDP: ${this.cdpManagers.size} IDE(s) connected`));
@@ -7692,6 +8307,37 @@ var init_adhdev_daemon = __esm({
7692
8307
  if (this.agentStreamTimer) return;
7693
8308
  this.agentStreamTimer = setInterval(async () => {
7694
8309
  if (!this.agentStreamManager || this.cdpManagers.size === 0) return;
8310
+ for (const [ideType, cdp2] of this.cdpManagers) {
8311
+ const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(ideType).map((p) => ({
8312
+ agentType: p.type,
8313
+ extensionId: p.extensionId || "",
8314
+ extensionIdPattern: p.extensionIdPattern
8315
+ }));
8316
+ cdp2.setExtensionProviders(enabledExtProviders);
8317
+ const ideInstance = this.instanceManager.getInstance(`ide:${ideType}`);
8318
+ if (ideInstance?.getExtensionTypes && ideInstance?.addExtension && ideInstance?.removeExtension) {
8319
+ const currentExtTypes = new Set(ideInstance.getExtensionTypes());
8320
+ const enabledExtTypes = new Set(
8321
+ this.providerLoader.getEnabledByCategory("extension", ideType).map((p) => p.type)
8322
+ );
8323
+ for (const extType of currentExtTypes) {
8324
+ if (!enabledExtTypes.has(extType)) {
8325
+ ideInstance.removeExtension(extType);
8326
+ LOG.info("AgentStream", `Extension removed: ${extType} (disabled for ${ideType})`);
8327
+ }
8328
+ }
8329
+ for (const extType of enabledExtTypes) {
8330
+ if (!currentExtTypes.has(extType)) {
8331
+ const extProvider = this.providerLoader.get(extType);
8332
+ if (extProvider) {
8333
+ const extSettings = this.providerLoader.getSettings(extType);
8334
+ ideInstance.addExtension(extProvider, extSettings);
8335
+ LOG.info("AgentStream", `Extension added: ${extType} (enabled for ${ideType})`);
8336
+ }
8337
+ }
8338
+ }
8339
+ }
8340
+ }
7695
8341
  if (this._agentStreamCdpIdeType) {
7696
8342
  const cdp2 = this.cdpManagers.get(this._agentStreamCdpIdeType);
7697
8343
  if (cdp2?.isConnected) {
@@ -7713,7 +8359,7 @@ var init_adhdev_daemon = __esm({
7713
8359
  if (discovered.length > 0) {
7714
8360
  this._agentStreamCdpIdeType = ideType;
7715
8361
  await this.agentStreamManager.switchActiveAgent(cdp2, discovered[0].agentType);
7716
- console.log(`[AgentStream] Auto-activated: ${discovered[0].agentType} (${ideType})`);
8362
+ LOG.info("AgentStream", `Auto-activated: ${discovered[0].agentType} (${ideType})`);
7717
8363
  await this.agentStreamManager.syncAgentSessions(cdp2);
7718
8364
  const streams = await this.agentStreamManager.collectAgentStreams(cdp2);
7719
8365
  this.statusReporter?.updateAgentStreams(ideType, streams);
@@ -7725,6 +8371,39 @@ var init_adhdev_daemon = __esm({
7725
8371
  }
7726
8372
  }, 5e3);
7727
8373
  }
8374
+ /**
8375
+ * CdpManager 초기화 공통 로직 — extension provider 등록, ideType 설정, ProviderInstance 생성
8376
+ * @param ideType provider 기반 IDE 타입 (e.g., 'antigravity', 'cursor')
8377
+ * @param manager 연결된 CdpManager
8378
+ */
8379
+ setupCdpManager(ideType, manager) {
8380
+ const enabledExtProviders = this.providerLoader.getEnabledExtensionProviders(ideType).map((p) => ({
8381
+ agentType: p.type,
8382
+ extensionId: p.extensionId || "",
8383
+ extensionIdPattern: p.extensionIdPattern
8384
+ }));
8385
+ manager.setExtensionProviders(enabledExtProviders);
8386
+ if (this.ideType === "unknown") {
8387
+ this.ideType = ideType;
8388
+ }
8389
+ const ideProvider = this.providerLoader.get(ideType);
8390
+ if (ideProvider) {
8391
+ const managerKey = [...this.cdpManagers.entries()].find(([, m]) => m === manager)?.[0] || ideType;
8392
+ const ideInstance = new IdeProviderInstance(ideProvider, managerKey !== ideType ? managerKey : void 0);
8393
+ const resolvedSettings = this.providerLoader.getSettings(ideType);
8394
+ this.instanceManager.addInstance(`ide:${managerKey}`, ideInstance, {
8395
+ cdp: manager,
8396
+ bridge: this.bridge || void 0,
8397
+ settings: resolvedSettings
8398
+ }).then(async () => {
8399
+ const extensionProviders = this.providerLoader.getEnabledByCategory("extension", ideType);
8400
+ for (const extProvider of extensionProviders) {
8401
+ const extSettings = this.providerLoader.getSettings(extProvider.type);
8402
+ await ideInstance.addExtension(extProvider, extSettings);
8403
+ }
8404
+ }).catch((e) => console.warn(`[Instance] Failed to init IDE instance ${managerKey}:`, e?.message));
8405
+ }
8406
+ }
7728
8407
  async initCdp() {
7729
8408
  const providerCdpMap = this.providerLoader.getCdpPortMap();
7730
8409
  const cdpPortMap = {};
@@ -7745,49 +8424,87 @@ var init_adhdev_daemon = __esm({
7745
8424
  const enabledIdes = loadConfig().enabledIdes || [];
7746
8425
  const filteredPorts = enabledIdes.length > 0 ? portsToTry.filter((p) => enabledIdes.includes(p.ide)) : portsToTry;
7747
8426
  for (const { port, ide } of filteredPorts) {
7748
- const manager = new DaemonCdpManager(port, (msg) => {
7749
- console.log(`[CDP:${ide}] ${msg}`);
7750
- });
7751
- const connected = await manager.connect();
7752
- if (connected) {
7753
- const actualPort = manager.getPort();
7754
- const actualIde = Object.entries(cdpPortMap).find(([, p]) => p === actualPort)?.[0] || ide;
7755
- this.cdpManagers.set(actualIde, manager);
7756
- console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${actualIde} (port ${actualPort})`));
7757
- if (this.ideType === "unknown") {
7758
- this.ideType = actualIde;
8427
+ const allTargets = await DaemonCdpManager.listAllTargets(port);
8428
+ if (allTargets.length === 0) {
8429
+ const manager = new DaemonCdpManager(port, (msg) => {
8430
+ console.log(`[CDP:${ide}] ${msg}`);
8431
+ });
8432
+ const connected = await manager.connect();
8433
+ if (connected) {
8434
+ this.cdpManagers.set(ide, manager);
8435
+ console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${ide} (port ${port})`));
8436
+ this.setupCdpManager(ide, manager);
7759
8437
  }
7760
- const ideProvider = this.providerLoader.get(actualIde);
7761
- if (ideProvider) {
7762
- const ideInstance = new IdeProviderInstance(ideProvider);
7763
- const resolvedSettings = this.providerLoader.getSettings(actualIde);
7764
- this.instanceManager.addInstance(`ide:${actualIde}`, ideInstance, {
7765
- cdp: manager,
7766
- bridge: this.bridge || void 0,
7767
- settings: resolvedSettings
7768
- }).then(async () => {
7769
- const extensionProviders = this.providerLoader.getAll().filter((p) => p.category === "extension");
7770
- for (const extProvider of extensionProviders) {
7771
- const extSettings = this.providerLoader.getSettings(extProvider.type);
7772
- await ideInstance.addExtension(extProvider, extSettings);
7773
- }
7774
- }).catch((e) => console.warn(`[Instance] Failed to init IDE instance ${actualIde}:`, e?.message));
8438
+ continue;
8439
+ }
8440
+ for (let i = 0; i < allTargets.length; i++) {
8441
+ const target = allTargets[i];
8442
+ let managerKey;
8443
+ if (allTargets.length === 1) {
8444
+ managerKey = ide;
8445
+ } else {
8446
+ const workspaceName = (target.title || "").split(" \u2014 ")[0].trim() || `window_${i}`;
8447
+ managerKey = `${ide}_${workspaceName}`;
8448
+ }
8449
+ if (this.cdpManagers.has(managerKey)) continue;
8450
+ const manager = new DaemonCdpManager(port, (msg) => {
8451
+ console.log(`[CDP:${managerKey}] ${msg}`);
8452
+ }, target.id);
8453
+ const connected = await manager.connect();
8454
+ if (connected) {
8455
+ this.cdpManagers.set(managerKey, manager);
8456
+ console.log(import_chalk2.default.green(` \u{1F50D} CDP connected: ${managerKey} (port ${port}, page "${target.title}")`));
8457
+ this.setupCdpManager(ide, manager);
7775
8458
  }
7776
8459
  }
7777
8460
  }
7778
8461
  if (this.cdpManagers.size > 0) {
7779
8462
  console.log(import_chalk2.default.green(` \u{1F4E1} CDP: ${this.cdpManagers.size} IDE(s) connected`));
7780
- this.cdpDiscoveryTimer = setInterval(async () => {
7781
- for (const m of this.cdpManagers.values()) {
7782
- if (m.isConnected) {
7783
- await m.discoverAgentWebviews();
7784
- }
7785
- }
7786
- }, 3e4);
7787
8463
  } else {
7788
8464
  console.log(import_chalk2.default.yellow(` \u26A0 CDP not available \u2014 tried ports: ${portsToTry.map((p) => `${p.ide}:${p.port}`).join(", ")}`));
7789
8465
  console.log(import_chalk2.default.yellow(` IDE may need relaunch with --remote-debugging-port`));
7790
8466
  }
8467
+ this.cdpDiscoveryTimer = setInterval(async () => {
8468
+ for (const m of this.cdpManagers.values()) {
8469
+ if (m.isConnected) {
8470
+ await m.discoverAgentWebviews();
8471
+ }
8472
+ }
8473
+ }, 3e4);
8474
+ setInterval(async () => {
8475
+ const portMap = this.providerLoader.getCdpPortMap();
8476
+ for (const [ide, ports] of Object.entries(portMap)) {
8477
+ const primaryPort = ports[0];
8478
+ const alreadyConnected = [...this.cdpManagers.entries()].some(
8479
+ ([key, m]) => m.isConnected && (key === ide || key.startsWith(ide + "_"))
8480
+ );
8481
+ if (alreadyConnected) continue;
8482
+ const targets = await DaemonCdpManager.listAllTargets(primaryPort);
8483
+ if (targets.length === 0) continue;
8484
+ console.log(import_chalk2.default.cyan(`[CDP-Scan] Found ${targets.length} page(s) on ${ide}:${primaryPort}`));
8485
+ for (let i = 0; i < targets.length; i++) {
8486
+ const target = targets[i];
8487
+ let managerKey;
8488
+ if (targets.length === 1) {
8489
+ managerKey = ide;
8490
+ } else {
8491
+ const workspaceName = (target.title || "").split(" \u2014 ")[0].trim() || `window_${i}`;
8492
+ managerKey = `${ide}_${workspaceName}`;
8493
+ }
8494
+ if (this.cdpManagers.has(managerKey)) continue;
8495
+ const manager = new DaemonCdpManager(primaryPort, (msg) => {
8496
+ console.log(`[CDP:${managerKey}] ${msg}`);
8497
+ }, target.id);
8498
+ const connected = await manager.connect();
8499
+ if (connected) {
8500
+ this.cdpManagers.set(managerKey, manager);
8501
+ console.log(import_chalk2.default.green(` \u{1F50D} CDP auto-connected: ${managerKey} (port ${primaryPort}, page "${target.title}")`));
8502
+ this.setupCdpManager(ide, manager);
8503
+ this.startAgentStreamPolling();
8504
+ }
8505
+ }
8506
+ }
8507
+ }, 3e4);
7791
8508
  }
7792
8509
  };
7793
8510
  }
@@ -7935,10 +8652,10 @@ async function installExtension(ide, extension) {
7935
8652
  const buffer = Buffer.from(await res.arrayBuffer());
7936
8653
  const fs7 = await import("fs");
7937
8654
  fs7.writeFileSync(vsixPath, buffer);
7938
- return new Promise((resolve5) => {
8655
+ return new Promise((resolve6) => {
7939
8656
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
7940
8657
  (0, import_child_process2.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
7941
- resolve5({
8658
+ resolve6({
7942
8659
  extensionId: extension.id,
7943
8660
  marketplaceId: extension.marketplaceId,
7944
8661
  success: !error,
@@ -7969,11 +8686,11 @@ async function installExtension(ide, extension) {
7969
8686
  }
7970
8687
  }
7971
8688
  }
7972
- return new Promise((resolve5) => {
8689
+ return new Promise((resolve6) => {
7973
8690
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
7974
8691
  (0, import_child_process2.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
7975
8692
  if (error) {
7976
- resolve5({
8693
+ resolve6({
7977
8694
  extensionId: extension.id,
7978
8695
  marketplaceId: extension.marketplaceId,
7979
8696
  success: false,
@@ -7981,7 +8698,7 @@ async function installExtension(ide, extension) {
7981
8698
  error: stderr || error.message
7982
8699
  });
7983
8700
  } else {
7984
- resolve5({
8701
+ resolve6({
7985
8702
  extensionId: extension.id,
7986
8703
  marketplaceId: extension.marketplaceId,
7987
8704
  success: true,
@@ -8157,11 +8874,12 @@ async function quickSetup() {
8157
8874
  console.log(` ${import_chalk3.default.bold("Status:")} ${import_chalk3.default.green("Ready to connect")}`);
8158
8875
  console.log();
8159
8876
  console.log(import_chalk3.default.gray(" Commands:"));
8160
- console.log(import_chalk3.default.gray(" adhdev daemon \u2014 Start daemon (IDE monitor + agent hub)"));
8161
- console.log(import_chalk3.default.gray(" adhdev launch cursor \u2014 Launch IDE with CDP"));
8162
- console.log(import_chalk3.default.gray(" adhdev launch gemini \u2014 Start CLI agent via daemon"));
8877
+ console.log(import_chalk3.default.gray(" adhdev daemon \u2014 Start the main daemon (required for all features)"));
8878
+ console.log(import_chalk3.default.gray(" adhdev launch <ide> \u2014 Launch an IDE with remote control (e.g. cursor)"));
8879
+ console.log(import_chalk3.default.gray(" adhdev launch <agent> \u2014 Start a CLI agent via daemon (e.g. gemini, claude)"));
8880
+ console.log(import_chalk3.default.gray(" adhdev cdp \u2014 Interactive CDP debug console"));
8163
8881
  console.log(import_chalk3.default.gray(" adhdev status \u2014 Check setup status"));
8164
- console.log(import_chalk3.default.gray(" adhdev setup \u2014 Reconfigure"));
8882
+ console.log(import_chalk3.default.gray(" adhdev setup \u2014 Reconfigure ADHDev"));
8165
8883
  console.log();
8166
8884
  await installCliOnly();
8167
8885
  await startDaemonFlow();
@@ -8333,16 +9051,16 @@ async function injectTokenToIDE(ide, connectionToken) {
8333
9051
  try {
8334
9052
  const os13 = await import("os");
8335
9053
  const fs7 = await import("fs");
8336
- const path10 = await import("path");
9054
+ const path11 = await import("path");
8337
9055
  const platform7 = os13.platform();
8338
9056
  const home = os13.homedir();
8339
9057
  const getSettingsPath = (appName2) => {
8340
9058
  if (platform7 === "darwin") {
8341
- return path10.join(home, "Library", "Application Support", appName2, "User", "settings.json");
9059
+ return path11.join(home, "Library", "Application Support", appName2, "User", "settings.json");
8342
9060
  } else if (platform7 === "win32") {
8343
- return path10.join(process.env.APPDATA || path10.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
9061
+ return path11.join(process.env.APPDATA || path11.join(home, "AppData", "Roaming"), appName2, "User", "settings.json");
8344
9062
  } else {
8345
- return path10.join(home, ".config", appName2, "User", "settings.json");
9063
+ return path11.join(home, ".config", appName2, "User", "settings.json");
8346
9064
  }
8347
9065
  };
8348
9066
  const loader = new ProviderLoader({ logFn: () => {
@@ -8360,7 +9078,7 @@ async function injectTokenToIDE(ide, connectionToken) {
8360
9078
  settings = {};
8361
9079
  }
8362
9080
  } else {
8363
- fs7.mkdirSync(path10.dirname(settingsPath), { recursive: true });
9081
+ fs7.mkdirSync(path11.dirname(settingsPath), { recursive: true });
8364
9082
  }
8365
9083
  settings["adhdev.connectionToken"] = connectionToken;
8366
9084
  settings["adhdev.autoConnect"] = true;
@@ -8382,7 +9100,7 @@ async function startDaemonFlow() {
8382
9100
  {
8383
9101
  type: "confirm",
8384
9102
  name: "startDaemon",
8385
- message: "Start ADHDev Daemon now? (IDE monitor + agent hub)",
9103
+ message: "Start the ADHDev Daemon now? (Required for all agent/IDE routing features)",
8386
9104
  default: true
8387
9105
  }
8388
9106
  ]);
@@ -8396,8 +9114,8 @@ async function startDaemonFlow() {
8396
9114
  const daemon = new AdhdevDaemon2();
8397
9115
  const { execSync: execSync6 } = await import("child_process");
8398
9116
  const os13 = await import("os");
8399
- const path10 = await import("path");
8400
- const logPath = path10.join(os13.homedir(), ".adhdev", "daemon.log");
9117
+ const path11 = await import("path");
9118
+ const logPath = path11.join(os13.homedir(), ".adhdev", "daemon.log");
8401
9119
  try {
8402
9120
  execSync6(`nohup adhdev daemon > "${logPath}" 2>&1 &`, {
8403
9121
  timeout: 3e3,
@@ -8439,10 +9157,11 @@ async function installCliOnly() {
8439
9157
  const isNpx = process.env.npm_execpath?.includes("npx") || process.argv[1]?.includes("npx") || process.argv[1]?.includes("_npx");
8440
9158
  console.log(import_chalk3.default.bold("\n\u{1F527} ADHDev CLI\n"));
8441
9159
  console.log(import_chalk3.default.gray(" The `adhdev` command lets you:"));
8442
- console.log(import_chalk3.default.gray(" \u2022 Start daemon \u2014 IDE monitor + agent hub (adhdev daemon)"));
8443
- console.log(import_chalk3.default.gray(" \u2022 Launch IDE with CDP (adhdev launch cursor)"));
8444
- console.log(import_chalk3.default.gray(" \u2022 Start CLI agents (adhdev launch gemini)"));
8445
- console.log(import_chalk3.default.gray(" \u2022 Check status (adhdev status)"));
9160
+ console.log(import_chalk3.default.gray(" \u2022 Start the main daemon (adhdev daemon)"));
9161
+ console.log(import_chalk3.default.gray(" \u2022 Launch IDE with CDP (adhdev launch <ide>)"));
9162
+ console.log(import_chalk3.default.gray(" \u2022 Start CLI agents (adhdev launch <agent>)"));
9163
+ console.log(import_chalk3.default.gray(" \u2022 CDP Debugging Console (adhdev cdp)"));
9164
+ console.log(import_chalk3.default.gray(" \u2022 Check setup status (adhdev status)"));
8446
9165
  console.log();
8447
9166
  if (currentVersion) {
8448
9167
  console.log(import_chalk3.default.green(` \u2713 Currently installed: v${currentVersion}`));
@@ -8824,7 +9543,7 @@ program.command("daemon:stop").description("Stop ADHDev Daemon").action(async ()
8824
9543
  async function sendDaemonCommand(cmd, args = {}, port = 19222) {
8825
9544
  const WebSocket4 = (await import("ws")).default;
8826
9545
  const { DAEMON_WS_PATH: DAEMON_WS_PATH2 } = await Promise.resolve().then(() => (init_ipc_protocol(), ipc_protocol_exports));
8827
- return new Promise((resolve5, reject) => {
9546
+ return new Promise((resolve6, reject) => {
8828
9547
  const wsUrl = `ws://127.0.0.1:${port}${DAEMON_WS_PATH2 || "/daemon"}`;
8829
9548
  const ws = new WebSocket4(wsUrl);
8830
9549
  const timeout = setTimeout(() => {
@@ -8855,7 +9574,7 @@ async function sendDaemonCommand(cmd, args = {}, port = 19222) {
8855
9574
  if (msg.type === "daemon:command_result" || msg.type === "command_result") {
8856
9575
  clearTimeout(timeout);
8857
9576
  ws.close();
8858
- resolve5(msg.payload?.result || msg.payload || msg);
9577
+ resolve6(msg.payload?.result || msg.payload || msg);
8859
9578
  }
8860
9579
  } catch {
8861
9580
  }
@@ -8872,13 +9591,13 @@ Is 'adhdev daemon' running?`));
8872
9591
  }
8873
9592
  async function directCdpEval(expression, port = 9222) {
8874
9593
  const http3 = await import("http");
8875
- const targets = await new Promise((resolve5, reject) => {
9594
+ const targets = await new Promise((resolve6, reject) => {
8876
9595
  http3.get(`http://127.0.0.1:${port}/json`, (res) => {
8877
9596
  let data = "";
8878
9597
  res.on("data", (c) => data += c);
8879
9598
  res.on("end", () => {
8880
9599
  try {
8881
- resolve5(JSON.parse(data));
9600
+ resolve6(JSON.parse(data));
8882
9601
  } catch {
8883
9602
  reject(new Error("Invalid JSON"));
8884
9603
  }
@@ -8891,7 +9610,7 @@ async function directCdpEval(expression, port = 9222) {
8891
9610
  const target = (mainPages.length > 0 ? mainPages[0] : pages[0]) || targets[0];
8892
9611
  if (!target?.webSocketDebuggerUrl) throw new Error("No CDP target found");
8893
9612
  const WebSocket4 = (await import("ws")).default;
8894
- return new Promise((resolve5, reject) => {
9613
+ return new Promise((resolve6, reject) => {
8895
9614
  const ws = new WebSocket4(target.webSocketDebuggerUrl);
8896
9615
  const timeout = setTimeout(() => {
8897
9616
  ws.close();
@@ -8913,11 +9632,11 @@ async function directCdpEval(expression, port = 9222) {
8913
9632
  clearTimeout(timeout);
8914
9633
  ws.close();
8915
9634
  if (msg.result?.result?.value !== void 0) {
8916
- resolve5(msg.result.result.value);
9635
+ resolve6(msg.result.result.value);
8917
9636
  } else if (msg.result?.exceptionDetails) {
8918
9637
  reject(new Error(msg.result.exceptionDetails.text));
8919
9638
  } else {
8920
- resolve5(msg.result);
9639
+ resolve6(msg.result);
8921
9640
  }
8922
9641
  }
8923
9642
  });
@@ -8971,7 +9690,7 @@ provider.command("list").description("List all loaded providers").option("-j, --
8971
9690
  provider.command("reload").description("Hot-reload all providers (requires daemon --dev)").action(async () => {
8972
9691
  try {
8973
9692
  const http3 = await import("http");
8974
- const result = await new Promise((resolve5, reject) => {
9693
+ const result = await new Promise((resolve6, reject) => {
8975
9694
  const req = http3.request({
8976
9695
  hostname: "127.0.0.1",
8977
9696
  port: 19280,
@@ -8983,9 +9702,9 @@ provider.command("reload").description("Hot-reload all providers (requires daemo
8983
9702
  res.on("data", (c) => data += c);
8984
9703
  res.on("end", () => {
8985
9704
  try {
8986
- resolve5(JSON.parse(data));
9705
+ resolve6(JSON.parse(data));
8987
9706
  } catch {
8988
- resolve5({ raw: data });
9707
+ resolve6({ raw: data });
8989
9708
  }
8990
9709
  });
8991
9710
  });
@@ -9019,7 +9738,7 @@ provider.command("create <type>").description("Scaffold a new provider.js from t
9019
9738
  const category = options.category;
9020
9739
  const location = options.builtin ? "builtin" : "user";
9021
9740
  const http3 = await import("http");
9022
- const result = await new Promise((resolve5, reject) => {
9741
+ const result = await new Promise((resolve6, reject) => {
9023
9742
  const postData = JSON.stringify({ type, name, category, location });
9024
9743
  const req = http3.request({
9025
9744
  hostname: "127.0.0.1",
@@ -9032,9 +9751,9 @@ provider.command("create <type>").description("Scaffold a new provider.js from t
9032
9751
  res.on("data", (c) => data += c);
9033
9752
  res.on("end", () => {
9034
9753
  try {
9035
- resolve5(JSON.parse(data));
9754
+ resolve6(JSON.parse(data));
9036
9755
  } catch {
9037
- resolve5({ raw: data });
9756
+ resolve6({ raw: data });
9038
9757
  }
9039
9758
  });
9040
9759
  });
@@ -9116,7 +9835,7 @@ provider.command("run <type> <script>").description("Run a specific provider scr
9116
9835
  script,
9117
9836
  params: options.param ? { text: options.param, sessionId: options.param, buttonText: options.param } : {}
9118
9837
  });
9119
- const result = await new Promise((resolve5, reject) => {
9838
+ const result = await new Promise((resolve6, reject) => {
9120
9839
  const req = http3.request({
9121
9840
  hostname: "127.0.0.1",
9122
9841
  port: 19280,
@@ -9128,9 +9847,9 @@ provider.command("run <type> <script>").description("Run a specific provider scr
9128
9847
  res.on("data", (c) => data += c);
9129
9848
  res.on("end", () => {
9130
9849
  try {
9131
- resolve5(JSON.parse(data));
9850
+ resolve6(JSON.parse(data));
9132
9851
  } catch {
9133
- resolve5({ raw: data });
9852
+ resolve6({ raw: data });
9134
9853
  }
9135
9854
  });
9136
9855
  });
@@ -9166,15 +9885,15 @@ provider.command("run <type> <script>").description("Run a specific provider scr
9166
9885
  provider.command("source <type>").description("View source code of a provider").action(async (type) => {
9167
9886
  try {
9168
9887
  const http3 = await import("http");
9169
- const result = await new Promise((resolve5, reject) => {
9888
+ const result = await new Promise((resolve6, reject) => {
9170
9889
  http3.get(`http://127.0.0.1:19280/api/providers/${type}/source`, (res) => {
9171
9890
  let data = "";
9172
9891
  res.on("data", (c) => data += c);
9173
9892
  res.on("end", () => {
9174
9893
  try {
9175
- resolve5(JSON.parse(data));
9894
+ resolve6(JSON.parse(data));
9176
9895
  } catch {
9177
- resolve5({ raw: data });
9896
+ resolve6({ raw: data });
9178
9897
  }
9179
9898
  });
9180
9899
  }).on("error", () => {
@@ -9378,13 +10097,13 @@ cdp.command("eval <expression>").description("Execute JavaScript expression via
9378
10097
  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) => {
9379
10098
  try {
9380
10099
  const http3 = await import("http");
9381
- const targets = await new Promise((resolve5, reject) => {
10100
+ const targets = await new Promise((resolve6, reject) => {
9382
10101
  http3.get(`http://127.0.0.1:${options.port}/json`, (res) => {
9383
10102
  let data = "";
9384
10103
  res.on("data", (c) => data += c);
9385
10104
  res.on("end", () => {
9386
10105
  try {
9387
- resolve5(JSON.parse(data));
10106
+ resolve6(JSON.parse(data));
9388
10107
  } catch {
9389
10108
  reject(new Error("Invalid JSON"));
9390
10109
  }
@@ -9398,7 +10117,7 @@ cdp.command("screenshot").description("Capture IDE screenshot").option("-p, --po
9398
10117
  if (!target?.webSocketDebuggerUrl) throw new Error("No CDP target");
9399
10118
  const WebSocket4 = (await import("ws")).default;
9400
10119
  const ws = new WebSocket4(target.webSocketDebuggerUrl);
9401
- await new Promise((resolve5, reject) => {
10120
+ await new Promise((resolve6, reject) => {
9402
10121
  ws.on("open", () => {
9403
10122
  ws.send(JSON.stringify({ id: 1, method: "Page.captureScreenshot", params: { format: "jpeg", quality: 50 } }));
9404
10123
  });
@@ -9411,7 +10130,7 @@ cdp.command("screenshot").description("Capture IDE screenshot").option("-p, --po
9411
10130
  \u2713 Screenshot saved to ${options.output}
9412
10131
  `));
9413
10132
  ws.close();
9414
- resolve5();
10133
+ resolve6();
9415
10134
  }
9416
10135
  });
9417
10136
  ws.on("error", (e) => reject(e));
@@ -9427,10 +10146,10 @@ if (process.argv.length <= 2) {
9427
10146
  program.outputHelp();
9428
10147
  console.log();
9429
10148
  console.log(import_chalk4.default.gray(" Quick start:"));
9430
- console.log(import_chalk4.default.gray(" adhdev setup \u2014 First-time setup"));
9431
- console.log(import_chalk4.default.gray(" adhdev daemon \u2014 Start unified daemon"));
9432
- console.log(import_chalk4.default.gray(" adhdev launch claude \u2014 Launch CLI agent"));
9433
- console.log(import_chalk4.default.gray(" adhdev launch cursor \u2014 Launch Cursor with CDP"));
10149
+ console.log(import_chalk4.default.gray(" adhdev daemon \u2014 Start unified daemon (Required)"));
10150
+ console.log(import_chalk4.default.gray(" adhdev launch cursor \u2014 Launch IDE with CDP (e.g. cursor, windsurf)"));
10151
+ console.log(import_chalk4.default.gray(" adhdev launch claude \u2014 Launch CLI agent (e.g. gemini, claude)"));
10152
+ console.log(import_chalk4.default.gray(" adhdev setup \u2014 First-time setup & configuration"));
9434
10153
  console.log(import_chalk4.default.gray(" adhdev status \u2014 Check current setup"));
9435
10154
  console.log();
9436
10155
  } else {