@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,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity v1 — resolve_action
|
|
3
|
+
*
|
|
4
|
+
* 버튼 찾기 + 좌표 반환 (CDP Input.dispatchMouseEvent로 클릭)
|
|
5
|
+
* 파라미터: ${BUTTON_TEXT}
|
|
6
|
+
*
|
|
7
|
+
* 핵심: viewport 안에 보이는 버튼 중 마지막(최신) 매칭 우선
|
|
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 raw = (el.textContent || '').trim();
|
|
17
|
+
const t = norm(raw);
|
|
18
|
+
if (!t || t.length > 80) return false;
|
|
19
|
+
if (t === wantNorm) return true;
|
|
20
|
+
if (t.indexOf(wantNorm) === 0) return true;
|
|
21
|
+
if (wantNorm.indexOf(t) >= 0 && t.length > 2) return true;
|
|
22
|
+
if (t.indexOf(wantNorm) >= 0) return true;
|
|
23
|
+
if (/^(run|approve|allow|accept|always|yes)\b/.test(wantNorm)) {
|
|
24
|
+
if (/^run\b/.test(t)) return true;
|
|
25
|
+
if (/^allow\b/.test(t)) return true;
|
|
26
|
+
if (/^accept\b/.test(t) && !t.includes('changes')) return true;
|
|
27
|
+
if (/^always\b/.test(t)) return true;
|
|
28
|
+
}
|
|
29
|
+
if (/^(reject|deny|no|abort)\b/.test(wantNorm)) {
|
|
30
|
+
if (/^reject\b/.test(t) && !t.includes('changes')) return true;
|
|
31
|
+
if (/^deny\b/.test(t)) return true;
|
|
32
|
+
}
|
|
33
|
+
if (/^(skip|cancel)\b/.test(wantNorm)) {
|
|
34
|
+
if (/^skip\b/.test(t) || /^cancel\b/.test(t)) return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const sel = 'button, [role="button"]';
|
|
40
|
+
const allBtns = [...document.querySelectorAll(sel)].filter(b => {
|
|
41
|
+
if (!b.offsetWidth || !b.getBoundingClientRect().height) return false;
|
|
42
|
+
const rect = b.getBoundingClientRect();
|
|
43
|
+
// viewport 안에 보이는 것만 (y > 0, y < window.innerHeight)
|
|
44
|
+
return rect.y > 0 && rect.y < window.innerHeight;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 마지막(최신) 매칭 우선 — 역순 검색
|
|
48
|
+
let found = null;
|
|
49
|
+
for (let i = allBtns.length - 1; i >= 0; i--) {
|
|
50
|
+
if (matches(allBtns[i])) {
|
|
51
|
+
found = allBtns[i];
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (found) {
|
|
57
|
+
const rect = found.getBoundingClientRect();
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
found: true,
|
|
60
|
+
text: found.textContent?.trim()?.substring(0, 40),
|
|
61
|
+
x: Math.round(rect.x + rect.width / 2),
|
|
62
|
+
y: Math.round(rect.y + rect.height / 2),
|
|
63
|
+
w: Math.round(rect.width),
|
|
64
|
+
h: Math.round(rect.height)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return JSON.stringify({ found: false, want: wantNorm });
|
|
68
|
+
})()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity CDP Scripts — legacy (< 1.107.0)
|
|
3
|
+
* DOM uses exact CSS class selectors (original Tailwind classes without arbitrary values)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const DIR = __dirname; // scripts/1.106/
|
|
11
|
+
|
|
12
|
+
function load(name) {
|
|
13
|
+
try { return fs.readFileSync(path.join(DIR, name), 'utf-8'); }
|
|
14
|
+
catch { return null; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports.readChat = () => load('read_chat.js');
|
|
18
|
+
module.exports.focusEditor = () => load('focus_editor.js');
|
|
19
|
+
module.exports.listSessions = () => load('list_chats.js');
|
|
20
|
+
module.exports.newSession = () => load('new_session.js');
|
|
21
|
+
module.exports.listModels = () => load('list_models.js');
|
|
22
|
+
module.exports.listModes = () => load('list_modes.js');
|
|
23
|
+
|
|
24
|
+
module.exports.sendMessage = (text) => {
|
|
25
|
+
const script = load('send_message.js');
|
|
26
|
+
if (!script) return null;
|
|
27
|
+
return script.replace(/\$\{\s*MESSAGE\s*\}/g, JSON.stringify(text));
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
module.exports.switchSession = (sessionId) => {
|
|
31
|
+
const script = load('switch_session.js');
|
|
32
|
+
if (!script) return null;
|
|
33
|
+
return script.replace(/\$\{\s*SESSION_ID\s*\}/g, JSON.stringify(sessionId));
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
module.exports.resolveAction = (params) => {
|
|
37
|
+
const action = typeof params === 'string' ? params : params?.action || 'approve';
|
|
38
|
+
const buttonText = params?.button || params?.buttonText
|
|
39
|
+
|| (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : action);
|
|
40
|
+
const script = load('resolve_action.js');
|
|
41
|
+
if (!script) return null;
|
|
42
|
+
return script.replace(/\$\{\s*BUTTON_TEXT\s*\}/g, JSON.stringify(buttonText));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
module.exports.setModel = (params) => {
|
|
46
|
+
const model = typeof params === 'string' ? params : params?.model;
|
|
47
|
+
const script = load('set_model.js');
|
|
48
|
+
if (!script) return null;
|
|
49
|
+
return script.replace(/\$\{\s*MODEL\s*\}/g, JSON.stringify(model));
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports.setMode = (params) => {
|
|
53
|
+
const mode = typeof params === 'string' ? params : params?.mode;
|
|
54
|
+
const script = load('set_mode.js');
|
|
55
|
+
if (!script) return null;
|
|
56
|
+
return script.replace(/\$\{\s*MODE\s*\}/g, JSON.stringify(mode));
|
|
57
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity v1 — send_message
|
|
3
|
+
*
|
|
4
|
+
* Antigravity는 contenteditable div[role="textbox"]를 사용.
|
|
5
|
+
* 여러 개의 contenteditable이 있을 수 있으므로 y좌표가 가장 큰 (메인 채팅) 것을 선택.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ Enter 이벤트에 composed: true + which 필수 (Shadow DOM 경계 통과 + React 호환)
|
|
8
|
+
* ⚠️ keydown + keypress + keyup 전체 시퀀스 필요
|
|
9
|
+
*
|
|
10
|
+
* 파라미터: ${ MESSAGE }
|
|
11
|
+
* 최종 확인: 2026-03-10
|
|
12
|
+
*/
|
|
13
|
+
(async () => {
|
|
14
|
+
try {
|
|
15
|
+
const msg = ${ MESSAGE };
|
|
16
|
+
|
|
17
|
+
// ─── 1. 메인 채팅 입력 필드 찾기 ───
|
|
18
|
+
const editors = document.querySelectorAll('[contenteditable="true"][role="textbox"]');
|
|
19
|
+
if (!editors.length) return 'error: no contenteditable textbox found';
|
|
20
|
+
|
|
21
|
+
// y좌표가 가장 큰 (화면 아래쪽 = 메인 채팅) 에디터 선택
|
|
22
|
+
const editor = [...editors].reduce((a, b) =>
|
|
23
|
+
b.getBoundingClientRect().y > a.getBoundingClientRect().y ? b : a
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// ─── 2. 텍스트 삽입 ───
|
|
27
|
+
editor.focus();
|
|
28
|
+
|
|
29
|
+
// 기존 내용 삭제
|
|
30
|
+
document.execCommand('selectAll', false, null);
|
|
31
|
+
document.execCommand('delete', false, null);
|
|
32
|
+
|
|
33
|
+
// 텍스트 삽입
|
|
34
|
+
document.execCommand('insertText', false, msg);
|
|
35
|
+
|
|
36
|
+
// React에 변경 알림
|
|
37
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
38
|
+
|
|
39
|
+
await new Promise(r => setTimeout(r, 300));
|
|
40
|
+
|
|
41
|
+
// ─── 3. Enter 키 전송 (full sequence) ───
|
|
42
|
+
const enterOpts = {
|
|
43
|
+
key: 'Enter', code: 'Enter',
|
|
44
|
+
keyCode: 13, which: 13,
|
|
45
|
+
bubbles: true, cancelable: true, composed: true,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
49
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
50
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
51
|
+
|
|
52
|
+
return 'sent';
|
|
53
|
+
} catch (e) {
|
|
54
|
+
return 'error: ' + e.message;
|
|
55
|
+
}
|
|
56
|
+
})()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity — set_mode
|
|
3
|
+
* Conversation mode 패널에서 Planning/Fast 클릭
|
|
4
|
+
* ${MODE} → JSON.stringify(modeName)
|
|
5
|
+
* → { success: boolean, mode?: string }
|
|
6
|
+
*/
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const target = ${MODE};
|
|
10
|
+
|
|
11
|
+
// "Conversation mode" 헤더의 부모에서 .font-medium 항목 찾기
|
|
12
|
+
const headers = document.querySelectorAll('.text-xs.px-2.pb-1.opacity-80');
|
|
13
|
+
for (const header of headers) {
|
|
14
|
+
if (header.textContent?.trim() === 'Conversation mode') {
|
|
15
|
+
const parent = header.parentElement;
|
|
16
|
+
if (!parent) continue;
|
|
17
|
+
const items = parent.querySelectorAll('.font-medium');
|
|
18
|
+
for (const item of items) {
|
|
19
|
+
const text = item.textContent?.trim();
|
|
20
|
+
if (text && text.toLowerCase() === target.toLowerCase()) {
|
|
21
|
+
item.click();
|
|
22
|
+
await new Promise(r => setTimeout(r, 300));
|
|
23
|
+
return JSON.stringify({ success: true, mode: text });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return JSON.stringify({ success: false, error: 'mode not found: ' + target });
|
|
31
|
+
} catch (e) {
|
|
32
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
33
|
+
}
|
|
34
|
+
})()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity — set_model
|
|
3
|
+
* antigravity-agent-side-panel 모델 드롭다운에서 모델 선택
|
|
4
|
+
* ${MODEL} → JSON.stringify(modelName)
|
|
5
|
+
* → { success: boolean, model?: string }
|
|
6
|
+
*/
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const target = ${MODEL};
|
|
10
|
+
|
|
11
|
+
// 1. 모델 드롭다운이 열려 있는 경우 → 직접 선택
|
|
12
|
+
const items = document.querySelectorAll('.px-2.py-1.flex.items-center.justify-between.cursor-pointer');
|
|
13
|
+
for (const item of items) {
|
|
14
|
+
const label = item.querySelector('.text-xs.font-medium');
|
|
15
|
+
const text = (label || item).textContent?.trim();
|
|
16
|
+
if (text && (text === target || text.toLowerCase().includes(target.toLowerCase()))) {
|
|
17
|
+
item.click();
|
|
18
|
+
await new Promise(r => setTimeout(r, 200));
|
|
19
|
+
return JSON.stringify({ success: true, model: text });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 2. 드롭다운이 닫혀 있으면 → 트리거 버튼 클릭해서 열기
|
|
24
|
+
const trigger = document.querySelector('.flex.min-w-0.max-w-full.cursor-pointer.items-center');
|
|
25
|
+
if (trigger) {
|
|
26
|
+
trigger.click();
|
|
27
|
+
await new Promise(r => setTimeout(r, 400));
|
|
28
|
+
|
|
29
|
+
// 다시 항목 탐색
|
|
30
|
+
const newItems = document.querySelectorAll('.px-2.py-1.flex.items-center.justify-between.cursor-pointer');
|
|
31
|
+
for (const item of newItems) {
|
|
32
|
+
const label = item.querySelector('.text-xs.font-medium');
|
|
33
|
+
const text = (label || item).textContent?.trim();
|
|
34
|
+
if (text && (text === target || text.toLowerCase().includes(target.toLowerCase()))) {
|
|
35
|
+
item.click();
|
|
36
|
+
return JSON.stringify({ success: true, model: text });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// 못 찾으면 드롭다운 닫기
|
|
40
|
+
trigger.click();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return JSON.stringify({ success: false, error: 'model not found: ' + target });
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
46
|
+
}
|
|
47
|
+
})()
|
|
@@ -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,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,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity v1 — list_chats (v3 — 강화된 셀렉터)
|
|
3
|
+
*
|
|
4
|
+
* 히스토리 토글을 클릭하여 대화 목록 패널을 열고,
|
|
5
|
+
* DOM에서 직접 대화 목록을 파싱한 뒤 패널을 닫고 결과를 반환.
|
|
6
|
+
*
|
|
7
|
+
* DOM 구조 (2026-03-03 확인):
|
|
8
|
+
* 토글: [data-past-conversations-toggle="true"]
|
|
9
|
+
* 패널: input[placeholder="Select a conversation"] 근처
|
|
10
|
+
* 섹션 헤더: .opacity-50 텍스트 (Current, Recent, Other)
|
|
11
|
+
* 행: .cursor-pointer.justify-between.rounded-md
|
|
12
|
+
* ├── 제목: span > span
|
|
13
|
+
* ├── 워크스페이스: .opacity-50.truncate > span
|
|
14
|
+
* └── 시간: .opacity-50.flex-shrink-0
|
|
15
|
+
*/
|
|
16
|
+
(async () => {
|
|
17
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// 1. 토글 클릭하여 히스토리 패널 열기
|
|
21
|
+
const toggle = document.querySelector('[data-past-conversations-toggle="true"]');
|
|
22
|
+
if (!toggle) return [];
|
|
23
|
+
toggle.click();
|
|
24
|
+
await sleep(1000);
|
|
25
|
+
|
|
26
|
+
// 2. 정확한 검색 input 찾기 (placeholder 정확 매칭)
|
|
27
|
+
const allInputs = document.querySelectorAll('input[type="text"]');
|
|
28
|
+
let searchInput = null;
|
|
29
|
+
for (const inp of allInputs) {
|
|
30
|
+
if (inp.placeholder === 'Select a conversation' && inp.offsetWidth > 0) {
|
|
31
|
+
searchInput = inp;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!searchInput) {
|
|
37
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true }));
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 3. "Current" 텍스트를 기준으로 대화 목록 스크롤 컨테이너 찾기
|
|
42
|
+
let container = null;
|
|
43
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
|
|
44
|
+
while (walker.nextNode()) {
|
|
45
|
+
if (walker.currentNode.textContent.trim() === 'Current') {
|
|
46
|
+
// "Current" 텍스트의 조상 — overflow-auto/scroll이 있는 스크롤 컨테이너까지 올라감
|
|
47
|
+
let el = walker.currentNode.parentElement;
|
|
48
|
+
for (let i = 0; i < 10 && el; i++) {
|
|
49
|
+
const cls = (el.className || '');
|
|
50
|
+
if (typeof cls === 'string' && (cls.includes('overflow-auto') || cls.includes('overflow-y-scroll'))) {
|
|
51
|
+
container = el;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
el = el.parentElement;
|
|
55
|
+
}
|
|
56
|
+
// overflow 컨테이너 못 찾으면 행이 가장 많은 조상 사용
|
|
57
|
+
if (!container) {
|
|
58
|
+
el = walker.currentNode.parentElement;
|
|
59
|
+
let bestEl = null;
|
|
60
|
+
let bestCount = 0;
|
|
61
|
+
for (let i = 0; i < 8 && el; i++) {
|
|
62
|
+
const rows = el.querySelectorAll('[class*="cursor-pointer"][class*="justify-between"][class*="rounded-md"]');
|
|
63
|
+
if (rows.length > bestCount) {
|
|
64
|
+
bestCount = rows.length;
|
|
65
|
+
bestEl = el;
|
|
66
|
+
}
|
|
67
|
+
el = el.parentElement;
|
|
68
|
+
}
|
|
69
|
+
container = bestEl;
|
|
70
|
+
}
|
|
71
|
+
if (container) break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 폴백: "Current" 텍스트가 없을 때 (새 대화 직후 등) searchInput 기반
|
|
76
|
+
if (!container && searchInput) {
|
|
77
|
+
let el = searchInput.parentElement;
|
|
78
|
+
for (let i = 0; i < 10 && el; i++) {
|
|
79
|
+
const cls = (el.className || '');
|
|
80
|
+
if (typeof cls === 'string' && (cls.includes('overflow-auto') || cls.includes('overflow-y-scroll'))) {
|
|
81
|
+
container = el; break;
|
|
82
|
+
}
|
|
83
|
+
const rows = el.querySelectorAll('[class*="cursor-pointer"][class*="justify-between"][class*="rounded-md"]');
|
|
84
|
+
if (rows.length > 0 && !container) {
|
|
85
|
+
container = el;
|
|
86
|
+
}
|
|
87
|
+
el = el.parentElement;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!container) {
|
|
92
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true }));
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 4. 대화 행 파싱
|
|
97
|
+
const rows = container.querySelectorAll('[class*="cursor-pointer"][class*="justify-between"][class*="rounded-md"]');
|
|
98
|
+
const chats = [];
|
|
99
|
+
|
|
100
|
+
for (const row of rows) {
|
|
101
|
+
const titleEl = row.querySelector('span span');
|
|
102
|
+
const title = titleEl ? titleEl.textContent.trim() : '';
|
|
103
|
+
if (!title) continue;
|
|
104
|
+
|
|
105
|
+
const timeEl = row.querySelector('span[class*="opacity-50"][class*="flex-shrink-0"]');
|
|
106
|
+
const time = timeEl ? timeEl.textContent.trim() : '';
|
|
107
|
+
|
|
108
|
+
const wsEl = row.querySelector('span[class*="opacity-50"][class*="truncate"] span');
|
|
109
|
+
const workspace = wsEl ? wsEl.textContent.trim() : '';
|
|
110
|
+
|
|
111
|
+
const isCurrent = (row.className || '').includes('focusBackground');
|
|
112
|
+
|
|
113
|
+
let section = '';
|
|
114
|
+
const sectionHeader = row.parentElement?.querySelector('[class*="opacity-50"]:not([class*="cursor-pointer"])');
|
|
115
|
+
if (sectionHeader) {
|
|
116
|
+
section = sectionHeader.textContent.trim();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
chats.push({
|
|
120
|
+
id: title,
|
|
121
|
+
title,
|
|
122
|
+
status: isCurrent ? 'current' : '',
|
|
123
|
+
time,
|
|
124
|
+
workspace,
|
|
125
|
+
section,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 5. 패널 닫기
|
|
130
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true }));
|
|
131
|
+
|
|
132
|
+
return chats;
|
|
133
|
+
} catch (e) {
|
|
134
|
+
try { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', bubbles: true })); } catch (_) { }
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
})()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity — list_models
|
|
3
|
+
* 모델 드롭다운 트리거 버튼 + 항목 목록 추출
|
|
4
|
+
*
|
|
5
|
+
* Version compatibility:
|
|
6
|
+
* v0 (old): .flex.min-w-0.max-w-full.cursor-pointer.items-center (exact CSS selector works)
|
|
7
|
+
* v1 (new): Tailwind arbitrary values (pl-[0.125rem]) — must use partial class matching
|
|
8
|
+
* Both: dropdown items use .px-2.py-1.flex.items-center.justify-between.cursor-pointer
|
|
9
|
+
*
|
|
10
|
+
* → { models: string[], current: string }
|
|
11
|
+
*/
|
|
12
|
+
(() => {
|
|
13
|
+
try {
|
|
14
|
+
const models = [];
|
|
15
|
+
let current = '';
|
|
16
|
+
|
|
17
|
+
// ── Step 1: Dropdown open state — extract item list ──────────────────
|
|
18
|
+
// Selector works for both v0 and v1 (hover class changed but cursor-pointer persists)
|
|
19
|
+
const items = document.querySelectorAll('.px-2.py-1.flex.items-center.justify-between.cursor-pointer');
|
|
20
|
+
for (const item of items) {
|
|
21
|
+
const label = item.querySelector('.text-xs.font-medium');
|
|
22
|
+
const text = (label || item).textContent?.trim();
|
|
23
|
+
if (!text || text.length > 60) continue;
|
|
24
|
+
models.push(text);
|
|
25
|
+
// Selected item: bg-gray-500/20 (both v0 & v1)
|
|
26
|
+
if ((item.className || '').includes('bg-gray-500/20')) {
|
|
27
|
+
current = text;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── Step 2: Dropdown closed — extract current model from trigger ──────
|
|
32
|
+
if (models.length === 0) {
|
|
33
|
+
// v0: exact class match works
|
|
34
|
+
let trigger = document.querySelector('.flex.min-w-0.max-w-full.cursor-pointer.items-center');
|
|
35
|
+
|
|
36
|
+
// v1: arbitrary Tailwind classes → partial matching
|
|
37
|
+
if (!trigger || trigger.offsetWidth === 0) {
|
|
38
|
+
trigger = [...document.querySelectorAll('div, button')].find(e => {
|
|
39
|
+
const cls = e.className || '';
|
|
40
|
+
return cls.includes('min-w-0') &&
|
|
41
|
+
cls.includes('max-w-full') &&
|
|
42
|
+
cls.includes('cursor-pointer') &&
|
|
43
|
+
cls.includes('items-center') &&
|
|
44
|
+
e.offsetWidth > 0;
|
|
45
|
+
}) || null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (trigger) {
|
|
49
|
+
// v0: .text-xs.font-medium span / v1: .text-xs span with opacity-70
|
|
50
|
+
const span = trigger.querySelector('.text-xs.font-medium') ||
|
|
51
|
+
trigger.querySelector('span.text-xs') ||
|
|
52
|
+
trigger;
|
|
53
|
+
current = span.textContent?.trim() || '';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return JSON.stringify({ models, current });
|
|
58
|
+
} catch (e) {
|
|
59
|
+
return JSON.stringify({ models: [], current: '', error: e.message });
|
|
60
|
+
}
|
|
61
|
+
})()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity — list_modes
|
|
3
|
+
* 현재 모드 + 사용 가능한 모드 목록 추출
|
|
4
|
+
*
|
|
5
|
+
* Version compatibility:
|
|
6
|
+
* v0 (old): span-based mode button (plain text, no opacity class)
|
|
7
|
+
* v1 (new): BUTTON element with py-1 pl-1 pr-2 opacity-70 classes
|
|
8
|
+
* Both: "Conversation mode" panel with .font-medium items (when dropdown open)
|
|
9
|
+
*
|
|
10
|
+
* → { modes: string[], current: string }
|
|
11
|
+
*/
|
|
12
|
+
(() => {
|
|
13
|
+
try {
|
|
14
|
+
const modes = [];
|
|
15
|
+
let current = '';
|
|
16
|
+
|
|
17
|
+
// ── Helper: find mode trigger button (v0 + v1 compat) ────────────────
|
|
18
|
+
function findModeTrigger() {
|
|
19
|
+
// v1: BUTTON with opacity-70 + py-1 pl-1 pr-2
|
|
20
|
+
const v1 = [...document.querySelectorAll('button')].find(b => {
|
|
21
|
+
const cls = b.className || '';
|
|
22
|
+
return cls.includes('py-1') &&
|
|
23
|
+
cls.includes('pl-1') &&
|
|
24
|
+
cls.includes('pr-2') &&
|
|
25
|
+
cls.includes('opacity-70') &&
|
|
26
|
+
b.offsetWidth > 0;
|
|
27
|
+
});
|
|
28
|
+
if (v1) return v1;
|
|
29
|
+
|
|
30
|
+
// v0: span/button with py-1 pl-1 pr-2 (without opacity-70)
|
|
31
|
+
return [...document.querySelectorAll('button, span')].find(b => {
|
|
32
|
+
const cls = b.className || '';
|
|
33
|
+
return cls.includes('py-1') &&
|
|
34
|
+
cls.includes('pl-1') &&
|
|
35
|
+
cls.includes('pr-2') &&
|
|
36
|
+
b.offsetWidth > 0 &&
|
|
37
|
+
// ensure it's in the model/mode area (not some other button)
|
|
38
|
+
(b.textContent?.trim() === 'Fast' || b.textContent?.trim() === 'Planning' || b.textContent?.trim() === 'Normal');
|
|
39
|
+
}) || null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ── Step 1: "Conversation mode" panel open — extract items ───────────
|
|
43
|
+
const headers = document.querySelectorAll('.text-xs.px-2.pb-1.opacity-80');
|
|
44
|
+
for (const header of headers) {
|
|
45
|
+
if (header.textContent?.trim() === 'Conversation mode') {
|
|
46
|
+
const parent = header.parentElement;
|
|
47
|
+
if (!parent) continue;
|
|
48
|
+
const items = parent.querySelectorAll('.font-medium');
|
|
49
|
+
for (const item of items) {
|
|
50
|
+
const text = item.textContent?.trim();
|
|
51
|
+
if (text && text.length < 20) modes.push(text);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Step 2: Read current mode from trigger button ─────────────────────
|
|
58
|
+
const modeBtn = findModeTrigger();
|
|
59
|
+
if (modeBtn) {
|
|
60
|
+
current = modeBtn.textContent?.trim() || '';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── Fallback: default modes ───────────────────────────────────────────
|
|
64
|
+
if (modes.length === 0) {
|
|
65
|
+
modes.push('Planning', 'Fast');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return JSON.stringify({ modes, current });
|
|
69
|
+
} catch (e) {
|
|
70
|
+
return JSON.stringify({ modes: [], current: '', error: e.message });
|
|
71
|
+
}
|
|
72
|
+
})()
|