@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,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — set_mode
|
|
3
|
+
*
|
|
4
|
+
* 모드 드롭다운에서 대상 모드 선택:
|
|
5
|
+
* 1. 드롭다운 열기
|
|
6
|
+
* 2. 매칭 아이템 클릭
|
|
7
|
+
*
|
|
8
|
+
* params.mode: string — 모드 이름
|
|
9
|
+
* → { success: true/false, mode? }
|
|
10
|
+
*/
|
|
11
|
+
async (params) => {
|
|
12
|
+
try {
|
|
13
|
+
const target = params.mode;
|
|
14
|
+
|
|
15
|
+
const modeBtn = document.querySelector('.composer-unified-dropdown:not(.composer-unified-dropdown-model)');
|
|
16
|
+
if (!modeBtn) return JSON.stringify({ success: false, error: 'Mode button not found' });
|
|
17
|
+
|
|
18
|
+
modeBtn.click();
|
|
19
|
+
await new Promise(r => setTimeout(r, 500));
|
|
20
|
+
|
|
21
|
+
const menu = document.querySelector('[data-testid="model-picker-menu"]') || document.querySelector('.typeahead-popover');
|
|
22
|
+
if (!menu) return JSON.stringify({ success: false, error: 'Mode menu not found' });
|
|
23
|
+
|
|
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 && (name === target || name.toLowerCase() === target.toLowerCase())) {
|
|
29
|
+
item.click();
|
|
30
|
+
await new Promise(r => setTimeout(r, 200));
|
|
31
|
+
return JSON.stringify({ success: true, mode: name });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
36
|
+
return JSON.stringify({ success: false, error: 'mode not found: ' + target });
|
|
37
|
+
} catch(e) { return JSON.stringify({ success: false, error: e.message }); }
|
|
38
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — set_model
|
|
3
|
+
*
|
|
4
|
+
* 모델 드롭다운에서 대상 모델 선택:
|
|
5
|
+
* 1. 드롭다운 열기
|
|
6
|
+
* 2. Auto 토글 끄기 (필요 시)
|
|
7
|
+
* 3. 검색 입력으로 필터
|
|
8
|
+
* 4. 매칭 아이템 클릭
|
|
9
|
+
* 5. 원래 Auto 상태 복원
|
|
10
|
+
*
|
|
11
|
+
* params.model: string — 모델 이름 (🧠 접미사 가능)
|
|
12
|
+
* → { success: true/false, model? }
|
|
13
|
+
*/
|
|
14
|
+
async (params) => {
|
|
15
|
+
try {
|
|
16
|
+
const target = params.model;
|
|
17
|
+
|
|
18
|
+
const modelBtn = document.querySelector('.composer-unified-dropdown-model');
|
|
19
|
+
if (!modelBtn) return JSON.stringify({ success: false, error: 'Model button not found' });
|
|
20
|
+
|
|
21
|
+
modelBtn.click();
|
|
22
|
+
await new Promise(r => setTimeout(r, 500));
|
|
23
|
+
|
|
24
|
+
const menu = document.querySelector('[data-testid="model-picker-menu"]');
|
|
25
|
+
if (!menu) return JSON.stringify({ success: false, error: 'Model picker menu not found' });
|
|
26
|
+
|
|
27
|
+
// 🧠 접미사 처리
|
|
28
|
+
const wantBrain = target.includes('🧠');
|
|
29
|
+
const searchName = target.replace(/\s*🧠\s*$/, '').trim();
|
|
30
|
+
|
|
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
|
+
// 검색 입력으로 필터링
|
|
45
|
+
const refreshedMenu = document.querySelector('[data-testid="model-picker-menu"]');
|
|
46
|
+
const searchInput = refreshedMenu?.querySelector('input[placeholder="Search models"]');
|
|
47
|
+
if (searchInput) {
|
|
48
|
+
searchInput.focus();
|
|
49
|
+
searchInput.value = searchName;
|
|
50
|
+
searchInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
51
|
+
await new Promise(r => setTimeout(r, 300));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 아이템에서 찾기
|
|
55
|
+
const items = (refreshedMenu || menu).querySelectorAll('.composer-unified-context-menu-item');
|
|
56
|
+
for (const item of items) {
|
|
57
|
+
const nameEl = item.querySelector('.monaco-highlighted-label');
|
|
58
|
+
const name = nameEl?.textContent?.trim() || '';
|
|
59
|
+
if (!name || name === 'Add Models') continue;
|
|
60
|
+
const hasBrain = !!item.querySelector('[class*="codicon-br"]');
|
|
61
|
+
|
|
62
|
+
if (name.toLowerCase().includes(searchName.toLowerCase()) && hasBrain === wantBrain) {
|
|
63
|
+
item.click();
|
|
64
|
+
await new Promise(r => setTimeout(r, 200));
|
|
65
|
+
const displayName = hasBrain ? name + ' 🧠' : name;
|
|
66
|
+
return JSON.stringify({ success: true, model: displayName });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Auto 복원 + 닫기
|
|
71
|
+
if (wasAutoOn) {
|
|
72
|
+
const nm = document.querySelector('[data-testid="model-picker-menu"]');
|
|
73
|
+
const nai = nm?.querySelector('.composer-unified-context-menu-item');
|
|
74
|
+
const nt = nai ? [...nai.querySelectorAll('[class*="rounded-full"]')].find(el => el.offsetWidth === 24) : null;
|
|
75
|
+
if (nt) nt.click();
|
|
76
|
+
await new Promise(r => setTimeout(r, 200));
|
|
77
|
+
}
|
|
78
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
79
|
+
return JSON.stringify({ success: false, error: 'model not found: ' + target });
|
|
80
|
+
} catch(e) { return JSON.stringify({ success: false, error: e.message }); }
|
|
81
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — switch_session
|
|
3
|
+
*
|
|
4
|
+
* 사이드바 셀 클릭으로 세션 전환:
|
|
5
|
+
* 제목 매칭 (params.title) 또는 인덱스 (params.index)
|
|
6
|
+
*
|
|
7
|
+
* params.index: number, params.title: string|null
|
|
8
|
+
* → { switched: true/false, title?, error? }
|
|
9
|
+
*/
|
|
10
|
+
(params) => {
|
|
11
|
+
try {
|
|
12
|
+
const cells = [...document.querySelectorAll('.agent-sidebar-cell')];
|
|
13
|
+
let target;
|
|
14
|
+
if (params.title) {
|
|
15
|
+
target = cells.find(c => {
|
|
16
|
+
const t = c.querySelector('.agent-sidebar-cell-text')?.textContent?.trim() || '';
|
|
17
|
+
return t.toLowerCase().includes(params.title.toLowerCase());
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
target = cells[params.index || 0];
|
|
21
|
+
}
|
|
22
|
+
if (!target) return JSON.stringify({ switched: false, error: 'Session not found', available: cells.length });
|
|
23
|
+
target.click();
|
|
24
|
+
return JSON.stringify({ switched: true, title: target.querySelector('.agent-sidebar-cell-text')?.textContent?.trim() });
|
|
25
|
+
} catch(e) {
|
|
26
|
+
return JSON.stringify({ switched: false, error: e.message });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "kiro",
|
|
3
|
+
"name": "Kiro",
|
|
4
|
+
"category": "ide",
|
|
5
|
+
"displayName": "Kiro",
|
|
6
|
+
"icon": "🪁",
|
|
7
|
+
"cli": "kiro",
|
|
8
|
+
"cdpPorts": [
|
|
9
|
+
9351,
|
|
10
|
+
9352
|
|
11
|
+
],
|
|
12
|
+
"targetFilter": {
|
|
13
|
+
"urlIncludes": "workbench.html",
|
|
14
|
+
"urlExcludes": [
|
|
15
|
+
"agent"
|
|
16
|
+
],
|
|
17
|
+
"titleExcludes": "extension-output|ADHDev CDP|Debug Console|Output\\s*$|Launchpad"
|
|
18
|
+
},
|
|
19
|
+
"processNames": {
|
|
20
|
+
"darwin": "Kiro",
|
|
21
|
+
"win32": [
|
|
22
|
+
"Kiro.exe"
|
|
23
|
+
],
|
|
24
|
+
"linux": [
|
|
25
|
+
"kiro"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"paths": {
|
|
29
|
+
"darwin": [
|
|
30
|
+
"/Applications/Kiro.app"
|
|
31
|
+
],
|
|
32
|
+
"win32": [
|
|
33
|
+
"C:\\Users\\*\\AppData\\Local\\Programs\\kiro\\Kiro.exe"
|
|
34
|
+
],
|
|
35
|
+
"linux": [
|
|
36
|
+
"/opt/kiro",
|
|
37
|
+
"/usr/share/kiro"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"inputMethod": "cdp-type-and-send",
|
|
41
|
+
"inputSelector": "[contenteditable=\"true\"][role=\"textbox\"]",
|
|
42
|
+
"webviewMatchText": "kiro",
|
|
43
|
+
"settings": {
|
|
44
|
+
"approvalAlert": {
|
|
45
|
+
"type": "boolean",
|
|
46
|
+
"default": true,
|
|
47
|
+
"public": true,
|
|
48
|
+
"label": "Approval Notifications",
|
|
49
|
+
"description": "Show notification when approval is needed"
|
|
50
|
+
},
|
|
51
|
+
"longGeneratingAlert": {
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"default": true,
|
|
54
|
+
"public": true,
|
|
55
|
+
"label": "Long Generation Alert",
|
|
56
|
+
"description": "Alert when generation takes too long"
|
|
57
|
+
},
|
|
58
|
+
"longGeneratingThresholdSec": {
|
|
59
|
+
"type": "number",
|
|
60
|
+
"default": 180,
|
|
61
|
+
"public": true,
|
|
62
|
+
"label": "Long Generation Threshold (sec)",
|
|
63
|
+
"min": 30,
|
|
64
|
+
"max": 600
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor v1 — focus_editor
|
|
3
|
+
*
|
|
4
|
+
* CURSOR.md 4-5: 셀렉터 우선순위
|
|
5
|
+
* [contenteditable="true"][role="textbox"]
|
|
6
|
+
* → .chat-input textarea
|
|
7
|
+
* → .composer-input
|
|
8
|
+
* → textarea
|
|
9
|
+
*
|
|
10
|
+
* 최종 확인: 2026-03-06
|
|
11
|
+
*/
|
|
12
|
+
(() => {
|
|
13
|
+
const editor = document.querySelector('[contenteditable="true"][role="textbox"]')
|
|
14
|
+
|| document.querySelector('.chat-input textarea')
|
|
15
|
+
|| document.querySelector('.composer-input')
|
|
16
|
+
|| document.querySelector('textarea.native-input')
|
|
17
|
+
|| document.querySelector('textarea');
|
|
18
|
+
if (editor) { editor.focus(); return 'focused'; }
|
|
19
|
+
return 'no editor found';
|
|
20
|
+
})()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — open_panel
|
|
3
|
+
*
|
|
4
|
+
* Kiro AI 채팅 패널 열기.
|
|
5
|
+
* Secondary Side Bar (#workbench.parts.auxiliarybar)에 위치.
|
|
6
|
+
* "Toggle Secondary Side Bar (⌥⌘B)" 또는 "Kiro" 버튼으로 열기.
|
|
7
|
+
*
|
|
8
|
+
* 반환: 'visible' | 'opened' | 'error: ...'
|
|
9
|
+
*/
|
|
10
|
+
(() => {
|
|
11
|
+
try {
|
|
12
|
+
// 1. 이미 열려 있는지 확인
|
|
13
|
+
const sidebar = document.getElementById('workbench.parts.auxiliarybar');
|
|
14
|
+
if (sidebar && sidebar.offsetWidth > 0 && sidebar.offsetHeight > 0) {
|
|
15
|
+
return 'visible';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 2. Toggle 버튼 클릭 시도
|
|
19
|
+
const toggleBtns = Array.from(document.querySelectorAll('li.action-item a, button, [role="button"]'));
|
|
20
|
+
for (const btn of toggleBtns) {
|
|
21
|
+
const label = (btn.getAttribute('aria-label') || '').toLowerCase();
|
|
22
|
+
if (label.includes('toggle secondary') || label.includes('toggle auxiliary') ||
|
|
23
|
+
label === 'kiro' || label.includes('kiro')) {
|
|
24
|
+
if (btn.offsetWidth > 0 || btn.offsetHeight > 0) {
|
|
25
|
+
btn.click();
|
|
26
|
+
return 'opened (toggle)';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 3. Cmd+Shift+I 단축키 폴백 (Kiro 기본 단축키)
|
|
32
|
+
document.dispatchEvent(new KeyboardEvent('keydown', {
|
|
33
|
+
key: 'b', code: 'KeyB', keyCode: 66,
|
|
34
|
+
metaKey: true, altKey: true, ctrlKey: false,
|
|
35
|
+
bubbles: true, cancelable: true,
|
|
36
|
+
}));
|
|
37
|
+
document.dispatchEvent(new KeyboardEvent('keyup', {
|
|
38
|
+
key: 'b', code: 'KeyB', keyCode: 66,
|
|
39
|
+
metaKey: true, altKey: true, ctrlKey: false,
|
|
40
|
+
bubbles: true, cancelable: true,
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
return 'opened (⌥⌘B)';
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return 'error: ' + e.message;
|
|
46
|
+
}
|
|
47
|
+
})()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — resolve_action
|
|
3
|
+
*
|
|
4
|
+
* 승인/거부 버튼 찾기 + 좌표 반환.
|
|
5
|
+
* Kiro의 approval 다이얼로그는 메인 DOM에 표시됨.
|
|
6
|
+
*
|
|
7
|
+
* 파라미터: ${ BUTTON_TEXT }
|
|
8
|
+
*/
|
|
9
|
+
(() => {
|
|
10
|
+
const want = ${ BUTTON_TEXT };
|
|
11
|
+
const wantNorm = (want || '').replace(/\s+/g, ' ').trim().toLowerCase();
|
|
12
|
+
|
|
13
|
+
function norm(t) { return (t || '').replace(/\s+/g, ' ').trim().toLowerCase(); }
|
|
14
|
+
|
|
15
|
+
function matches(el) {
|
|
16
|
+
const t = norm(el.textContent);
|
|
17
|
+
if (!t || t.length > 80) return false;
|
|
18
|
+
if (t === wantNorm) return true;
|
|
19
|
+
if (t.indexOf(wantNorm) === 0) return true;
|
|
20
|
+
if (wantNorm.indexOf(t) >= 0 && t.length > 2) return true;
|
|
21
|
+
if (/^(run|approve|allow|accept|yes)\b/.test(wantNorm)) {
|
|
22
|
+
if (/^(run|allow|accept|approve)\b/.test(t)) return true;
|
|
23
|
+
}
|
|
24
|
+
if (/^(reject|deny|no|abort)\b/.test(wantNorm)) {
|
|
25
|
+
if (/^(reject|deny)\b/.test(t)) return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const sel = 'button, [role="button"], .monaco-button';
|
|
31
|
+
const allBtns = [...document.querySelectorAll(sel)].filter(b => {
|
|
32
|
+
if (!b.offsetWidth || !b.getBoundingClientRect().height) return false;
|
|
33
|
+
const rect = b.getBoundingClientRect();
|
|
34
|
+
return rect.y > 0 && rect.y < window.innerHeight;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
let found = null;
|
|
38
|
+
for (let i = allBtns.length - 1; i >= 0; i--) {
|
|
39
|
+
if (matches(allBtns[i])) { found = allBtns[i]; break; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (found) {
|
|
43
|
+
const rect = found.getBoundingClientRect();
|
|
44
|
+
return JSON.stringify({
|
|
45
|
+
found: true,
|
|
46
|
+
text: found.textContent?.trim()?.substring(0, 40),
|
|
47
|
+
x: Math.round(rect.x + rect.width / 2),
|
|
48
|
+
y: Math.round(rect.y + rect.height / 2),
|
|
49
|
+
w: Math.round(rect.width),
|
|
50
|
+
h: Math.round(rect.height)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return JSON.stringify({ found: false, want: wantNorm });
|
|
54
|
+
})()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — send_message
|
|
3
|
+
*
|
|
4
|
+
* Kiro의 채팅 입력은 webview iframe 안에 있어 메인 DOM에서 직접 접근 불가.
|
|
5
|
+
* auxbar 하단의 입력 필드 좌표를 계산하여 clickCoords로 반환.
|
|
6
|
+
* 데몬이 CDP Input API로 해당 좌표에 클릭+타이핑+Enter를 수행.
|
|
7
|
+
*
|
|
8
|
+
* 파라미터: ${ MESSAGE }
|
|
9
|
+
*/
|
|
10
|
+
(() => {
|
|
11
|
+
try {
|
|
12
|
+
const auxbar = document.getElementById('workbench.parts.auxiliarybar');
|
|
13
|
+
if (!auxbar || auxbar.offsetWidth === 0) {
|
|
14
|
+
return JSON.stringify({ sent: false, error: 'auxbar not found' });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const rect = auxbar.getBoundingClientRect();
|
|
18
|
+
const x = Math.round(rect.x + rect.width / 2);
|
|
19
|
+
const y = Math.round(rect.y + rect.height - 80);
|
|
20
|
+
|
|
21
|
+
return JSON.stringify({
|
|
22
|
+
sent: false,
|
|
23
|
+
needsTypeAndSend: true,
|
|
24
|
+
clickCoords: { x, y },
|
|
25
|
+
});
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return JSON.stringify({ sent: false, error: e.message });
|
|
28
|
+
}
|
|
29
|
+
})()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic fallback — list_models
|
|
3
|
+
*/
|
|
4
|
+
(() => {
|
|
5
|
+
try {
|
|
6
|
+
const models = [];
|
|
7
|
+
let current = '';
|
|
8
|
+
|
|
9
|
+
// Try generic Model string from select/button
|
|
10
|
+
const sel = document.querySelectorAll('select, [class*="model"], [id*="model"]');
|
|
11
|
+
for (const el of sel) {
|
|
12
|
+
const txt = (el.textContent || '').trim();
|
|
13
|
+
if (txt && /claude|gpt|gemini|sonnet|opus/i.test(txt)) {
|
|
14
|
+
if (txt.length < 50) {
|
|
15
|
+
models.push(txt);
|
|
16
|
+
if (!current) current = txt;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (models.length === 0) {
|
|
22
|
+
const btns = document.querySelectorAll('button');
|
|
23
|
+
for (const b of btns) {
|
|
24
|
+
const txt = (b.textContent || '').trim();
|
|
25
|
+
if (txt && /claude|gpt|gemini|sonnet/i.test(txt) && txt.length < 30) {
|
|
26
|
+
models.push(txt);
|
|
27
|
+
current = txt;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return JSON.stringify({
|
|
33
|
+
models: [...new Set(models)],
|
|
34
|
+
current: current || 'Default'
|
|
35
|
+
});
|
|
36
|
+
} catch (e) {
|
|
37
|
+
return JSON.stringify({ models: [], current: '', error: e.message });
|
|
38
|
+
}
|
|
39
|
+
})()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic fallback — list_models
|
|
3
|
+
*/
|
|
4
|
+
(() => {
|
|
5
|
+
try {
|
|
6
|
+
const models = [];
|
|
7
|
+
let current = '';
|
|
8
|
+
|
|
9
|
+
// Try generic Model string from select/button
|
|
10
|
+
const sel = document.querySelectorAll('select, [class*="model"], [id*="model"]');
|
|
11
|
+
for (const el of sel) {
|
|
12
|
+
const txt = (el.textContent || '').trim();
|
|
13
|
+
if (txt && /claude|gpt|gemini|sonnet|opus/i.test(txt)) {
|
|
14
|
+
if (txt.length < 50) {
|
|
15
|
+
models.push(txt);
|
|
16
|
+
if (!current) current = txt;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (models.length === 0) {
|
|
22
|
+
const btns = document.querySelectorAll('button');
|
|
23
|
+
for (const b of btns) {
|
|
24
|
+
const txt = (b.textContent || '').trim();
|
|
25
|
+
if (txt && /claude|gpt|gemini|sonnet/i.test(txt) && txt.length < 30) {
|
|
26
|
+
models.push(txt);
|
|
27
|
+
current = txt;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return JSON.stringify({
|
|
33
|
+
models: [...new Set(models)],
|
|
34
|
+
current: current || 'Default'
|
|
35
|
+
});
|
|
36
|
+
} catch (e) {
|
|
37
|
+
return JSON.stringify({ models: [], current: '', error: e.message });
|
|
38
|
+
}
|
|
39
|
+
})()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — webview_list_sessions (webview iframe 내부에서 실행)
|
|
3
|
+
*
|
|
4
|
+
* Kiro의 세션 탭 목록을 반환.
|
|
5
|
+
* DOM: .kiro-tabs-item
|
|
6
|
+
*/
|
|
7
|
+
(() => {
|
|
8
|
+
try {
|
|
9
|
+
const tabs = document.querySelectorAll('.kiro-tabs-item');
|
|
10
|
+
const sessions = Array.from(tabs).map((tab, i) => {
|
|
11
|
+
const label = tab.querySelector('.kiro-tabs-item-label');
|
|
12
|
+
const title = (label?.textContent || tab.textContent || '').trim();
|
|
13
|
+
const active = tab.classList.contains('active') ||
|
|
14
|
+
tab.getAttribute('aria-selected') === 'true';
|
|
15
|
+
return { id: String(i), title, active };
|
|
16
|
+
});
|
|
17
|
+
return JSON.stringify({ sessions });
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return JSON.stringify({ sessions: [], error: e.message });
|
|
20
|
+
}
|
|
21
|
+
})()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — webview_new_session (webview iframe 내부에서 실행)
|
|
3
|
+
*
|
|
4
|
+
* "New Session" 버튼/탭 클릭.
|
|
5
|
+
* Kiro는 탭 바에 + 버튼 또는 "New Session" 액션이 있음.
|
|
6
|
+
*/
|
|
7
|
+
(() => {
|
|
8
|
+
try {
|
|
9
|
+
// kiro-icon-button (+ 버튼) 찾기
|
|
10
|
+
const addBtns = document.querySelectorAll('.kiro-icon-button, button, [role="button"]');
|
|
11
|
+
for (const btn of addBtns) {
|
|
12
|
+
const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
|
|
13
|
+
const title = (btn.getAttribute('title') || '').toLowerCase();
|
|
14
|
+
if (ariaLabel.includes('new') || title.includes('new') ||
|
|
15
|
+
ariaLabel.includes('add') || title.includes('add')) {
|
|
16
|
+
btn.click();
|
|
17
|
+
return JSON.stringify({ created: true, method: 'button' });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Checkpoint > New Session 영역 찾기
|
|
22
|
+
const allText = document.querySelectorAll('*');
|
|
23
|
+
for (const el of allText) {
|
|
24
|
+
if (el.children.length === 0 && (el.textContent || '').trim() === 'New Session') {
|
|
25
|
+
el.click();
|
|
26
|
+
return JSON.stringify({ created: true, method: 'text-click' });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return JSON.stringify({ created: false, error: 'New Session button not found' });
|
|
31
|
+
} catch (e) {
|
|
32
|
+
return JSON.stringify({ created: false, error: e.message });
|
|
33
|
+
}
|
|
34
|
+
})()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — webview_read_chat (webview iframe 내부에서 실행)
|
|
3
|
+
*
|
|
4
|
+
* Kiro의 채팅 UI는 webview iframe 안에 위치하며,
|
|
5
|
+
* 데몬의 evaluateInWebviewFrame을 통해 실행됨.
|
|
6
|
+
*
|
|
7
|
+
* DOM 구조:
|
|
8
|
+
* .kiro-chat-timeline
|
|
9
|
+
* .kiro-chat-message (유저/어시스턴트 메시지)
|
|
10
|
+
* .kiro-chat-message-meta → .kiro-chat-message-role (발신자)
|
|
11
|
+
* .kiro-chat-message-body → .kiro-chat-message-markdown (내용)
|
|
12
|
+
*
|
|
13
|
+
* 반환: ReadChatResult { id, status, messages, inputContent? }
|
|
14
|
+
*/
|
|
15
|
+
(() => {
|
|
16
|
+
try {
|
|
17
|
+
const messages = [];
|
|
18
|
+
const msgElements = document.querySelectorAll('.kiro-chat-message');
|
|
19
|
+
|
|
20
|
+
msgElements.forEach((msg, idx) => {
|
|
21
|
+
const roleMeta = msg.querySelector('.kiro-chat-message-role');
|
|
22
|
+
const roleText = (roleMeta?.textContent || '').trim();
|
|
23
|
+
const isKiro = roleText.toLowerCase() === 'kiro';
|
|
24
|
+
const role = isKiro ? 'assistant' : 'user';
|
|
25
|
+
|
|
26
|
+
const body = msg.querySelector('.kiro-chat-message-body');
|
|
27
|
+
let content = '';
|
|
28
|
+
if (body) {
|
|
29
|
+
const markdown = body.querySelector('.kiro-chat-message-markdown');
|
|
30
|
+
content = (markdown || body).textContent?.trim() || '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (content) {
|
|
34
|
+
messages.push({ role, content, index: idx });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// 상태 감지
|
|
39
|
+
let status = 'idle';
|
|
40
|
+
|
|
41
|
+
// "Working" / "Cancel" 버튼 → generating
|
|
42
|
+
const workingBar = document.querySelector('.kiro-snackbar');
|
|
43
|
+
if (workingBar && workingBar.offsetWidth > 0) {
|
|
44
|
+
const barText = (workingBar.textContent || '').toLowerCase();
|
|
45
|
+
if (barText.includes('working') || barText.includes('cancel')) {
|
|
46
|
+
status = 'generating';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 입력 필드 내용
|
|
51
|
+
const input = document.querySelector('.tiptap.ProseMirror, [contenteditable="true"]');
|
|
52
|
+
const inputContent = input ? input.textContent?.trim() : '';
|
|
53
|
+
|
|
54
|
+
// 세션 탭
|
|
55
|
+
const tab = document.querySelector('.kiro-tabs-item.active, .kiro-tabs-item[aria-selected="true"]');
|
|
56
|
+
const title = tab?.textContent?.trim() || '';
|
|
57
|
+
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
id: title || 'kiro-default',
|
|
60
|
+
status,
|
|
61
|
+
messages,
|
|
62
|
+
title: title || undefined,
|
|
63
|
+
inputContent: inputContent || undefined,
|
|
64
|
+
});
|
|
65
|
+
} catch (e) {
|
|
66
|
+
return JSON.stringify({ id: '', status: 'error', messages: [], error: e.message });
|
|
67
|
+
}
|
|
68
|
+
})()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiro — webview_send_message (webview iframe 내부에서 실행)
|
|
3
|
+
*
|
|
4
|
+
* Kiro의 채팅 입력은 webview iframe 안의 ProseMirror/tiptap 에디터.
|
|
5
|
+
* execCommand('insertText') + Enter 키 이벤트로 메시지 전송.
|
|
6
|
+
*
|
|
7
|
+
* 파라미터: ${ MESSAGE }
|
|
8
|
+
*/
|
|
9
|
+
(async () => {
|
|
10
|
+
try {
|
|
11
|
+
const msg = ${ MESSAGE };
|
|
12
|
+
|
|
13
|
+
// ─── 1. 입력 필드 찾기 ───
|
|
14
|
+
const editor =
|
|
15
|
+
document.querySelector('.tiptap.ProseMirror') ||
|
|
16
|
+
document.querySelector('[contenteditable="true"]') ||
|
|
17
|
+
document.querySelector('textarea');
|
|
18
|
+
|
|
19
|
+
if (!editor) return JSON.stringify({ sent: false, error: 'no input found in webview' });
|
|
20
|
+
|
|
21
|
+
const isTextarea = editor.tagName === 'TEXTAREA';
|
|
22
|
+
|
|
23
|
+
if (isTextarea) {
|
|
24
|
+
editor.focus();
|
|
25
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set;
|
|
26
|
+
if (nativeSetter) nativeSetter.call(editor, msg);
|
|
27
|
+
else editor.value = msg;
|
|
28
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
29
|
+
await new Promise(r => setTimeout(r, 300));
|
|
30
|
+
|
|
31
|
+
const enterOpts = { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true, cancelable: true, composed: true };
|
|
32
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
33
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
34
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
35
|
+
return JSON.stringify({ sent: true });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── 2. contenteditable (ProseMirror / tiptap) ───
|
|
39
|
+
editor.focus();
|
|
40
|
+
await new Promise(r => setTimeout(r, 100));
|
|
41
|
+
|
|
42
|
+
// 전체 선택 + 삭제 + 삽입
|
|
43
|
+
const sel = window.getSelection();
|
|
44
|
+
const range = document.createRange();
|
|
45
|
+
range.selectNodeContents(editor);
|
|
46
|
+
sel.removeAllRanges();
|
|
47
|
+
sel.addRange(range);
|
|
48
|
+
await new Promise(r => setTimeout(r, 50));
|
|
49
|
+
|
|
50
|
+
document.execCommand('delete', false, null);
|
|
51
|
+
await new Promise(r => setTimeout(r, 50));
|
|
52
|
+
document.execCommand('insertText', false, msg);
|
|
53
|
+
|
|
54
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
55
|
+
await new Promise(r => setTimeout(r, 400));
|
|
56
|
+
|
|
57
|
+
// ─── 3. Enter 키 전송 ───
|
|
58
|
+
const enterOpts = {
|
|
59
|
+
key: 'Enter', code: 'Enter',
|
|
60
|
+
keyCode: 13, which: 13,
|
|
61
|
+
bubbles: true, cancelable: true, composed: true,
|
|
62
|
+
};
|
|
63
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
64
|
+
await new Promise(r => setTimeout(r, 50));
|
|
65
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
66
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
67
|
+
|
|
68
|
+
return JSON.stringify({ sent: true });
|
|
69
|
+
} catch (e) {
|
|
70
|
+
return JSON.stringify({ sent: false, error: e.message });
|
|
71
|
+
}
|
|
72
|
+
})()
|
|
@@ -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
|
+
})()
|