@adhdev/daemon-core 0.6.35 → 0.6.37
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 +2 -1
- package/dist/index.js +112 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/acp/codex-cli/provider.json +2 -2
- package/providers/_builtin/cli/codex-cli/provider.json +8 -18
- package/providers/_builtin/ide/antigravity/provider.json +2 -3
- package/providers/_builtin/ide/cursor/provider.json +2 -2
- package/providers/_builtin/ide/cursor/scripts/{0.49 → 1.0}/read_chat.js +1 -1
- package/providers/_builtin/ide/cursor/scripts/{0.49 → 1.0}/resolve_action.js +1 -1
- package/providers/_builtin/ide/windsurf/scripts/1.0/focus_editor.js +16 -10
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_chats.js +9 -103
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_models.js +43 -26
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_modes.js +51 -27
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_sessions.js +79 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0/new_session.js +30 -41
- package/providers/_builtin/ide/windsurf/scripts/1.0/open_panel.js +44 -35
- package/providers/_builtin/ide/windsurf/scripts/1.0/read_chat.js +211 -273
- package/providers/_builtin/ide/windsurf/scripts/1.0/resolve_action.js +64 -50
- package/providers/_builtin/ide/windsurf/scripts/1.0/send_message.js +14 -81
- package/providers/_builtin/ide/windsurf/scripts/1.0/set_mode.js +34 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/set_model.js +40 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/switch_session.js +66 -42
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/focus_editor.js +30 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_chats.js +117 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_models.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_modes.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/new_session.js +69 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/open_panel.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/read_chat.js +315 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/resolve_action.js +68 -0
- package/providers/_builtin/ide/{cursor/scripts/0.49 → windsurf/scripts/1.0.bak}/scripts.js +27 -23
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/send_message.js +87 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/set_mode.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/set_model.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/switch_session.js +58 -0
- package/providers/_builtin/registry.json +5 -9
- package/src/cdp/manager.ts +38 -12
- package/src/commands/handler.ts +1 -8
- package/src/daemon/dev-server.ts +66 -8
- package/src/detection/ide-detector.ts +0 -3
- package/src/providers/provider-loader.ts +4 -2
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +0 -38
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +0 -48
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +0 -290
- package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +0 -57
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +0 -34
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +0 -47
- package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +0 -20
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +0 -137
- package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +0 -75
- package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +0 -63
- package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +0 -56
- package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +0 -114
- package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +0 -30
- package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +0 -13
- package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +0 -78
- package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +0 -40
- package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +0 -23
- package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +0 -20
- package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +0 -23
- package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +0 -23
- package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +0 -38
- package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +0 -81
- package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +0 -28
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_sessions.js +0 -42
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/read_chat.js +0 -79
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/resolve_action.js +0 -19
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/focus_editor.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/list_chats.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/list_models.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/list_modes.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/new_session.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/read_chat.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/resolve_action.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/scripts.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/send_message.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/set_mode.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/set_model.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/switch_session.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/dismiss_notification.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/focus_editor.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/list_models.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/list_modes.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/list_notifications.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49 → 1.0}/list_sessions.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/new_session.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/open_panel.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/scripts.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/send_message.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/set_mode.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/set_model.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/switch_session.js +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf v1 — send_message
|
|
3
|
+
*
|
|
4
|
+
* Windsurf는 Lexical 에디터 ([data-lexical-editor="true"])를 사용합니다.
|
|
5
|
+
* contenteditable div이므로 execCommand('insertText') 또는 InputEvent로 입력 가능.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ Lexical은 입력 이벤트를 정밀하게 감지하므로:
|
|
8
|
+
* - execCommand('insertText')가 가장 안정적
|
|
9
|
+
* - nativeSetter 방식은 동작하지 않음
|
|
10
|
+
* - InputEvent('insertText')를 폴백으로 사용
|
|
11
|
+
*
|
|
12
|
+
* Enter 키는 KeyboardEvent 전체 시퀀스 필요 (keydown + keypress + keyup).
|
|
13
|
+
*
|
|
14
|
+
* 파라미터: ${ MESSAGE }
|
|
15
|
+
* 최종 확인: Windsurf 1.108.x (2026-03-10)
|
|
16
|
+
*/
|
|
17
|
+
(async () => {
|
|
18
|
+
try {
|
|
19
|
+
const msg = ${ MESSAGE };
|
|
20
|
+
|
|
21
|
+
// ─── 1. Lexical 에디터 찾기 (폴백 체인) ───
|
|
22
|
+
const editor =
|
|
23
|
+
document.querySelector('[data-lexical-editor="true"]') ||
|
|
24
|
+
document.querySelector('[contenteditable="true"][role="textbox"]') ||
|
|
25
|
+
document.querySelector('.cascade-input [contenteditable="true"]') ||
|
|
26
|
+
document.querySelector('.chat-input textarea') ||
|
|
27
|
+
document.querySelector('textarea:not(.xterm-helper-textarea)');
|
|
28
|
+
|
|
29
|
+
if (!editor) return 'error: no input found';
|
|
30
|
+
|
|
31
|
+
const isTextarea = editor.tagName === 'TEXTAREA';
|
|
32
|
+
|
|
33
|
+
if (isTextarea) {
|
|
34
|
+
// ─── textarea 폴백 (미로그인 등) ───
|
|
35
|
+
editor.focus();
|
|
36
|
+
const proto = HTMLTextAreaElement.prototype;
|
|
37
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
|
|
38
|
+
if (nativeSetter) nativeSetter.call(editor, msg);
|
|
39
|
+
else editor.value = msg;
|
|
40
|
+
|
|
41
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
42
|
+
editor.dispatchEvent(new Event('change', { bubbles: true }));
|
|
43
|
+
|
|
44
|
+
await new Promise(r => setTimeout(r, 300));
|
|
45
|
+
|
|
46
|
+
const enterOpts = {
|
|
47
|
+
key: 'Enter', code: 'Enter',
|
|
48
|
+
keyCode: 13, which: 13,
|
|
49
|
+
bubbles: true, cancelable: true, composed: true,
|
|
50
|
+
};
|
|
51
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
52
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
53
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
54
|
+
|
|
55
|
+
return 'sent';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ─── 2. contenteditable (Lexical) 에디터 ───
|
|
59
|
+
editor.focus();
|
|
60
|
+
|
|
61
|
+
// 기존 내용 선택 후 삭제
|
|
62
|
+
document.execCommand('selectAll', false, null);
|
|
63
|
+
document.execCommand('delete', false, null);
|
|
64
|
+
|
|
65
|
+
// 텍스트 삽입 (Lexical은 execCommand('insertText')를 인식)
|
|
66
|
+
document.execCommand('insertText', false, msg);
|
|
67
|
+
|
|
68
|
+
// React/Lexical에 변경 알림
|
|
69
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
70
|
+
|
|
71
|
+
await new Promise(r => setTimeout(r, 300));
|
|
72
|
+
|
|
73
|
+
// ─── 3. Enter 키 전송 (전체 시퀀스) ───
|
|
74
|
+
const enterOpts = {
|
|
75
|
+
key: 'Enter', code: 'Enter',
|
|
76
|
+
keyCode: 13, which: 13,
|
|
77
|
+
bubbles: true, cancelable: true, composed: true,
|
|
78
|
+
};
|
|
79
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
80
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
81
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
82
|
+
|
|
83
|
+
return 'sent';
|
|
84
|
+
} catch (e) {
|
|
85
|
+
return 'error: ' + e.message;
|
|
86
|
+
}
|
|
87
|
+
})()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic fallback — set_model
|
|
3
|
+
* ${ MODEL }
|
|
4
|
+
*/
|
|
5
|
+
(() => {
|
|
6
|
+
try {
|
|
7
|
+
const want = ${ MODEL } || '';
|
|
8
|
+
const norm = (t) => t.toLowerCase().trim();
|
|
9
|
+
|
|
10
|
+
// Very basic click attempt
|
|
11
|
+
return JSON.stringify({ success: false, error: 'Model selection requires UI interaction not supported by generic script' });
|
|
12
|
+
} catch (e) {
|
|
13
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
14
|
+
}
|
|
15
|
+
})()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic fallback — set_model
|
|
3
|
+
* ${ MODEL }
|
|
4
|
+
*/
|
|
5
|
+
(() => {
|
|
6
|
+
try {
|
|
7
|
+
const want = ${ MODEL } || '';
|
|
8
|
+
const norm = (t) => t.toLowerCase().trim();
|
|
9
|
+
|
|
10
|
+
// Very basic click attempt
|
|
11
|
+
return JSON.stringify({ success: false, error: 'Model selection requires UI interaction not supported by generic script' });
|
|
12
|
+
} catch (e) {
|
|
13
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
14
|
+
}
|
|
15
|
+
})()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf v1 — switch_session
|
|
3
|
+
*
|
|
4
|
+
* Cascade 세션(대화) 탭을 전환합니다.
|
|
5
|
+
* cascade-tab-{id} 내부의 실제 클릭 가능한 자식 DIV의
|
|
6
|
+
* React onClick 핸들러를 직접 호출합니다.
|
|
7
|
+
*
|
|
8
|
+
* 파라미터: ${ SESSION_ID } — 전환할 세션 ID (cascade-tab의 UUID)
|
|
9
|
+
*
|
|
10
|
+
* 최종 확인: Windsurf 1.108.x (2026-03-10)
|
|
11
|
+
*/
|
|
12
|
+
(() => {
|
|
13
|
+
try {
|
|
14
|
+
const id = ${ SESSION_ID };
|
|
15
|
+
|
|
16
|
+
// Helper: find React onClick on an element or its children
|
|
17
|
+
function clickReact(el) {
|
|
18
|
+
// Check element itself and children for React onClick
|
|
19
|
+
const targets = [el, ...el.querySelectorAll('*')];
|
|
20
|
+
for (const t of targets) {
|
|
21
|
+
const rp = Object.keys(t).find(k => k.startsWith('__reactProps'));
|
|
22
|
+
if (rp && typeof t[rp].onClick === 'function') {
|
|
23
|
+
t[rp].onClick({
|
|
24
|
+
preventDefault: () => { },
|
|
25
|
+
stopPropagation: () => { },
|
|
26
|
+
nativeEvent: { stopImmediatePropagation: () => { } },
|
|
27
|
+
target: t, currentTarget: t, button: 0, type: 'click'
|
|
28
|
+
});
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 1. cascade-tab-{id} 요소 찾기
|
|
36
|
+
const tab = document.getElementById('cascade-tab-' + id);
|
|
37
|
+
if (tab) {
|
|
38
|
+
if (clickReact(tab)) return 'switched';
|
|
39
|
+
// Fallback: DOM click
|
|
40
|
+
tab.click();
|
|
41
|
+
return 'switched-dom';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 2. 제목으로 매칭
|
|
45
|
+
const tabs = document.querySelectorAll('[id^="cascade-tab-"]');
|
|
46
|
+
for (const t of tabs) {
|
|
47
|
+
if (t.textContent?.trim() === id) {
|
|
48
|
+
if (clickReact(t)) return 'switched-by-title';
|
|
49
|
+
t.click();
|
|
50
|
+
return 'switched-by-title-dom';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return 'not_found';
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return 'error: ' + e.message;
|
|
57
|
+
}
|
|
58
|
+
})()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2026.03.
|
|
2
|
+
"version": "2026.03.27",
|
|
3
3
|
"providers": {
|
|
4
4
|
"agentpool-acp": {
|
|
5
5
|
"providerVersion": "0.0.0",
|
|
@@ -212,12 +212,8 @@
|
|
|
212
212
|
"name": "Antigravity",
|
|
213
213
|
"compatibility": [
|
|
214
214
|
{
|
|
215
|
-
"ideVersion": ">=1.
|
|
216
|
-
"scriptDir": "scripts/1.
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
"ideVersion": ">=1.105.0",
|
|
220
|
-
"scriptDir": "scripts/1.106"
|
|
215
|
+
"ideVersion": ">=1.0.0",
|
|
216
|
+
"scriptDir": "scripts/1.0"
|
|
221
217
|
}
|
|
222
218
|
]
|
|
223
219
|
},
|
|
@@ -227,8 +223,8 @@
|
|
|
227
223
|
"name": "Cursor",
|
|
228
224
|
"compatibility": [
|
|
229
225
|
{
|
|
230
|
-
"ideVersion": ">=0.
|
|
231
|
-
"scriptDir": "scripts/0
|
|
226
|
+
"ideVersion": ">=1.0.0",
|
|
227
|
+
"scriptDir": "scripts/1.0"
|
|
232
228
|
}
|
|
233
229
|
]
|
|
234
230
|
},
|
package/src/cdp/manager.ts
CHANGED
|
@@ -503,18 +503,31 @@ export class DaemonCdpManager {
|
|
|
503
503
|
});
|
|
504
504
|
await new Promise(r => setTimeout(r, 150));
|
|
505
505
|
|
|
506
|
-
// Step 3: Insert text
|
|
507
|
-
|
|
506
|
+
// Step 3: Insert text & handle newlines
|
|
507
|
+
const lines = text.split('\n');
|
|
508
|
+
for (let i = 0; i < lines.length; i++) {
|
|
509
|
+
if (lines[i].length > 0) {
|
|
510
|
+
await this.sendInternal('Input.insertText', { text: lines[i] });
|
|
511
|
+
await new Promise(r => setTimeout(r, 100));
|
|
512
|
+
}
|
|
513
|
+
if (i < lines.length - 1) {
|
|
514
|
+
await this.sendInternal('Input.dispatchKeyEvent', { type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 }); // Shift
|
|
515
|
+
await this.sendInternal('Input.dispatchKeyEvent', { type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r', modifiers: 8 });
|
|
516
|
+
await this.sendInternal('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 });
|
|
517
|
+
await new Promise(r => setTimeout(r, 100));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
508
520
|
await new Promise(r => setTimeout(r, 200));
|
|
509
521
|
|
|
510
522
|
// Step 4: Press Enter
|
|
511
523
|
await this.sendInternal('Input.dispatchKeyEvent', {
|
|
512
|
-
type: 'rawKeyDown', key: 'Enter', code: 'Enter',
|
|
513
|
-
|
|
524
|
+
type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
|
|
525
|
+
});
|
|
526
|
+
await this.sendInternal('Input.dispatchKeyEvent', {
|
|
527
|
+
type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
|
|
514
528
|
});
|
|
515
529
|
await this.sendInternal('Input.dispatchKeyEvent', {
|
|
516
|
-
type: 'keyUp', key: 'Enter', code: 'Enter',
|
|
517
|
-
windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13,
|
|
530
|
+
type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13
|
|
518
531
|
});
|
|
519
532
|
|
|
520
533
|
this.log(`[CDP] typeAndSend: sent "${text.substring(0, 50)}..."`);
|
|
@@ -558,18 +571,31 @@ export class DaemonCdpManager {
|
|
|
558
571
|
});
|
|
559
572
|
await new Promise(r => setTimeout(r, 150));
|
|
560
573
|
|
|
561
|
-
// Step 3: Insert text
|
|
562
|
-
|
|
574
|
+
// Step 3: Insert text & handle newlines
|
|
575
|
+
const lines = text.split('\n');
|
|
576
|
+
for (let i = 0; i < lines.length; i++) {
|
|
577
|
+
if (lines[i].length > 0) {
|
|
578
|
+
await this.sendInternal('Input.insertText', { text: lines[i] });
|
|
579
|
+
await new Promise(r => setTimeout(r, 100));
|
|
580
|
+
}
|
|
581
|
+
if (i < lines.length - 1) {
|
|
582
|
+
await this.sendInternal('Input.dispatchKeyEvent', { type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 }); // Shift
|
|
583
|
+
await this.sendInternal('Input.dispatchKeyEvent', { type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r', modifiers: 8 });
|
|
584
|
+
await this.sendInternal('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, modifiers: 8 });
|
|
585
|
+
await new Promise(r => setTimeout(r, 100));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
563
588
|
await new Promise(r => setTimeout(r, 200));
|
|
564
589
|
|
|
565
590
|
// Step 4: Press Enter
|
|
566
591
|
await this.sendInternal('Input.dispatchKeyEvent', {
|
|
567
|
-
type: 'rawKeyDown', key: 'Enter', code: 'Enter',
|
|
568
|
-
|
|
592
|
+
type: 'rawKeyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
|
|
593
|
+
});
|
|
594
|
+
await this.sendInternal('Input.dispatchKeyEvent', {
|
|
595
|
+
type: 'char', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13, text: '\r', unmodifiedText: '\r'
|
|
569
596
|
});
|
|
570
597
|
await this.sendInternal('Input.dispatchKeyEvent', {
|
|
571
|
-
type: 'keyUp', key: 'Enter', code: 'Enter',
|
|
572
|
-
windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13,
|
|
598
|
+
type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13
|
|
573
599
|
});
|
|
574
600
|
|
|
575
601
|
this.log(`[CDP] typeAndSendAt(${Math.round(x)},${Math.round(y)}): sent "${text.substring(0, 50)}..."`);
|
package/src/commands/handler.ts
CHANGED
|
@@ -317,14 +317,7 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
317
317
|
}
|
|
318
318
|
return { success: false, error: `VSCode command not available: ${resolvedCmd || cmd}` };
|
|
319
319
|
}
|
|
320
|
-
|
|
321
|
-
case 'open_tab':
|
|
322
|
-
case 'close_tab':
|
|
323
|
-
case 'open_folder':
|
|
324
|
-
case 'open_folder_picker':
|
|
325
|
-
case 'open_recent':
|
|
326
|
-
case 'get_commands':
|
|
327
|
-
return { success: false, error: `${cmd} requires bridge-extension (removed)` };
|
|
320
|
+
// ─── Workspace cmds ──────────────
|
|
328
321
|
case 'get_recent_workspaces': return this.handleGetRecentWorkspaces(args);
|
|
329
322
|
case 'get_cli_history': {
|
|
330
323
|
const config = loadConfig();
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -78,6 +78,7 @@ export class DevServer {
|
|
|
78
78
|
{ method: 'GET', pattern: '/api/providers/versions', handler: (q, s) => this.handleDetectVersions(q, s) },
|
|
79
79
|
{ method: 'POST', pattern: '/api/providers/reload', handler: (q, s) => this.handleReload(q, s) },
|
|
80
80
|
{ method: 'POST', pattern: '/api/cdp/evaluate', handler: (q, s) => this.handleCdpEvaluate(q, s) },
|
|
81
|
+
{ method: 'POST', pattern: '/api/cdp/click', handler: (q, s) => this.handleCdpClick(q, s) },
|
|
81
82
|
{ method: 'POST', pattern: '/api/cdp/dom/query', handler: (q, s) => this.handleCdpDomQuery(q, s) },
|
|
82
83
|
{ method: 'POST', pattern: '/api/cdp/dom/inspect', handler: (q, s) => this.handleDomInspect(q, s) },
|
|
83
84
|
{ method: 'POST', pattern: '/api/cdp/dom/children', handler: (q, s) => this.handleDomChildren(q, s) },
|
|
@@ -108,6 +109,7 @@ export class DevServer {
|
|
|
108
109
|
{ method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleWriteFile(p![0], q, s) },
|
|
109
110
|
{ method: 'GET', pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s, p) => this.handleSource(p![0], q, s) },
|
|
110
111
|
{ method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s, p) => this.handleSave(p![0], q, s) },
|
|
112
|
+
{ method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s, p) => this.handleTypeAndSend(p![0], q, s) },
|
|
111
113
|
{ method: 'GET', pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s, p) => this.handleProviderConfig(p![0], q, s) },
|
|
112
114
|
{ method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s, p) => this.handleDomContext(p![0], q, s) },
|
|
113
115
|
{ method: 'POST', pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s, p) => this.handleAutoImplement(p![0], q, s) },
|
|
@@ -330,9 +332,18 @@ export class DevServer {
|
|
|
330
332
|
}
|
|
331
333
|
|
|
332
334
|
try {
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
335
|
+
// Emulate production CommandHandler behavior
|
|
336
|
+
let scriptCode: string | null = null;
|
|
337
|
+
if (['sendMessage', 'webviewSendMessage', 'switchSession', 'webviewSwitchSession', 'setMode', 'webviewSetMode', 'setModel', 'webviewSetModel'].includes(scriptName)) {
|
|
338
|
+
// Production daemon's getProviderScript always unpacks the object and sends the first value
|
|
339
|
+
const firstVal = params && typeof params === 'object' && Object.keys(params).length > 0
|
|
340
|
+
? Object.values(params)[0]
|
|
341
|
+
: params;
|
|
342
|
+
scriptCode = firstVal !== undefined ? fn(firstVal) : fn();
|
|
343
|
+
} else {
|
|
344
|
+
// Scripts like resolveAction are passed the raw parameters object in production
|
|
345
|
+
scriptCode = params !== undefined ? fn(params) : fn();
|
|
346
|
+
}
|
|
336
347
|
if (!scriptCode) {
|
|
337
348
|
this.json(res, 500, { error: 'Script function returned null' });
|
|
338
349
|
return;
|
|
@@ -371,6 +382,7 @@ export class DevServer {
|
|
|
371
382
|
if (typeof raw === 'string') {
|
|
372
383
|
try { result = JSON.parse(raw); } catch { /* keep */ }
|
|
373
384
|
}
|
|
385
|
+
this.log(`Script raw debug: typeof=${typeof raw}, raw=${JSON.stringify(raw)}, parsed=${JSON.stringify(result)}`);
|
|
374
386
|
this.json(res, 200, { type, script: scriptName, result });
|
|
375
387
|
} catch (e: any) {
|
|
376
388
|
this.json(res, 500, { error: `Script execution failed: ${e.message}` });
|
|
@@ -406,6 +418,29 @@ export class DevServer {
|
|
|
406
418
|
}
|
|
407
419
|
}
|
|
408
420
|
|
|
421
|
+
private async handleCdpClick(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
422
|
+
const body = await this.readBody(req);
|
|
423
|
+
const { ideType, x, y } = body;
|
|
424
|
+
if (x == null || y == null) {
|
|
425
|
+
this.json(res, 400, { error: 'x and y coordinates required' });
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const cdp = this.getCdp(ideType);
|
|
430
|
+
if (!cdp?.isConnected) {
|
|
431
|
+
this.json(res, 503, { error: 'No CDP connection available' });
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
try {
|
|
436
|
+
await cdp.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 });
|
|
437
|
+
await cdp.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });
|
|
438
|
+
this.json(res, 200, { success: true, clicked: true, x, y });
|
|
439
|
+
} catch (e: any) {
|
|
440
|
+
this.json(res, 500, { error: e.message });
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
409
444
|
private async handleCdpDomQuery(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
410
445
|
const body = await this.readBody(req);
|
|
411
446
|
const { selector, limit = 10, ideType } = body;
|
|
@@ -522,6 +557,11 @@ export class DevServer {
|
|
|
522
557
|
const providers = this.providerLoader.getAll().map(p => ({
|
|
523
558
|
type: p.type, name: p.name, category: p.category,
|
|
524
559
|
}));
|
|
560
|
+
for (const cdp of this.cdpManagers.values()) {
|
|
561
|
+
if (!cdp.isConnected) {
|
|
562
|
+
(cdp as any)._targetId = null;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
525
565
|
this.json(res, 200, { reloaded: true, providers });
|
|
526
566
|
} catch (e: any) {
|
|
527
567
|
this.json(res, 500, { error: e.message });
|
|
@@ -692,7 +732,7 @@ export class DevServer {
|
|
|
692
732
|
const provider = this.providerLoader.getMeta(type);
|
|
693
733
|
if (!provider) return null;
|
|
694
734
|
const cat = provider.category;
|
|
695
|
-
const builtinDir = (this.providerLoader as any).
|
|
735
|
+
const builtinDir = (this.providerLoader as any).builtinDirs?.[0] || path.resolve(__dirname, '../providers/_builtin');
|
|
696
736
|
const userDir = path.join(os.homedir(), '.adhdev', 'providers');
|
|
697
737
|
|
|
698
738
|
// Direct match first
|
|
@@ -833,6 +873,24 @@ export class DevServer {
|
|
|
833
873
|
}
|
|
834
874
|
}
|
|
835
875
|
|
|
876
|
+
private async handleTypeAndSend(type: string, req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
877
|
+
const body = await this.readBody(req);
|
|
878
|
+
const { selector, text } = body;
|
|
879
|
+
if (!selector || typeof selector !== 'string' || !text || typeof text !== 'string') {
|
|
880
|
+
this.json(res, 400, { error: 'selector and text strings required' }); return;
|
|
881
|
+
}
|
|
882
|
+
const cdp = this.getCdp(type);
|
|
883
|
+
if (!cdp) {
|
|
884
|
+
this.json(res, 503, { error: `CDP not connected for '${type}'` }); return;
|
|
885
|
+
}
|
|
886
|
+
try {
|
|
887
|
+
const sent = await cdp.typeAndSend(selector, text);
|
|
888
|
+
this.json(res, 200, { sent });
|
|
889
|
+
} catch (e: any) {
|
|
890
|
+
this.json(res, 500, { error: e.message });
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
836
894
|
private async handleScriptHints(type: string, _req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
|
837
895
|
const dir = this.findProviderDir(type);
|
|
838
896
|
if (!dir) { this.json(res, 404, { error: `Provider not found: ${type}` }); return; }
|
|
@@ -1065,7 +1123,7 @@ export class DevServer {
|
|
|
1065
1123
|
if (location === 'user') {
|
|
1066
1124
|
targetDir = path.join(os.homedir(), '.adhdev', 'providers', type);
|
|
1067
1125
|
} else {
|
|
1068
|
-
const builtinDir = path.resolve(__dirname, '../providers/_builtin');
|
|
1126
|
+
const builtinDir = (this.providerLoader as any).builtinDirs?.[0] || path.resolve(__dirname, '../providers/_builtin');
|
|
1069
1127
|
targetDir = path.join(builtinDir, category, type);
|
|
1070
1128
|
}
|
|
1071
1129
|
|
|
@@ -1851,7 +1909,7 @@ export class DevServer {
|
|
|
1851
1909
|
this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'loading_reference', message: `레퍼런스 스크립트 로드 중 (${reference})...` } });
|
|
1852
1910
|
|
|
1853
1911
|
let referenceScripts: Record<string, string> = {};
|
|
1854
|
-
const builtinDir = (this.providerLoader as any).
|
|
1912
|
+
const builtinDir = (this.providerLoader as any).builtinDirs?.[0] || path.resolve(__dirname, '../providers/_builtin');
|
|
1855
1913
|
const refDir = path.join(builtinDir, 'ide', reference);
|
|
1856
1914
|
if (fs.existsSync(refDir)) {
|
|
1857
1915
|
// Find latest versioned scripts dir
|
|
@@ -2053,7 +2111,7 @@ export class DevServer {
|
|
|
2053
2111
|
}
|
|
2054
2112
|
if (model) args.push('--model', model);
|
|
2055
2113
|
const escapedArgs = args.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(' ');
|
|
2056
|
-
const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions recursively. You have full authority to implement ALL required script files, update provider.json configurations based on the reference patterns, and independently test them against 127.0.0.1:19280 via CDP CURL. Upon complete validation of ALL assigned files, print exactly "
|
|
2114
|
+
const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions recursively. You have full authority to implement ALL required script files, update provider.json configurations based on the reference patterns, and independently test them against 127.0.0.1:19280 via CDP CURL. Upon complete validation of ALL assigned files, print exactly "_PIPELINE_COMPLETE_SIGNAL_" to gracefully close the pipeline. DO NOT WAIT FOR APPROVAL, execute completely autonomously.`;
|
|
2057
2115
|
shellCmd = `${command} ${escapedArgs} "${metaPrompt}"`;
|
|
2058
2116
|
} else {
|
|
2059
2117
|
// Generic fallback: pipe prompt via stdin
|
|
@@ -2131,7 +2189,7 @@ export class DevServer {
|
|
|
2131
2189
|
|
|
2132
2190
|
// Force exit on completion signal (ignore during first 15s — prompt echo contains the token)
|
|
2133
2191
|
const elapsed = Date.now() - spawnedAt;
|
|
2134
|
-
if (elapsed > 15000 && approvalBuffer.includes('
|
|
2192
|
+
if (elapsed > 15000 && approvalBuffer.includes('_PIPELINE_COMPLETE_SIGNAL_')) {
|
|
2135
2193
|
this.log(`Agent finished task after ${Math.round(elapsed/1000)}s. Terminating interactive CLI session to unblock pipeline.`);
|
|
2136
2194
|
this.sendAutoImplSSE({ event: 'output', data: { chunk: `\n[🤖 ADHDev Pipeline] Completion token detected. Proceeding...\n`, stream: 'stdout' } });
|
|
2137
2195
|
approvalBuffer = '';
|
|
@@ -22,7 +22,6 @@ export interface IDEInfo {
|
|
|
22
22
|
cliCommand: string | null;
|
|
23
23
|
version: string | null;
|
|
24
24
|
icon: string;
|
|
25
|
-
extensionSupport: 'full' | 'partial' | 'none';
|
|
26
25
|
notes?: string;
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -31,7 +30,6 @@ export interface IDEDefinition {
|
|
|
31
30
|
name: string;
|
|
32
31
|
displayName: string;
|
|
33
32
|
icon: string;
|
|
34
|
-
extensionSupport: 'full' | 'partial' | 'none';
|
|
35
33
|
cli: string;
|
|
36
34
|
paths: {
|
|
37
35
|
darwin?: string[];
|
|
@@ -149,7 +147,6 @@ export async function detectIDEs(): Promise<IDEInfo[]> {
|
|
|
149
147
|
cliCommand: resolvedCli || null,
|
|
150
148
|
version,
|
|
151
149
|
icon: def.icon,
|
|
152
|
-
extensionSupport: def.extensionSupport,
|
|
153
150
|
});
|
|
154
151
|
}
|
|
155
152
|
|
|
@@ -57,7 +57,10 @@ export class ProviderLoader {
|
|
|
57
57
|
if (options?.builtinDir) {
|
|
58
58
|
this.builtinDirs = Array.isArray(options.builtinDir) ? options.builtinDir : [options.builtinDir];
|
|
59
59
|
} else {
|
|
60
|
-
|
|
60
|
+
// Handle both development (src/providers -> ../../providers) and production (dist -> ../providers)
|
|
61
|
+
const bundledDir = path.resolve(__dirname, '../providers/_builtin');
|
|
62
|
+
const devDir = path.resolve(__dirname, '../../providers/_builtin');
|
|
63
|
+
this.builtinDirs = [fs.existsSync(devDir) ? devDir : bundledDir];
|
|
61
64
|
}
|
|
62
65
|
// User custom directory: ~/.adhdev/providers/
|
|
63
66
|
this.userDir = options?.userDir ||
|
|
@@ -322,7 +325,6 @@ export class ProviderLoader {
|
|
|
322
325
|
name: p.name,
|
|
323
326
|
displayName: p.displayName || p.name,
|
|
324
327
|
icon: p.icon || '💻',
|
|
325
|
-
extensionSupport: 'full',
|
|
326
328
|
cli: p.cli,
|
|
327
329
|
paths: p.paths as { darwin?: string[]; win32?: string[]; linux?: string[] },
|
|
328
330
|
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity — list_models
|
|
3
|
-
* antigravity-agent-side-panel 내부 모델 드롭다운에서 목록 + 현재 모델 추출
|
|
4
|
-
* → { models: string[], current: string }
|
|
5
|
-
*/
|
|
6
|
-
(() => {
|
|
7
|
-
try {
|
|
8
|
-
const models = [];
|
|
9
|
-
let current = '';
|
|
10
|
-
|
|
11
|
-
// 1. 모델 항목에서 목록 추출
|
|
12
|
-
// 셀렉터: .px-2.py-1.flex.items-center.justify-between.cursor-pointer
|
|
13
|
-
const items = document.querySelectorAll('.px-2.py-1.flex.items-center.justify-between.cursor-pointer');
|
|
14
|
-
for (const item of items) {
|
|
15
|
-
const label = item.querySelector('.text-xs.font-medium');
|
|
16
|
-
const text = (label || item).textContent?.trim();
|
|
17
|
-
if (!text || text.length > 60) continue;
|
|
18
|
-
// 모델명 검증 (Claude, Gemini, GPT, etc.)
|
|
19
|
-
models.push(text);
|
|
20
|
-
// 선택된 항목: bg-gray-500/20
|
|
21
|
-
if ((item.className || '').includes('bg-gray-500/20')) {
|
|
22
|
-
current = text;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 2. 모델 목록이 없으면 (드롭다운 닫힘) → 트리거 버튼에서 현재 모델만
|
|
27
|
-
if (models.length === 0) {
|
|
28
|
-
const trigger = document.querySelector('.flex.min-w-0.max-w-full.cursor-pointer.items-center');
|
|
29
|
-
if (trigger) {
|
|
30
|
-
current = trigger.textContent?.trim() || '';
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return JSON.stringify({ models, current });
|
|
35
|
-
} catch (e) {
|
|
36
|
-
return JSON.stringify({ models: [], current: '', error: e.message });
|
|
37
|
-
}
|
|
38
|
-
})()
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity — list_modes
|
|
3
|
-
* Conversation mode: Planning / Fast 세그먼트 컨트롤
|
|
4
|
-
* inputBox 근처의 "Conversation mode" 패널에서 읽기
|
|
5
|
-
* → { modes: string[], current: string }
|
|
6
|
-
*/
|
|
7
|
-
(() => {
|
|
8
|
-
try {
|
|
9
|
-
const modes = [];
|
|
10
|
-
let current = '';
|
|
11
|
-
|
|
12
|
-
// "Conversation mode" 헤더를 포함하는 패널 찾기
|
|
13
|
-
const headers = document.querySelectorAll('.text-xs.px-2.pb-1.opacity-80');
|
|
14
|
-
for (const header of headers) {
|
|
15
|
-
if (header.textContent?.trim() === 'Conversation mode') {
|
|
16
|
-
// 형제 요소들에서 모드 항목 추출
|
|
17
|
-
const parent = header.parentElement;
|
|
18
|
-
if (!parent) continue;
|
|
19
|
-
const items = parent.querySelectorAll('.font-medium');
|
|
20
|
-
for (const item of items) {
|
|
21
|
-
const text = item.textContent?.trim();
|
|
22
|
-
if (text && text.length < 20) {
|
|
23
|
-
modes.push(text);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// 현재 모드: Fast 버튼의 텍스트 (현재 활성 모드 표시)
|
|
31
|
-
const modeBtn = [...document.querySelectorAll('button')].find(b => {
|
|
32
|
-
const cls = b.className || '';
|
|
33
|
-
return cls.includes('py-1') && cls.includes('pl-1') && cls.includes('pr-2') && b.offsetWidth > 0;
|
|
34
|
-
});
|
|
35
|
-
if (modeBtn) {
|
|
36
|
-
current = modeBtn.textContent?.trim() || '';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// modes가 비어있으면 기본값
|
|
40
|
-
if (modes.length === 0) {
|
|
41
|
-
modes.push('Planning', 'Fast');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return JSON.stringify({ modes, current });
|
|
45
|
-
} catch (e) {
|
|
46
|
-
return JSON.stringify({ modes: [], current: '', error: e.message });
|
|
47
|
-
}
|
|
48
|
-
})()
|