@adhdev/daemon-core 0.6.36 → 0.6.39
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 +0 -1
- package/dist/index.js +9 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/acp/codex-cli/provider.json +2 -2
- package/providers/_builtin/cli/codex-cli/provider.json +8 -18
- package/providers/_builtin/ide/antigravity/provider.json +2 -3
- package/providers/_builtin/ide/cursor/provider.json +2 -2
- package/providers/_builtin/ide/cursor/scripts/{0.49 → 1.0}/read_chat.js +1 -1
- package/providers/_builtin/ide/cursor/scripts/{0.49 → 1.0}/resolve_action.js +1 -1
- package/providers/_builtin/ide/windsurf/scripts/1.0/focus_editor.js +16 -10
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_chats.js +9 -103
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_models.js +43 -26
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_modes.js +51 -27
- package/providers/_builtin/ide/windsurf/scripts/1.0/list_sessions.js +79 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0/new_session.js +30 -41
- package/providers/_builtin/ide/windsurf/scripts/1.0/open_panel.js +44 -35
- package/providers/_builtin/ide/windsurf/scripts/1.0/read_chat.js +211 -273
- package/providers/_builtin/ide/windsurf/scripts/1.0/resolve_action.js +64 -50
- package/providers/_builtin/ide/windsurf/scripts/1.0/send_message.js +14 -81
- package/providers/_builtin/ide/windsurf/scripts/1.0/set_mode.js +34 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/set_model.js +40 -6
- package/providers/_builtin/ide/windsurf/scripts/1.0/switch_session.js +66 -42
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/focus_editor.js +30 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_chats.js +117 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_models.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_modes.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/new_session.js +69 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/open_panel.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/read_chat.js +315 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/resolve_action.js +68 -0
- package/providers/_builtin/ide/{cursor/scripts/0.49 → windsurf/scripts/1.0.bak}/scripts.js +27 -23
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/send_message.js +87 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/set_mode.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/set_model.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/1.0.bak/switch_session.js +58 -0
- package/providers/_builtin/registry.json +5 -9
- package/src/commands/handler.ts +1 -8
- package/src/daemon/dev-server.ts +12 -3
- package/src/detection/ide-detector.ts +0 -3
- package/src/providers/provider-loader.ts +0 -1
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +0 -38
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +0 -48
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +0 -290
- package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +0 -57
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +0 -34
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +0 -47
- package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +0 -20
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +0 -137
- package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +0 -75
- package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +0 -63
- package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +0 -56
- package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +0 -114
- package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +0 -30
- package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +0 -13
- package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +0 -78
- package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +0 -40
- package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +0 -23
- package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +0 -20
- package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +0 -23
- package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +0 -23
- package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +0 -38
- package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +0 -81
- package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +0 -28
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/list_sessions.js +0 -42
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/read_chat.js +0 -79
- package/providers/_builtin/ide/cursor/scripts/0.49.bak/resolve_action.js +0 -19
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/focus_editor.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/list_chats.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/list_models.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/list_modes.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/new_session.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/read_chat.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/resolve_action.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/scripts.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/send_message.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/set_mode.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.107 → 1.0}/set_model.js +0 -0
- /package/providers/_builtin/ide/antigravity/scripts/{1.106 → 1.0}/switch_session.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/dismiss_notification.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/focus_editor.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/list_models.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/list_modes.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/list_notifications.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49 → 1.0}/list_sessions.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/new_session.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/open_panel.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/scripts.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/send_message.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/set_mode.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/set_model.js +0 -0
- /package/providers/_builtin/ide/cursor/scripts/{0.49.bak → 1.0}/switch_session.js +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf v1 — send_message
|
|
3
|
+
*
|
|
4
|
+
* Windsurf는 Lexical 에디터 ([data-lexical-editor="true"])를 사용합니다.
|
|
5
|
+
* contenteditable div이므로 execCommand('insertText') 또는 InputEvent로 입력 가능.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ Lexical은 입력 이벤트를 정밀하게 감지하므로:
|
|
8
|
+
* - execCommand('insertText')가 가장 안정적
|
|
9
|
+
* - nativeSetter 방식은 동작하지 않음
|
|
10
|
+
* - InputEvent('insertText')를 폴백으로 사용
|
|
11
|
+
*
|
|
12
|
+
* Enter 키는 KeyboardEvent 전체 시퀀스 필요 (keydown + keypress + keyup).
|
|
13
|
+
*
|
|
14
|
+
* 파라미터: ${ MESSAGE }
|
|
15
|
+
* 최종 확인: Windsurf 1.108.x (2026-03-10)
|
|
16
|
+
*/
|
|
17
|
+
(async () => {
|
|
18
|
+
try {
|
|
19
|
+
const msg = ${ MESSAGE };
|
|
20
|
+
|
|
21
|
+
// ─── 1. Lexical 에디터 찾기 (폴백 체인) ───
|
|
22
|
+
const editor =
|
|
23
|
+
document.querySelector('[data-lexical-editor="true"]') ||
|
|
24
|
+
document.querySelector('[contenteditable="true"][role="textbox"]') ||
|
|
25
|
+
document.querySelector('.cascade-input [contenteditable="true"]') ||
|
|
26
|
+
document.querySelector('.chat-input textarea') ||
|
|
27
|
+
document.querySelector('textarea:not(.xterm-helper-textarea)');
|
|
28
|
+
|
|
29
|
+
if (!editor) return 'error: no input found';
|
|
30
|
+
|
|
31
|
+
const isTextarea = editor.tagName === 'TEXTAREA';
|
|
32
|
+
|
|
33
|
+
if (isTextarea) {
|
|
34
|
+
// ─── textarea 폴백 (미로그인 등) ───
|
|
35
|
+
editor.focus();
|
|
36
|
+
const proto = HTMLTextAreaElement.prototype;
|
|
37
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
|
|
38
|
+
if (nativeSetter) nativeSetter.call(editor, msg);
|
|
39
|
+
else editor.value = msg;
|
|
40
|
+
|
|
41
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
42
|
+
editor.dispatchEvent(new Event('change', { bubbles: true }));
|
|
43
|
+
|
|
44
|
+
await new Promise(r => setTimeout(r, 300));
|
|
45
|
+
|
|
46
|
+
const enterOpts = {
|
|
47
|
+
key: 'Enter', code: 'Enter',
|
|
48
|
+
keyCode: 13, which: 13,
|
|
49
|
+
bubbles: true, cancelable: true, composed: true,
|
|
50
|
+
};
|
|
51
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
52
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
53
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
54
|
+
|
|
55
|
+
return 'sent';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ─── 2. contenteditable (Lexical) 에디터 ───
|
|
59
|
+
editor.focus();
|
|
60
|
+
|
|
61
|
+
// 기존 내용 선택 후 삭제
|
|
62
|
+
document.execCommand('selectAll', false, null);
|
|
63
|
+
document.execCommand('delete', false, null);
|
|
64
|
+
|
|
65
|
+
// 텍스트 삽입 (Lexical은 execCommand('insertText')를 인식)
|
|
66
|
+
document.execCommand('insertText', false, msg);
|
|
67
|
+
|
|
68
|
+
// React/Lexical에 변경 알림
|
|
69
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
70
|
+
|
|
71
|
+
await new Promise(r => setTimeout(r, 300));
|
|
72
|
+
|
|
73
|
+
// ─── 3. Enter 키 전송 (전체 시퀀스) ───
|
|
74
|
+
const enterOpts = {
|
|
75
|
+
key: 'Enter', code: 'Enter',
|
|
76
|
+
keyCode: 13, which: 13,
|
|
77
|
+
bubbles: true, cancelable: true, composed: true,
|
|
78
|
+
};
|
|
79
|
+
editor.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
|
|
80
|
+
editor.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
|
|
81
|
+
editor.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
|
|
82
|
+
|
|
83
|
+
return 'sent';
|
|
84
|
+
} catch (e) {
|
|
85
|
+
return 'error: ' + e.message;
|
|
86
|
+
}
|
|
87
|
+
})()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic fallback — set_model
|
|
3
|
+
* ${ MODEL }
|
|
4
|
+
*/
|
|
5
|
+
(() => {
|
|
6
|
+
try {
|
|
7
|
+
const want = ${ MODEL } || '';
|
|
8
|
+
const norm = (t) => t.toLowerCase().trim();
|
|
9
|
+
|
|
10
|
+
// Very basic click attempt
|
|
11
|
+
return JSON.stringify({ success: false, error: 'Model selection requires UI interaction not supported by generic script' });
|
|
12
|
+
} catch (e) {
|
|
13
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
14
|
+
}
|
|
15
|
+
})()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic fallback — set_model
|
|
3
|
+
* ${ MODEL }
|
|
4
|
+
*/
|
|
5
|
+
(() => {
|
|
6
|
+
try {
|
|
7
|
+
const want = ${ MODEL } || '';
|
|
8
|
+
const norm = (t) => t.toLowerCase().trim();
|
|
9
|
+
|
|
10
|
+
// Very basic click attempt
|
|
11
|
+
return JSON.stringify({ success: false, error: 'Model selection requires UI interaction not supported by generic script' });
|
|
12
|
+
} catch (e) {
|
|
13
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
14
|
+
}
|
|
15
|
+
})()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf v1 — switch_session
|
|
3
|
+
*
|
|
4
|
+
* Cascade 세션(대화) 탭을 전환합니다.
|
|
5
|
+
* cascade-tab-{id} 내부의 실제 클릭 가능한 자식 DIV의
|
|
6
|
+
* React onClick 핸들러를 직접 호출합니다.
|
|
7
|
+
*
|
|
8
|
+
* 파라미터: ${ SESSION_ID } — 전환할 세션 ID (cascade-tab의 UUID)
|
|
9
|
+
*
|
|
10
|
+
* 최종 확인: Windsurf 1.108.x (2026-03-10)
|
|
11
|
+
*/
|
|
12
|
+
(() => {
|
|
13
|
+
try {
|
|
14
|
+
const id = ${ SESSION_ID };
|
|
15
|
+
|
|
16
|
+
// Helper: find React onClick on an element or its children
|
|
17
|
+
function clickReact(el) {
|
|
18
|
+
// Check element itself and children for React onClick
|
|
19
|
+
const targets = [el, ...el.querySelectorAll('*')];
|
|
20
|
+
for (const t of targets) {
|
|
21
|
+
const rp = Object.keys(t).find(k => k.startsWith('__reactProps'));
|
|
22
|
+
if (rp && typeof t[rp].onClick === 'function') {
|
|
23
|
+
t[rp].onClick({
|
|
24
|
+
preventDefault: () => { },
|
|
25
|
+
stopPropagation: () => { },
|
|
26
|
+
nativeEvent: { stopImmediatePropagation: () => { } },
|
|
27
|
+
target: t, currentTarget: t, button: 0, type: 'click'
|
|
28
|
+
});
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 1. cascade-tab-{id} 요소 찾기
|
|
36
|
+
const tab = document.getElementById('cascade-tab-' + id);
|
|
37
|
+
if (tab) {
|
|
38
|
+
if (clickReact(tab)) return 'switched';
|
|
39
|
+
// Fallback: DOM click
|
|
40
|
+
tab.click();
|
|
41
|
+
return 'switched-dom';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 2. 제목으로 매칭
|
|
45
|
+
const tabs = document.querySelectorAll('[id^="cascade-tab-"]');
|
|
46
|
+
for (const t of tabs) {
|
|
47
|
+
if (t.textContent?.trim() === id) {
|
|
48
|
+
if (clickReact(t)) return 'switched-by-title';
|
|
49
|
+
t.click();
|
|
50
|
+
return 'switched-by-title-dom';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return 'not_found';
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return 'error: ' + e.message;
|
|
57
|
+
}
|
|
58
|
+
})()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2026.03.
|
|
2
|
+
"version": "2026.03.27",
|
|
3
3
|
"providers": {
|
|
4
4
|
"agentpool-acp": {
|
|
5
5
|
"providerVersion": "0.0.0",
|
|
@@ -212,12 +212,8 @@
|
|
|
212
212
|
"name": "Antigravity",
|
|
213
213
|
"compatibility": [
|
|
214
214
|
{
|
|
215
|
-
"ideVersion": ">=1.
|
|
216
|
-
"scriptDir": "scripts/1.
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
"ideVersion": ">=1.105.0",
|
|
220
|
-
"scriptDir": "scripts/1.106"
|
|
215
|
+
"ideVersion": ">=1.0.0",
|
|
216
|
+
"scriptDir": "scripts/1.0"
|
|
221
217
|
}
|
|
222
218
|
]
|
|
223
219
|
},
|
|
@@ -227,8 +223,8 @@
|
|
|
227
223
|
"name": "Cursor",
|
|
228
224
|
"compatibility": [
|
|
229
225
|
{
|
|
230
|
-
"ideVersion": ">=0.
|
|
231
|
-
"scriptDir": "scripts/0
|
|
226
|
+
"ideVersion": ">=1.0.0",
|
|
227
|
+
"scriptDir": "scripts/1.0"
|
|
232
228
|
}
|
|
233
229
|
]
|
|
234
230
|
},
|
package/src/commands/handler.ts
CHANGED
|
@@ -317,14 +317,7 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
317
317
|
}
|
|
318
318
|
return { success: false, error: `VSCode command not available: ${resolvedCmd || cmd}` };
|
|
319
319
|
}
|
|
320
|
-
|
|
321
|
-
case 'open_tab':
|
|
322
|
-
case 'close_tab':
|
|
323
|
-
case 'open_folder':
|
|
324
|
-
case 'open_folder_picker':
|
|
325
|
-
case 'open_recent':
|
|
326
|
-
case 'get_commands':
|
|
327
|
-
return { success: false, error: `${cmd} requires bridge-extension (removed)` };
|
|
320
|
+
// ─── Workspace cmds ──────────────
|
|
328
321
|
case 'get_recent_workspaces': return this.handleGetRecentWorkspaces(args);
|
|
329
322
|
case 'get_cli_history': {
|
|
330
323
|
const config = loadConfig();
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -332,9 +332,18 @@ export class DevServer {
|
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
try {
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
// Emulate production CommandHandler behavior
|
|
336
|
+
let scriptCode: string | null = null;
|
|
337
|
+
if (['sendMessage', 'webviewSendMessage', 'switchSession', 'webviewSwitchSession', 'setMode', 'webviewSetMode', 'setModel', 'webviewSetModel'].includes(scriptName)) {
|
|
338
|
+
// Production daemon's getProviderScript always unpacks the object and sends the first value
|
|
339
|
+
const firstVal = params && typeof params === 'object' && Object.keys(params).length > 0
|
|
340
|
+
? Object.values(params)[0]
|
|
341
|
+
: params;
|
|
342
|
+
scriptCode = firstVal !== undefined ? fn(firstVal) : fn();
|
|
343
|
+
} else {
|
|
344
|
+
// Scripts like resolveAction are passed the raw parameters object in production
|
|
345
|
+
scriptCode = params !== undefined ? fn(params) : fn();
|
|
346
|
+
}
|
|
338
347
|
if (!scriptCode) {
|
|
339
348
|
this.json(res, 500, { error: 'Script function returned null' });
|
|
340
349
|
return;
|
|
@@ -22,7 +22,6 @@ export interface IDEInfo {
|
|
|
22
22
|
cliCommand: string | null;
|
|
23
23
|
version: string | null;
|
|
24
24
|
icon: string;
|
|
25
|
-
extensionSupport: 'full' | 'partial' | 'none';
|
|
26
25
|
notes?: string;
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -31,7 +30,6 @@ export interface IDEDefinition {
|
|
|
31
30
|
name: string;
|
|
32
31
|
displayName: string;
|
|
33
32
|
icon: string;
|
|
34
|
-
extensionSupport: 'full' | 'partial' | 'none';
|
|
35
33
|
cli: string;
|
|
36
34
|
paths: {
|
|
37
35
|
darwin?: string[];
|
|
@@ -149,7 +147,6 @@ export async function detectIDEs(): Promise<IDEInfo[]> {
|
|
|
149
147
|
cliCommand: resolvedCli || null,
|
|
150
148
|
version,
|
|
151
149
|
icon: def.icon,
|
|
152
|
-
extensionSupport: def.extensionSupport,
|
|
153
150
|
});
|
|
154
151
|
}
|
|
155
152
|
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity — list_models
|
|
3
|
-
* antigravity-agent-side-panel 내부 모델 드롭다운에서 목록 + 현재 모델 추출
|
|
4
|
-
* → { models: string[], current: string }
|
|
5
|
-
*/
|
|
6
|
-
(() => {
|
|
7
|
-
try {
|
|
8
|
-
const models = [];
|
|
9
|
-
let current = '';
|
|
10
|
-
|
|
11
|
-
// 1. 모델 항목에서 목록 추출
|
|
12
|
-
// 셀렉터: .px-2.py-1.flex.items-center.justify-between.cursor-pointer
|
|
13
|
-
const items = document.querySelectorAll('.px-2.py-1.flex.items-center.justify-between.cursor-pointer');
|
|
14
|
-
for (const item of items) {
|
|
15
|
-
const label = item.querySelector('.text-xs.font-medium');
|
|
16
|
-
const text = (label || item).textContent?.trim();
|
|
17
|
-
if (!text || text.length > 60) continue;
|
|
18
|
-
// 모델명 검증 (Claude, Gemini, GPT, etc.)
|
|
19
|
-
models.push(text);
|
|
20
|
-
// 선택된 항목: bg-gray-500/20
|
|
21
|
-
if ((item.className || '').includes('bg-gray-500/20')) {
|
|
22
|
-
current = text;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 2. 모델 목록이 없으면 (드롭다운 닫힘) → 트리거 버튼에서 현재 모델만
|
|
27
|
-
if (models.length === 0) {
|
|
28
|
-
const trigger = document.querySelector('.flex.min-w-0.max-w-full.cursor-pointer.items-center');
|
|
29
|
-
if (trigger) {
|
|
30
|
-
current = trigger.textContent?.trim() || '';
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return JSON.stringify({ models, current });
|
|
35
|
-
} catch (e) {
|
|
36
|
-
return JSON.stringify({ models: [], current: '', error: e.message });
|
|
37
|
-
}
|
|
38
|
-
})()
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity — list_modes
|
|
3
|
-
* Conversation mode: Planning / Fast 세그먼트 컨트롤
|
|
4
|
-
* inputBox 근처의 "Conversation mode" 패널에서 읽기
|
|
5
|
-
* → { modes: string[], current: string }
|
|
6
|
-
*/
|
|
7
|
-
(() => {
|
|
8
|
-
try {
|
|
9
|
-
const modes = [];
|
|
10
|
-
let current = '';
|
|
11
|
-
|
|
12
|
-
// "Conversation mode" 헤더를 포함하는 패널 찾기
|
|
13
|
-
const headers = document.querySelectorAll('.text-xs.px-2.pb-1.opacity-80');
|
|
14
|
-
for (const header of headers) {
|
|
15
|
-
if (header.textContent?.trim() === 'Conversation mode') {
|
|
16
|
-
// 형제 요소들에서 모드 항목 추출
|
|
17
|
-
const parent = header.parentElement;
|
|
18
|
-
if (!parent) continue;
|
|
19
|
-
const items = parent.querySelectorAll('.font-medium');
|
|
20
|
-
for (const item of items) {
|
|
21
|
-
const text = item.textContent?.trim();
|
|
22
|
-
if (text && text.length < 20) {
|
|
23
|
-
modes.push(text);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// 현재 모드: Fast 버튼의 텍스트 (현재 활성 모드 표시)
|
|
31
|
-
const modeBtn = [...document.querySelectorAll('button')].find(b => {
|
|
32
|
-
const cls = b.className || '';
|
|
33
|
-
return cls.includes('py-1') && cls.includes('pl-1') && cls.includes('pr-2') && b.offsetWidth > 0;
|
|
34
|
-
});
|
|
35
|
-
if (modeBtn) {
|
|
36
|
-
current = modeBtn.textContent?.trim() || '';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// modes가 비어있으면 기본값
|
|
40
|
-
if (modes.length === 0) {
|
|
41
|
-
modes.push('Planning', 'Fast');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return JSON.stringify({ modes, current });
|
|
45
|
-
} catch (e) {
|
|
46
|
-
return JSON.stringify({ modes: [], current: '', error: e.message });
|
|
47
|
-
}
|
|
48
|
-
})()
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity v1 — read_chat (v4 — 스크롤 아래만, 가시 영역만 수집)
|
|
3
|
-
*
|
|
4
|
-
* 원칙:
|
|
5
|
-
* - 스크롤은 아래로만 (위로 절대 안 감)
|
|
6
|
-
* - 가상화로 사라진 과거 사용자 메시지는 무시
|
|
7
|
-
* - 현재 보이는 메시지만 수집 (최신 턴 중심)
|
|
8
|
-
*
|
|
9
|
-
* DOM 구조:
|
|
10
|
-
* 사용자: bg-gray-500/15 + select-text + p-2, 내부 whitespace-pre-wrap
|
|
11
|
-
* 어시스턴트: .leading-relaxed.select-text
|
|
12
|
-
*/
|
|
13
|
-
(() => {
|
|
14
|
-
try {
|
|
15
|
-
const conv = document.querySelector('#conversation') || document.querySelector('.antigravity-agent-side-panel') || document.body;
|
|
16
|
-
const scroll = conv.querySelector('.overflow-y-auto') || conv;
|
|
17
|
-
|
|
18
|
-
// 1. 상태 감지 — 사이드바 하단 Send/Stop 버튼 기반 (오탐 방지)
|
|
19
|
-
let status = 'idle';
|
|
20
|
-
|
|
21
|
-
// 시그널 A (1순위): 사이드바 하단 빨간 Stop 사각형 (.bg-red-500) — generating 중일 때 표시됨
|
|
22
|
-
const stopSquare = conv.querySelector('[class*="bg-red-500"]') || conv.querySelector('button[class*="rounded"] [class*="bg-red"]');
|
|
23
|
-
if (stopSquare && stopSquare.offsetWidth > 0) {
|
|
24
|
-
status = 'generating';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// 시그널 B: conv 내부의 animate-markdown (생성 중 마크다운 렌더링)
|
|
28
|
-
if (status === 'idle') {
|
|
29
|
-
const animMarkdown = scroll.querySelector('.leading-relaxed [class*="animate-markdown"]');
|
|
30
|
-
if (animMarkdown && animMarkdown.offsetWidth > 0) status = 'generating';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const titleParts = document.title.split(' \u2014 ');
|
|
34
|
-
const title = (titleParts.length >= 2 ? titleParts[titleParts.length - 1] : titleParts[0] || '').trim() || 'Active Session';
|
|
35
|
-
|
|
36
|
-
// ─── HTML → Markdown 변환기 (대시보드가 ReactMarkdown+remarkGfm 사용) ───
|
|
37
|
-
// extractCodeText: layout-independent code text extraction
|
|
38
|
-
// Works on cloneNode'd (detached) elements where innerText == textContent
|
|
39
|
-
// Walks child nodes and inserts \n between block-level elements (DIV, P, etc.)
|
|
40
|
-
const BLOCK_TAGS = new Set(['DIV', 'P', 'BR', 'LI', 'TR', 'SECTION', 'ARTICLE', 'HEADER', 'FOOTER']);
|
|
41
|
-
function extractCodeText(node) {
|
|
42
|
-
if (node.nodeType === 3) return node.textContent || '';
|
|
43
|
-
if (node.nodeType !== 1) return '';
|
|
44
|
-
if (node.tagName === 'BR') return '\n';
|
|
45
|
-
const parts = [];
|
|
46
|
-
for (const child of node.childNodes) {
|
|
47
|
-
const isBlock = child.nodeType === 1 && BLOCK_TAGS.has(child.tagName);
|
|
48
|
-
const text = extractCodeText(child);
|
|
49
|
-
if (text) {
|
|
50
|
-
if (isBlock && parts.length > 0) parts.push('\n');
|
|
51
|
-
parts.push(text);
|
|
52
|
-
if (isBlock) parts.push('\n');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
// Collapse multiple consecutive newlines into single \n
|
|
56
|
-
return parts.join('').replace(/\n{2,}/g, '\n');
|
|
57
|
-
}
|
|
58
|
-
function htmlToMd(node) {
|
|
59
|
-
if (node.nodeType === 3) return node.textContent || '';
|
|
60
|
-
if (node.nodeType !== 1) return '';
|
|
61
|
-
const tag = node.tagName;
|
|
62
|
-
|
|
63
|
-
// 스타일/스크립트 제거
|
|
64
|
-
if (tag === 'STYLE' || tag === 'SCRIPT' || tag === 'SVG') return '';
|
|
65
|
-
|
|
66
|
-
// 테이블 → GFM
|
|
67
|
-
if (tag === 'TABLE') {
|
|
68
|
-
const rows = Array.from(node.querySelectorAll('tr'));
|
|
69
|
-
if (rows.length === 0) return '';
|
|
70
|
-
const table = rows.map(tr =>
|
|
71
|
-
Array.from(tr.querySelectorAll('th, td')).map(cell => (cell.textContent || '').trim().replace(/\|/g, '\\|'))
|
|
72
|
-
);
|
|
73
|
-
if (table.length === 0) return '';
|
|
74
|
-
const colCount = Math.max(...table.map(r => r.length));
|
|
75
|
-
const header = table[0];
|
|
76
|
-
const sep = Array(colCount).fill('---');
|
|
77
|
-
const body = table.slice(1);
|
|
78
|
-
let md = '| ' + header.join(' | ') + ' |\n';
|
|
79
|
-
md += '| ' + sep.join(' | ') + ' |\n';
|
|
80
|
-
for (const row of body) {
|
|
81
|
-
while (row.length < colCount) row.push('');
|
|
82
|
-
md += '| ' + row.join(' | ') + ' |\n';
|
|
83
|
-
}
|
|
84
|
-
return '\n' + md + '\n';
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (tag === 'UL') return '\n' + Array.from(node.children).map(li => '- ' + childrenToMd(li).trim()).join('\n') + '\n';
|
|
88
|
-
if (tag === 'OL') return '\n' + Array.from(node.children).map((li, i) => (i + 1) + '. ' + childrenToMd(li).trim()).join('\n') + '\n';
|
|
89
|
-
if (tag === 'LI') return childrenToMd(node);
|
|
90
|
-
|
|
91
|
-
if (tag === 'H1') return '\n# ' + childrenToMd(node).trim() + '\n';
|
|
92
|
-
if (tag === 'H2') return '\n## ' + childrenToMd(node).trim() + '\n';
|
|
93
|
-
if (tag === 'H3') return '\n### ' + childrenToMd(node).trim() + '\n';
|
|
94
|
-
if (tag === 'H4') return '\n#### ' + childrenToMd(node).trim() + '\n';
|
|
95
|
-
|
|
96
|
-
if (tag === 'STRONG' || tag === 'B') return '**' + childrenToMd(node).trim() + '**';
|
|
97
|
-
if (tag === 'EM' || tag === 'I') return '*' + childrenToMd(node).trim() + '*';
|
|
98
|
-
|
|
99
|
-
if (tag === 'PRE') {
|
|
100
|
-
const codeEl = node.querySelector('code');
|
|
101
|
-
const lang = codeEl ? (codeEl.className.match(/language-(\w+)/)?.[1] || '') : '';
|
|
102
|
-
// Custom extraction: walk child nodes and insert \n between block elements
|
|
103
|
-
// This works on cloneNode'd elements (no layout → innerText == textContent)
|
|
104
|
-
const code = extractCodeText(codeEl || node);
|
|
105
|
-
return '\n```' + lang + '\n' + code.trim() + '\n```\n';
|
|
106
|
-
}
|
|
107
|
-
if (tag === 'CODE') {
|
|
108
|
-
if (node.parentElement && node.parentElement.tagName === 'PRE') return node.textContent || '';
|
|
109
|
-
return '`' + (node.textContent || '').trim() + '`';
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (tag === 'BLOCKQUOTE') return '\n> ' + childrenToMd(node).trim().replace(/\n/g, '\n> ') + '\n';
|
|
113
|
-
if (tag === 'A') return '[' + childrenToMd(node).trim() + '](' + (node.getAttribute('href') || '') + ')';
|
|
114
|
-
if (tag === 'BR') return '\n';
|
|
115
|
-
if (tag === 'P') return '\n' + childrenToMd(node).trim() + '\n';
|
|
116
|
-
|
|
117
|
-
return childrenToMd(node);
|
|
118
|
-
}
|
|
119
|
-
function childrenToMd(node) {
|
|
120
|
-
return Array.from(node.childNodes).map(htmlToMd).join('');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function getCleanMd(el) {
|
|
124
|
-
const clone = el.cloneNode(true);
|
|
125
|
-
// 노이즈 제거
|
|
126
|
-
clone.querySelectorAll('button, [role="button"], style, script, svg, .codicon, [class*="feedback"], [aria-label*="Good"], [aria-label*="Bad"]').forEach(n => n.remove());
|
|
127
|
-
// 상태 텍스트 제거 (leaf만, 60자 이하만)
|
|
128
|
-
clone.querySelectorAll('*').forEach(child => {
|
|
129
|
-
if (!child.parentNode) return;
|
|
130
|
-
const t = (child.textContent || '').trim();
|
|
131
|
-
if (t.length > 60) return;
|
|
132
|
-
const low = t.toLowerCase();
|
|
133
|
-
if (/^(analyzed\s+\d|edited\s+\d|ran\s+\S|terminal\s|reading|searching)/i.test(low)) child.remove();
|
|
134
|
-
if (/^(mcp|customizationmcp|serversexport)/i.test(low)) child.remove();
|
|
135
|
-
});
|
|
136
|
-
let md = htmlToMd(clone);
|
|
137
|
-
// "Thought for X seconds" 제거
|
|
138
|
-
md = md.replace(/^Thought for\s+[\d.]+\s*(seconds?|s)\s*/i, '');
|
|
139
|
-
md = md.replace(/\n{3,}/g, '\n\n').trim();
|
|
140
|
-
return md;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// 2. 메시지 수집 (스크롤 조작 없음 — 현재 DOM에 있는 것만)
|
|
144
|
-
const collected = [];
|
|
145
|
-
const seenHashes = new Set();
|
|
146
|
-
|
|
147
|
-
// 사용자 메시지 (bg-gray-500/15 + select-text + p-2)
|
|
148
|
-
const allDivs = scroll.querySelectorAll('div');
|
|
149
|
-
for (const el of allDivs) {
|
|
150
|
-
const cls = (el.className || '');
|
|
151
|
-
if (typeof cls !== 'string') continue;
|
|
152
|
-
if (cls.includes('bg-gray-500/15') && cls.includes('select-text') && cls.includes('p-2')) {
|
|
153
|
-
const textEl = el.querySelector('[class*="whitespace-pre-wrap"]') || el;
|
|
154
|
-
const text = (textEl.innerText || '').trim();
|
|
155
|
-
if (!text || text.length < 1) continue;
|
|
156
|
-
const hash = 'user:' + text.slice(0, 200);
|
|
157
|
-
if (seenHashes.has(hash)) continue;
|
|
158
|
-
seenHashes.add(hash);
|
|
159
|
-
collected.push({ role: 'user', text, el });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 어시스턴트 메시지 (leading-relaxed.select-text) — HTML→Markdown 변환
|
|
164
|
-
const assistantBlocks = scroll.querySelectorAll('.leading-relaxed.select-text');
|
|
165
|
-
for (const ab of assistantBlocks) {
|
|
166
|
-
if (ab.offsetHeight < 10) continue;
|
|
167
|
-
if (ab.closest('[class*="max-h-"][class*="overflow-y-auto"]')) continue;
|
|
168
|
-
|
|
169
|
-
let text = getCleanMd(ab);
|
|
170
|
-
if (!text || text.length < 2) continue;
|
|
171
|
-
if (/^(Running command|Checked command|collectStatus)/i.test(text)) continue;
|
|
172
|
-
|
|
173
|
-
const hash = 'assistant:' + text.slice(0, 200);
|
|
174
|
-
if (seenHashes.has(hash)) continue;
|
|
175
|
-
seenHashes.add(hash);
|
|
176
|
-
collected.push({ role: 'assistant', text, el: ab });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// 3. DOM 순서 정렬
|
|
180
|
-
collected.sort((a, b) => {
|
|
181
|
-
const pos = a.el.compareDocumentPosition(b.el);
|
|
182
|
-
if (pos & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
183
|
-
if (pos & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
184
|
-
return 0;
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// 최신 30개만 유지 (대화 첫 로드 시 수백 개 수집 방지)
|
|
188
|
-
const trimmed = collected.length > 30 ? collected.slice(-30) : collected;
|
|
189
|
-
|
|
190
|
-
const final = trimmed.map((m, i) => ({
|
|
191
|
-
id: 'msg_' + i,
|
|
192
|
-
role: m.role,
|
|
193
|
-
content: m.text.length > 6000 ? m.text.slice(0, 6000) + '\n[... truncated]' : m.text,
|
|
194
|
-
index: i,
|
|
195
|
-
kind: 'standard',
|
|
196
|
-
vsc_history: true
|
|
197
|
-
}));
|
|
198
|
-
|
|
199
|
-
// 4. 입력창
|
|
200
|
-
const editor = conv.querySelector('[contenteditable="true"][role="textbox"]') ||
|
|
201
|
-
conv.querySelector('[data-lexical-editor="true"]') ||
|
|
202
|
-
conv.querySelector('textarea');
|
|
203
|
-
const inputContent = editor ? (editor.innerText || editor.value || '').trim() : '';
|
|
204
|
-
|
|
205
|
-
// 5. 모달/승인 감지 — Run⌥⏎/Reject 인라인 + Deny/Allow 브라우저 승인
|
|
206
|
-
let activeModal = null;
|
|
207
|
-
try {
|
|
208
|
-
// Strip Mac symbols and Windows shortcut labels (e.g. "RunAlt+⏎" → "Run")
|
|
209
|
-
const stripShortcut = (s) => s
|
|
210
|
-
.replace(/[⌥⏎⇧⌫⌘⌃↵]/g, '')
|
|
211
|
-
.replace(/\s*(Alt|Ctrl|Shift|Cmd|Enter|Return|Esc|Tab|Backspace)(\+\s*\w+)*/gi, '')
|
|
212
|
-
.trim();
|
|
213
|
-
const isApprovalLike = (el) => {
|
|
214
|
-
const raw = (el.textContent || '').trim();
|
|
215
|
-
const t = stripShortcut(raw).toLowerCase();
|
|
216
|
-
// 드롭다운 옵션 제외
|
|
217
|
-
if (t === 'ask every time') return false;
|
|
218
|
-
return /^(run|reject|skip|approve|allow|deny|cancel|accept|yes|no)\b/i.test(t)
|
|
219
|
-
|| t === 'always allow' || t === 'always deny'
|
|
220
|
-
|| t.includes('run ') || t.includes('approve') || t.includes('reject')
|
|
221
|
-
|| t.includes('skip');
|
|
222
|
-
};
|
|
223
|
-
// A: 전통적 모달 다이얼로그
|
|
224
|
-
const dialog = document.querySelector('.monaco-dialog-box, [role="dialog"], .monaco-modal-block');
|
|
225
|
-
if (dialog && dialog.offsetWidth > 80 && dialog.offsetHeight > 40) {
|
|
226
|
-
const msg = (dialog.querySelector('.dialog-message, .dialog-message-text') || dialog).innerText?.trim() || '';
|
|
227
|
-
const buttons = Array.from(dialog.querySelectorAll('.monaco-button, button'))
|
|
228
|
-
.map(b => (b.innerText || '').trim())
|
|
229
|
-
.filter(t => t.length > 0 && t.length < 30);
|
|
230
|
-
if (msg || buttons.length > 0) {
|
|
231
|
-
activeModal = { message: msg.slice(0, 300), buttons, width: dialog.offsetWidth, height: dialog.offsetHeight };
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
// B: 인라인 approval 버튼 (Run⌥⏎, Reject, Deny, Allow 등)
|
|
235
|
-
// ⚠ 사이드바(conv) 내부의 버튼만 검사 — 에디터의 Accept/Reject Changes 제외
|
|
236
|
-
if (!activeModal) {
|
|
237
|
-
const panelBtns = Array.from(conv.querySelectorAll('button')).filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
|
|
238
|
-
const approvalBtns = panelBtns.filter(isApprovalLike);
|
|
239
|
-
if (approvalBtns.length > 0) {
|
|
240
|
-
const hasActionBtn = approvalBtns.some(b => {
|
|
241
|
-
const t = stripShortcut((b.textContent || '').trim()).toLowerCase();
|
|
242
|
-
return /^(run|reject|skip|deny|allow|accept|approve|yes|no)\b/.test(t)
|
|
243
|
-
|| t === 'always allow' || t === 'always deny';
|
|
244
|
-
});
|
|
245
|
-
if (hasActionBtn) {
|
|
246
|
-
const btnTexts = [...new Set(
|
|
247
|
-
approvalBtns.map(b => (b.textContent || '').trim())
|
|
248
|
-
.filter(t => t.length > 0 && t.length < 40)
|
|
249
|
-
)];
|
|
250
|
-
const firstApproval = approvalBtns[0];
|
|
251
|
-
let wrapper = firstApproval.parentElement;
|
|
252
|
-
for (let up = 0; up < 5 && wrapper; up++, wrapper = wrapper.parentElement) {
|
|
253
|
-
if (wrapper.offsetHeight > 40) break;
|
|
254
|
-
}
|
|
255
|
-
const msg = wrapper ? (wrapper.textContent || '').trim().slice(0, 300) : '';
|
|
256
|
-
activeModal = { message: msg, buttons: btnTexts, width: 400, height: 100 };
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
// C: footer 기반 사용량/quota 다이얼로그 (Dismiss / See Plans / Enable Overages 등)
|
|
261
|
-
// <footer> 요소가 conv 안에 존재하고 2개 이상 버튼이 있으면 사용자 액션이 필요한 카드로 판단
|
|
262
|
-
if (!activeModal) {
|
|
263
|
-
const footers = Array.from(conv.querySelectorAll('footer')).filter(f => f.offsetWidth > 0 && f.offsetHeight > 0);
|
|
264
|
-
for (const footer of footers) {
|
|
265
|
-
const footerBtns = Array.from(footer.querySelectorAll('button, a')).filter(b => b.offsetWidth > 0);
|
|
266
|
-
if (footerBtns.length >= 2) {
|
|
267
|
-
// 카드 컨테이너: footer 상위에서 충분한 높이를 가진 첫 번째 요소
|
|
268
|
-
let card = footer.parentElement;
|
|
269
|
-
for (let up = 0; up < 4 && card; up++) {
|
|
270
|
-
if (card.offsetHeight > 60) break;
|
|
271
|
-
card = card.parentElement;
|
|
272
|
-
}
|
|
273
|
-
const msg = card ? (card.innerText || '').trim().slice(0, 300) : '';
|
|
274
|
-
const btnTexts = footerBtns.map(b => (b.innerText || '').trim()).filter(t => t.length > 0 && t.length < 40);
|
|
275
|
-
if (btnTexts.length >= 2) {
|
|
276
|
-
activeModal = { message: msg, buttons: btnTexts, width: card ? card.offsetWidth : 300, height: card ? card.offsetHeight : 100 };
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
// 모달이 감지되면 status를 waiting_approval로 변경
|
|
283
|
-
if (activeModal) status = 'waiting_approval';
|
|
284
|
-
} catch (e) { activeModal = null; }
|
|
285
|
-
|
|
286
|
-
return { id: 'active_session', status, title, messages: final, inputContent, activeModal };
|
|
287
|
-
} catch (e) {
|
|
288
|
-
return { id: 'error', status: 'error', error: e.message, messages: [] };
|
|
289
|
-
}
|
|
290
|
-
})()
|