@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,659 @@
1
+ /**
2
+ * CDP Scripts for Roo Code
3
+ */
4
+
5
+ module.exports.readChat = function readChat() {
6
+ return `(() => {
7
+ try {
8
+ const inner = document.querySelector('iframe');
9
+ if (!inner) return JSON.stringify({ error: 'no inner iframe' });
10
+ const doc = inner.contentDocument || inner.contentWindow?.document;
11
+ if (!doc) return JSON.stringify({ error: 'cannot access contentDocument' });
12
+
13
+ const chatView = doc.querySelector('[data-testid="chat-view"]');
14
+ const root = doc.getElementById('root') || doc.body;
15
+ const isVisible = root ? (root.offsetHeight > 0 || (root.offsetWidth > 0 && !!chatView)) : false;
16
+
17
+ // ─── 1. Fiber data 배열 추출 ───
18
+ const virtuosoList = doc.querySelector('[data-testid="virtuoso-item-list"]');
19
+ let fiberData = null;
20
+
21
+ if (virtuosoList && virtuosoList.children.length > 0) {
22
+ const firstItem = virtuosoList.children[0];
23
+ const fiberKey = Object.keys(firstItem).find(k =>
24
+ k.startsWith('__reactFiber') || k.startsWith('__reactInternalInstance')
25
+ );
26
+ if (fiberKey) {
27
+ let fiber = firstItem[fiberKey];
28
+ for (let d = 0; d < 25 && fiber; d++) {
29
+ const props = fiber.memoizedProps || fiber.pendingProps;
30
+ if (props && props.data && Array.isArray(props.data) && props.data.length > 0) {
31
+ fiberData = props.data;
32
+ break;
33
+ }
34
+ fiber = fiber.return;
35
+ }
36
+ }
37
+ }
38
+
39
+ // ─── 2. 메시지 파싱 ───
40
+ const messages = [];
41
+
42
+ if (fiberData) {
43
+ for (let i = 0; i < fiberData.length; i++) {
44
+ const item = fiberData[i];
45
+ if (!item || typeof item !== 'object') continue;
46
+
47
+ const msgType = item.type;
48
+ const saySub = item.say;
49
+ const askSub = item.ask;
50
+ const text = item.text || '';
51
+
52
+ if (saySub === 'checkpoint_created') continue;
53
+ if (saySub === 'api_req_started' || saySub === 'api_req_finished') continue;
54
+ if (saySub === 'shell_integration_warning') continue;
55
+
56
+ let role = 'assistant';
57
+ if (saySub === 'user_feedback') role = 'user';
58
+ if (saySub === 'user_feedback_diff') role = 'user';
59
+
60
+ let content = '';
61
+ if (text) {
62
+ if (askSub === 'followup' && text.startsWith('{')) {
63
+ try {
64
+ const parsed = JSON.parse(text);
65
+ content = parsed.question || parsed.text || text;
66
+ } catch { content = text; }
67
+ } else {
68
+ content = text;
69
+ }
70
+ }
71
+
72
+ if (!content && virtuosoList && virtuosoList.children[i]) {
73
+ content = (virtuosoList.children[i].textContent || '').trim();
74
+ }
75
+
76
+ if (!content || content.length < 2) continue;
77
+
78
+ content = content
79
+ .replace(/CheckpointCompareRestore(Save)?/gi, '')
80
+ .replace(/^\\s*API Request.*$/gm, '')
81
+ .replace(/^\\s*Cost:.*$/gm, '')
82
+ .replace(/\\s{3,}/g, '\\n')
83
+ .trim();
84
+
85
+ if (content.length < 2) continue;
86
+ if (content.length > 2000) content = content.substring(0, 2000) + '…';
87
+
88
+ messages.push({
89
+ role,
90
+ content,
91
+ timestamp: item.ts || (Date.now() - (fiberData.length - i) * 1000),
92
+ _type: msgType,
93
+ _sub: saySub || askSub,
94
+ });
95
+ }
96
+ } else if (virtuosoList && virtuosoList.children.length > 0) {
97
+ for (const item of virtuosoList.children) {
98
+ const text = (item.textContent || '').trim();
99
+ if (!text || text.length < 2) continue;
100
+ if (/^API Request/i.test(text) || /^Thinking$/i.test(text)) continue;
101
+ let role = 'assistant';
102
+ if (/^You (said|asked)/i.test(text)) role = 'user';
103
+ let content = text.substring(0, 500);
104
+ messages.push({ role, content, timestamp: Date.now() - messages.length * 1000 });
105
+ }
106
+ }
107
+
108
+ // ─── 3. 웰컴 화면 감지 ───
109
+ const fullText = (chatView?.textContent || '').trim();
110
+ const isWelcomeScreen = messages.length === 0 &&
111
+ /Roo is a whole AI dev team/i.test(fullText);
112
+
113
+ // ─── 4. 입력 필드 ───
114
+ let inputContent = '';
115
+ const textareas = doc.querySelectorAll('textarea');
116
+ for (const ta of textareas) {
117
+ const val = ta.value || ta.textContent || '';
118
+ if (val.trim()) { inputContent = val; break; }
119
+ }
120
+
121
+ // ─── 5. 상태 ───
122
+ let status = 'idle';
123
+ const allBtns = [...doc.querySelectorAll('button'), ...doc.querySelectorAll('vscode-button')];
124
+ const buttonTexts = allBtns.map(b => (b.textContent || '').trim().toLowerCase());
125
+
126
+ if (buttonTexts.includes('cancel')) status = 'generating';
127
+
128
+ if (fiberData && fiberData.length > 0) {
129
+ const last = fiberData[fiberData.length - 1];
130
+ if (last.type === 'ask') {
131
+ if (last.ask === 'followup') status = 'waiting_approval';
132
+ if (last.ask === 'tool' || last.ask === 'command') status = 'waiting_approval';
133
+ }
134
+ }
135
+
136
+ const approvalPatterns = /^(proceed|approve|allow|accept|save|run|yes|confirm|resume)/i;
137
+ if (buttonTexts.some(b => approvalPatterns.test(b))) status = 'waiting_approval';
138
+
139
+ if ((!isVisible && messages.length === 0) || isWelcomeScreen) {
140
+ status = !isVisible ? 'panel_hidden' : 'idle';
141
+ }
142
+
143
+ // ─── 6. 모드/모델 ───
144
+ const modeBtn = doc.querySelector('[data-testid="mode-selector-trigger"]');
145
+ const mode = modeBtn ? (modeBtn.textContent || '').trim() : '';
146
+ const modelBtn = doc.querySelector('[data-testid="dropdown-trigger"]');
147
+ const model = modelBtn ? (modelBtn.textContent || '').trim() : '';
148
+ const autoApproveBtn = doc.querySelector('[data-testid="auto-approve-dropdown-trigger"]');
149
+ const autoApprove = autoApproveBtn ? (autoApproveBtn.textContent || '').trim() : '';
150
+
151
+ // ─── 7. 승인 모달 ───
152
+ let activeModal = null;
153
+ if (status === 'waiting_approval') {
154
+ const approvalBtns = buttonTexts
155
+ .filter(b => /proceed|approve|allow|accept|run|yes|reject|deny|cancel|no|skip|save|confirm|resume/i.test(b))
156
+ .map(b => b.substring(0, 30));
157
+ activeModal = { message: 'Roo Code requires your input', buttons: [...new Set(approvalBtns)] };
158
+ }
159
+
160
+ return JSON.stringify({
161
+ agentType: 'roo-code',
162
+ agentName: 'Roo Code',
163
+ extensionId: 'RooVeterinaryInc.roo-cline',
164
+ status,
165
+ isVisible,
166
+ isWelcomeScreen,
167
+ messages: messages.slice(-30),
168
+ inputContent,
169
+ model,
170
+ mode,
171
+ autoApprove,
172
+ activeModal,
173
+ });
174
+ } catch (e) {
175
+ return JSON.stringify({ error: e.message || String(e) });
176
+ }
177
+ })()`;
178
+ };
179
+
180
+ module.exports.sendMessage = function sendMessage(text) {
181
+ const escaped = JSON.stringify(text);
182
+ return `(async () => {
183
+ try {
184
+ const inner = document.querySelector('iframe');
185
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
186
+ if (!doc) return 'error: no doc';
187
+
188
+ let target = null;
189
+ const textareas = doc.querySelectorAll('textarea');
190
+ for (const ta of textareas) {
191
+ if (ta.offsetParent !== null && ta.offsetHeight > 20) { target = ta; break; }
192
+ }
193
+ if (!target) return 'error: no textarea';
194
+
195
+ const proto = inner.contentWindow?.HTMLTextAreaElement?.prototype
196
+ || HTMLTextAreaElement.prototype;
197
+ const nativeSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
198
+
199
+ if (nativeSetter) nativeSetter.call(target, ${escaped});
200
+ else target.value = ${escaped};
201
+
202
+ target.dispatchEvent(new Event('input', { bubbles: true }));
203
+ target.dispatchEvent(new Event('change', { bubbles: true }));
204
+
205
+ await new Promise(r => setTimeout(r, 300));
206
+
207
+ // Fiber onSend 직접 호출
208
+ const allEls = doc.querySelectorAll('*');
209
+ for (const el of allEls) {
210
+ const fk = Object.keys(el).find(k => k.startsWith('__reactFiber'));
211
+ if (!fk) continue;
212
+ let fiber = el[fk];
213
+ for (let d = 0; d < 15 && fiber; d++) {
214
+ const props = fiber.memoizedProps || fiber.pendingProps;
215
+ if (props && typeof props.onSend === 'function') {
216
+ props.onSend();
217
+ return JSON.stringify({ sent: true });
218
+ }
219
+ fiber = fiber.return;
220
+ }
221
+ }
222
+
223
+ // Fallback: Enter 키
224
+ target.focus();
225
+ target.dispatchEvent(new KeyboardEvent('keydown', {
226
+ key: 'Enter', code: 'Enter', keyCode: 13,
227
+ bubbles: true, cancelable: true,
228
+ }));
229
+
230
+ return JSON.stringify({ sent: true });
231
+ } catch (e) { return JSON.stringify({ sent: false, error: e.message }); }
232
+ })()`;
233
+ };
234
+
235
+ module.exports.listSessions = function listSessions() {
236
+ return `(() => {
237
+ try {
238
+ const inner = document.querySelector('iframe');
239
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
240
+ if (!doc) return JSON.stringify({ sessions: [] });
241
+
242
+ const findFiberKey = (el) => Object.keys(el).find(k =>
243
+ k.startsWith('__reactFiber') || k.startsWith('__reactProps') || k.startsWith('__reactContainer'));
244
+ const getFiber = (el) => {
245
+ const fk = findFiberKey(el);
246
+ if (!fk) return null;
247
+ let fiber = el[fk];
248
+ if (fk.startsWith('__reactContainer') && fiber?._internalRoot?.current)
249
+ fiber = fiber._internalRoot.current;
250
+ return fiber;
251
+ };
252
+
253
+ const allEls = doc.querySelectorAll('*');
254
+ let taskHistory = null;
255
+
256
+ for (const el of allEls) {
257
+ let fiber = getFiber(el);
258
+ if (!fiber) continue;
259
+ for (let d = 0; d < 30 && fiber; d++) {
260
+ const props = fiber.memoizedProps || fiber.pendingProps;
261
+ if (props && props.taskHistory && Array.isArray(props.taskHistory)) {
262
+ taskHistory = props.taskHistory;
263
+ break;
264
+ }
265
+ if (fiber.memoizedState) {
266
+ let st = fiber.memoizedState;
267
+ while (st) {
268
+ try {
269
+ const ms = st.memoizedState;
270
+ if (ms && typeof ms === 'object' && !Array.isArray(ms)) {
271
+ if (ms.taskHistory && Array.isArray(ms.taskHistory)) {
272
+ taskHistory = ms.taskHistory;
273
+ break;
274
+ }
275
+ }
276
+ } catch { }
277
+ st = st.next;
278
+ }
279
+ }
280
+ if (taskHistory) break;
281
+ fiber = fiber.return;
282
+ }
283
+ if (taskHistory) break;
284
+ }
285
+
286
+ if (taskHistory && taskHistory.length > 0) {
287
+ const sessions = taskHistory.slice(0, 50).map((task, i) => ({
288
+ id: task.id || String(task.ts),
289
+ title: (task.task || '').substring(0, 120),
290
+ time: task.ts ? new Date(task.ts).toISOString() : '',
291
+ }));
292
+ return JSON.stringify({ sessions });
293
+ }
294
+
295
+ // DOM fallback
296
+ const taskItems = doc.querySelectorAll('[data-testid^="task-item-"]');
297
+ if (taskItems.length > 0) {
298
+ const sessions = [];
299
+ for (const item of taskItems) {
300
+ const testId = item.getAttribute('data-testid') || '';
301
+ const id = testId.replace('task-item-', '');
302
+ const contentEl = item.querySelector('[data-testid="task-content"]');
303
+ const title = contentEl ? (contentEl.textContent || '').trim() : (item.textContent || '').trim().substring(0, 80);
304
+ sessions.push({ id, title, time: '' });
305
+ }
306
+ return JSON.stringify({ sessions });
307
+ }
308
+
309
+ return JSON.stringify({ sessions: [] });
310
+ } catch (e) {
311
+ return JSON.stringify({ sessions: [], error: e.message });
312
+ }
313
+ })()`;
314
+ };
315
+
316
+ module.exports.switchSession = function switchSession(sessionId) {
317
+ const escaped = JSON.stringify(sessionId);
318
+ return `(async () => {
319
+ try {
320
+ const inner = document.querySelector('iframe');
321
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
322
+ if (!doc) return JSON.stringify({ switched: false, error: 'no doc' });
323
+
324
+ const sid = ${escaped};
325
+ if (!sid) return JSON.stringify({ switched: false, error: 'no sessionId' });
326
+
327
+ const pm = window.__vscode_post_message__;
328
+ if (typeof pm !== 'function') return JSON.stringify({ switched: false, error: 'no postMessage' });
329
+
330
+ const findFiberKey = (el) => Object.keys(el).find(k =>
331
+ k.startsWith('__reactFiber') || k.startsWith('__reactProps') || k.startsWith('__reactContainer'));
332
+
333
+ const root = doc.getElementById('root');
334
+ if (!root) return JSON.stringify({ switched: false, error: 'no root' });
335
+ const fk = findFiberKey(root);
336
+ if (!fk) return JSON.stringify({ switched: false, error: 'no fiber' });
337
+ let rootFiber = root[fk];
338
+ if (fk.startsWith('__reactContainer') && rootFiber?._internalRoot?.current)
339
+ rootFiber = rootFiber._internalRoot.current;
340
+
341
+ let taskHistory = null;
342
+ const visited = new Set();
343
+ const dfs = (f, depth) => {
344
+ if (!f || depth > 80 || visited.has(f) || taskHistory) return;
345
+ visited.add(f);
346
+ const props = f.memoizedProps || f.pendingProps;
347
+ if (props?.taskHistory && Array.isArray(props.taskHistory)) {
348
+ taskHistory = props.taskHistory;
349
+ return;
350
+ }
351
+ if (f.memoizedState) {
352
+ let st = f.memoizedState; let i = 0;
353
+ while (st && i < 20 && !taskHistory) {
354
+ try {
355
+ const ms = st.memoizedState;
356
+ if (ms?.taskHistory && Array.isArray(ms.taskHistory)) taskHistory = ms.taskHistory;
357
+ } catch { }
358
+ st = st.next; i++;
359
+ }
360
+ }
361
+ if (f.child) dfs(f.child, depth + 1);
362
+ if (f.sibling) dfs(f.sibling, depth + 1);
363
+ };
364
+ dfs(rootFiber, 0);
365
+
366
+ if (!taskHistory || taskHistory.length === 0) return JSON.stringify({ switched: false, error: 'no history' });
367
+
368
+ const norm = s => (s || '').trim().toLowerCase().replace(/\\s+/g, ' ');
369
+ const idNorm = norm(sid);
370
+ let targetTask = taskHistory.find(t => String(t.id) === sid);
371
+ if (!targetTask) {
372
+ targetTask = taskHistory.find(t => {
373
+ const title = norm(t.task || '');
374
+ return title.includes(idNorm) || idNorm.includes(title);
375
+ });
376
+ }
377
+ if (!targetTask) return JSON.stringify({ switched: false, error: 'task not found' });
378
+
379
+ pm('onmessage', { message: { type: 'showTaskWithId', text: String(targetTask.id) } });
380
+
381
+ await new Promise(r => setTimeout(r, 2000));
382
+ return JSON.stringify({ switched: true });
383
+ } catch (e) { return JSON.stringify({ switched: false, error: e.message }); }
384
+ })()`;
385
+ };
386
+
387
+ module.exports.newSession = function newSession() {
388
+ return `(() => {
389
+ try {
390
+ const inner = document.querySelector('iframe');
391
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
392
+ if (!doc) return 'no doc';
393
+
394
+ const allBtns = [
395
+ ...Array.from(doc.querySelectorAll('button')),
396
+ ...Array.from(doc.querySelectorAll('vscode-button')),
397
+ ].filter(b => b.offsetWidth > 0 || b.offsetHeight > 0 || b.textContent?.trim());
398
+
399
+ for (const btn of allBtns) {
400
+ const tid = (btn.getAttribute('data-testid') || '').toLowerCase();
401
+ if (tid.includes('new-task') || tid.includes('new-chat') || tid.includes('new_session')) {
402
+ btn.click(); return 'clicked (testid)';
403
+ }
404
+ }
405
+ for (const btn of allBtns) {
406
+ const label = (btn.getAttribute('aria-label') || '').toLowerCase();
407
+ if (label.includes('new task') || label.includes('new chat') || label.includes('plus')) {
408
+ btn.click(); return 'clicked (aria)';
409
+ }
410
+ }
411
+ for (const btn of allBtns) {
412
+ const text = (btn.textContent || '').trim();
413
+ if (text === '+' || text.includes('New Task') || text.includes('New Chat')) {
414
+ btn.click(); return 'clicked (text)';
415
+ }
416
+ }
417
+
418
+ const bodyText = (doc.body.textContent || '').toLowerCase();
419
+ if (bodyText.includes('what can i do for you') || bodyText.includes('type your task') || bodyText.includes('start a new')) {
420
+ return 'clicked (already new)';
421
+ }
422
+
423
+ const root = doc.getElementById('root');
424
+ const chatView = doc.querySelector('[data-testid="chat-view"]');
425
+ if (root && root.offsetHeight === 0 && root.offsetWidth === 0 && !chatView) return 'panel_hidden';
426
+
427
+ return 'no button found';
428
+ } catch (e) { return 'error: ' + e.message; }
429
+ })()`;
430
+ };
431
+
432
+ module.exports.resolveAction = function resolveAction(action) {
433
+ const escaped = JSON.stringify(action);
434
+ return `(() => {
435
+ try {
436
+ const inner = document.querySelector('iframe');
437
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
438
+ if (!doc) return false;
439
+
440
+ const action = ${escaped};
441
+ const approvePatterns = ['proceed', 'approve', 'allow', 'accept', 'save', 'run command', 'yes', 'confirm', 'resume'];
442
+ const rejectPatterns = ['reject', 'deny', 'cancel', 'skip'];
443
+ const patterns = action === 'approve' ? approvePatterns : rejectPatterns;
444
+ const excludeTexts = ['auto-approve', 'read', 'write', 'mcp', 'mode', 'subtasks', 'execute', 'question', 'all', 'none', 'enabled'];
445
+
446
+ try { doc.body.click(); } catch { }
447
+
448
+ const allBtns = [
449
+ ...Array.from(doc.querySelectorAll('button')),
450
+ ...Array.from(doc.querySelectorAll('vscode-button')),
451
+ ].filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
452
+
453
+ for (const btn of allBtns) {
454
+ const testId = (btn.getAttribute('data-testid') || '').toLowerCase();
455
+ if (action === 'approve' && (testId.includes('approve') || testId.includes('proceed') || testId.includes('accept') || testId.includes('primary'))) {
456
+ btn.click(); return true;
457
+ }
458
+ if (action === 'reject' && (testId.includes('reject') || testId.includes('deny') || testId.includes('cancel') || testId.includes('secondary'))) {
459
+ btn.click(); return true;
460
+ }
461
+ }
462
+
463
+ const largeBtns = allBtns.filter(b => b.offsetWidth > 100);
464
+ for (const btn of largeBtns) {
465
+ const text = (btn.textContent || '').trim().toLowerCase();
466
+ if (text.length === 0 || text.length > 30) continue;
467
+ if (excludeTexts.some(e => text === e || text.startsWith('auto-approve'))) continue;
468
+ if (patterns.some(p => text === p || text.startsWith(p))) {
469
+ btn.click(); return true;
470
+ }
471
+ }
472
+
473
+ for (const btn of allBtns) {
474
+ const text = (btn.textContent || '').trim().toLowerCase();
475
+ if (text.length === 0 || text.length > 30) continue;
476
+ if (excludeTexts.some(e => text === e || text.startsWith('auto-approve'))) continue;
477
+ if (patterns.some(p => text === p || text.startsWith(p))) {
478
+ btn.click(); return true;
479
+ }
480
+ }
481
+
482
+ for (const btn of allBtns) {
483
+ const label = (btn.getAttribute('aria-label') || '').toLowerCase();
484
+ if (patterns.some(p => label.includes(p))) {
485
+ btn.click(); return true;
486
+ }
487
+ }
488
+
489
+ return false;
490
+ } catch { return false; }
491
+ })()`;
492
+ };
493
+
494
+ module.exports.focusEditor = function focusEditor() {
495
+ return `(() => {
496
+ try {
497
+ const inner = document.querySelector('iframe');
498
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
499
+ if (!doc) return 'no doc';
500
+ const textareas = doc.querySelectorAll('textarea');
501
+ for (const ta of textareas) {
502
+ if (ta.offsetParent !== null && ta.offsetHeight > 20) {
503
+ ta.focus();
504
+ return 'focused';
505
+ }
506
+ }
507
+ return 'no textarea found';
508
+ } catch (e) { return 'error: ' + e.message; }
509
+ })()`;
510
+ };
511
+
512
+ module.exports.openPanel = function openPanel() {
513
+ return `(() => {
514
+ try {
515
+ const inner = document.querySelector('iframe');
516
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
517
+ if (!doc) return 'panel_hidden';
518
+ const root = doc.getElementById('root');
519
+ if (root && root.offsetHeight > 0) return 'visible';
520
+ return 'panel_hidden';
521
+ } catch (e) { return 'error: ' + e.message; }
522
+ })()`;
523
+ };
524
+
525
+ module.exports.listModels = function listModels() {
526
+ return `(async () => {
527
+ try {
528
+ const inner = document.querySelector('iframe');
529
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
530
+ if (!doc) return JSON.stringify({ models: [], current: '', error: 'no doc' });
531
+
532
+ // 현재 모델 읽기
533
+ const trigger = doc.querySelector('[data-testid="dropdown-trigger"]');
534
+ if (!trigger) return JSON.stringify({ models: [], current: '', error: 'no model trigger' });
535
+ const current = (trigger.textContent || '').trim();
536
+
537
+ // 드롭다운 열기
538
+ trigger.click();
539
+ await new Promise(r => setTimeout(r, 300));
540
+
541
+ // 옵션 수집
542
+ const options = doc.querySelectorAll('[data-testid*="dropdown-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
543
+ const models = [];
544
+ for (const opt of options) {
545
+ const text = (opt.textContent || '').trim();
546
+ if (text && text.length > 1 && text.length < 100) models.push(text);
547
+ }
548
+
549
+ // 닫기
550
+ doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
551
+ trigger.click(); // fallback close
552
+
553
+ return JSON.stringify({ models: [...new Set(models)], current });
554
+ } catch (e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
555
+ })()`;
556
+ };
557
+
558
+ module.exports.setModel = function setModel(params) {
559
+ const model = params?.model || params;
560
+ const escaped = JSON.stringify(model);
561
+ return `(async () => {
562
+ try {
563
+ const inner = document.querySelector('iframe');
564
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
565
+ if (!doc) return JSON.stringify({ success: false, error: 'no doc' });
566
+
567
+ const target = ${escaped};
568
+ const trigger = doc.querySelector('[data-testid="dropdown-trigger"]');
569
+ if (!trigger) return JSON.stringify({ success: false, error: 'no model trigger' });
570
+
571
+ // 드롭다운 열기
572
+ trigger.click();
573
+ await new Promise(r => setTimeout(r, 300));
574
+
575
+ // 옵션에서 타겟 모델 찾기
576
+ const options = doc.querySelectorAll('[data-testid*="dropdown-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
577
+ for (const opt of options) {
578
+ const text = (opt.textContent || '').trim();
579
+ if (text === target || text.includes(target)) {
580
+ opt.click();
581
+ await new Promise(r => setTimeout(r, 200));
582
+ return JSON.stringify({ success: true, model: text });
583
+ }
584
+ }
585
+
586
+ // 닫기
587
+ doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
588
+ return JSON.stringify({ success: false, error: 'model not found: ' + target });
589
+ } catch (e) { return JSON.stringify({ success: false, error: e.message }); }
590
+ })()`;
591
+ };
592
+
593
+ module.exports.listModes = function listModes() {
594
+ return `(async () => {
595
+ try {
596
+ const inner = document.querySelector('iframe');
597
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
598
+ if (!doc) return JSON.stringify({ modes: [], current: '', error: 'no doc' });
599
+
600
+ const trigger = doc.querySelector('[data-testid="mode-selector-trigger"]');
601
+ if (!trigger) return JSON.stringify({ modes: [], current: '', error: 'no mode trigger' });
602
+ const current = (trigger.textContent || '').trim();
603
+
604
+ // 드롭다운 열기
605
+ trigger.click();
606
+ await new Promise(r => setTimeout(r, 300));
607
+
608
+ // 옵션 수집
609
+ const options = doc.querySelectorAll('[data-testid*="mode-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
610
+ const modes = [];
611
+ for (const opt of options) {
612
+ const text = (opt.textContent || '').trim();
613
+ if (text && text.length > 1 && text.length < 50) modes.push(text);
614
+ }
615
+
616
+ // 닫기
617
+ doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
618
+ trigger.click(); // fallback close
619
+
620
+ return JSON.stringify({ modes: [...new Set(modes)], current });
621
+ } catch (e) { return JSON.stringify({ modes: [], current: '', error: e.message }); }
622
+ })()`;
623
+ };
624
+
625
+ module.exports.setMode = function setMode(params) {
626
+ const mode = params?.mode || params;
627
+ const escaped = JSON.stringify(mode);
628
+ return `(async () => {
629
+ try {
630
+ const inner = document.querySelector('iframe');
631
+ const doc = inner?.contentDocument || inner?.contentWindow?.document;
632
+ if (!doc) return JSON.stringify({ success: false, error: 'no doc' });
633
+
634
+ const target = ${escaped};
635
+ const trigger = doc.querySelector('[data-testid="mode-selector-trigger"]');
636
+ if (!trigger) return JSON.stringify({ success: false, error: 'no mode trigger' });
637
+
638
+ // 드롭다운 열기
639
+ trigger.click();
640
+ await new Promise(r => setTimeout(r, 300));
641
+
642
+ // 옵션에서 타겟 모드 찾기
643
+ const options = doc.querySelectorAll('[data-testid*="mode-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
644
+ for (const opt of options) {
645
+ const text = (opt.textContent || '').trim();
646
+ if (text === target || text.toLowerCase().includes(target.toLowerCase())) {
647
+ opt.click();
648
+ await new Promise(r => setTimeout(r, 200));
649
+ return JSON.stringify({ success: true, mode: text });
650
+ }
651
+ }
652
+
653
+ // 닫기
654
+ doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
655
+ return JSON.stringify({ success: false, error: 'mode not found: ' + target });
656
+ } catch (e) { return JSON.stringify({ success: false, error: e.message }); }
657
+ })()`;
658
+ };
659
+