@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.
- package/dist/index.d.ts +2662 -0
- package/dist/index.js +11341 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/providers/_builtin/.github/workflows/generate-registry.yml +57 -0
- package/providers/_builtin/COMPATIBILITY.md +217 -0
- package/providers/_builtin/CONTRIBUTING.md +200 -0
- package/providers/_builtin/README.md +119 -0
- package/providers/_builtin/_helpers/index.js +188 -0
- package/providers/_builtin/acp/agentpool/provider.json +54 -0
- package/providers/_builtin/acp/amp/provider.json +52 -0
- package/providers/_builtin/acp/auggie/provider.json +57 -0
- package/providers/_builtin/acp/autodev/provider.json +54 -0
- package/providers/_builtin/acp/autohand/provider.json +52 -0
- package/providers/_builtin/acp/blackbox-ai/provider.json +54 -0
- package/providers/_builtin/acp/claude-agent/provider.json +57 -0
- package/providers/_builtin/acp/cline-acp/provider.json +54 -0
- package/providers/_builtin/acp/codebuddy/provider.json +54 -0
- package/providers/_builtin/acp/codex-cli/provider.json +57 -0
- package/providers/_builtin/acp/corust-agent/provider.json +52 -0
- package/providers/_builtin/acp/crow-cli/provider.json +54 -0
- package/providers/_builtin/acp/cursor-acp/provider.json +54 -0
- package/providers/_builtin/acp/deepagents/provider.json +52 -0
- package/providers/_builtin/acp/dimcode/provider.json +54 -0
- package/providers/_builtin/acp/docker-cagent/provider.json +57 -0
- package/providers/_builtin/acp/factory-droid/provider.json +60 -0
- package/providers/_builtin/acp/fast-agent/provider.json +52 -0
- package/providers/_builtin/acp/gemini-cli/provider.json +114 -0
- package/providers/_builtin/acp/github-copilot/provider.json +54 -0
- package/providers/_builtin/acp/goose/provider.json +57 -0
- package/providers/_builtin/acp/junie/provider.json +52 -0
- package/providers/_builtin/acp/kilo/provider.json +54 -0
- package/providers/_builtin/acp/kimi-cli/provider.json +57 -0
- package/providers/_builtin/acp/minion-code/provider.json +52 -0
- package/providers/_builtin/acp/mistral-vibe/provider.json +57 -0
- package/providers/_builtin/acp/nova/provider.json +54 -0
- package/providers/_builtin/acp/openclaw/provider.json +54 -0
- package/providers/_builtin/acp/opencode/provider.json +52 -0
- package/providers/_builtin/acp/openhands/provider.json +54 -0
- package/providers/_builtin/acp/pi-acp/provider.json +52 -0
- package/providers/_builtin/acp/qoder/provider.json +54 -0
- package/providers/_builtin/acp/qwen-code/provider.json +60 -0
- package/providers/_builtin/acp/stakpak/provider.json +54 -0
- package/providers/_builtin/acp/vtcode/provider.json +54 -0
- package/providers/_builtin/cli/claude-cli/provider.json +100 -0
- package/providers/_builtin/cli/codex-cli/provider.json +89 -0
- package/providers/_builtin/cli/gemini-cli/provider.json +93 -0
- package/providers/_builtin/docs/CDP_SELECTOR_GUIDE.md +370 -0
- package/providers/_builtin/docs/PROVIDER_GUIDE.md +916 -0
- package/providers/_builtin/extension/cline/provider.json +35 -0
- package/providers/_builtin/extension/cline/scripts/focus_editor.js +48 -0
- package/providers/_builtin/extension/cline/scripts/list_chats.js +100 -0
- package/providers/_builtin/extension/cline/scripts/list_models.js +43 -0
- package/providers/_builtin/extension/cline/scripts/list_modes.js +35 -0
- package/providers/_builtin/extension/cline/scripts/new_session.js +85 -0
- package/providers/_builtin/extension/cline/scripts/open_panel.js +25 -0
- package/providers/_builtin/extension/cline/scripts/read_chat.js +257 -0
- package/providers/_builtin/extension/cline/scripts/resolve_action.js +83 -0
- package/providers/_builtin/extension/cline/scripts/send_message.js +95 -0
- package/providers/_builtin/extension/cline/scripts/set_mode.js +36 -0
- package/providers/_builtin/extension/cline/scripts/set_model.js +36 -0
- package/providers/_builtin/extension/cline/scripts/switch_session.js +206 -0
- package/providers/_builtin/extension/cline/scripts.js +73 -0
- package/providers/_builtin/extension/roo-code/provider.json +35 -0
- package/providers/_builtin/extension/roo-code/scripts.js +659 -0
- package/providers/_builtin/ide/antigravity/provider.json +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/focus_editor.js +20 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_chats.js +137 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +38 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +48 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/new_session.js +75 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +262 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/resolve_action.js +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +57 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/send_message.js +56 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +34 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +47 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/switch_session.js +114 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +20 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +137 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_models.js +61 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_modes.js +72 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +75 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +262 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/scripts.js +67 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +56 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/set_mode.js +67 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/set_model.js +72 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +114 -0
- package/providers/_builtin/ide/cursor/provider.json +70 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +30 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +13 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +40 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_sessions.js +42 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +20 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +75 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/resolve_action.js +19 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/scripts.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +38 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +81 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +28 -0
- package/providers/_builtin/ide/kiro/provider.json +67 -0
- package/providers/_builtin/ide/kiro/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/kiro/scripts/open_panel.js +47 -0
- package/providers/_builtin/ide/kiro/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/kiro/scripts/send_message.js +29 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +39 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +39 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +21 -0
- package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +34 -0
- package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +68 -0
- package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +72 -0
- package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +15 -0
- package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +15 -0
- package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +26 -0
- package/providers/_builtin/ide/kiro/scripts.js +62 -0
- package/providers/_builtin/ide/pearai/provider.json +67 -0
- package/providers/_builtin/ide/pearai/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/pearai/scripts/list_sessions.js +38 -0
- package/providers/_builtin/ide/pearai/scripts/new_session.js +55 -0
- package/providers/_builtin/ide/pearai/scripts/open_panel.js +46 -0
- package/providers/_builtin/ide/pearai/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/pearai/scripts/send_message.js +29 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +43 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +35 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +62 -0
- package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +49 -0
- package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +92 -0
- package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +59 -0
- package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +72 -0
- package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +36 -0
- package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +36 -0
- package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +34 -0
- package/providers/_builtin/ide/pearai/scripts.js +74 -0
- package/providers/_builtin/ide/trae/provider.json +66 -0
- package/providers/_builtin/ide/trae/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/trae/scripts/list_chats.js +24 -0
- package/providers/_builtin/ide/trae/scripts/list_models.js +39 -0
- package/providers/_builtin/ide/trae/scripts/list_modes.js +39 -0
- package/providers/_builtin/ide/trae/scripts/new_session.js +30 -0
- package/providers/_builtin/ide/trae/scripts/open_panel.js +44 -0
- package/providers/_builtin/ide/trae/scripts/read_chat.js +113 -0
- package/providers/_builtin/ide/trae/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/trae/scripts/send_message.js +69 -0
- package/providers/_builtin/ide/trae/scripts/set_mode.js +15 -0
- package/providers/_builtin/ide/trae/scripts/set_model.js +15 -0
- package/providers/_builtin/ide/trae/scripts/switch_session.js +23 -0
- package/providers/_builtin/ide/trae/scripts.js +57 -0
- package/providers/_builtin/ide/vscode/provider.json +64 -0
- package/providers/_builtin/ide/vscode-insiders/provider.json +62 -0
- package/providers/_builtin/ide/vscodium/provider.json +63 -0
- package/providers/_builtin/ide/windsurf/provider.json +53 -0
- package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +30 -0
- package/providers/_builtin/ide/windsurf/scripts/list_chats.js +117 -0
- package/providers/_builtin/ide/windsurf/scripts/list_models.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/list_modes.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/new_session.js +69 -0
- package/providers/_builtin/ide/windsurf/scripts/open_panel.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts/read_chat.js +297 -0
- package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +68 -0
- package/providers/_builtin/ide/windsurf/scripts/send_message.js +87 -0
- package/providers/_builtin/ide/windsurf/scripts/set_mode.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/set_model.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/switch_session.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts.js +57 -0
- package/providers/_builtin/registry.json +266 -0
- package/providers/_builtin/validate.js +156 -0
- package/src/agent-stream/index.ts +6 -0
- package/src/agent-stream/manager.ts +286 -0
- package/src/agent-stream/poller.ts +154 -0
- package/src/agent-stream/provider-adapter.ts +138 -0
- package/src/agent-stream/types.ts +61 -0
- package/src/boot/daemon-lifecycle.ts +252 -0
- package/src/cdp/devtools.ts +335 -0
- package/src/cdp/initializer.ts +191 -0
- package/src/cdp/manager.ts +897 -0
- package/src/cdp/scanner.ts +185 -0
- package/src/cdp/setup.ts +150 -0
- package/src/cli-adapter-types.ts +25 -0
- package/src/cli-adapters/provider-cli-adapter.ts +448 -0
- package/src/commands/cdp-commands.ts +208 -0
- package/src/commands/chat-commands.ts +675 -0
- package/src/commands/cli-manager.ts +353 -0
- package/src/commands/handler.ts +328 -0
- package/src/commands/router.ts +258 -0
- package/src/commands/stream-commands.ts +325 -0
- package/src/config/chat-history.ts +211 -0
- package/src/config/config.ts +219 -0
- package/src/daemon/dev-server.ts +2378 -0
- package/src/daemon/scaffold-template.ts +394 -0
- package/src/daemon-core.ts +50 -0
- package/src/detection/cli-detector.ts +89 -0
- package/src/detection/ide-detector.ts +157 -0
- package/src/index.ts +103 -0
- package/src/installer.ts +263 -0
- package/src/ipc-protocol.ts +133 -0
- package/src/launch.ts +433 -0
- package/src/logging/command-log.ts +180 -0
- package/src/logging/logger.ts +316 -0
- package/src/providers/acp-provider-instance.ts +1140 -0
- package/src/providers/cli-provider-instance.ts +207 -0
- package/src/providers/contracts.ts +524 -0
- package/src/providers/extension-provider-instance.ts +156 -0
- package/src/providers/ide-provider-instance.ts +377 -0
- package/src/providers/index.ts +18 -0
- package/src/providers/provider-instance-manager.ts +182 -0
- package/src/providers/provider-instance.ts +112 -0
- package/src/providers/provider-loader.ts +1031 -0
- package/src/providers/status-monitor.ts +125 -0
- package/src/providers/version-archive.ts +266 -0
- package/src/status/reporter.ts +294 -0
- package/src/types.ts +206 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cline v1 — resolve_action
|
|
3
|
+
*
|
|
4
|
+
* Cline의 승인/거부 처리.
|
|
5
|
+
* Cline은 button 태그 외에 vscode-button 웹 컴포넌트도 사용.
|
|
6
|
+
* chatState.primaryButtonText / secondaryButtonText로 정확한 매칭.
|
|
7
|
+
*
|
|
8
|
+
* 파라미터: ${ ACTION } — "approve" 또는 "reject"
|
|
9
|
+
*
|
|
10
|
+
* 전략:
|
|
11
|
+
* 1. chatState.primaryButtonText == Approve → primary vscode-button 클릭
|
|
12
|
+
* 2. data-testid 기반 탐색
|
|
13
|
+
* 3. 텍스트 매칭 (button + vscode-button)
|
|
14
|
+
* 4. Fiber onSendMessage로 직접 승인 전달
|
|
15
|
+
*
|
|
16
|
+
* 최종 확인: 2026-03-07
|
|
17
|
+
*/
|
|
18
|
+
(() => {
|
|
19
|
+
try {
|
|
20
|
+
const inner = document.querySelector('iframe');
|
|
21
|
+
const doc = inner?.contentDocument || inner?.contentWindow?.document;
|
|
22
|
+
if (!doc) return false;
|
|
23
|
+
|
|
24
|
+
const action = ${ ACTION };
|
|
25
|
+
const approvePatterns = ['proceed', 'approve', 'allow', 'accept', 'save', 'run', 'yes', 'confirm', 'resume'];
|
|
26
|
+
const rejectPatterns = ['reject', 'deny', 'cancel', 'no', 'skip'];
|
|
27
|
+
const patterns = action === 'approve' ? approvePatterns : rejectPatterns;
|
|
28
|
+
|
|
29
|
+
// ─── 모든 클릭 가능 요소 수집 (button + vscode-button) ───
|
|
30
|
+
const allBtns = [
|
|
31
|
+
...Array.from(doc.querySelectorAll('button')),
|
|
32
|
+
...Array.from(doc.querySelectorAll('vscode-button')),
|
|
33
|
+
].filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
|
|
34
|
+
|
|
35
|
+
// ─── 1단계: data-testid 기반 ───
|
|
36
|
+
for (const btn of allBtns) {
|
|
37
|
+
const testId = (btn.getAttribute('data-testid') || '').toLowerCase();
|
|
38
|
+
if (action === 'approve' && (testId.includes('approve') || testId.includes('proceed') || testId.includes('accept') || testId.includes('run') || testId.includes('primary'))) {
|
|
39
|
+
btn.click(); return true;
|
|
40
|
+
}
|
|
41
|
+
if (action === 'reject' && (testId.includes('reject') || testId.includes('deny') || testId.includes('cancel') || testId.includes('secondary'))) {
|
|
42
|
+
btn.click(); return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ─── 2단계: 텍스트 매칭 ───
|
|
47
|
+
for (const btn of allBtns) {
|
|
48
|
+
const text = (btn.textContent || '').trim().toLowerCase();
|
|
49
|
+
if (text.length === 0 || text.length > 40) continue;
|
|
50
|
+
if (patterns.some(p => text.startsWith(p) || text === p || text.includes(p))) {
|
|
51
|
+
btn.click(); return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ─── 3단계: aria-label ───
|
|
56
|
+
for (const btn of allBtns) {
|
|
57
|
+
const label = (btn.getAttribute('aria-label') || '').toLowerCase();
|
|
58
|
+
if (patterns.some(p => label.includes(p))) {
|
|
59
|
+
btn.click(); return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─── 4단계: chatState 기반 — primary/secondary 버튼 직접 매칭 ───
|
|
64
|
+
// chatState.primaryButtonText = "Approve", secondaryButtonText = "Reject"
|
|
65
|
+
// 가장 큰 vscode-button이 primary 버튼
|
|
66
|
+
const vscBtns = Array.from(doc.querySelectorAll('vscode-button'))
|
|
67
|
+
.filter(b => b.offsetWidth > 100); // 큰 버튼만
|
|
68
|
+
if (vscBtns.length > 0) {
|
|
69
|
+
if (action === 'approve') {
|
|
70
|
+
// 가장 큰 버튼이 primary
|
|
71
|
+
vscBtns.sort((a, b) => b.offsetWidth - a.offsetWidth);
|
|
72
|
+
vscBtns[0].click(); return true;
|
|
73
|
+
}
|
|
74
|
+
// reject: 가장 작은 큰 버튼
|
|
75
|
+
if (action === 'reject' && vscBtns.length > 1) {
|
|
76
|
+
vscBtns.sort((a, b) => a.offsetWidth - b.offsetWidth);
|
|
77
|
+
vscBtns[0].click(); return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return false;
|
|
82
|
+
} catch { return false; }
|
|
83
|
+
})()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cline v1 — send_message
|
|
3
|
+
*
|
|
4
|
+
* 구조:
|
|
5
|
+
* 1. outer webview → inner iframe의 contentDocument 접근
|
|
6
|
+
* 2. data-testid="chat-input" textarea에 값 설정 (React controlled)
|
|
7
|
+
* 3. React Fiber에서 onSend 함수 찾아 직접 호출 (가장 확실한 방법)
|
|
8
|
+
* 4. Fallback: data-testid="send-button" 클릭 or Enter 키
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ Cline의 send-button은 DIV 태그이며, 일반 click 이벤트로는 React가
|
|
11
|
+
* 전송을 처리하지 않음. Fiber onSend()를 직접 호출해야 정확하게 동작.
|
|
12
|
+
*
|
|
13
|
+
* 최종 확인: 2026-03-07
|
|
14
|
+
*/
|
|
15
|
+
(async () => {
|
|
16
|
+
try {
|
|
17
|
+
const inner = document.querySelector('iframe');
|
|
18
|
+
const doc = inner?.contentDocument || inner?.contentWindow?.document;
|
|
19
|
+
if (!doc) return 'error: no doc';
|
|
20
|
+
|
|
21
|
+
// ─── 1. 입력 필드 찾기 ───
|
|
22
|
+
let target = doc.querySelector('[data-testid="chat-input"]');
|
|
23
|
+
if (!target) {
|
|
24
|
+
const textareas = doc.querySelectorAll('textarea');
|
|
25
|
+
for (const ta of textareas) {
|
|
26
|
+
if (ta.offsetParent !== null && ta.offsetHeight > 20) {
|
|
27
|
+
target = ta;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (!target) return 'error: no chat-input';
|
|
33
|
+
|
|
34
|
+
// ─── 2. React controlled input 값 설정 ───
|
|
35
|
+
const proto = inner.contentWindow?.HTMLTextAreaElement?.prototype
|
|
36
|
+
|| HTMLTextAreaElement.prototype;
|
|
37
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
|
|
38
|
+
|
|
39
|
+
if (nativeSetter) {
|
|
40
|
+
nativeSetter.call(target, ${ MESSAGE });
|
|
41
|
+
} else {
|
|
42
|
+
target.value = ${ MESSAGE };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// React 이벤트 트리거
|
|
46
|
+
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
47
|
+
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
48
|
+
|
|
49
|
+
// React setState 반영 대기
|
|
50
|
+
await new Promise(r => setTimeout(r, 300));
|
|
51
|
+
|
|
52
|
+
// ─── 3. Fiber onSend 직접 호출 (최우선) ───
|
|
53
|
+
const allEls = doc.querySelectorAll('*');
|
|
54
|
+
for (const el of allEls) {
|
|
55
|
+
const fk = Object.keys(el).find(k => k.startsWith('__reactFiber'));
|
|
56
|
+
if (!fk) continue;
|
|
57
|
+
let fiber = el[fk];
|
|
58
|
+
for (let d = 0; d < 15 && fiber; d++) {
|
|
59
|
+
const props = fiber.memoizedProps || fiber.pendingProps;
|
|
60
|
+
if (props && typeof props.onSend === 'function') {
|
|
61
|
+
props.onSend();
|
|
62
|
+
return 'sent';
|
|
63
|
+
}
|
|
64
|
+
fiber = fiber.return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ─── 4. Fallback: send-button 클릭 ───
|
|
69
|
+
const sendBtn = doc.querySelector('[data-testid="send-button"]');
|
|
70
|
+
if (sendBtn) {
|
|
71
|
+
try {
|
|
72
|
+
const rect = sendBtn.getBoundingClientRect();
|
|
73
|
+
const opts = {
|
|
74
|
+
bubbles: true, cancelable: true, view: inner.contentWindow,
|
|
75
|
+
clientX: rect.left + rect.width / 2, clientY: rect.top + rect.height / 2
|
|
76
|
+
};
|
|
77
|
+
sendBtn.dispatchEvent(new MouseEvent('mousedown', opts));
|
|
78
|
+
sendBtn.dispatchEvent(new MouseEvent('mouseup', opts));
|
|
79
|
+
sendBtn.dispatchEvent(new MouseEvent('click', opts));
|
|
80
|
+
return 'sent';
|
|
81
|
+
} catch (e) { }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── 5. 최후 Fallback: Enter 키 ───
|
|
85
|
+
target.focus();
|
|
86
|
+
target.dispatchEvent(new KeyboardEvent('keydown', {
|
|
87
|
+
key: 'Enter', code: 'Enter', keyCode: 13,
|
|
88
|
+
bubbles: true, cancelable: true,
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
return 'sent';
|
|
92
|
+
} catch (e) {
|
|
93
|
+
return 'error: ' + e.message;
|
|
94
|
+
}
|
|
95
|
+
})()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cline — set_mode
|
|
3
|
+
* 모드 selector에서 지정된 모드 선택
|
|
4
|
+
* ${MODE} → JSON.stringify(modeName)
|
|
5
|
+
* → { success: boolean }
|
|
6
|
+
*/
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const inner = document.querySelector('iframe');
|
|
10
|
+
const doc = inner?.contentDocument || inner?.contentWindow?.document;
|
|
11
|
+
if (!doc) return JSON.stringify({ success: false, error: 'no doc' });
|
|
12
|
+
|
|
13
|
+
const target = ${MODE};
|
|
14
|
+
const trigger = doc.querySelector('[data-testid="mode-selector-trigger"], [data-testid="mode-switch"]');
|
|
15
|
+
if (!trigger) return JSON.stringify({ success: false, error: 'no mode trigger' });
|
|
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
|
+
for (const opt of options) {
|
|
24
|
+
const text = (opt.textContent || '').trim();
|
|
25
|
+
if (text === target || text.toLowerCase().includes(target.toLowerCase())) {
|
|
26
|
+
opt.click();
|
|
27
|
+
await new Promise(r => setTimeout(r, 200));
|
|
28
|
+
return JSON.stringify({ success: true, mode: text });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 닫기
|
|
33
|
+
doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
34
|
+
return JSON.stringify({ success: false, error: 'mode not found: ' + target });
|
|
35
|
+
} catch (e) { return JSON.stringify({ success: false, error: e.message }); }
|
|
36
|
+
})()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cline — set_model
|
|
3
|
+
* 드롭다운에서 지정된 모델 선택
|
|
4
|
+
* ${MODEL} → JSON.stringify(modelName)
|
|
5
|
+
* → { success: boolean }
|
|
6
|
+
*/
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const inner = document.querySelector('iframe');
|
|
10
|
+
const doc = inner?.contentDocument || inner?.contentWindow?.document;
|
|
11
|
+
if (!doc) return JSON.stringify({ success: false, error: 'no doc' });
|
|
12
|
+
|
|
13
|
+
const target = ${MODEL};
|
|
14
|
+
const trigger = doc.querySelector('[data-testid="model-selector"], [data-testid*="model-dropdown"], [data-testid="dropdown-trigger"]');
|
|
15
|
+
if (!trigger) return JSON.stringify({ success: false, error: 'no model trigger' });
|
|
16
|
+
|
|
17
|
+
// 드롭다운 열기
|
|
18
|
+
trigger.click();
|
|
19
|
+
await new Promise(r => setTimeout(r, 300));
|
|
20
|
+
|
|
21
|
+
// 옵션에서 타겟 모델 찾기
|
|
22
|
+
const options = doc.querySelectorAll('[data-testid*="dropdown-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
|
|
23
|
+
for (const opt of options) {
|
|
24
|
+
const text = (opt.textContent || '').trim();
|
|
25
|
+
if (text === target || text.includes(target)) {
|
|
26
|
+
opt.click();
|
|
27
|
+
await new Promise(r => setTimeout(r, 200));
|
|
28
|
+
return JSON.stringify({ success: true, model: text });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 닫기
|
|
33
|
+
doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
34
|
+
return JSON.stringify({ success: false, error: 'model not found: ' + target });
|
|
35
|
+
} catch (e) { return JSON.stringify({ success: false, error: e.message }); }
|
|
36
|
+
})()
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cline v1 — switch_session (Fiber hooks → showTaskWithId gRPC)
|
|
3
|
+
*
|
|
4
|
+
* 전략:
|
|
5
|
+
* 1. Fiber DFS에서 taskHistory, showHistoryView 찾기
|
|
6
|
+
* 2. Done 클릭으로 히스토리 닫기 → showHistoryView() → 재열기
|
|
7
|
+
* 3. Virtuoso 렌더링 대기 (최대 5초, 500ms 간격 재시도 + scroll/resize 트리거)
|
|
8
|
+
* 4. 렌더된 아이템의 Fiber hooks에서 showTaskWithId 콜백 추출
|
|
9
|
+
* 5. showTaskWithId(taskId) 호출 → gRPC로 Task 전환
|
|
10
|
+
*
|
|
11
|
+
* 파라미터: ${ SESSION_ID } — task ID (숫자 문자열) 또는 제목
|
|
12
|
+
* 최종 확인: 2026-03-07
|
|
13
|
+
*/
|
|
14
|
+
(async () => {
|
|
15
|
+
try {
|
|
16
|
+
const inner = document.querySelector('iframe');
|
|
17
|
+
const doc = inner?.contentDocument || inner?.contentWindow?.document;
|
|
18
|
+
if (!doc) return false;
|
|
19
|
+
|
|
20
|
+
const sessionId = ${ SESSION_ID };
|
|
21
|
+
if (!sessionId) return false;
|
|
22
|
+
|
|
23
|
+
const findFiberKey = (el) => Object.keys(el).find(k =>
|
|
24
|
+
k.startsWith('__reactFiber') || k.startsWith('__reactProps') || k.startsWith('__reactContainer'));
|
|
25
|
+
const getFiber = (el) => {
|
|
26
|
+
const fk = findFiberKey(el);
|
|
27
|
+
if (!fk) return null;
|
|
28
|
+
let fiber = el[fk];
|
|
29
|
+
if (fk.startsWith('__reactContainer') && fiber?._internalRoot?.current)
|
|
30
|
+
fiber = fiber._internalRoot.current;
|
|
31
|
+
return fiber;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ─── 1. Fiber DFS에서 taskHistory, showHistoryView 찾기 ───
|
|
35
|
+
const root = doc.getElementById('root');
|
|
36
|
+
if (!root) return false;
|
|
37
|
+
const rootFk = findFiberKey(root);
|
|
38
|
+
if (!rootFk) return false;
|
|
39
|
+
let rootFiber = root[rootFk];
|
|
40
|
+
if (rootFk.startsWith('__reactContainer') && rootFiber?._internalRoot?.current)
|
|
41
|
+
rootFiber = rootFiber._internalRoot.current;
|
|
42
|
+
|
|
43
|
+
let showHistoryView = null;
|
|
44
|
+
let taskHistory = null;
|
|
45
|
+
const visited = new Set();
|
|
46
|
+
const scanFiber = (f, depth) => {
|
|
47
|
+
if (!f || depth > 60 || visited.has(f)) return;
|
|
48
|
+
visited.add(f);
|
|
49
|
+
const props = f.memoizedProps || f.pendingProps;
|
|
50
|
+
if (props) {
|
|
51
|
+
if (typeof props.showHistoryView === 'function' && !showHistoryView)
|
|
52
|
+
showHistoryView = props.showHistoryView;
|
|
53
|
+
if (props.taskHistory && Array.isArray(props.taskHistory) && !taskHistory)
|
|
54
|
+
taskHistory = props.taskHistory;
|
|
55
|
+
}
|
|
56
|
+
if (!taskHistory && f.memoizedState) {
|
|
57
|
+
let st = f.memoizedState;
|
|
58
|
+
while (st) {
|
|
59
|
+
try {
|
|
60
|
+
const ms = st.memoizedState;
|
|
61
|
+
if (ms?.taskHistory && Array.isArray(ms.taskHistory)) {
|
|
62
|
+
taskHistory = ms.taskHistory;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
} catch { }
|
|
66
|
+
st = st.next;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (f.child) scanFiber(f.child, depth + 1);
|
|
70
|
+
if (f.sibling) scanFiber(f.sibling, depth + 1);
|
|
71
|
+
};
|
|
72
|
+
scanFiber(rootFiber, 0);
|
|
73
|
+
|
|
74
|
+
if (!taskHistory || taskHistory.length === 0) return false;
|
|
75
|
+
|
|
76
|
+
// 대상 task 찾기 (ID 또는 제목 매칭)
|
|
77
|
+
const norm = s => (s || '').trim().toLowerCase().replace(/\s+/g, ' ');
|
|
78
|
+
const idNorm = norm(sessionId);
|
|
79
|
+
let targetTask = taskHistory.find(t => String(t.id) === sessionId);
|
|
80
|
+
if (!targetTask) {
|
|
81
|
+
targetTask = taskHistory.find(t => {
|
|
82
|
+
const title = norm(t.task || '');
|
|
83
|
+
return title.includes(idNorm) || idNorm.includes(title);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (!targetTask) return false;
|
|
87
|
+
const targetId = String(targetTask.id);
|
|
88
|
+
|
|
89
|
+
// ─── 2. showHistoryView가 없으면 Fiber root DFS 재시도 ───
|
|
90
|
+
if (!showHistoryView) {
|
|
91
|
+
// DOM 요소 기반 탐색 (Fiber root에서 못 찾은 경우)
|
|
92
|
+
for (const el of doc.querySelectorAll('*')) {
|
|
93
|
+
let fiber = getFiber(el);
|
|
94
|
+
for (let d = 0; d < 20 && fiber; d++) {
|
|
95
|
+
const p = fiber.memoizedProps;
|
|
96
|
+
if (p && typeof p.showHistoryView === 'function') {
|
|
97
|
+
showHistoryView = p.showHistoryView;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
fiber = fiber.return;
|
|
101
|
+
}
|
|
102
|
+
if (showHistoryView) break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!showHistoryView) return false;
|
|
106
|
+
|
|
107
|
+
// ─── 3. 히스토리 뷰 토글 (닫기 → 열기) ───
|
|
108
|
+
// Done 버튼으로 닫기
|
|
109
|
+
const doneBtn = Array.from(doc.querySelectorAll('button'))
|
|
110
|
+
.find(b => b.textContent.trim() === 'Done' && b.offsetHeight > 0);
|
|
111
|
+
if (doneBtn) {
|
|
112
|
+
doneBtn.click();
|
|
113
|
+
await new Promise(r => setTimeout(r, 400));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 히스토리 열기
|
|
117
|
+
showHistoryView();
|
|
118
|
+
|
|
119
|
+
// ─── 4. Virtuoso 렌더링 대기 (최대 5초, 500ms 간격 재시도) ───
|
|
120
|
+
let il = null;
|
|
121
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
122
|
+
await new Promise(r => setTimeout(r, 500));
|
|
123
|
+
// scroll + resize 트리거
|
|
124
|
+
const sd = doc.querySelector('.overflow-y-scroll, [data-testid=virtuoso-scroller]');
|
|
125
|
+
if (sd) {
|
|
126
|
+
sd.dispatchEvent(new Event('scroll', { bubbles: true }));
|
|
127
|
+
doc.defaultView?.dispatchEvent(new Event('resize'));
|
|
128
|
+
}
|
|
129
|
+
il = doc.querySelector('[data-testid=virtuoso-item-list]');
|
|
130
|
+
if (il && il.children.length > 0) break;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!il || il.children.length === 0) return false;
|
|
134
|
+
|
|
135
|
+
// ─── 5. Fiber hooks에서 showTaskWithId 추출 ───
|
|
136
|
+
let showTaskFn = null;
|
|
137
|
+
const findFiberKeySimple = (el) => Object.keys(el).find(k => k.startsWith('__reactFiber'));
|
|
138
|
+
|
|
139
|
+
for (const child of il.children) {
|
|
140
|
+
// child 또는 child 내부의 모든 요소에서 탐색
|
|
141
|
+
const targets = [child, ...child.querySelectorAll('*')];
|
|
142
|
+
for (const el of targets) {
|
|
143
|
+
const fk = findFiberKeySimple(el);
|
|
144
|
+
if (!fk) continue;
|
|
145
|
+
let fiber = el[fk];
|
|
146
|
+
for (let d = 0; d < 30 && fiber; d++) {
|
|
147
|
+
if (fiber.memoizedState) {
|
|
148
|
+
let hook = fiber.memoizedState;
|
|
149
|
+
let hookIdx = 0;
|
|
150
|
+
while (hook && hookIdx < 30) {
|
|
151
|
+
const ms = hook.memoizedState;
|
|
152
|
+
if (Array.isArray(ms) && ms.length === 2 && typeof ms[0] === 'function') {
|
|
153
|
+
const fnSrc = ms[0].toString();
|
|
154
|
+
if (fnSrc.includes('showTaskWithId')) {
|
|
155
|
+
showTaskFn = ms[0];
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
hook = hook.next;
|
|
160
|
+
hookIdx++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (showTaskFn) break;
|
|
164
|
+
fiber = fiber.return;
|
|
165
|
+
}
|
|
166
|
+
if (showTaskFn) break;
|
|
167
|
+
}
|
|
168
|
+
if (showTaskFn) break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Fallback: Fiber DFS 전체 탐색
|
|
172
|
+
if (!showTaskFn) {
|
|
173
|
+
const visited2 = new Set();
|
|
174
|
+
const dfs2 = (f, depth) => {
|
|
175
|
+
if (!f || depth > 60 || visited2.has(f) || showTaskFn) return;
|
|
176
|
+
visited2.add(f);
|
|
177
|
+
if (f.memoizedState) {
|
|
178
|
+
let h = f.memoizedState; let i = 0;
|
|
179
|
+
while (h && i < 30) {
|
|
180
|
+
const ms = h.memoizedState;
|
|
181
|
+
if (Array.isArray(ms) && ms.length === 2 && typeof ms[0] === 'function' &&
|
|
182
|
+
ms[0].toString().includes('showTaskWithId')) {
|
|
183
|
+
showTaskFn = ms[0]; return;
|
|
184
|
+
}
|
|
185
|
+
h = h.next; i++;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (f.child) dfs2(f.child, depth + 1);
|
|
189
|
+
if (f.sibling) dfs2(f.sibling, depth + 1);
|
|
190
|
+
};
|
|
191
|
+
dfs2(rootFiber, 0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!showTaskFn) return false;
|
|
195
|
+
|
|
196
|
+
// ─── 6. showTaskWithId(targetId) 호출 ───
|
|
197
|
+
try {
|
|
198
|
+
await showTaskFn(targetId);
|
|
199
|
+
} catch {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
204
|
+
return true;
|
|
205
|
+
} catch { return false; }
|
|
206
|
+
})()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP Scripts for Cline
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const SCRIPTS_DIR = path.join(__dirname, 'scripts');
|
|
8
|
+
function loadScript(name) {
|
|
9
|
+
try { return fs.readFileSync(path.join(SCRIPTS_DIR, name), 'utf8'); }
|
|
10
|
+
catch { return null; }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module.exports.readChat = function readChat() {
|
|
15
|
+
return loadScript('read_chat.js');
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports.sendMessage = function sendMessage(text) {
|
|
19
|
+
const script = loadScript('send_message.js');
|
|
20
|
+
if (!script) return null;
|
|
21
|
+
return script.replace(/\$\{\s*MESSAGE\s*\}/g, JSON.stringify(text));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports.listSessions = function listSessions() {
|
|
25
|
+
return loadScript('list_chats.js');
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
module.exports.switchSession = function switchSession(sessionId) {
|
|
29
|
+
const script = loadScript('switch_session.js');
|
|
30
|
+
if (!script) return null;
|
|
31
|
+
return script.replace(/\$\{\s*SESSION_ID\s*\}/g, JSON.stringify(sessionId));
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
module.exports.newSession = function newSession() {
|
|
35
|
+
return loadScript('new_session.js');
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports.resolveAction = function resolveAction(action) {
|
|
39
|
+
const script = loadScript('resolve_action.js');
|
|
40
|
+
if (!script) return null;
|
|
41
|
+
return script.replace(/\$\{\s*ACTION\s*\}/g, JSON.stringify(action));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
module.exports.focusEditor = function focusEditor() {
|
|
45
|
+
return loadScript('focus_editor.js');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
module.exports.openPanel = function openPanel() {
|
|
49
|
+
return loadScript('open_panel.js');
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports.listModels = function listModels() {
|
|
53
|
+
return loadScript('list_models.js');
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
module.exports.setModel = function setModel(params) {
|
|
57
|
+
const model = params?.model || params;
|
|
58
|
+
const script = loadScript('set_model.js');
|
|
59
|
+
if (!script) return null;
|
|
60
|
+
return script.replace(/\$\{\s*MODEL\s*\}/g, JSON.stringify(model));
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
module.exports.listModes = function listModes() {
|
|
64
|
+
return loadScript('list_modes.js');
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
module.exports.setMode = function setMode(params) {
|
|
68
|
+
const mode = params?.mode || params;
|
|
69
|
+
const script = loadScript('set_mode.js');
|
|
70
|
+
if (!script) return null;
|
|
71
|
+
return script.replace(/\$\{\s*MODE\s*\}/g, JSON.stringify(mode));
|
|
72
|
+
};
|
|
73
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "roo-code",
|
|
3
|
+
"name": "Roo Code",
|
|
4
|
+
"category": "extension",
|
|
5
|
+
"extensionId": "RooVeterinaryInc.roo-cline",
|
|
6
|
+
"extensionIdPattern": "extensionId=RooVeterinaryInc\\.roo-cline",
|
|
7
|
+
"extensionIdPattern_flags": "i",
|
|
8
|
+
"vscodeCommands": {
|
|
9
|
+
"focusPanel": "roo-cline.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
|
+
}
|