@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,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity v1 — switch_session (v7 — CDP 마우스 클릭 좌표 반환)
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ 삭제 버튼(trash SVG)에 절대 접근하지 않음.
|
|
5
|
+
*
|
|
6
|
+
* 두 가지 모드:
|
|
7
|
+
* 1) 히스토리 토글을 열고 행 좌표를 찾으면 {clickX, clickY} 반환 → daemon이 CDP 클릭으로 처리
|
|
8
|
+
* 2) 워크스페이스 다이얼로그가 뜨면 첫 번째 행 좌표 반환 (자동 선택용)
|
|
9
|
+
*
|
|
10
|
+
* 파라미터: ${SESSION_ID} — 대화 제목 (문자열)
|
|
11
|
+
*/
|
|
12
|
+
(async () => {
|
|
13
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
14
|
+
const id = ${SESSION_ID};
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// 1. 히스토리 토글 클릭
|
|
18
|
+
const toggle = document.querySelector('[data-past-conversations-toggle="true"]');
|
|
19
|
+
if (!toggle) return JSON.stringify({ error: 'no_toggle' });
|
|
20
|
+
toggle.click();
|
|
21
|
+
await sleep(1200);
|
|
22
|
+
|
|
23
|
+
// 2. 컨테이너 찾기 (기존 로직: "Current" 텍스트 또는 "Select a conversation" input)
|
|
24
|
+
let container = null;
|
|
25
|
+
|
|
26
|
+
// 2a. "Current" 텍스트 기반
|
|
27
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
|
|
28
|
+
while (walker.nextNode()) {
|
|
29
|
+
if (walker.currentNode.textContent.trim() === 'Current') {
|
|
30
|
+
let el = walker.currentNode.parentElement;
|
|
31
|
+
for (let i = 0; i < 10 && el; i++) {
|
|
32
|
+
const cls = (el.className || '');
|
|
33
|
+
if (typeof cls === 'string' && (cls.includes('overflow-auto') || cls.includes('overflow-y-scroll'))) {
|
|
34
|
+
container = el; break;
|
|
35
|
+
}
|
|
36
|
+
el = el.parentElement;
|
|
37
|
+
}
|
|
38
|
+
if (!container) {
|
|
39
|
+
el = walker.currentNode.parentElement;
|
|
40
|
+
let bestEl = null, bestCount = 0;
|
|
41
|
+
for (let i = 0; i < 8 && el; i++) {
|
|
42
|
+
const rows = el.querySelectorAll('[class*="cursor-pointer"][class*="justify-between"][class*="rounded-md"]');
|
|
43
|
+
if (rows.length > bestCount) { bestCount = rows.length; bestEl = el; }
|
|
44
|
+
el = el.parentElement;
|
|
45
|
+
}
|
|
46
|
+
container = bestEl;
|
|
47
|
+
}
|
|
48
|
+
if (container) break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 2b. 폴백: "Select a conversation" input 기반
|
|
53
|
+
if (!container) {
|
|
54
|
+
const searchInput = Array.from(document.querySelectorAll('input[type="text"]'))
|
|
55
|
+
.find(i => i.offsetWidth > 0 && (i.placeholder || '').includes('Select a conversation'));
|
|
56
|
+
if (searchInput) {
|
|
57
|
+
let el = searchInput.parentElement;
|
|
58
|
+
for (let i = 0; i < 10 && el; i++) {
|
|
59
|
+
const cls = (el.className || '');
|
|
60
|
+
if (typeof cls === 'string' && (cls.includes('overflow-auto') || cls.includes('overflow-y-scroll'))) {
|
|
61
|
+
container = el; break;
|
|
62
|
+
}
|
|
63
|
+
const rows = el.querySelectorAll('[class*="cursor-pointer"][class*="justify-between"][class*="rounded-md"]');
|
|
64
|
+
if (rows.length > 0 && !container) container = el;
|
|
65
|
+
el = el.parentElement;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!container) {
|
|
71
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true }));
|
|
72
|
+
return JSON.stringify({ error: 'no_container' });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 3. 행 매칭
|
|
76
|
+
const rows = container.querySelectorAll('[class*="cursor-pointer"][class*="justify-between"][class*="rounded-md"]');
|
|
77
|
+
const norm = s => (s || '').trim().toLowerCase().replace(/\s+/g, ' ');
|
|
78
|
+
const idNorm = norm(id);
|
|
79
|
+
let targetRow = null;
|
|
80
|
+
|
|
81
|
+
for (const row of rows) {
|
|
82
|
+
// 현재 활성 대화 스킵
|
|
83
|
+
if ((row.className || '').includes('focusBackground')) continue;
|
|
84
|
+
const titleEl = row.querySelector('span span');
|
|
85
|
+
const title = titleEl ? norm(titleEl.textContent) : '';
|
|
86
|
+
if (!title) continue;
|
|
87
|
+
if (title.includes(idNorm) || idNorm.includes(title)) {
|
|
88
|
+
targetRow = row;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!targetRow) {
|
|
94
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true }));
|
|
95
|
+
return JSON.stringify({ error: 'no_match', rowCount: rows.length });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 4. 행의 좌표 계산 → daemon이 CDP Input.dispatchMouseEvent로 클릭
|
|
99
|
+
const rect = targetRow.getBoundingClientRect();
|
|
100
|
+
const clickX = Math.round(rect.left + rect.width * 0.3);
|
|
101
|
+
const clickY = Math.round(rect.top + rect.height / 2);
|
|
102
|
+
|
|
103
|
+
return JSON.stringify({
|
|
104
|
+
action: 'click',
|
|
105
|
+
clickX,
|
|
106
|
+
clickY,
|
|
107
|
+
title: (targetRow.querySelector('span span')?.textContent || '').substring(0, 60)
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
} catch (e) {
|
|
111
|
+
try { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true })); } catch (_) { }
|
|
112
|
+
return JSON.stringify({ error: e.message });
|
|
113
|
+
}
|
|
114
|
+
})()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "cursor",
|
|
3
|
+
"name": "Cursor",
|
|
4
|
+
"category": "ide",
|
|
5
|
+
"displayName": "Cursor",
|
|
6
|
+
"icon": "⚡",
|
|
7
|
+
"cli": "cursor",
|
|
8
|
+
"cdpPorts": [
|
|
9
|
+
9333,
|
|
10
|
+
9334
|
|
11
|
+
],
|
|
12
|
+
"targetFilter": {
|
|
13
|
+
"urlIncludes": "workbench.html",
|
|
14
|
+
"urlExcludes": ["agent"],
|
|
15
|
+
"titleExcludes": "extension-output|ADHDev CDP|Debug Console|Output\\s*$|Launchpad"
|
|
16
|
+
},
|
|
17
|
+
"processNames": {
|
|
18
|
+
"darwin": "Cursor",
|
|
19
|
+
"win32": [
|
|
20
|
+
"Cursor.exe"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"paths": {
|
|
24
|
+
"darwin": [
|
|
25
|
+
"/Applications/Cursor.app"
|
|
26
|
+
],
|
|
27
|
+
"win32": [
|
|
28
|
+
"C:\\Users\\*\\AppData\\Local\\Programs\\cursor\\Cursor.exe"
|
|
29
|
+
],
|
|
30
|
+
"linux": [
|
|
31
|
+
"/opt/Cursor",
|
|
32
|
+
"/usr/share/cursor"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"inputMethod": "cdp-type-and-send",
|
|
36
|
+
"inputSelector": ".aislash-editor-input[contenteditable=\"true\"]",
|
|
37
|
+
"versionCommand": "cursor --version",
|
|
38
|
+
"providerVersion": "1.0.0",
|
|
39
|
+
"compatibility": [
|
|
40
|
+
{ "ideVersion": ">=0.49.0", "scriptDir": "scripts/0.49" }
|
|
41
|
+
],
|
|
42
|
+
"defaultScriptDir": "scripts/0.49",
|
|
43
|
+
"vscodeCommands": {
|
|
44
|
+
"changeModel": "cursor.model"
|
|
45
|
+
},
|
|
46
|
+
"settings": {
|
|
47
|
+
"approvalAlert": {
|
|
48
|
+
"type": "boolean",
|
|
49
|
+
"default": true,
|
|
50
|
+
"public": true,
|
|
51
|
+
"label": "Approval Notifications",
|
|
52
|
+
"description": "Show notification when approval is needed"
|
|
53
|
+
},
|
|
54
|
+
"longGeneratingAlert": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"default": true,
|
|
57
|
+
"public": true,
|
|
58
|
+
"label": "Long Generation Alert",
|
|
59
|
+
"description": "Alert when generation takes too long"
|
|
60
|
+
},
|
|
61
|
+
"longGeneratingThresholdSec": {
|
|
62
|
+
"type": "number",
|
|
63
|
+
"default": 180,
|
|
64
|
+
"public": true,
|
|
65
|
+
"label": "Long Generation Threshold (sec)",
|
|
66
|
+
"min": 30,
|
|
67
|
+
"max": 600
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — dismiss_notification
|
|
3
|
+
*
|
|
4
|
+
* 알림 토스트 닫기/버튼 클릭:
|
|
5
|
+
* 인덱스 또는 메시지 매칭으로 대상 선택
|
|
6
|
+
* 버튼 텍스트 지정 시 해당 버튼 클릭, 아니면 닫기
|
|
7
|
+
*
|
|
8
|
+
* params.index: number, params.button: string|null, params.message: string|null
|
|
9
|
+
* → { dismissed: true/false }
|
|
10
|
+
*/
|
|
11
|
+
(params) => {
|
|
12
|
+
try {
|
|
13
|
+
const toasts = [...document.querySelectorAll('.notifications-toasts .notification-toast, .notification-list-item')].filter(t => t.offsetWidth > 0);
|
|
14
|
+
let toast;
|
|
15
|
+
if (params.message) {
|
|
16
|
+
toast = toasts.find(t => (t.querySelector('.notification-list-item-message')?.textContent || t.textContent || '').toLowerCase().includes(params.message.toLowerCase()));
|
|
17
|
+
} else {
|
|
18
|
+
toast = toasts[params.index || 0];
|
|
19
|
+
}
|
|
20
|
+
if (!toast) return JSON.stringify({ dismissed: false, error: 'Toast not found', count: toasts.length });
|
|
21
|
+
if (params.button) {
|
|
22
|
+
const btn = [...toast.querySelectorAll('button')].find(b => b.textContent?.trim().toLowerCase().includes(params.button.toLowerCase()));
|
|
23
|
+
if (btn) { btn.click(); return JSON.stringify({ dismissed: true, clicked: btn.textContent.trim() }); }
|
|
24
|
+
return JSON.stringify({ dismissed: false, error: 'Button not found' });
|
|
25
|
+
}
|
|
26
|
+
const closeBtn = toast.querySelector('.codicon-notifications-clear, .clear-notification-action, .codicon-close');
|
|
27
|
+
if (closeBtn) { closeBtn.click(); return JSON.stringify({ dismissed: true }); }
|
|
28
|
+
return JSON.stringify({ dismissed: false, error: 'Close button not found' });
|
|
29
|
+
} catch(e) { return JSON.stringify({ dismissed: false, error: e.message }); }
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — focus_editor
|
|
3
|
+
*
|
|
4
|
+
* 채팅 입력 필드에 포커스:
|
|
5
|
+
* .aislash-editor-input[contenteditable="true"]
|
|
6
|
+
*/
|
|
7
|
+
(() => {
|
|
8
|
+
try {
|
|
9
|
+
const input = document.querySelector('.aislash-editor-input[contenteditable="true"]');
|
|
10
|
+
if (input) { input.focus(); return 'focused'; }
|
|
11
|
+
return 'not_found';
|
|
12
|
+
} catch(e) { return 'error'; }
|
|
13
|
+
})()
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — list_models
|
|
3
|
+
*
|
|
4
|
+
* 모델 드롭다운 목록 추출:
|
|
5
|
+
* 버튼: .composer-unified-dropdown-model
|
|
6
|
+
* 메뉴: [data-testid="model-picker-menu"]
|
|
7
|
+
* 아이템: .composer-unified-context-menu-item
|
|
8
|
+
* 모델명: .monaco-highlighted-label
|
|
9
|
+
* Think 모드: codicon-br (brain) 아이콘
|
|
10
|
+
* Auto 토글: rounded-full 24x14 요소
|
|
11
|
+
*
|
|
12
|
+
* → { models[], current }
|
|
13
|
+
*/
|
|
14
|
+
(async () => {
|
|
15
|
+
try {
|
|
16
|
+
let current = '';
|
|
17
|
+
const models = [];
|
|
18
|
+
|
|
19
|
+
const modelBtn = document.querySelector('.composer-unified-dropdown-model');
|
|
20
|
+
if (modelBtn) {
|
|
21
|
+
current = modelBtn.textContent?.trim() || '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 드롭다운 열기
|
|
25
|
+
if (modelBtn) {
|
|
26
|
+
modelBtn.click();
|
|
27
|
+
await new Promise(r => setTimeout(r, 500));
|
|
28
|
+
|
|
29
|
+
const menu = document.querySelector('[data-testid="model-picker-menu"]');
|
|
30
|
+
if (menu) {
|
|
31
|
+
// Auto 토글 확인 및 끄기
|
|
32
|
+
const autoItem = menu.querySelector('.composer-unified-context-menu-item[data-is-selected="true"]');
|
|
33
|
+
const autoToggle = autoItem ? [...autoItem.querySelectorAll('[class*="rounded-full"]')].find(el => el.offsetWidth === 24 && el.offsetHeight === 14) : null;
|
|
34
|
+
let wasAutoOn = false;
|
|
35
|
+
if (autoToggle) {
|
|
36
|
+
const bgStyle = autoToggle.getAttribute('style') || '';
|
|
37
|
+
wasAutoOn = bgStyle.includes('green');
|
|
38
|
+
if (wasAutoOn) {
|
|
39
|
+
autoToggle.click();
|
|
40
|
+
await new Promise(r => setTimeout(r, 500));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 모델 목록 수집 (Auto 끈 상태)
|
|
45
|
+
const refreshedMenu = document.querySelector('[data-testid="model-picker-menu"]');
|
|
46
|
+
if (refreshedMenu) {
|
|
47
|
+
const items = refreshedMenu.querySelectorAll('.composer-unified-context-menu-item');
|
|
48
|
+
for (const item of items) {
|
|
49
|
+
const nameEl = item.querySelector('.monaco-highlighted-label');
|
|
50
|
+
const name = nameEl?.textContent?.trim() || '';
|
|
51
|
+
if (name && name !== 'Add Models') {
|
|
52
|
+
const hasBrain = !!item.querySelector('[class*="codicon-br"]');
|
|
53
|
+
const displayName = hasBrain ? name + ' 🧠' : name;
|
|
54
|
+
models.push(displayName);
|
|
55
|
+
if (item.getAttribute('data-is-selected') === 'true') current = displayName;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Auto 다시 켜기 (원래 상태 복원)
|
|
61
|
+
if (wasAutoOn) {
|
|
62
|
+
const newMenu = document.querySelector('[data-testid="model-picker-menu"]');
|
|
63
|
+
const newAutoItem = newMenu?.querySelector('.composer-unified-context-menu-item');
|
|
64
|
+
const newToggle = newAutoItem ? [...newAutoItem.querySelectorAll('[class*="rounded-full"]')].find(el => el.offsetWidth === 24) : null;
|
|
65
|
+
if (newToggle) {
|
|
66
|
+
newToggle.click();
|
|
67
|
+
await new Promise(r => setTimeout(r, 200));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 닫기 (Escape)
|
|
73
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return JSON.stringify({ models, current });
|
|
77
|
+
} catch(e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
|
|
78
|
+
})()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — list_modes
|
|
3
|
+
*
|
|
4
|
+
* 모드 드롭다운 목록 추출:
|
|
5
|
+
* 버튼: .composer-unified-dropdown (model이 아닌 것)
|
|
6
|
+
* 메뉴: [data-testid="model-picker-menu"] 또는 .typeahead-popover
|
|
7
|
+
* 아이템: .composer-unified-context-menu-item
|
|
8
|
+
*
|
|
9
|
+
* → { modes[], current }
|
|
10
|
+
*/
|
|
11
|
+
(async () => {
|
|
12
|
+
try {
|
|
13
|
+
const modes = [];
|
|
14
|
+
let current = '';
|
|
15
|
+
|
|
16
|
+
const modeBtn = document.querySelector('.composer-unified-dropdown:not(.composer-unified-dropdown-model)');
|
|
17
|
+
if (!modeBtn) return JSON.stringify({ modes: [], current: '', error: 'Mode button not found' });
|
|
18
|
+
|
|
19
|
+
modeBtn.click();
|
|
20
|
+
await new Promise(r => setTimeout(r, 500));
|
|
21
|
+
|
|
22
|
+
const menu = document.querySelector('[data-testid="model-picker-menu"]') || document.querySelector('.typeahead-popover');
|
|
23
|
+
if (menu) {
|
|
24
|
+
const items = menu.querySelectorAll('.composer-unified-context-menu-item');
|
|
25
|
+
for (const item of items) {
|
|
26
|
+
const nameEl = item.querySelector('.monaco-highlighted-label');
|
|
27
|
+
const name = nameEl?.textContent?.trim() || '';
|
|
28
|
+
if (name) {
|
|
29
|
+
modes.push(name);
|
|
30
|
+
if (item.getAttribute('data-is-selected') === 'true') current = name;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 닫기
|
|
36
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
37
|
+
|
|
38
|
+
return JSON.stringify({ modes, current });
|
|
39
|
+
} catch(e) { return JSON.stringify({ modes: [], current: '', error: e.message }); }
|
|
40
|
+
})()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — list_notifications
|
|
3
|
+
*
|
|
4
|
+
* VS Code 알림 토스트 목록:
|
|
5
|
+
* .notifications-toasts .notification-toast
|
|
6
|
+
* .notification-list-item
|
|
7
|
+
*
|
|
8
|
+
* params.filter: string|null — 메시지 필터
|
|
9
|
+
* → [{ index, message, severity, buttons }]
|
|
10
|
+
*/
|
|
11
|
+
(params) => {
|
|
12
|
+
try {
|
|
13
|
+
const toasts = [...document.querySelectorAll('.notifications-toasts .notification-toast, .notification-list-item')];
|
|
14
|
+
const visible = toasts.filter(t => t.offsetWidth > 0).map((t, i) => ({
|
|
15
|
+
index: i,
|
|
16
|
+
message: t.querySelector('.notification-list-item-message')?.textContent?.trim() || t.textContent?.trim().substring(0, 200),
|
|
17
|
+
severity: t.querySelector('.codicon-error') ? 'error' : t.querySelector('.codicon-warning') ? 'warning' : 'info',
|
|
18
|
+
buttons: [...t.querySelectorAll('.notification-list-item-buttons-container button, .monaco-button')].map(b => b.textContent?.trim()).filter(Boolean),
|
|
19
|
+
}));
|
|
20
|
+
const f = params.filter || null;
|
|
21
|
+
return JSON.stringify(f ? visible.filter(n => n.message.toLowerCase().includes(f.toLowerCase())) : visible);
|
|
22
|
+
} catch(e) { return JSON.stringify([]); }
|
|
23
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — list_sessions
|
|
3
|
+
*
|
|
4
|
+
* 사이드바 셀 목록에서 세션 파싱:
|
|
5
|
+
* 셀: .agent-sidebar-cell
|
|
6
|
+
* 제목: .agent-sidebar-cell-text
|
|
7
|
+
* 선택 상태: data-selected="true"
|
|
8
|
+
* 활성 ID: [data-composer-id]에서 추출
|
|
9
|
+
*
|
|
10
|
+
* → { sessions: [{ id, title, active, index }] }
|
|
11
|
+
*/
|
|
12
|
+
(() => {
|
|
13
|
+
try {
|
|
14
|
+
const sessions = [];
|
|
15
|
+
const cells = [...document.querySelectorAll('.agent-sidebar-cell')];
|
|
16
|
+
const activeComposer = document.querySelector('[data-composer-id]');
|
|
17
|
+
const activeId = activeComposer?.getAttribute('data-composer-id') || null;
|
|
18
|
+
cells.forEach((cell, i) => {
|
|
19
|
+
const titleEl = cell.querySelector('.agent-sidebar-cell-text');
|
|
20
|
+
const title = titleEl?.textContent?.trim() || 'Untitled';
|
|
21
|
+
const isSelected = cell.getAttribute('data-selected') === 'true';
|
|
22
|
+
sessions.push({
|
|
23
|
+
id: isSelected && activeId ? activeId : 'sidebar-' + i,
|
|
24
|
+
title,
|
|
25
|
+
active: isSelected,
|
|
26
|
+
index: i,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
// If no sidebar cells, fallback to current composer
|
|
30
|
+
if (sessions.length === 0 && activeComposer) {
|
|
31
|
+
sessions.push({
|
|
32
|
+
id: activeId,
|
|
33
|
+
title: document.title.split(' — ')[0],
|
|
34
|
+
active: true,
|
|
35
|
+
index: 0,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return JSON.stringify({ sessions });
|
|
39
|
+
} catch(e) {
|
|
40
|
+
return JSON.stringify({ sessions: [], error: e.message });
|
|
41
|
+
}
|
|
42
|
+
})()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — new_session
|
|
3
|
+
*
|
|
4
|
+
* 새 채팅/컴포저 버튼 클릭:
|
|
5
|
+
* a.action-label.codicon-add-two
|
|
6
|
+
* [aria-label*="New Chat"]
|
|
7
|
+
* [aria-label*="New Composer"]
|
|
8
|
+
*
|
|
9
|
+
* → { created: true/false }
|
|
10
|
+
*/
|
|
11
|
+
(() => {
|
|
12
|
+
try {
|
|
13
|
+
const newBtn = [...document.querySelectorAll('a.action-label.codicon-add-two, [aria-label*="New Chat"], [aria-label*="New Composer"]')]
|
|
14
|
+
.find(a => a.offsetWidth > 0);
|
|
15
|
+
if (newBtn) { newBtn.click(); return JSON.stringify({ created: true }); }
|
|
16
|
+
return JSON.stringify({ created: false, error: 'New Chat button not found' });
|
|
17
|
+
} catch(e) {
|
|
18
|
+
return JSON.stringify({ created: false, error: e.message });
|
|
19
|
+
}
|
|
20
|
+
})()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — open_panel
|
|
3
|
+
*
|
|
4
|
+
* 채팅/컴포저 패널 열기:
|
|
5
|
+
* 1. 이미 보이면 'visible' 반환
|
|
6
|
+
* 2. Agent/Chat/Composer 탭 찾아서 클릭
|
|
7
|
+
*/
|
|
8
|
+
(() => {
|
|
9
|
+
try {
|
|
10
|
+
const sidebar = document.getElementById('workbench.parts.auxiliarybar');
|
|
11
|
+
if (sidebar && sidebar.offsetWidth > 0) {
|
|
12
|
+
const chatView = document.querySelector('[data-composer-id]');
|
|
13
|
+
if (chatView) return 'visible';
|
|
14
|
+
}
|
|
15
|
+
const btns = [...document.querySelectorAll('li.action-item a, button, [role="tab"]')];
|
|
16
|
+
const toggle = btns.find(b => {
|
|
17
|
+
const label = (b.textContent || b.getAttribute('aria-label') || '').toLowerCase();
|
|
18
|
+
return /agent|chat|composer|cursor tab/i.test(label);
|
|
19
|
+
});
|
|
20
|
+
if (toggle) { toggle.click(); return 'opened'; }
|
|
21
|
+
return 'not_found';
|
|
22
|
+
} catch (e) { return 'error'; }
|
|
23
|
+
})()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — read_chat
|
|
3
|
+
*
|
|
4
|
+
* DOM 구조 (v0.49):
|
|
5
|
+
* 컴포저: [data-composer-id] + [data-composer-status]
|
|
6
|
+
* 메시지 쌍: .composer-human-ai-pair-container
|
|
7
|
+
* 사용자: .composer-human-message
|
|
8
|
+
* AI: direct children after first (tool/assistant)
|
|
9
|
+
* 입력: .aislash-editor-input[contenteditable="true"]
|
|
10
|
+
* 승인: .run-command-review-active + button/cursor-pointer 요소
|
|
11
|
+
*
|
|
12
|
+
* → { id, status, title, messages[], inputContent, activeModal }
|
|
13
|
+
*/
|
|
14
|
+
(() => {
|
|
15
|
+
try {
|
|
16
|
+
const c = document.querySelector('[data-composer-id]');
|
|
17
|
+
const id = c?.getAttribute('data-composer-id') || 'active';
|
|
18
|
+
const rawStatus = c?.getAttribute('data-composer-status') || 'idle';
|
|
19
|
+
let status = rawStatus;
|
|
20
|
+
if (rawStatus === 'thinking' || rawStatus === 'streaming') status = 'generating';
|
|
21
|
+
else if (rawStatus === 'completed' || rawStatus === 'idle' || !rawStatus) status = 'idle';
|
|
22
|
+
|
|
23
|
+
// Detect approval dialogs
|
|
24
|
+
let activeModal = null;
|
|
25
|
+
|
|
26
|
+
// Primary signal: Cursor uses .run-command-review-active on conversations container
|
|
27
|
+
const reviewActive = !!document.querySelector('.run-command-review-active');
|
|
28
|
+
|
|
29
|
+
// Also check clickable elements (Cursor uses divs with cursor-pointer, not buttons)
|
|
30
|
+
// Note: Cursor concatenates button text with shortcut key labels (e.g. "SkipEsc", "Run⏎")
|
|
31
|
+
const clickableEls = [...document.querySelectorAll('button, [role="button"], .cursor-pointer')].filter(b =>
|
|
32
|
+
b.offsetWidth > 0 && /^(accept|reject|approve|deny|run|skip|allow|cancel)/i.test((b.textContent || b.getAttribute('aria-label') || '').trim())
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (reviewActive || clickableEls.length > 0) {
|
|
36
|
+
status = 'waiting_approval';
|
|
37
|
+
const reviewContainer = document.querySelector('.run-command-review-active');
|
|
38
|
+
const renderedMsgs = reviewContainer?.querySelectorAll('.composer-rendered-message');
|
|
39
|
+
const lastRendered = renderedMsgs?.length ? renderedMsgs[renderedMsgs.length - 1] : null;
|
|
40
|
+
const toolMsg = lastRendered || reviewContainer?.querySelector('.composer-tool-former-message:last-of-type');
|
|
41
|
+
activeModal = {
|
|
42
|
+
message: toolMsg?.textContent?.trim()?.substring(0, 200) || 'Command approval required',
|
|
43
|
+
buttons: clickableEls.map(b => b.textContent.trim().replace(/[⏎↵]/g, '').trim()).filter(Boolean),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const msgs = [];
|
|
48
|
+
document.querySelectorAll('.composer-human-ai-pair-container').forEach((p, i) => {
|
|
49
|
+
if (p.children.length === 0) return; // skip virtual-scroll placeholders
|
|
50
|
+
const h = p.querySelector('.composer-human-message');
|
|
51
|
+
if (h) {
|
|
52
|
+
const userText = (h.innerText || '').trim().substring(0, 6000);
|
|
53
|
+
if (userText) msgs.push({ role: 'user', content: userText, index: msgs.length });
|
|
54
|
+
}
|
|
55
|
+
// Iterate direct children after the first (user message block)
|
|
56
|
+
for (let ci = 1; ci < p.children.length; ci++) {
|
|
57
|
+
const b = p.children[ci];
|
|
58
|
+
if ((b.className || '').includes('opacity-50')) continue;
|
|
59
|
+
const t = (b.innerText || '').trim();
|
|
60
|
+
if (t.length < 2) continue;
|
|
61
|
+
// Filter noise: "Thought for Xs", "Explored N files"
|
|
62
|
+
if (/^Thought\nfor \d+s?$/i.test(t) || /^Explored\n/i.test(t)) continue;
|
|
63
|
+
const hasTool = b.querySelector('.composer-tool-former-message, .composer-diff-block, .composer-code-block-container');
|
|
64
|
+
msgs.push({ role: hasTool ? 'tool' : 'assistant', content: t.substring(0, 6000), index: msgs.length });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const inputEl = document.querySelector('.aislash-editor-input[contenteditable="true"]');
|
|
68
|
+
const inputContent = inputEl?.textContent?.trim() || '';
|
|
69
|
+
const titleParts = document.title.split(' — ');
|
|
70
|
+
const projectTitle = (titleParts.length >= 2 ? titleParts[titleParts.length - 2] : titleParts[0] || '').trim();
|
|
71
|
+
return JSON.stringify({ id, status, title: projectTitle, messages: msgs, inputContent, activeModal });
|
|
72
|
+
} catch(e) {
|
|
73
|
+
return JSON.stringify({ id: '', status: 'error', messages: [] });
|
|
74
|
+
}
|
|
75
|
+
})()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — resolve_action
|
|
3
|
+
*
|
|
4
|
+
* 승인/거부 버튼 찾기 + 클릭:
|
|
5
|
+
* button, [role="button"], .cursor-pointer 중 텍스트 매칭
|
|
6
|
+
* Cursor는 단축키 라벨을 붙임 (e.g. "Run⏎", "SkipEsc") → ⏎↵ 제거 후 비교
|
|
7
|
+
*
|
|
8
|
+
* params.buttonText: string — 찾을 버튼 텍스트
|
|
9
|
+
* → { resolved: true/false, clicked?, available? }
|
|
10
|
+
*/
|
|
11
|
+
(params) => {
|
|
12
|
+
try {
|
|
13
|
+
const btns = [...document.querySelectorAll('button, [role="button"], .cursor-pointer')].filter(b => b.offsetWidth > 0);
|
|
14
|
+
const searchText = (params.buttonText || '').toLowerCase();
|
|
15
|
+
const target = btns.find(b => (b.textContent||'').trim().replace(/[⏎↵]/g, '').trim().toLowerCase().includes(searchText));
|
|
16
|
+
if (target) { target.click(); return JSON.stringify({ resolved: true, clicked: target.textContent.trim() }); }
|
|
17
|
+
return JSON.stringify({ resolved: false, available: btns.map(b => b.textContent.trim()).filter(Boolean).slice(0, 15) });
|
|
18
|
+
} catch(e) { return JSON.stringify({ resolved: false, error: e.message }); }
|
|
19
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor CDP Scripts — Router
|
|
3
|
+
*
|
|
4
|
+
* Version routing is handled by ProviderLoader:
|
|
5
|
+
* - provider.json "compatibility" field declares script directory overrides
|
|
6
|
+
* - VersionArchive detects installed Cursor version at daemon startup
|
|
7
|
+
* - resolve() picks the appropriate scripts/ directory
|
|
8
|
+
*
|
|
9
|
+
* Pattern:
|
|
10
|
+
* - Scripts WITHOUT params: loaded as-is (self-invoking IIFE)
|
|
11
|
+
* - Scripts WITH params: loaded as function expression, invoked with params JSON
|
|
12
|
+
* e.g. `(${script})(${JSON.stringify(params)})`
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
|
|
20
|
+
function load(name) {
|
|
21
|
+
try { return fs.readFileSync(path.join(__dirname, name), 'utf-8'); }
|
|
22
|
+
catch { return null; }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Wrap a function-expression script with params invocation */
|
|
26
|
+
function withParams(name, params) {
|
|
27
|
+
const script = load(name);
|
|
28
|
+
if (!script) return null;
|
|
29
|
+
return `(${script})(${JSON.stringify(params)})`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── Core (no params — IIFE) ───
|
|
33
|
+
|
|
34
|
+
module.exports.readChat = () => load('read_chat.js');
|
|
35
|
+
module.exports.sendMessage = () => load('send_message.js');
|
|
36
|
+
module.exports.listSessions = () => load('list_sessions.js');
|
|
37
|
+
module.exports.newSession = () => load('new_session.js');
|
|
38
|
+
module.exports.focusEditor = () => load('focus_editor.js');
|
|
39
|
+
module.exports.openPanel = () => load('open_panel.js');
|
|
40
|
+
module.exports.listModels = () => load('list_models.js');
|
|
41
|
+
module.exports.listModes = () => load('list_modes.js');
|
|
42
|
+
|
|
43
|
+
// ─── With params (function expression) ───
|
|
44
|
+
|
|
45
|
+
module.exports.switchSession = (params) => {
|
|
46
|
+
const index = typeof params === 'number' ? params : params?.index ?? 0;
|
|
47
|
+
const title = typeof params === 'string' ? params : params?.title || null;
|
|
48
|
+
return withParams('switch_session.js', { index, title });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
module.exports.resolveAction = (params) => {
|
|
52
|
+
const action = typeof params === 'string' ? params : params?.action || 'approve';
|
|
53
|
+
const buttonText = params?.button || params?.buttonText
|
|
54
|
+
|| (action === 'approve' ? 'Run' : action === 'reject' ? 'Skip' : action);
|
|
55
|
+
return withParams('resolve_action.js', { buttonText });
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
module.exports.listNotifications = (params) => {
|
|
59
|
+
const filter = typeof params === 'string' ? params : params?.message || null;
|
|
60
|
+
return withParams('list_notifications.js', { filter });
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
module.exports.dismissNotification = (params) => {
|
|
64
|
+
const index = typeof params === 'number' ? params : params?.index ?? 0;
|
|
65
|
+
const button = typeof params === 'string' ? params : params?.button || null;
|
|
66
|
+
const message = params?.message || null;
|
|
67
|
+
return withParams('dismiss_notification.js', { index, button, message });
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
module.exports.setModel = (params) => {
|
|
71
|
+
const model = typeof params === 'string' ? params : params?.model;
|
|
72
|
+
return withParams('set_model.js', { model });
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
module.exports.setMode = (params) => {
|
|
76
|
+
const mode = typeof params === 'string' ? params : params?.mode;
|
|
77
|
+
return withParams('set_mode.js', { mode });
|
|
78
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — send_message
|
|
3
|
+
*
|
|
4
|
+
* Cursor는 cdp-type-and-send 방식:
|
|
5
|
+
* 1. 입력 필드 존재 확인
|
|
6
|
+
* 2. needsTypeAndSend: true 반환 → daemon이 CDP로 타이핑 + Enter 처리
|
|
7
|
+
*
|
|
8
|
+
* 입력 셀렉터: .aislash-editor-input[contenteditable="true"]
|
|
9
|
+
* 파라미터: ${ MESSAGE } (사용되지 않음 — daemon이 직접 타이핑)
|
|
10
|
+
*/
|
|
11
|
+
(() => {
|
|
12
|
+
try {
|
|
13
|
+
const input = document.querySelector('.aislash-editor-input[contenteditable="true"]');
|
|
14
|
+
if (!input) return JSON.stringify({ sent: false, error: 'Input box not found' });
|
|
15
|
+
return JSON.stringify({
|
|
16
|
+
sent: false,
|
|
17
|
+
needsTypeAndSend: true,
|
|
18
|
+
selector: '.aislash-editor-input[contenteditable="true"]',
|
|
19
|
+
});
|
|
20
|
+
} catch(e) {
|
|
21
|
+
return JSON.stringify({ sent: false, error: e.message });
|
|
22
|
+
}
|
|
23
|
+
})()
|