adhdev 0.1.51 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/index.js +390 -40
  2. package/package.json +1 -1
  3. package/providers/_builtin/ide/antigravity/scripts/read_chat.js +22 -0
  4. package/providers/_builtin/ide/kiro/provider.js +25 -1
  5. package/providers/_builtin/ide/kiro/scripts/focus_editor.js +20 -0
  6. package/providers/_builtin/ide/kiro/scripts/open_panel.js +47 -0
  7. package/providers/_builtin/ide/kiro/scripts/resolve_action.js +54 -0
  8. package/providers/_builtin/ide/kiro/scripts/send_message.js +29 -0
  9. package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +39 -0
  10. package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +39 -0
  11. package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +21 -0
  12. package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +34 -0
  13. package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +68 -0
  14. package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +15 -0
  15. package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +15 -0
  16. package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +26 -0
  17. package/providers/_builtin/ide/pearai/provider.js +27 -1
  18. package/providers/_builtin/ide/pearai/scripts/focus_editor.js +20 -0
  19. package/providers/_builtin/ide/pearai/scripts/open_panel.js +46 -0
  20. package/providers/_builtin/ide/pearai/scripts/resolve_action.js +54 -0
  21. package/providers/_builtin/ide/pearai/scripts/send_message.js +29 -0
  22. package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +43 -0
  23. package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +35 -0
  24. package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +21 -0
  25. package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +92 -0
  26. package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +59 -0
  27. package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +36 -0
  28. package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +36 -0
  29. package/providers/_builtin/ide/trae/provider.js +22 -1
  30. package/providers/_builtin/ide/trae/scripts/focus_editor.js +20 -0
  31. package/providers/_builtin/ide/trae/scripts/list_chats.js +24 -0
  32. package/providers/_builtin/ide/trae/scripts/list_models.js +39 -0
  33. package/providers/_builtin/ide/trae/scripts/list_modes.js +39 -0
  34. package/providers/_builtin/ide/trae/scripts/new_session.js +30 -0
  35. package/providers/_builtin/ide/trae/scripts/open_panel.js +44 -0
  36. package/providers/_builtin/ide/trae/scripts/read_chat.js +113 -0
  37. package/providers/_builtin/ide/trae/scripts/resolve_action.js +54 -0
  38. package/providers/_builtin/ide/trae/scripts/send_message.js +19 -0
  39. package/providers/_builtin/ide/trae/scripts/set_mode.js +15 -0
  40. package/providers/_builtin/ide/trae/scripts/set_model.js +15 -0
  41. package/providers/_builtin/ide/trae/scripts/switch_session.js +23 -0
  42. package/providers/_builtin/ide/windsurf/provider.js +12 -0
  43. package/providers/_builtin/ide/windsurf/scripts/list_models.js +39 -0
  44. package/providers/_builtin/ide/windsurf/scripts/list_modes.js +39 -0
  45. package/providers/_builtin/ide/windsurf/scripts/set_mode.js +15 -0
  46. package/providers/_builtin/ide/windsurf/scripts/set_model.js +15 -0
package/dist/index.js CHANGED
@@ -1991,6 +1991,193 @@ var init_daemon_cdp = __esm({
1991
1991
  this.log(`[CDP] typeAndSend: sent "${text.substring(0, 50)}..."`);
1992
1992
  return true;
1993
1993
  }
1994
+ /**
1995
+ * 좌표 기반 typeAndSend — webview iframe 안의 입력 필드에 사용
1996
+ * selector 대신 직접 좌표를 받아 클릭+입력+Enter
1997
+ */
1998
+ async typeAndSendAt(x, y, text) {
1999
+ if (!this.isConnected) return false;
2000
+ await this.sendInternal("Input.dispatchMouseEvent", {
2001
+ type: "mousePressed",
2002
+ x: Math.round(x),
2003
+ y: Math.round(y),
2004
+ button: "left",
2005
+ clickCount: 1
2006
+ });
2007
+ await this.sendInternal("Input.dispatchMouseEvent", {
2008
+ type: "mouseReleased",
2009
+ x: Math.round(x),
2010
+ y: Math.round(y),
2011
+ button: "left",
2012
+ clickCount: 1
2013
+ });
2014
+ await new Promise((r) => setTimeout(r, 300));
2015
+ await this.sendInternal("Input.dispatchKeyEvent", {
2016
+ type: "rawKeyDown",
2017
+ key: "a",
2018
+ code: "KeyA",
2019
+ windowsVirtualKeyCode: 65,
2020
+ modifiers: 8
2021
+ // Meta
2022
+ });
2023
+ await this.sendInternal("Input.dispatchKeyEvent", {
2024
+ type: "keyUp",
2025
+ key: "a",
2026
+ code: "KeyA",
2027
+ windowsVirtualKeyCode: 65,
2028
+ modifiers: 8
2029
+ });
2030
+ await this.sendInternal("Input.dispatchKeyEvent", {
2031
+ type: "rawKeyDown",
2032
+ key: "Backspace",
2033
+ code: "Backspace",
2034
+ windowsVirtualKeyCode: 8
2035
+ });
2036
+ await this.sendInternal("Input.dispatchKeyEvent", {
2037
+ type: "keyUp",
2038
+ key: "Backspace",
2039
+ code: "Backspace",
2040
+ windowsVirtualKeyCode: 8
2041
+ });
2042
+ await new Promise((r) => setTimeout(r, 150));
2043
+ await this.sendInternal("Input.insertText", { text });
2044
+ await new Promise((r) => setTimeout(r, 200));
2045
+ await this.sendInternal("Input.dispatchKeyEvent", {
2046
+ type: "rawKeyDown",
2047
+ key: "Enter",
2048
+ code: "Enter",
2049
+ windowsVirtualKeyCode: 13,
2050
+ nativeVirtualKeyCode: 13
2051
+ });
2052
+ await this.sendInternal("Input.dispatchKeyEvent", {
2053
+ type: "keyUp",
2054
+ key: "Enter",
2055
+ code: "Enter",
2056
+ windowsVirtualKeyCode: 13,
2057
+ nativeVirtualKeyCode: 13
2058
+ });
2059
+ this.log(`[CDP] typeAndSendAt(${Math.round(x)},${Math.round(y)}): sent "${text.substring(0, 50)}..."`);
2060
+ return true;
2061
+ }
2062
+ /**
2063
+ * Webview iframe 내부에서 JS evaluate
2064
+ * Kiro, PearAI 등 채팅 UI가 webview iframe 안에 있는 IDE에서 사용.
2065
+ *
2066
+ * 1. browser WS로 Target.getTargets → vscode-webview iframe 찾기
2067
+ * 2. Target.attachToTarget → session 획득
2068
+ * 3. Page.getFrameTree → nested iframe 찾기
2069
+ * 4. Page.createIsolatedWorld → contextId 획득
2070
+ * 5. Runtime.evaluate → 결과 반환
2071
+ *
2072
+ * @param expression 실행할 JS 표현식
2073
+ * @param matchFn webview iframe URL 매칭 함수 (optional, 모든 webview 시도)
2074
+ * @returns evaluate 결과 또는 null
2075
+ */
2076
+ async evaluateInWebviewFrame(expression, matchFn) {
2077
+ if (!this._browserConnected) {
2078
+ await this.connectBrowserWs().catch(() => {
2079
+ });
2080
+ }
2081
+ if (!this.browserWs || !this._browserConnected) {
2082
+ this.log("[CDP] evaluateInWebviewFrame: no browser WS");
2083
+ return null;
2084
+ }
2085
+ const browserWs = this.browserWs;
2086
+ let msgId = this.browserMsgId;
2087
+ const sendWs = (method, params = {}, sessionId) => {
2088
+ return new Promise((resolve6, reject) => {
2089
+ const mid = msgId++;
2090
+ this.browserMsgId = msgId;
2091
+ const handler = (raw) => {
2092
+ try {
2093
+ const msg = JSON.parse(raw.toString());
2094
+ if (msg.id === mid) {
2095
+ browserWs.removeListener("message", handler);
2096
+ if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
2097
+ else resolve6(msg.result);
2098
+ }
2099
+ } catch {
2100
+ }
2101
+ };
2102
+ browserWs.on("message", handler);
2103
+ const payload = { id: mid, method, params };
2104
+ if (sessionId) payload.sessionId = sessionId;
2105
+ browserWs.send(JSON.stringify(payload));
2106
+ setTimeout(() => {
2107
+ browserWs.removeListener("message", handler);
2108
+ reject(new Error(`timeout: ${method}`));
2109
+ }, 1e4);
2110
+ });
2111
+ };
2112
+ try {
2113
+ const { targetInfos } = await sendWs("Target.getTargets");
2114
+ const webviewIframes = (targetInfos || []).filter(
2115
+ (t) => t.type === "iframe" && (t.url || "").includes("vscode-webview")
2116
+ );
2117
+ if (webviewIframes.length === 0) {
2118
+ this.log("[CDP] evaluateInWebviewFrame: no webview iframes found");
2119
+ return null;
2120
+ }
2121
+ for (const iframe of webviewIframes) {
2122
+ let sessionId = null;
2123
+ try {
2124
+ const attached = await sendWs("Target.attachToTarget", {
2125
+ targetId: iframe.targetId,
2126
+ flatten: true
2127
+ });
2128
+ sessionId = attached.sessionId;
2129
+ const { frameTree } = await sendWs("Page.getFrameTree", {}, sessionId);
2130
+ const childFrame = frameTree?.childFrames?.[0]?.frame;
2131
+ if (!childFrame) {
2132
+ await sendWs("Target.detachFromTarget", { sessionId }).catch(() => {
2133
+ });
2134
+ continue;
2135
+ }
2136
+ const { executionContextId } = await sendWs("Page.createIsolatedWorld", {
2137
+ frameId: childFrame.id,
2138
+ worldName: "adhdev-eval",
2139
+ grantUniveralAccess: true
2140
+ }, sessionId);
2141
+ if (matchFn) {
2142
+ const checkResult = await sendWs("Runtime.evaluate", {
2143
+ expression: `document.documentElement?.outerHTML?.substring(0, 500000) || ''`,
2144
+ returnByValue: true,
2145
+ contextId: executionContextId
2146
+ }, sessionId);
2147
+ const bodyText = checkResult?.result?.value || "";
2148
+ if (!matchFn(bodyText)) {
2149
+ await sendWs("Target.detachFromTarget", { sessionId }).catch(() => {
2150
+ });
2151
+ continue;
2152
+ }
2153
+ }
2154
+ const result = await sendWs("Runtime.evaluate", {
2155
+ expression,
2156
+ returnByValue: true,
2157
+ contextId: executionContextId
2158
+ }, sessionId);
2159
+ await sendWs("Target.detachFromTarget", { sessionId }).catch(() => {
2160
+ });
2161
+ const value = result?.result?.value;
2162
+ if (value != null) {
2163
+ this.log(`[CDP] evaluateInWebviewFrame: success in ${iframe.targetId.substring(0, 12)}`);
2164
+ return typeof value === "string" ? value : JSON.stringify(value);
2165
+ }
2166
+ } catch (e) {
2167
+ if (sessionId) {
2168
+ await sendWs("Target.detachFromTarget", { sessionId }).catch(() => {
2169
+ });
2170
+ }
2171
+ this.log(`[CDP] evaluateInWebviewFrame: error in ${iframe.targetId.substring(0, 12)}: ${e.message}`);
2172
+ }
2173
+ }
2174
+ this.log("[CDP] evaluateInWebviewFrame: no matching webview found");
2175
+ return null;
2176
+ } catch (e) {
2177
+ this.log(`[CDP] evaluateInWebviewFrame error: ${e.message}`);
2178
+ return null;
2179
+ }
2180
+ }
1994
2181
  // ─── Agent Webview Multi-Session ─────────────────────────
1995
2182
  async discoverAgentWebviews() {
1996
2183
  if (!this.isConnected) return [];
@@ -3306,7 +3493,15 @@ var init_dev_server = __esm({
3306
3493
  this.json(res, 500, { error: "Script function returned null" });
3307
3494
  return;
3308
3495
  }
3309
- const raw = await cdp2.evaluate(scriptCode, 3e4);
3496
+ const isWebviewScript = scriptName.toLowerCase().includes("webview");
3497
+ let raw;
3498
+ if (isWebviewScript) {
3499
+ const matchText = provider2.webviewMatchText;
3500
+ const matchFn = matchText ? (body2) => body2.includes(matchText) : void 0;
3501
+ raw = await cdp2.evaluateInWebviewFrame(scriptCode, matchFn);
3502
+ } else {
3503
+ raw = await cdp2.evaluate(scriptCode, 3e4);
3504
+ }
3310
3505
  let result = raw;
3311
3506
  if (typeof raw === "string") {
3312
3507
  try {
@@ -4286,8 +4481,11 @@ var init_daemon_commands = __esm({
4286
4481
  let raw = args._targetInstance;
4287
4482
  const ideMatch = raw.match(/:ide:(.+)$/);
4288
4483
  const cliMatch = raw.match(/:cli:(.+)$/);
4484
+ const acpMatch = raw.match(/:acp:(.+)$/);
4289
4485
  if (ideMatch) raw = ideMatch[1];
4290
4486
  else if (cliMatch) raw = cliMatch[1];
4487
+ else if (acpMatch) raw = acpMatch[1];
4488
+ if (raw.startsWith("acp_")) raw = raw.substring(4);
4291
4489
  const lastUnderscore = raw.lastIndexOf("_");
4292
4490
  if (lastUnderscore > 0) return raw.substring(0, lastUnderscore);
4293
4491
  }
@@ -4554,15 +4752,44 @@ var init_daemon_commands = __esm({
4554
4752
  }
4555
4753
  const cdp2 = this.getCdp();
4556
4754
  if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
4755
+ const webviewScript = this.getProviderScript("webviewReadChat") || this.getProviderScript("webview_read_chat");
4756
+ if (webviewScript) {
4757
+ try {
4758
+ const matchText = provider2?.webviewMatchText;
4759
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
4760
+ const raw = await cdp2.evaluateInWebviewFrame(webviewScript, matchFn);
4761
+ if (raw) {
4762
+ let parsed = raw;
4763
+ if (typeof parsed === "string") {
4764
+ try {
4765
+ parsed = JSON.parse(parsed);
4766
+ } catch {
4767
+ }
4768
+ }
4769
+ if (parsed && typeof parsed === "object") {
4770
+ _log(`Webview OK: ${parsed.messages?.length || 0} msgs`);
4771
+ return { success: true, ...parsed };
4772
+ }
4773
+ }
4774
+ } catch (e) {
4775
+ _log(`Webview readChat error: ${e.message}`);
4776
+ }
4777
+ return { success: true, messages: [], status: "idle" };
4778
+ }
4557
4779
  const script = this.getProviderScript("readChat") || this.getProviderScript("read_chat");
4558
4780
  if (script) {
4559
4781
  try {
4560
4782
  const result = await cdp2.evaluate(script, 5e4);
4561
- if (result && typeof result === "object" && result.messages?.length > 0) {
4562
- _log(`OK: ${result.messages?.length} msgs`);
4563
- return { success: true, ...result };
4783
+ let parsed = result;
4784
+ if (typeof parsed === "string") {
4785
+ try {
4786
+ parsed = JSON.parse(parsed);
4787
+ } catch {
4788
+ }
4564
4789
  }
4565
- if (result && typeof result === "object") {
4790
+ if (parsed && typeof parsed === "object" && parsed.messages?.length > 0) {
4791
+ _log(`OK: ${parsed.messages?.length} msgs`);
4792
+ return { success: true, ...parsed };
4566
4793
  }
4567
4794
  } catch (e) {
4568
4795
  console.log(`[read_chat] Script error: ${e.message}`);
@@ -4652,10 +4879,26 @@ var init_daemon_commands = __esm({
4652
4879
  return { success: true, sent: true, method: "script" };
4653
4880
  }
4654
4881
  if (parsed?.needsTypeAndSend && parsed?.selector) {
4655
- const sent = await targetCdp.typeAndSend(parsed.selector, text);
4656
- if (sent) {
4657
- _log(`typeAndSend(script.selector=${parsed.selector}) success`);
4658
- return { success: true, sent: true, method: "typeAndSend-script" };
4882
+ try {
4883
+ const sent = await targetCdp.typeAndSend(parsed.selector, text);
4884
+ if (sent) {
4885
+ _log(`typeAndSend(script.selector=${parsed.selector}) success`);
4886
+ return { success: true, sent: true, method: "typeAndSend-script" };
4887
+ }
4888
+ } catch (e) {
4889
+ _log(`typeAndSend(script.selector) failed: ${e.message}`);
4890
+ }
4891
+ }
4892
+ if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
4893
+ try {
4894
+ const { x, y } = parsed.clickCoords;
4895
+ const sent = await targetCdp.typeAndSendAt(x, y, text);
4896
+ if (sent) {
4897
+ _log(`typeAndSendAt(${x},${y}) success`);
4898
+ return { success: true, sent: true, method: "typeAndSendAt-script" };
4899
+ }
4900
+ } catch (e) {
4901
+ _log(`typeAndSendAt failed: ${e.message}`);
4659
4902
  }
4660
4903
  }
4661
4904
  } catch (e) {
@@ -4676,6 +4919,27 @@ var init_daemon_commands = __esm({
4676
4919
  console.log(`[list_chats] Extension error: ${e.message}`);
4677
4920
  }
4678
4921
  }
4922
+ try {
4923
+ const webviewScript = this.getProviderScript("webviewListSessions") || this.getProviderScript("webview_list_sessions");
4924
+ if (webviewScript) {
4925
+ const matchText = provider2?.webviewMatchText;
4926
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
4927
+ const raw = await this.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
4928
+ let parsed = raw;
4929
+ if (typeof parsed === "string") {
4930
+ try {
4931
+ parsed = JSON.parse(parsed);
4932
+ } catch {
4933
+ }
4934
+ }
4935
+ if (parsed?.sessions) {
4936
+ console.log(`[list_chats] Webview OK: ${parsed.sessions.length} chats`);
4937
+ return { success: true, chats: parsed.sessions };
4938
+ }
4939
+ }
4940
+ } catch (e) {
4941
+ console.log(`[list_chats] Webview error: ${e.message}`);
4942
+ }
4679
4943
  try {
4680
4944
  const evalResult = await this.evaluateProviderScript("listSessions");
4681
4945
  if (evalResult) {
@@ -4702,6 +4966,17 @@ var init_daemon_commands = __esm({
4702
4966
  const ok = await this.agentStream.newAgentSession(this.getCdp(), provider2.type, this._currentIdeType);
4703
4967
  return { success: ok };
4704
4968
  }
4969
+ try {
4970
+ const webviewScript = this.getProviderScript("webviewNewSession") || this.getProviderScript("webview_new_session");
4971
+ if (webviewScript) {
4972
+ const matchText = provider2?.webviewMatchText;
4973
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
4974
+ const raw = await this.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
4975
+ if (raw) return { success: true, result: raw };
4976
+ }
4977
+ } catch (e) {
4978
+ return { success: false, error: `webviewNewSession failed: ${e.message}` };
4979
+ }
4705
4980
  try {
4706
4981
  const evalResult = await this.evaluateProviderScript("newSession");
4707
4982
  if (evalResult) return { success: true };
@@ -4722,6 +4997,17 @@ var init_daemon_commands = __esm({
4722
4997
  }
4723
4998
  const cdp2 = this.getCdp(ideType);
4724
4999
  if (!cdp2?.isConnected) return { success: false, error: "CDP not connected" };
5000
+ try {
5001
+ const webviewScript = this.getProviderScript("webviewSwitchSession", { SESSION_ID: JSON.stringify(sessionId) });
5002
+ if (webviewScript) {
5003
+ const matchText = provider2?.webviewMatchText;
5004
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
5005
+ const raw = await cdp2.evaluateInWebviewFrame?.(webviewScript, matchFn);
5006
+ if (raw) return { success: true, result: raw };
5007
+ }
5008
+ } catch (e) {
5009
+ return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
5010
+ }
4725
5011
  const script = this.getProviderScript("switchSession", { SESSION_ID: JSON.stringify(sessionId) }) || this.getProviderScript("switch_session", { SESSION_ID: JSON.stringify(sessionId) });
4726
5012
  if (!script) return { success: false, error: "switch_session script not available" };
4727
5013
  try {
@@ -4822,6 +5108,36 @@ var init_daemon_commands = __esm({
4822
5108
  );
4823
5109
  return { success: ok };
4824
5110
  }
5111
+ if (provider2?.scripts?.webviewResolveAction || provider2?.scripts?.webview_resolve_action) {
5112
+ const script = this.getProviderScript("webviewResolveAction", { action, button, buttonText: button }) || this.getProviderScript("webview_resolve_action", { action, button, buttonText: button });
5113
+ if (script) {
5114
+ const cdp2 = this.getCdp();
5115
+ if (cdp2?.isConnected) {
5116
+ try {
5117
+ const matchText = provider2?.webviewMatchText;
5118
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
5119
+ const raw = await cdp2.evaluateInWebviewFrame?.(script, matchFn);
5120
+ let result = raw;
5121
+ if (typeof raw === "string") {
5122
+ try {
5123
+ result = JSON.parse(raw);
5124
+ } catch {
5125
+ }
5126
+ }
5127
+ console.log(`[resolveAction] webview script result:`, JSON.stringify(result));
5128
+ if (result?.resolved) {
5129
+ return { success: true, clicked: result.clicked };
5130
+ }
5131
+ if (result?.found && result.x != null && result.y != null) {
5132
+ console.log(`[resolveAction] Webview coordinate click not fully supported via CDP. Click directly in script.`);
5133
+ }
5134
+ if (result?.found || result?.resolved) return { success: true };
5135
+ } catch (e) {
5136
+ return { success: false, error: `webviewResolveAction failed: ${e.message}` };
5137
+ }
5138
+ }
5139
+ }
5140
+ }
4825
5141
  if (provider2?.scripts?.resolveAction) {
4826
5142
  const script = provider2.scripts.resolveAction({ action, button, buttonText: button });
4827
5143
  if (script) {
@@ -5274,11 +5590,14 @@ var init_daemon_commands = __esm({
5274
5590
  if (!loader) return { success: false, error: "ProviderLoader not initialized" };
5275
5591
  const provider2 = loader.get(agentType);
5276
5592
  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` };
5593
+ const isWebviewScript = provider2.category === "ide" && ["webviewListModels", "webviewSetModel", "webviewListModes", "webviewSetMode"].includes(`webview${scriptName.charAt(0).toUpperCase() + scriptName.slice(1)}`);
5594
+ const actualScriptName = isWebviewScript ? `webview${scriptName.charAt(0).toUpperCase() + scriptName.slice(1)}` : scriptName;
5595
+ if (!provider2.scripts?.[actualScriptName]) {
5596
+ return { success: false, error: `Script '${actualScriptName}' not available for ${agentType}` };
5597
+ }
5598
+ const scriptFn = provider2.scripts[actualScriptName];
5599
+ const scriptCode = scriptFn(args);
5600
+ if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
5282
5601
  const cdpKey = provider2.category === "ide" ? this._currentIdeType || agentType : this._currentIdeType || ideType;
5283
5602
  console.log(`[ExtScript] provider=${provider2.type} category=${provider2.category} cdpKey=${cdpKey}`);
5284
5603
  const cdp2 = this.getCdp(cdpKey);
@@ -5297,9 +5616,13 @@ var init_daemon_commands = __esm({
5297
5616
  if (!targetSessionId) {
5298
5617
  return { success: false, error: `No active session found for ${agentType}` };
5299
5618
  }
5300
- result = await cdp2.evaluateInSession(targetSessionId, script);
5619
+ result = await cdp2.evaluateInSession(targetSessionId, scriptCode);
5620
+ } else if (isWebviewScript && cdp2.evaluateInWebviewFrame) {
5621
+ const matchText = provider2.webviewMatchText;
5622
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
5623
+ result = await cdp2.evaluateInWebviewFrame(scriptCode, matchFn);
5301
5624
  } else {
5302
- result = await cdp2.evaluate(script, 3e4);
5625
+ result = await cdp2.evaluate(scriptCode, 3e4);
5303
5626
  }
5304
5627
  if (typeof result === "string") {
5305
5628
  try {
@@ -6074,9 +6397,10 @@ var init_daemon_status = __esm({
6074
6397
  const exts = (s.extensions || []).length;
6075
6398
  return `${s.type}(${s.status},${msgs}msg,${exts}ext${s.currentModel ? ",model=" + s.currentModel : ""})`;
6076
6399
  }).join(", ");
6077
- const cliSummary = [...cliStates, ...acpStates].map((s) => `${s.type}(${s.status})`).join(", ");
6400
+ const cliSummary = cliStates.map((s) => `${s.type}(${s.status})`).join(", ");
6401
+ const acpSummary = acpStates.map((s) => `${s.type}(${s.status})`).join(", ");
6078
6402
  const logLevel = opts?.p2pOnly ? "debug" : "info";
6079
- LOG[logLevel]("StatusReport", `\u2192${target} IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length + acpStates.length} [${cliSummary}]`);
6403
+ LOG[logLevel]("StatusReport", `\u2192${target} IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`);
6080
6404
  const managedIdes = ideStates.map((s) => ({
6081
6405
  ideType: s.type,
6082
6406
  ideVersion: "",
@@ -6151,19 +6475,16 @@ var init_daemon_status = __esm({
6151
6475
  workingDir: s.workingDir || "",
6152
6476
  activeChat: s.activeChat
6153
6477
  }));
6154
- for (const s of acpStates) {
6155
- managedClis.push({
6156
- id: s.instanceId,
6157
- cliType: s.type,
6158
- cliName: s.name,
6159
- status: s.status,
6160
- mode: "chat",
6161
- workingDir: s.workingDir || "",
6162
- activeChat: s.activeChat,
6163
- currentModel: s.currentModel,
6164
- isAcp: true
6165
- });
6166
- }
6478
+ const managedAcps = acpStates.map((s) => ({
6479
+ id: s.instanceId,
6480
+ acpType: s.type,
6481
+ acpName: s.name,
6482
+ status: s.status,
6483
+ mode: "chat",
6484
+ workingDir: s.workingDir || "",
6485
+ activeChat: s.activeChat,
6486
+ currentModel: s.currentModel
6487
+ }));
6167
6488
  const extSummary = localServer?.getLatestExtensionData() || {
6168
6489
  activeFile: null,
6169
6490
  workspaceFolders: [],
@@ -6187,6 +6508,7 @@ var init_daemon_status = __esm({
6187
6508
  },
6188
6509
  managedIdes,
6189
6510
  managedClis,
6511
+ managedAcps,
6190
6512
  detectedIdes: this.deps.detectedIdes.map((ide) => ({ ...ide, type: ide.id })),
6191
6513
  p2p: {
6192
6514
  available: p2p?.isAvailable || false,
@@ -7521,7 +7843,14 @@ var init_daemon_cli = __esm({
7521
7843
  sendMessage: async (text) => {
7522
7844
  acpInstance.onEvent("send_message", { text });
7523
7845
  },
7524
- getStatus: () => ({ status: "idle", messages: [], activeModal: null }),
7846
+ getStatus: () => {
7847
+ const state = acpInstance.getState();
7848
+ return {
7849
+ status: state.status,
7850
+ messages: state.activeChat?.messages || [],
7851
+ activeModal: state.activeChat?.activeModal || null
7852
+ };
7853
+ },
7525
7854
  setOnStatusChange: () => {
7526
7855
  },
7527
7856
  setOnPtyData: () => {
@@ -8130,15 +8459,36 @@ var init_ide_provider_instance = __esm({
8130
8459
  async readChat() {
8131
8460
  const { cdp: cdp2 } = this.context;
8132
8461
  if (!cdp2?.isConnected) return;
8133
- const readChatScript = this.getReadChatScript();
8134
- if (!readChatScript) return;
8135
8462
  try {
8136
- let raw = await cdp2.evaluate(readChatScript, 3e4);
8137
- if (typeof raw === "string") {
8138
- try {
8139
- raw = JSON.parse(raw);
8140
- } catch {
8141
- return;
8463
+ let raw = null;
8464
+ const webviewFn = this.provider.scripts?.webviewReadChat;
8465
+ if (typeof webviewFn === "function" && cdp2.evaluateInWebviewFrame) {
8466
+ const webviewScript = webviewFn();
8467
+ if (webviewScript) {
8468
+ const matchText = this.provider.webviewMatchText;
8469
+ const matchFn = matchText ? (body) => body.includes(matchText) : void 0;
8470
+ const webviewRaw = await cdp2.evaluateInWebviewFrame(webviewScript, matchFn);
8471
+ if (webviewRaw) {
8472
+ raw = typeof webviewRaw === "string" ? (() => {
8473
+ try {
8474
+ return JSON.parse(webviewRaw);
8475
+ } catch {
8476
+ return null;
8477
+ }
8478
+ })() : webviewRaw;
8479
+ }
8480
+ }
8481
+ }
8482
+ if (!raw) {
8483
+ const readChatScript = this.getReadChatScript();
8484
+ if (!readChatScript) return;
8485
+ raw = await cdp2.evaluate(readChatScript, 3e4);
8486
+ if (typeof raw === "string") {
8487
+ try {
8488
+ raw = JSON.parse(raw);
8489
+ } catch {
8490
+ return;
8491
+ }
8142
8492
  }
8143
8493
  }
8144
8494
  if (!raw || typeof raw !== "object") return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adhdev",
3
- "version": "0.1.51",
3
+ "version": "0.1.53",
4
4
  "description": "ADHDev CLI — Detect, install and configure your IDE + AI agent extensions",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -229,6 +229,28 @@
229
229
  }
230
230
  }
231
231
  }
232
+ // C: footer 기반 사용량/quota 다이얼로그 (Dismiss / See Plans / Enable Overages 등)
233
+ // <footer> 요소가 conv 안에 존재하고 2개 이상 버튼이 있으면 사용자 액션이 필요한 카드로 판단
234
+ if (!activeModal) {
235
+ const footers = Array.from(conv.querySelectorAll('footer')).filter(f => f.offsetWidth > 0 && f.offsetHeight > 0);
236
+ for (const footer of footers) {
237
+ const footerBtns = Array.from(footer.querySelectorAll('button, a')).filter(b => b.offsetWidth > 0);
238
+ if (footerBtns.length >= 2) {
239
+ // 카드 컨테이너: footer 상위에서 충분한 높이를 가진 첫 번째 요소
240
+ let card = footer.parentElement;
241
+ for (let up = 0; up < 4 && card; up++) {
242
+ if (card.offsetHeight > 60) break;
243
+ card = card.parentElement;
244
+ }
245
+ const msg = card ? (card.innerText || '').trim().slice(0, 300) : '';
246
+ const btnTexts = footerBtns.map(b => (b.innerText || '').trim()).filter(t => t.length > 0 && t.length < 40);
247
+ if (btnTexts.length >= 2) {
248
+ activeModal = { message: msg, buttons: btnTexts, width: card ? card.offsetWidth : 300, height: card ? card.offsetHeight : 100 };
249
+ break;
250
+ }
251
+ }
252
+ }
253
+ }
232
254
  // 모달이 감지되면 status를 waiting_approval로 변경
233
255
  if (activeModal) status = 'waiting_approval';
234
256
  } catch (e) { activeModal = null; }
@@ -45,8 +45,11 @@ module.exports = {
45
45
  inputMethod: 'cdp-type-and-send',
46
46
  inputSelector: '[contenteditable="true"][role="textbox"]',
47
47
 
48
+ // Kiro의 채팅 UI는 webview iframe 내부
49
+ webviewMatchText: 'kiro-chat',
50
+
48
51
  scripts: {
49
- readChat() { return loadScript('read_chat.js'); },
52
+ webviewReadChat() { return loadScript('webview_read_chat.js'); },
50
53
  sendMessage(text) {
51
54
  const s = loadScript('send_message.js');
52
55
  return s ? s.replace(/\$\{\s*MESSAGE\s*\}/g, JSON.stringify(text)) : null;
@@ -58,5 +61,26 @@ module.exports = {
58
61
  const s = loadScript('resolve_action.js');
59
62
  return s ? s.replace(/\$\{\s*BUTTON_TEXT\s*\}/g, JSON.stringify(buttonText)) : null;
60
63
  },
64
+ openPanel() { return loadScript('open_panel.js'); },
65
+ focusEditor() { return loadScript('focus_editor.js'); },
66
+ // 세션 관리 (webview)
67
+ webviewListSessions() { return loadScript('webview_list_sessions.js'); },
68
+ webviewNewSession() { return loadScript('webview_new_session.js'); },
69
+ webviewSwitchSession(sessionId) {
70
+ const s = loadScript('webview_switch_session.js');
71
+ return s ? s.replace(/\$\{\s*SESSION_ID\s*\}/g, JSON.stringify(sessionId)) : null;
72
+ },
73
+ webviewListModels() { return loadScript('webview_list_models.js'); },
74
+ webviewSetModel(params) {
75
+ const model = typeof params === 'string' ? params : params?.model;
76
+ const s = loadScript('webview_set_model.js');
77
+ return s ? s.replace(/\$\{\s*MODEL\s*\}/g, JSON.stringify(model)) : null;
78
+ },
79
+ webviewListModes() { return loadScript('webview_list_modes.js'); },
80
+ webviewSetMode(params) {
81
+ const mode = typeof params === 'string' ? params : params?.mode;
82
+ const s = loadScript('webview_set_mode.js');
83
+ return s ? s.replace(/\$\{\s*MODE\s*\}/g, JSON.stringify(mode)) : null;
84
+ },
61
85
  },
62
86
  };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Cursor v1 — focus_editor
3
+ *
4
+ * CURSOR.md 4-5: 셀렉터 우선순위
5
+ * [contenteditable="true"][role="textbox"]
6
+ * → .chat-input textarea
7
+ * → .composer-input
8
+ * → textarea
9
+ *
10
+ * 최종 확인: 2026-03-06
11
+ */
12
+ (() => {
13
+ const editor = document.querySelector('[contenteditable="true"][role="textbox"]')
14
+ || document.querySelector('.chat-input textarea')
15
+ || document.querySelector('.composer-input')
16
+ || document.querySelector('textarea.native-input')
17
+ || document.querySelector('textarea');
18
+ if (editor) { editor.focus(); return 'focused'; }
19
+ return 'no editor found';
20
+ })()