@adhdev/daemon-core 0.5.3

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 (217) hide show
  1. package/dist/index.d.ts +2662 -0
  2. package/dist/index.js +11341 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +48 -0
  5. package/providers/_builtin/.github/workflows/generate-registry.yml +57 -0
  6. package/providers/_builtin/COMPATIBILITY.md +217 -0
  7. package/providers/_builtin/CONTRIBUTING.md +200 -0
  8. package/providers/_builtin/README.md +119 -0
  9. package/providers/_builtin/_helpers/index.js +188 -0
  10. package/providers/_builtin/acp/agentpool/provider.json +54 -0
  11. package/providers/_builtin/acp/amp/provider.json +52 -0
  12. package/providers/_builtin/acp/auggie/provider.json +57 -0
  13. package/providers/_builtin/acp/autodev/provider.json +54 -0
  14. package/providers/_builtin/acp/autohand/provider.json +52 -0
  15. package/providers/_builtin/acp/blackbox-ai/provider.json +54 -0
  16. package/providers/_builtin/acp/claude-agent/provider.json +57 -0
  17. package/providers/_builtin/acp/cline-acp/provider.json +54 -0
  18. package/providers/_builtin/acp/codebuddy/provider.json +54 -0
  19. package/providers/_builtin/acp/codex-cli/provider.json +57 -0
  20. package/providers/_builtin/acp/corust-agent/provider.json +52 -0
  21. package/providers/_builtin/acp/crow-cli/provider.json +54 -0
  22. package/providers/_builtin/acp/cursor-acp/provider.json +54 -0
  23. package/providers/_builtin/acp/deepagents/provider.json +52 -0
  24. package/providers/_builtin/acp/dimcode/provider.json +54 -0
  25. package/providers/_builtin/acp/docker-cagent/provider.json +57 -0
  26. package/providers/_builtin/acp/factory-droid/provider.json +60 -0
  27. package/providers/_builtin/acp/fast-agent/provider.json +52 -0
  28. package/providers/_builtin/acp/gemini-cli/provider.json +114 -0
  29. package/providers/_builtin/acp/github-copilot/provider.json +54 -0
  30. package/providers/_builtin/acp/goose/provider.json +57 -0
  31. package/providers/_builtin/acp/junie/provider.json +52 -0
  32. package/providers/_builtin/acp/kilo/provider.json +54 -0
  33. package/providers/_builtin/acp/kimi-cli/provider.json +57 -0
  34. package/providers/_builtin/acp/minion-code/provider.json +52 -0
  35. package/providers/_builtin/acp/mistral-vibe/provider.json +57 -0
  36. package/providers/_builtin/acp/nova/provider.json +54 -0
  37. package/providers/_builtin/acp/openclaw/provider.json +54 -0
  38. package/providers/_builtin/acp/opencode/provider.json +52 -0
  39. package/providers/_builtin/acp/openhands/provider.json +54 -0
  40. package/providers/_builtin/acp/pi-acp/provider.json +52 -0
  41. package/providers/_builtin/acp/qoder/provider.json +54 -0
  42. package/providers/_builtin/acp/qwen-code/provider.json +60 -0
  43. package/providers/_builtin/acp/stakpak/provider.json +54 -0
  44. package/providers/_builtin/acp/vtcode/provider.json +54 -0
  45. package/providers/_builtin/cli/claude-cli/provider.json +100 -0
  46. package/providers/_builtin/cli/codex-cli/provider.json +89 -0
  47. package/providers/_builtin/cli/gemini-cli/provider.json +93 -0
  48. package/providers/_builtin/docs/CDP_SELECTOR_GUIDE.md +370 -0
  49. package/providers/_builtin/docs/PROVIDER_GUIDE.md +916 -0
  50. package/providers/_builtin/extension/cline/provider.json +35 -0
  51. package/providers/_builtin/extension/cline/scripts/focus_editor.js +48 -0
  52. package/providers/_builtin/extension/cline/scripts/list_chats.js +100 -0
  53. package/providers/_builtin/extension/cline/scripts/list_models.js +43 -0
  54. package/providers/_builtin/extension/cline/scripts/list_modes.js +35 -0
  55. package/providers/_builtin/extension/cline/scripts/new_session.js +85 -0
  56. package/providers/_builtin/extension/cline/scripts/open_panel.js +25 -0
  57. package/providers/_builtin/extension/cline/scripts/read_chat.js +257 -0
  58. package/providers/_builtin/extension/cline/scripts/resolve_action.js +83 -0
  59. package/providers/_builtin/extension/cline/scripts/send_message.js +95 -0
  60. package/providers/_builtin/extension/cline/scripts/set_mode.js +36 -0
  61. package/providers/_builtin/extension/cline/scripts/set_model.js +36 -0
  62. package/providers/_builtin/extension/cline/scripts/switch_session.js +206 -0
  63. package/providers/_builtin/extension/cline/scripts.js +73 -0
  64. package/providers/_builtin/extension/roo-code/provider.json +35 -0
  65. package/providers/_builtin/extension/roo-code/scripts.js +659 -0
  66. package/providers/_builtin/ide/antigravity/provider.json +68 -0
  67. package/providers/_builtin/ide/antigravity/scripts/1.106/focus_editor.js +20 -0
  68. package/providers/_builtin/ide/antigravity/scripts/1.106/list_chats.js +137 -0
  69. package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +38 -0
  70. package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +48 -0
  71. package/providers/_builtin/ide/antigravity/scripts/1.106/new_session.js +75 -0
  72. package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +262 -0
  73. package/providers/_builtin/ide/antigravity/scripts/1.106/resolve_action.js +68 -0
  74. package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +57 -0
  75. package/providers/_builtin/ide/antigravity/scripts/1.106/send_message.js +56 -0
  76. package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +34 -0
  77. package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +47 -0
  78. package/providers/_builtin/ide/antigravity/scripts/1.106/switch_session.js +114 -0
  79. package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +20 -0
  80. package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +137 -0
  81. package/providers/_builtin/ide/antigravity/scripts/1.107/list_models.js +61 -0
  82. package/providers/_builtin/ide/antigravity/scripts/1.107/list_modes.js +72 -0
  83. package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +75 -0
  84. package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +262 -0
  85. package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +68 -0
  86. package/providers/_builtin/ide/antigravity/scripts/1.107/scripts.js +67 -0
  87. package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +56 -0
  88. package/providers/_builtin/ide/antigravity/scripts/1.107/set_mode.js +67 -0
  89. package/providers/_builtin/ide/antigravity/scripts/1.107/set_model.js +72 -0
  90. package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +114 -0
  91. package/providers/_builtin/ide/cursor/provider.json +70 -0
  92. package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +30 -0
  93. package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +13 -0
  94. package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +78 -0
  95. package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +40 -0
  96. package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +23 -0
  97. package/providers/_builtin/ide/cursor/scripts/0.49/list_sessions.js +42 -0
  98. package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +20 -0
  99. package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +23 -0
  100. package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +75 -0
  101. package/providers/_builtin/ide/cursor/scripts/0.49/resolve_action.js +19 -0
  102. package/providers/_builtin/ide/cursor/scripts/0.49/scripts.js +78 -0
  103. package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +23 -0
  104. package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +38 -0
  105. package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +81 -0
  106. package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +28 -0
  107. package/providers/_builtin/ide/kiro/provider.json +67 -0
  108. package/providers/_builtin/ide/kiro/scripts/focus_editor.js +20 -0
  109. package/providers/_builtin/ide/kiro/scripts/open_panel.js +47 -0
  110. package/providers/_builtin/ide/kiro/scripts/resolve_action.js +54 -0
  111. package/providers/_builtin/ide/kiro/scripts/send_message.js +29 -0
  112. package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +39 -0
  113. package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +39 -0
  114. package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +21 -0
  115. package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +34 -0
  116. package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +68 -0
  117. package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +72 -0
  118. package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +15 -0
  119. package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +15 -0
  120. package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +26 -0
  121. package/providers/_builtin/ide/kiro/scripts.js +62 -0
  122. package/providers/_builtin/ide/pearai/provider.json +67 -0
  123. package/providers/_builtin/ide/pearai/scripts/focus_editor.js +20 -0
  124. package/providers/_builtin/ide/pearai/scripts/list_sessions.js +38 -0
  125. package/providers/_builtin/ide/pearai/scripts/new_session.js +55 -0
  126. package/providers/_builtin/ide/pearai/scripts/open_panel.js +46 -0
  127. package/providers/_builtin/ide/pearai/scripts/resolve_action.js +54 -0
  128. package/providers/_builtin/ide/pearai/scripts/send_message.js +29 -0
  129. package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +43 -0
  130. package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +35 -0
  131. package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +62 -0
  132. package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +49 -0
  133. package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +92 -0
  134. package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +59 -0
  135. package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +72 -0
  136. package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +36 -0
  137. package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +36 -0
  138. package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +34 -0
  139. package/providers/_builtin/ide/pearai/scripts.js +74 -0
  140. package/providers/_builtin/ide/trae/provider.json +66 -0
  141. package/providers/_builtin/ide/trae/scripts/focus_editor.js +20 -0
  142. package/providers/_builtin/ide/trae/scripts/list_chats.js +24 -0
  143. package/providers/_builtin/ide/trae/scripts/list_models.js +39 -0
  144. package/providers/_builtin/ide/trae/scripts/list_modes.js +39 -0
  145. package/providers/_builtin/ide/trae/scripts/new_session.js +30 -0
  146. package/providers/_builtin/ide/trae/scripts/open_panel.js +44 -0
  147. package/providers/_builtin/ide/trae/scripts/read_chat.js +113 -0
  148. package/providers/_builtin/ide/trae/scripts/resolve_action.js +54 -0
  149. package/providers/_builtin/ide/trae/scripts/send_message.js +69 -0
  150. package/providers/_builtin/ide/trae/scripts/set_mode.js +15 -0
  151. package/providers/_builtin/ide/trae/scripts/set_model.js +15 -0
  152. package/providers/_builtin/ide/trae/scripts/switch_session.js +23 -0
  153. package/providers/_builtin/ide/trae/scripts.js +57 -0
  154. package/providers/_builtin/ide/vscode/provider.json +64 -0
  155. package/providers/_builtin/ide/vscode-insiders/provider.json +62 -0
  156. package/providers/_builtin/ide/vscodium/provider.json +63 -0
  157. package/providers/_builtin/ide/windsurf/provider.json +53 -0
  158. package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +30 -0
  159. package/providers/_builtin/ide/windsurf/scripts/list_chats.js +117 -0
  160. package/providers/_builtin/ide/windsurf/scripts/list_models.js +39 -0
  161. package/providers/_builtin/ide/windsurf/scripts/list_modes.js +39 -0
  162. package/providers/_builtin/ide/windsurf/scripts/new_session.js +69 -0
  163. package/providers/_builtin/ide/windsurf/scripts/open_panel.js +58 -0
  164. package/providers/_builtin/ide/windsurf/scripts/read_chat.js +297 -0
  165. package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +68 -0
  166. package/providers/_builtin/ide/windsurf/scripts/send_message.js +87 -0
  167. package/providers/_builtin/ide/windsurf/scripts/set_mode.js +15 -0
  168. package/providers/_builtin/ide/windsurf/scripts/set_model.js +15 -0
  169. package/providers/_builtin/ide/windsurf/scripts/switch_session.js +58 -0
  170. package/providers/_builtin/ide/windsurf/scripts.js +57 -0
  171. package/providers/_builtin/registry.json +266 -0
  172. package/providers/_builtin/validate.js +156 -0
  173. package/src/agent-stream/index.ts +6 -0
  174. package/src/agent-stream/manager.ts +286 -0
  175. package/src/agent-stream/poller.ts +154 -0
  176. package/src/agent-stream/provider-adapter.ts +138 -0
  177. package/src/agent-stream/types.ts +61 -0
  178. package/src/boot/daemon-lifecycle.ts +252 -0
  179. package/src/cdp/devtools.ts +335 -0
  180. package/src/cdp/initializer.ts +191 -0
  181. package/src/cdp/manager.ts +897 -0
  182. package/src/cdp/scanner.ts +185 -0
  183. package/src/cdp/setup.ts +150 -0
  184. package/src/cli-adapter-types.ts +25 -0
  185. package/src/cli-adapters/provider-cli-adapter.ts +448 -0
  186. package/src/commands/cdp-commands.ts +208 -0
  187. package/src/commands/chat-commands.ts +675 -0
  188. package/src/commands/cli-manager.ts +353 -0
  189. package/src/commands/handler.ts +328 -0
  190. package/src/commands/router.ts +258 -0
  191. package/src/commands/stream-commands.ts +325 -0
  192. package/src/config/chat-history.ts +211 -0
  193. package/src/config/config.ts +219 -0
  194. package/src/daemon/dev-server.ts +2378 -0
  195. package/src/daemon/scaffold-template.ts +394 -0
  196. package/src/daemon-core.ts +50 -0
  197. package/src/detection/cli-detector.ts +89 -0
  198. package/src/detection/ide-detector.ts +157 -0
  199. package/src/index.ts +103 -0
  200. package/src/installer.ts +263 -0
  201. package/src/ipc-protocol.ts +133 -0
  202. package/src/launch.ts +433 -0
  203. package/src/logging/command-log.ts +180 -0
  204. package/src/logging/logger.ts +316 -0
  205. package/src/providers/acp-provider-instance.ts +1140 -0
  206. package/src/providers/cli-provider-instance.ts +207 -0
  207. package/src/providers/contracts.ts +524 -0
  208. package/src/providers/extension-provider-instance.ts +156 -0
  209. package/src/providers/ide-provider-instance.ts +377 -0
  210. package/src/providers/index.ts +18 -0
  211. package/src/providers/provider-instance-manager.ts +182 -0
  212. package/src/providers/provider-instance.ts +112 -0
  213. package/src/providers/provider-loader.ts +1031 -0
  214. package/src/providers/status-monitor.ts +125 -0
  215. package/src/providers/version-archive.ts +266 -0
  216. package/src/status/reporter.ts +294 -0
  217. package/src/types.ts +206 -0
@@ -0,0 +1,35 @@
1
+ {
2
+ "type": "cline",
3
+ "name": "Cline",
4
+ "category": "extension",
5
+ "extensionId": "saoudrizwan.claude-dev",
6
+ "extensionIdPattern": "extensionId=saoudrizwan\\.claude-dev",
7
+ "extensionIdPattern_flags": "i",
8
+ "vscodeCommands": {
9
+ "focusPanel": "claude-dev.SidebarProvider.focus"
10
+ },
11
+ "settings": {
12
+ "approvalAlert": {
13
+ "type": "boolean",
14
+ "default": true,
15
+ "public": true,
16
+ "label": "Approval Notifications",
17
+ "description": "Show notification when approval is needed"
18
+ },
19
+ "longGeneratingAlert": {
20
+ "type": "boolean",
21
+ "default": true,
22
+ "public": true,
23
+ "label": "Long Generation Alert",
24
+ "description": "Alert when generation takes too long"
25
+ },
26
+ "longGeneratingThresholdSec": {
27
+ "type": "number",
28
+ "default": 180,
29
+ "public": true,
30
+ "label": "Long Generation Threshold (sec)",
31
+ "min": 30,
32
+ "max": 600
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Cline v1 — focus_editor
3
+ *
4
+ * Cline webview iframe 내부의 입력 필드에 포커스.
5
+ * send_message 전에 호출하거나, 대시보드 "Focus" 버튼에 사용.
6
+ *
7
+ * 최종 확인: 2026-03-07
8
+ */
9
+ (() => {
10
+ try {
11
+ const inner = document.querySelector('iframe');
12
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
13
+ if (!doc) return 'no doc';
14
+
15
+ // data-testid 우선 → fallback
16
+ let target = doc.querySelector('[data-testid="chat-input"]');
17
+ if (!target) {
18
+ const textareas = doc.querySelectorAll('textarea');
19
+ for (const ta of textareas) {
20
+ if (ta.offsetParent !== null && ta.offsetHeight > 20) {
21
+ target = ta;
22
+ break;
23
+ }
24
+ }
25
+ }
26
+ if (!target) {
27
+ // contenteditable fallback
28
+ const editables = doc.querySelectorAll('[contenteditable="true"]');
29
+ for (const el of editables) {
30
+ if (el.offsetParent !== null && el.offsetHeight > 10) {
31
+ target = el;
32
+ break;
33
+ }
34
+ }
35
+ }
36
+ if (!target) return 'no input';
37
+
38
+ target.focus();
39
+ // 커서를 끝으로 이동
40
+ if (target.tagName === 'TEXTAREA' || target.tagName === 'INPUT') {
41
+ const len = (target.value || '').length;
42
+ target.setSelectionRange(len, len);
43
+ }
44
+ return 'focused';
45
+ } catch (e) {
46
+ return 'error: ' + e.message;
47
+ }
48
+ })()
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Cline v1 — list_chats (Fiber + DOM 이중 접근)
3
+ *
4
+ * 1차: React Fiber에서 taskHistory 배열 추출
5
+ * __reactFiber, __reactProps, __reactContainer 모두 탐색
6
+ * 2차: Virtuoso DOM 파싱
7
+ *
8
+ * 반환: JSON 문자열 — [{id, title, status, time, cost, tokensIn, tokensOut, modelId}]
9
+ *
10
+ * 최종 확인: 2026-03-07
11
+ */
12
+ (() => {
13
+ try {
14
+ const inner = document.querySelector('iframe');
15
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
16
+ if (!doc) return JSON.stringify({ error: 'no_doc', panel: 'hidden' });
17
+
18
+ // Fiber 키 찾기 helper — __reactFiber, __reactProps, __reactContainer 모두 검색
19
+ const findFiberKey = (el) => Object.keys(el).find(k =>
20
+ k.startsWith('__reactFiber') || k.startsWith('__reactProps') || k.startsWith('__reactContainer'));
21
+
22
+ const getFiber = (el) => {
23
+ const fk = findFiberKey(el);
24
+ if (!fk) return null;
25
+ let fiber = el[fk];
26
+ // __reactContainer인 경우 내부 fiber tree root로 접근
27
+ if (fk.startsWith('__reactContainer') && fiber?._internalRoot?.current) {
28
+ fiber = fiber._internalRoot.current;
29
+ }
30
+ return fiber;
31
+ };
32
+
33
+ // ─── 1차: Fiber props에서 taskHistory 찾기 ───
34
+ const allEls = doc.querySelectorAll('*');
35
+ let taskHistory = null;
36
+
37
+ for (const el of allEls) {
38
+ let fiber = getFiber(el);
39
+ if (!fiber) continue;
40
+
41
+ for (let d = 0; d < 30 && fiber; d++) {
42
+ const props = fiber.memoizedProps || fiber.pendingProps;
43
+ if (props && props.taskHistory && Array.isArray(props.taskHistory)) {
44
+ taskHistory = props.taskHistory;
45
+ break;
46
+ }
47
+ // memoizedState 체인에서도 탐색
48
+ if (fiber.memoizedState) {
49
+ let st = fiber.memoizedState;
50
+ while (st) {
51
+ try {
52
+ const ms = st.memoizedState;
53
+ if (ms && typeof ms === 'object' && !Array.isArray(ms)) {
54
+ if (ms.taskHistory && Array.isArray(ms.taskHistory)) {
55
+ taskHistory = ms.taskHistory;
56
+ break;
57
+ }
58
+ }
59
+ } catch { }
60
+ st = st.next;
61
+ }
62
+ }
63
+ if (taskHistory) break;
64
+ fiber = fiber.return;
65
+ }
66
+ if (taskHistory) break;
67
+ }
68
+
69
+ if (taskHistory && taskHistory.length > 0) {
70
+ const results = taskHistory.slice(0, 50).map((task, i) => ({
71
+ id: task.id || String(task.ts),
72
+ title: (task.task || '').substring(0, 120),
73
+ status: i === 0 ? 'current' : '',
74
+ time: task.ts ? new Date(task.ts).toISOString() : '',
75
+ cost: task.totalCost ? `$${task.totalCost.toFixed(4)}` : '',
76
+ tokensIn: task.tokensIn || 0,
77
+ tokensOut: task.tokensOut || 0,
78
+ modelId: task.modelId || '',
79
+ size: task.size || 0,
80
+ isFavorited: !!task.isFavorited,
81
+ }));
82
+ return JSON.stringify(results);
83
+ }
84
+
85
+ // ─── 2차: Virtuoso DOM 파싱 ───
86
+ const items = doc.querySelectorAll('[data-item-index]');
87
+ if (items.length > 0) {
88
+ const results = Array.from(items).slice(0, 50).map(el => ({
89
+ id: el.getAttribute('data-item-index') || '',
90
+ title: (el.textContent || '').trim().substring(0, 120),
91
+ status: '',
92
+ }));
93
+ return JSON.stringify(results);
94
+ }
95
+
96
+ return JSON.stringify([]);
97
+ } catch (e) {
98
+ return JSON.stringify({ error: e.message || String(e) });
99
+ }
100
+ })()
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Cline — list_models
3
+ * 드롭다운에서 사용 가능한 모델 목록 + 현재 선택된 모델 반환
4
+ * → { models: string[], current: string }
5
+ */
6
+ (async () => {
7
+ try {
8
+ const inner = document.querySelector('iframe');
9
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
10
+ if (!doc) return JSON.stringify({ models: [], current: '', error: 'no doc' });
11
+
12
+ // 현재 모델: mode-switch 또는 model selector에서 읽기
13
+ let current = '';
14
+ const modeSwitch = doc.querySelector('[data-testid="mode-switch"]');
15
+ if (modeSwitch) current = (modeSwitch.textContent || '').trim();
16
+ if (!current) {
17
+ const modelSel = doc.querySelector('[data-testid*="model"], [aria-label*="model" i]');
18
+ if (modelSel) current = (modelSel.textContent || '').trim();
19
+ }
20
+
21
+ // 드롭다운 트리거 찾기
22
+ const trigger = doc.querySelector('[data-testid="model-selector"], [data-testid*="model-dropdown"], [data-testid="dropdown-trigger"]');
23
+ if (!trigger) return JSON.stringify({ models: [], current, error: 'no model trigger' });
24
+
25
+ // 드롭다운 열기
26
+ trigger.click();
27
+ await new Promise(r => setTimeout(r, 300));
28
+
29
+ // 옵션 수집
30
+ const options = doc.querySelectorAll('[data-testid*="dropdown-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
31
+ const models = [];
32
+ for (const opt of options) {
33
+ const text = (opt.textContent || '').trim();
34
+ if (text && text.length > 1 && text.length < 100) models.push(text);
35
+ }
36
+
37
+ // 닫기
38
+ doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
39
+ if (trigger.click) trigger.click(); // fallback close
40
+
41
+ return JSON.stringify({ models: [...new Set(models)], current });
42
+ } catch (e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
43
+ })()
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Cline — list_modes
3
+ * 모드 selector에서 사용 가능한 모드 목록 + 현재 모드 반환
4
+ * → { modes: string[], current: string }
5
+ */
6
+ (async () => {
7
+ try {
8
+ const inner = document.querySelector('iframe');
9
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
10
+ if (!doc) return JSON.stringify({ modes: [], current: '', error: 'no doc' });
11
+
12
+ // 현재 모드
13
+ const trigger = doc.querySelector('[data-testid="mode-selector-trigger"], [data-testid="mode-switch"]');
14
+ if (!trigger) return JSON.stringify({ modes: [], current: '', error: 'no mode trigger' });
15
+ const current = (trigger.textContent || '').trim();
16
+
17
+ // 드롭다운 열기
18
+ trigger.click();
19
+ await new Promise(r => setTimeout(r, 300));
20
+
21
+ // 옵션 수집
22
+ const options = doc.querySelectorAll('[data-testid*="mode-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
23
+ const modes = [];
24
+ for (const opt of options) {
25
+ const text = (opt.textContent || '').trim();
26
+ if (text && text.length > 1 && text.length < 50) modes.push(text);
27
+ }
28
+
29
+ // 닫기
30
+ doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
31
+ if (trigger.click) trigger.click(); // fallback close
32
+
33
+ return JSON.stringify({ modes: [...new Set(modes)], current });
34
+ } catch (e) { return JSON.stringify({ modes: [], current: '', error: e.message }); }
35
+ })()
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Cline v1 — new_session
3
+ *
4
+ * 구조:
5
+ * 1. "New Task" 버튼 또는 "+" 버튼 클릭
6
+ * 2. data-testid 우선 → aria-label → 텍스트 매칭
7
+ *
8
+ * 최종 확인: 2026-03-07
9
+ */
10
+ (() => {
11
+ try {
12
+ const inner = document.querySelector('iframe');
13
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
14
+ if (!doc) return 'no doc';
15
+
16
+ const buttons = Array.from(doc.querySelectorAll('button'))
17
+ .filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
18
+
19
+ // ─── 1단계: data-testid 기반 ───
20
+ for (const btn of buttons) {
21
+ const testId = (btn.getAttribute('data-testid') || '').toLowerCase();
22
+ if (testId.includes('new-task') || testId.includes('new-chat') || testId.includes('new_task')) {
23
+ btn.click();
24
+ return 'clicked (testid)';
25
+ }
26
+ }
27
+
28
+ // ─── 2단계: aria-label 기반 ───
29
+ for (const btn of buttons) {
30
+ const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
31
+ if (ariaLabel.includes('new task') || ariaLabel.includes('new chat')
32
+ || ariaLabel.includes('plus') || ariaLabel === 'new') {
33
+ btn.click();
34
+ return 'clicked (aria)';
35
+ }
36
+ }
37
+
38
+ // ─── 3단계: 텍스트 매칭 ───
39
+ for (const btn of buttons) {
40
+ const text = (btn.textContent || '').trim();
41
+ if (text === '+' || text.includes('New Task') || text.includes('New Chat')) {
42
+ btn.click();
43
+ return 'clicked (text)';
44
+ }
45
+ }
46
+
47
+ // ─── 4단계: SVG plus 아이콘 버튼 ───
48
+ for (const btn of buttons) {
49
+ const svg = btn.querySelector('svg');
50
+ if (!svg) continue;
51
+ const path = svg.querySelector('path');
52
+ if (path) {
53
+ const d = path.getAttribute('d') || '';
54
+ // SVG plus icon의 일반적인 path pattern
55
+ if (d.includes('M12') && (d.includes('H5') || d.includes('h') || d.includes('v'))) {
56
+ // 다른 버튼 텍스트가 없는 아이콘 전용 버튼
57
+ const text = (btn.textContent || '').trim();
58
+ if (text.length < 3) {
59
+ btn.click();
60
+ return 'clicked (svg)';
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ // ─── 5단계: 웰컴 화면 감지 (이미 새 세션) ───
67
+ const bodyText = (doc.body.textContent || '').toLowerCase();
68
+ if (bodyText.includes('what can i do for you') || bodyText.includes('start a new task') || bodyText.includes('type your task')) {
69
+ return 'clicked (already new)';
70
+ }
71
+
72
+ // ─── 6단계: History 뷰 감지 → Done 클릭으로 웰컴 복귀 ───
73
+ if (bodyText.includes('history') && bodyText.includes('done')) {
74
+ for (const btn of buttons) {
75
+ const text = (btn.textContent || '').trim();
76
+ if (text === 'Done') {
77
+ btn.click();
78
+ return 'clicked (history done)';
79
+ }
80
+ }
81
+ }
82
+
83
+ return 'no button found';
84
+ } catch (e) { return 'error: ' + e.message; }
85
+ })()
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Cline v1 — open_panel
3
+ *
4
+ * 패널 상태 확인 및 열기 시도.
5
+ *
6
+ * iframe 컨텍스트에서는 VS Code API 접근이 제한적이므로,
7
+ * 패널이 숨겨져 있을 때는 'panel_hidden' 상태를 반환.
8
+ * → daemon의 AgentStreamManager 또는
9
+ * agent_stream_focus 메시지를 통해 열어야 함.
10
+ *
11
+ * 반환: 'visible' | 'panel_hidden'
12
+ * 최종 확인: 2026-03-07
13
+ */
14
+ (() => {
15
+ try {
16
+ const inner = document.querySelector('iframe');
17
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
18
+ if (!doc) return 'panel_hidden';
19
+
20
+ const root = doc.getElementById('root');
21
+ if (root && root.offsetHeight > 0) return 'visible';
22
+
23
+ return 'panel_hidden';
24
+ } catch (e) { return 'error: ' + e.message; }
25
+ })()
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Cline v1 — read_chat (v2 — Fiber 기반 역할 판별)
3
+ *
4
+ * 구조 (Cline 3.x — saoudrizwan.claude-dev):
5
+ * 1. outer webview iframe → inner contentDocument
6
+ * 2. data-testid="virtuoso-item-list" (React Virtuoso) — 활성 메시지 블록
7
+ * 3. React Fiber → data 배열에서 메시지 타입 직접 추출
8
+ * - type: "say", say: "user_feedback" → user
9
+ * - type: "say", say: "text" → assistant
10
+ * - type: "say", say: "checkpoint_created" → system (skip)
11
+ * - type: "ask", ask: "followup" → assistant (질문)
12
+ * - type: "ask", ask: "tool" → assistant (tool 승인 대기)
13
+ * 4. DOM textContent에서 콘텐츠 추출 + 정제
14
+ *
15
+ * 최종 확인: 2026-03-07
16
+ */
17
+ (() => {
18
+ try {
19
+ const inner = document.querySelector('iframe');
20
+ if (!inner) return JSON.stringify({ error: 'no inner iframe' });
21
+ const doc = inner.contentDocument || inner.contentWindow?.document;
22
+ if (!doc) return JSON.stringify({ error: 'cannot access contentDocument' });
23
+
24
+ const root = doc.getElementById('root');
25
+ if (!root) return JSON.stringify({ error: 'no root element' });
26
+
27
+ const isVisible = root.offsetHeight > 0;
28
+
29
+ // ─── 1. Fiber에서 data 배열 추출 ───
30
+ const virtuosoList = doc.querySelector('[data-testid="virtuoso-item-list"]');
31
+ let fiberData = null;
32
+
33
+ if (virtuosoList && virtuosoList.children.length > 0) {
34
+ const firstItem = virtuosoList.children[0];
35
+ const fiberKey = Object.keys(firstItem).find(k =>
36
+ k.startsWith('__reactFiber') || k.startsWith('__reactInternalInstance')
37
+ );
38
+ if (fiberKey) {
39
+ let fiber = firstItem[fiberKey];
40
+ for (let d = 0; d < 25 && fiber; d++) {
41
+ const props = fiber.memoizedProps || fiber.pendingProps;
42
+ if (props && props.data && Array.isArray(props.data) && props.data.length > 0) {
43
+ fiberData = props.data;
44
+ break;
45
+ }
46
+ fiber = fiber.return;
47
+ }
48
+ }
49
+ }
50
+
51
+ // ─── 2. 메시지 파싱 ───
52
+ const messages = [];
53
+
54
+ if (fiberData) {
55
+ // ★ Fiber 기반: 가장 정확한 역할 판별
56
+ for (let i = 0; i < fiberData.length; i++) {
57
+ const item = fiberData[i];
58
+ if (!item || typeof item !== 'object') continue;
59
+
60
+ const msgType = item.type; // "say" or "ask"
61
+ const saySub = item.say; // "user_feedback", "text", "checkpoint_created", etc.
62
+ const askSub = item.ask; // "followup", "tool", "command", etc.
63
+ const text = item.text || '';
64
+
65
+ // 시스템 이벤트 스킵
66
+ if (saySub === 'checkpoint_created') continue;
67
+ if (saySub === 'api_req_started' || saySub === 'api_req_finished') continue;
68
+ if (saySub === 'shell_integration_warning') continue;
69
+
70
+ // 역할 판별
71
+ let role = 'assistant';
72
+ if (saySub === 'user_feedback') role = 'user';
73
+ if (saySub === 'user_feedback_diff') role = 'user';
74
+
75
+ // 콘텐츠 추출
76
+ let content = '';
77
+ if (text) {
78
+ // ask.followup의 text는 JSON일 수 있음
79
+ if (askSub === 'followup' && text.startsWith('{')) {
80
+ try {
81
+ const parsed = JSON.parse(text);
82
+ content = parsed.question || parsed.text || text;
83
+ } catch { content = text; }
84
+ } else {
85
+ content = text;
86
+ }
87
+ }
88
+
89
+ // DOM 텍스트 fallback (Fiber text가 비어있을 때)
90
+ if (!content && virtuosoList && virtuosoList.children[i]) {
91
+ content = (virtuosoList.children[i].textContent || '').trim();
92
+ }
93
+
94
+ // 너무 짧거나 빈 콘텐츠 스킵
95
+ if (!content || content.length < 2) continue;
96
+
97
+ // 노이즈 정리
98
+ content = content
99
+ .replace(/CheckpointCompareRestore(Save)?/gi, '')
100
+ .replace(/^\s*API Request.*$/gm, '')
101
+ .replace(/^\s*Cost:.*$/gm, '')
102
+ .replace(/\s{3,}/g, '\n')
103
+ .trim();
104
+
105
+ if (content.length < 2) continue;
106
+
107
+ // 코드 블록 보존 (DOM에서 구조 추출)
108
+ if (virtuosoList.children[i]) {
109
+ const domItem = virtuosoList.children[i];
110
+ const preBlocks = domItem.querySelectorAll('pre');
111
+ if (preBlocks.length > 0 && role === 'assistant') {
112
+ let structured = '';
113
+ const walk = (node) => {
114
+ if (node.nodeType === 3) {
115
+ structured += node.textContent;
116
+ return;
117
+ }
118
+ if (node.nodeType !== 1) return;
119
+ const el = node;
120
+ if (el.tagName === 'PRE') {
121
+ const codeEl = el.querySelector('code');
122
+ const lang = codeEl ? (codeEl.className.match(/language-(\w+)/)?.[1] || '') : '';
123
+ const code = (codeEl || el).textContent || '';
124
+ structured += '\n```' + lang + '\n' + code.trim() + '\n```\n';
125
+ return;
126
+ }
127
+ for (const child of el.childNodes) walk(child);
128
+ };
129
+ walk(domItem);
130
+ const cleaned = structured.replace(/CheckpointCompareRestore(Save)?/gi, '').trim();
131
+ if (cleaned.length > content.length * 0.5) {
132
+ content = cleaned;
133
+ }
134
+ }
135
+ }
136
+
137
+ // 길이 제한
138
+ if (content.length > 2000) content = content.substring(0, 2000) + '…';
139
+
140
+ messages.push({
141
+ role,
142
+ content,
143
+ timestamp: item.ts || (Date.now() - (fiberData.length - i) * 1000),
144
+ // 디버그: 메시지 서브타입
145
+ _type: msgType,
146
+ _sub: saySub || askSub,
147
+ });
148
+ }
149
+ } else if (virtuosoList && virtuosoList.children.length > 0) {
150
+ // Fallback: DOM 기반 파싱 (Fiber 접근 실패 시)
151
+ for (let i = 0; i < virtuosoList.children.length; i++) {
152
+ const item = virtuosoList.children[i];
153
+ const rawText = (item.textContent || '').trim();
154
+ if (!rawText || rawText.length < 2) continue;
155
+ if (/^Checkpoint(Compare|Restore|Save)/i.test(rawText)) continue;
156
+ if (/^(Thinking\.\.\.|Loading\.\.\.)$/i.test(rawText)) continue;
157
+
158
+ let role = 'assistant';
159
+ let content = rawText
160
+ .replace(/CheckpointCompareRestore(Save)?/gi, '')
161
+ .replace(/\s{3,}/g, '\n')
162
+ .trim();
163
+ if (content.length < 2) continue;
164
+ if (content.length > 2000) content = content.substring(0, 2000) + '…';
165
+
166
+ messages.push({ role, content, timestamp: Date.now() - (virtuosoList.children.length - i) * 1000 });
167
+ }
168
+ }
169
+
170
+ // ─── 3. 입력 필드 ───
171
+ let inputContent = '';
172
+ const chatInput = doc.querySelector('[data-testid="chat-input"]');
173
+ if (chatInput) {
174
+ inputContent = chatInput.value || chatInput.textContent || '';
175
+ }
176
+
177
+ // ─── 4. 상태 판별 ───
178
+ let status = 'idle';
179
+ const buttons = Array.from(doc.querySelectorAll('button'))
180
+ .filter(b => b.offsetWidth > 0);
181
+ const buttonTexts = buttons.map(b => (b.textContent || '').trim().toLowerCase());
182
+
183
+ if (buttonTexts.includes('cancel')) status = 'generating';
184
+
185
+ // Fiber data에서 마지막 type=ask인지 확인
186
+ if (fiberData && fiberData.length > 0) {
187
+ const last = fiberData[fiberData.length - 1];
188
+ if (last.type === 'ask') {
189
+ if (last.ask === 'followup') status = 'waiting_approval';
190
+ if (last.ask === 'tool' || last.ask === 'command') status = 'waiting_approval';
191
+ }
192
+ }
193
+
194
+ // 버튼 기반 보완
195
+ const approvalPatterns = /^(proceed|approve|allow|accept|save|run command|yes|confirm)/i;
196
+ if (buttonTexts.some(b => approvalPatterns.test(b))) status = 'waiting_approval';
197
+
198
+ if (!isVisible && messages.length === 0) status = 'panel_hidden';
199
+
200
+ // ─── 5. 모델/모드 ───
201
+ let model = '';
202
+ const modeSwitch = doc.querySelector('[data-testid="mode-switch"]');
203
+ if (modeSwitch) model = (modeSwitch.textContent || '').trim();
204
+ if (!model) {
205
+ const modelSel = doc.querySelector('[data-testid*="model"], [aria-label*="model" i]');
206
+ if (modelSel) model = (modelSel.textContent || '').trim();
207
+ }
208
+ const mode = modeSwitch ? (modeSwitch.textContent || '').trim() : '';
209
+
210
+ // ─── 6. 승인 모달 ───
211
+ let activeModal = null;
212
+ if (status === 'waiting_approval') {
213
+ const approvalBtns = buttons
214
+ .map(b => (b.textContent || '').trim())
215
+ .filter(t => t && t.length > 0 && t.length < 40 &&
216
+ /proceed|approve|allow|accept|run|yes|reject|deny|cancel|no|skip|save|confirm/i.test(t));
217
+
218
+ let modalMessage = 'Cline wants to perform an action';
219
+ if (fiberData && fiberData.length > 0) {
220
+ const last = fiberData[fiberData.length - 1];
221
+ if (last.ask === 'followup' && last.text) {
222
+ try {
223
+ const parsed = JSON.parse(last.text);
224
+ modalMessage = parsed.question || last.text.substring(0, 200);
225
+ } catch { modalMessage = last.text.substring(0, 200); }
226
+ } else if (last.ask === 'tool' || last.ask === 'command') {
227
+ modalMessage = `Cline wants to use ${last.ask}`;
228
+ }
229
+ }
230
+
231
+ if (approvalBtns.length > 0) {
232
+ activeModal = { message: modalMessage, buttons: [...new Set(approvalBtns)] };
233
+ }
234
+ }
235
+
236
+ // ─── 7. 토큰/비용 ───
237
+ let tokenInfo = '';
238
+ const costEl = doc.querySelector('[data-testid*="cost"], [data-testid*="token"]');
239
+ if (costEl) tokenInfo = (costEl.textContent || '').trim();
240
+
241
+ return JSON.stringify({
242
+ agentType: 'cline',
243
+ agentName: 'Cline',
244
+ extensionId: 'saoudrizwan.claude-dev',
245
+ status,
246
+ isVisible,
247
+ messages: messages.slice(-30),
248
+ inputContent,
249
+ model,
250
+ mode,
251
+ tokenInfo,
252
+ activeModal,
253
+ });
254
+ } catch (e) {
255
+ return JSON.stringify({ error: e.message || String(e) });
256
+ }
257
+ })()