adhdev 0.2.0 → 0.4.1

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.
Files changed (145) hide show
  1. package/dist/cli-entrypoint.js +18710 -1198
  2. package/dist/cli-entrypoint.js.map +1 -1
  3. package/dist/index.js +18720 -1228
  4. package/dist/index.js.map +1 -1
  5. package/package.json +2 -2
  6. package/providers/_builtin/CONTRIBUTING.md +0 -141
  7. package/providers/_builtin/README.md +0 -51
  8. package/providers/_builtin/_helpers/index.js +0 -188
  9. package/providers/_builtin/acp/agentpool/provider.json +0 -47
  10. package/providers/_builtin/acp/amp/provider.json +0 -45
  11. package/providers/_builtin/acp/auggie/provider.json +0 -50
  12. package/providers/_builtin/acp/autodev/provider.json +0 -47
  13. package/providers/_builtin/acp/autohand/provider.json +0 -45
  14. package/providers/_builtin/acp/blackbox-ai/provider.json +0 -47
  15. package/providers/_builtin/acp/claude-agent/provider.json +0 -50
  16. package/providers/_builtin/acp/cline-acp/provider.json +0 -47
  17. package/providers/_builtin/acp/code-assistant/provider.json +0 -47
  18. package/providers/_builtin/acp/codebuddy/provider.json +0 -47
  19. package/providers/_builtin/acp/codex-cli/provider.json +0 -50
  20. package/providers/_builtin/acp/corust-agent/provider.json +0 -45
  21. package/providers/_builtin/acp/crow-cli/provider.json +0 -47
  22. package/providers/_builtin/acp/cursor-acp/provider.json +0 -47
  23. package/providers/_builtin/acp/deepagents/provider.json +0 -45
  24. package/providers/_builtin/acp/dimcode/provider.json +0 -47
  25. package/providers/_builtin/acp/docker-cagent/provider.json +0 -50
  26. package/providers/_builtin/acp/factory-droid/provider.json +0 -53
  27. package/providers/_builtin/acp/fast-agent/provider.json +0 -45
  28. package/providers/_builtin/acp/fount/provider.json +0 -47
  29. package/providers/_builtin/acp/gemini-cli/provider.json +0 -107
  30. package/providers/_builtin/acp/github-copilot/provider.json +0 -47
  31. package/providers/_builtin/acp/goose/provider.json +0 -50
  32. package/providers/_builtin/acp/junie/provider.json +0 -45
  33. package/providers/_builtin/acp/kilo/provider.json +0 -45
  34. package/providers/_builtin/acp/kimi-cli/provider.json +0 -50
  35. package/providers/_builtin/acp/kiro-cli/provider.json +0 -47
  36. package/providers/_builtin/acp/minion-code/provider.json +0 -45
  37. package/providers/_builtin/acp/mistral-vibe/provider.json +0 -50
  38. package/providers/_builtin/acp/nova/provider.json +0 -47
  39. package/providers/_builtin/acp/openclaw/provider.json +0 -47
  40. package/providers/_builtin/acp/opencode/provider.json +0 -45
  41. package/providers/_builtin/acp/openhands/provider.json +0 -47
  42. package/providers/_builtin/acp/pi-acp/provider.json +0 -45
  43. package/providers/_builtin/acp/qoder/provider.json +0 -47
  44. package/providers/_builtin/acp/qwen-code/provider.json +0 -53
  45. package/providers/_builtin/acp/stakpak/provider.json +0 -47
  46. package/providers/_builtin/acp/vtcode/provider.json +0 -47
  47. package/providers/_builtin/cli/claude-cli/provider.json +0 -78
  48. package/providers/_builtin/cli/codex-cli/provider.json +0 -60
  49. package/providers/_builtin/cli/gemini-cli/provider.json +0 -64
  50. package/providers/_builtin/extension/cline/provider.json +0 -11
  51. package/providers/_builtin/extension/cline/scripts/focus_editor.js +0 -48
  52. package/providers/_builtin/extension/cline/scripts/list_chats.js +0 -100
  53. package/providers/_builtin/extension/cline/scripts/list_models.js +0 -43
  54. package/providers/_builtin/extension/cline/scripts/list_modes.js +0 -35
  55. package/providers/_builtin/extension/cline/scripts/new_session.js +0 -85
  56. package/providers/_builtin/extension/cline/scripts/open_panel.js +0 -25
  57. package/providers/_builtin/extension/cline/scripts/read_chat.js +0 -257
  58. package/providers/_builtin/extension/cline/scripts/resolve_action.js +0 -83
  59. package/providers/_builtin/extension/cline/scripts/send_message.js +0 -95
  60. package/providers/_builtin/extension/cline/scripts/set_mode.js +0 -36
  61. package/providers/_builtin/extension/cline/scripts/set_model.js +0 -36
  62. package/providers/_builtin/extension/cline/scripts/switch_session.js +0 -206
  63. package/providers/_builtin/extension/cline/scripts.js +0 -73
  64. package/providers/_builtin/extension/roo-code/provider.json +0 -11
  65. package/providers/_builtin/extension/roo-code/scripts.js +0 -659
  66. package/providers/_builtin/ide/antigravity/provider.json +0 -32
  67. package/providers/_builtin/ide/antigravity/scripts/focus_editor.js +0 -20
  68. package/providers/_builtin/ide/antigravity/scripts/list_chats.js +0 -137
  69. package/providers/_builtin/ide/antigravity/scripts/list_models.js +0 -38
  70. package/providers/_builtin/ide/antigravity/scripts/list_modes.js +0 -48
  71. package/providers/_builtin/ide/antigravity/scripts/new_session.js +0 -75
  72. package/providers/_builtin/ide/antigravity/scripts/read_chat.js +0 -262
  73. package/providers/_builtin/ide/antigravity/scripts/resolve_action.js +0 -68
  74. package/providers/_builtin/ide/antigravity/scripts/send_message.js +0 -56
  75. package/providers/_builtin/ide/antigravity/scripts/set_mode.js +0 -34
  76. package/providers/_builtin/ide/antigravity/scripts/set_model.js +0 -47
  77. package/providers/_builtin/ide/antigravity/scripts/switch_session.js +0 -114
  78. package/providers/_builtin/ide/antigravity/scripts.js +0 -73
  79. package/providers/_builtin/ide/cursor/provider.json +0 -35
  80. package/providers/_builtin/ide/cursor/scripts.js +0 -452
  81. package/providers/_builtin/ide/kiro/provider.json +0 -36
  82. package/providers/_builtin/ide/kiro/scripts/focus_editor.js +0 -20
  83. package/providers/_builtin/ide/kiro/scripts/open_panel.js +0 -47
  84. package/providers/_builtin/ide/kiro/scripts/resolve_action.js +0 -54
  85. package/providers/_builtin/ide/kiro/scripts/send_message.js +0 -29
  86. package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +0 -39
  87. package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +0 -39
  88. package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +0 -21
  89. package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +0 -34
  90. package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +0 -68
  91. package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +0 -72
  92. package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +0 -15
  93. package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +0 -15
  94. package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +0 -26
  95. package/providers/_builtin/ide/kiro/scripts.js +0 -62
  96. package/providers/_builtin/ide/pearai/provider.json +0 -36
  97. package/providers/_builtin/ide/pearai/scripts/focus_editor.js +0 -20
  98. package/providers/_builtin/ide/pearai/scripts/list_sessions.js +0 -38
  99. package/providers/_builtin/ide/pearai/scripts/new_session.js +0 -55
  100. package/providers/_builtin/ide/pearai/scripts/open_panel.js +0 -46
  101. package/providers/_builtin/ide/pearai/scripts/resolve_action.js +0 -54
  102. package/providers/_builtin/ide/pearai/scripts/send_message.js +0 -29
  103. package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +0 -43
  104. package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +0 -35
  105. package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +0 -62
  106. package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +0 -49
  107. package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +0 -92
  108. package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +0 -59
  109. package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +0 -72
  110. package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +0 -36
  111. package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +0 -36
  112. package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +0 -34
  113. package/providers/_builtin/ide/pearai/scripts.js +0 -74
  114. package/providers/_builtin/ide/trae/provider.json +0 -35
  115. package/providers/_builtin/ide/trae/scripts/focus_editor.js +0 -20
  116. package/providers/_builtin/ide/trae/scripts/list_chats.js +0 -24
  117. package/providers/_builtin/ide/trae/scripts/list_models.js +0 -39
  118. package/providers/_builtin/ide/trae/scripts/list_modes.js +0 -39
  119. package/providers/_builtin/ide/trae/scripts/new_session.js +0 -30
  120. package/providers/_builtin/ide/trae/scripts/open_panel.js +0 -44
  121. package/providers/_builtin/ide/trae/scripts/read_chat.js +0 -113
  122. package/providers/_builtin/ide/trae/scripts/resolve_action.js +0 -54
  123. package/providers/_builtin/ide/trae/scripts/send_message.js +0 -69
  124. package/providers/_builtin/ide/trae/scripts/set_mode.js +0 -15
  125. package/providers/_builtin/ide/trae/scripts/set_model.js +0 -15
  126. package/providers/_builtin/ide/trae/scripts/switch_session.js +0 -23
  127. package/providers/_builtin/ide/trae/scripts.js +0 -57
  128. package/providers/_builtin/ide/vscode/provider.json +0 -33
  129. package/providers/_builtin/ide/vscode-insiders/provider.json +0 -31
  130. package/providers/_builtin/ide/vscodium/provider.json +0 -32
  131. package/providers/_builtin/ide/windsurf/provider.json +0 -22
  132. package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +0 -30
  133. package/providers/_builtin/ide/windsurf/scripts/list_chats.js +0 -117
  134. package/providers/_builtin/ide/windsurf/scripts/list_models.js +0 -39
  135. package/providers/_builtin/ide/windsurf/scripts/list_modes.js +0 -39
  136. package/providers/_builtin/ide/windsurf/scripts/new_session.js +0 -69
  137. package/providers/_builtin/ide/windsurf/scripts/open_panel.js +0 -58
  138. package/providers/_builtin/ide/windsurf/scripts/read_chat.js +0 -297
  139. package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +0 -68
  140. package/providers/_builtin/ide/windsurf/scripts/send_message.js +0 -87
  141. package/providers/_builtin/ide/windsurf/scripts/set_mode.js +0 -15
  142. package/providers/_builtin/ide/windsurf/scripts/set_model.js +0 -15
  143. package/providers/_builtin/ide/windsurf/scripts/switch_session.js +0 -58
  144. package/providers/_builtin/ide/windsurf/scripts.js +0 -57
  145. package/providers/_builtin/validate.js +0 -156
@@ -1,30 +0,0 @@
1
- /**
2
- * Windsurf v1 — focus_editor
3
- *
4
- * Cascade(채팅) 입력창에 포커스를 맞춥니다.
5
- * Windsurf는 VS Code 포크로, 채팅 UI를 "Cascade"라고 부릅니다.
6
- *
7
- * DOM 구조:
8
- * #windsurf.cascadePanel → .chat-client-root
9
- * 입력: [contenteditable="true"][role="textbox"]
10
- * 또는 textarea (미로그인)
11
- *
12
- * 최종 확인: Windsurf (2026-03-06)
13
- */
14
- (() => {
15
- try {
16
- const editor =
17
- document.querySelector('[contenteditable="true"][role="textbox"]') ||
18
- document.querySelector('[data-lexical-editor="true"]') ||
19
- document.querySelector('.chat-input textarea') ||
20
- document.querySelector('.cascade-input [contenteditable="true"]') ||
21
- document.querySelector('textarea:not(.xterm-helper-textarea)');
22
- if (editor) {
23
- editor.focus();
24
- return true;
25
- }
26
- return false;
27
- } catch (e) {
28
- return false;
29
- }
30
- })()
@@ -1,117 +0,0 @@
1
- /**
2
- * Windsurf v1 — list_chats
3
- *
4
- * Cascade 탭 목록을 가져옵니다.
5
- * 패널이 닫혀 있으면 먼저 열고 탭이 렌더링될 때까지 대기합니다.
6
- * cascade-tab-{uuid} 요소들의 React Fiber에서 제목을 추출합니다.
7
- *
8
- * 최종 확인: Windsurf 1.108.x (2026-03-10)
9
- */
10
- (async () => {
11
- try {
12
- // ─── 1. 패널이 닫혀 있으면 열기 ───
13
- let tabs = document.querySelectorAll('[id^="cascade-tab-"]');
14
- if (tabs.length === 0) {
15
- // Cascade 패널 보이는지 확인
16
- const cascade = document.querySelector('#windsurf\\.cascadePanel') ||
17
- document.querySelector('.chat-client-root');
18
- const sidebar = document.getElementById('workbench.parts.auxiliarybar');
19
- const panelVisible = (cascade && cascade.offsetWidth > 0) ||
20
- (sidebar && sidebar.offsetWidth > 0 && cascade);
21
-
22
- if (!panelVisible) {
23
- // Toggle 버튼 클릭 시도
24
- const toggleBtns = Array.from(document.querySelectorAll('li.action-item a, button, [role="button"]'));
25
- let toggled = false;
26
- for (const btn of toggleBtns) {
27
- const label = (btn.getAttribute('aria-label') || '').toLowerCase();
28
- if (label.includes('toggle cascade') || label.includes('toggle secondary') ||
29
- label.includes('toggle auxiliary') || label.includes('cascade')) {
30
- if (btn.offsetWidth > 0 || btn.offsetHeight > 0) {
31
- btn.click();
32
- toggled = true;
33
- break;
34
- }
35
- }
36
- }
37
- // 버튼 없으면 Cmd+L
38
- if (!toggled) {
39
- document.dispatchEvent(new KeyboardEvent('keydown', {
40
- key: 'l', code: 'KeyL', keyCode: 76,
41
- metaKey: true, ctrlKey: false,
42
- bubbles: true, cancelable: true,
43
- }));
44
- document.dispatchEvent(new KeyboardEvent('keyup', {
45
- key: 'l', code: 'KeyL', keyCode: 76,
46
- metaKey: true, ctrlKey: false,
47
- bubbles: true, cancelable: true,
48
- }));
49
- }
50
-
51
- // 패널 렌더링 대기 (최대 3초)
52
- for (let i = 0; i < 30; i++) {
53
- await new Promise(r => setTimeout(r, 100));
54
- tabs = document.querySelectorAll('[id^="cascade-tab-"]');
55
- if (tabs.length > 0) break;
56
- }
57
- }
58
- }
59
-
60
- // ─── 2. 탭 정보 수집 ───
61
- tabs = document.querySelectorAll('[id^="cascade-tab-"]');
62
- if (tabs.length === 0) return [];
63
-
64
- const result = [];
65
- const seen = new Set();
66
-
67
- tabs.forEach(tab => {
68
- const tabId = tab.id.replace('cascade-tab-', '');
69
- if (seen.has(tabId)) return;
70
- seen.add(tabId);
71
-
72
- let title = '';
73
- let cascadeId = tabId;
74
- let status = 'completed';
75
-
76
- // React Fiber에서 제목 추출
77
- const fk = Object.keys(tab).find(k => k.startsWith('__reactFiber'));
78
- if (fk) {
79
- let fiber = tab[fk];
80
- for (let d = 0; d < 30 && fiber; d++) {
81
- const p = fiber.memoizedProps;
82
- if (p) {
83
- if (p.title && typeof p.title === 'string') {
84
- title = p.title;
85
- }
86
- if (p.cascadeId) {
87
- cascadeId = p.cascadeId;
88
- }
89
- if (p.status && typeof p.status === 'string') {
90
- status = p.status;
91
- }
92
- if (title) break;
93
- }
94
- fiber = fiber.return;
95
- }
96
- }
97
-
98
- // DOM 폴백
99
- if (!title) {
100
- title = tab.textContent?.trim().substring(0, 100) || ('Chat ' + (result.length + 1));
101
- }
102
-
103
- const isVisible = tab.offsetHeight > 0 && tab.offsetWidth > 0;
104
-
105
- result.push({
106
- id: tabId,
107
- title: title.substring(0, 100),
108
- status: status,
109
- active: isVisible
110
- });
111
- });
112
-
113
- return result;
114
- } catch (e) {
115
- return [];
116
- }
117
- })()
@@ -1,39 +0,0 @@
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
- })()
@@ -1,39 +0,0 @@
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
- })()
@@ -1,69 +0,0 @@
1
- /**
2
- * Windsurf v1 — new_session
3
- *
4
- * 새 Cascade 세션을 시작합니다.
5
- *
6
- * 전략:
7
- * 1. aria-label 기반 "New" 버튼 탐색
8
- * 2. 텍스트 기반 버튼 탐색
9
- * 3. Codicon 아이콘(+) 기반 탐색
10
- * 4. Cmd+L 단축키 폴백 (Windsurf에서 새 Cascade 열기)
11
- *
12
- * Windsurf에서는 Cascade가 AI 채팅 패널이며,
13
- * "New Chat" 또는 "+" 버튼으로 새 세션을 시작합니다.
14
- *
15
- * 최종 확인: Windsurf 1.108.x (2026-03-10)
16
- */
17
- (() => {
18
- try {
19
- // ─── 1. aria-label 기반 ───
20
- const allBtns = Array.from(document.querySelectorAll('button, [role="button"], .action-item'))
21
- .filter(b => b.offsetWidth > 0);
22
-
23
- for (const btn of allBtns) {
24
- const label = (btn.getAttribute('aria-label') || '').toLowerCase();
25
- if (label.includes('new chat') || label.includes('new cascade') ||
26
- label.includes('new conversation') || label.includes('start new') ||
27
- label.includes('new session')) {
28
- btn.click();
29
- return 'clicked (aria)';
30
- }
31
- }
32
-
33
- // ─── 2. 텍스트 기반 ───
34
- for (const btn of allBtns) {
35
- const text = (btn.textContent || '').trim();
36
- if (text === '+' || text === 'New Chat' || text === 'New Cascade' ||
37
- text === 'Start New Chat' || text === 'New Session') {
38
- btn.click();
39
- return 'clicked (text)';
40
- }
41
- }
42
-
43
- // ─── 3. Codicon 아이콘(+) 기반 ───
44
- for (const btn of allBtns) {
45
- const hasPlus = btn.querySelector('.codicon-plus, .codicon-add, [class*="plus"]');
46
- if (hasPlus) {
47
- const label = (btn.getAttribute('aria-label') || btn.getAttribute('title') || '').toLowerCase();
48
- // Cascade 관련 컨텍스트이거나 라벨이 비어있으면 새 세션 버튼일 가능성
49
- if (label.includes('chat') || label.includes('cascade') ||
50
- label.includes('new') || label === '') {
51
- btn.click();
52
- return 'clicked (icon)';
53
- }
54
- }
55
- }
56
-
57
- // ─── 4. Cmd+L 단축키 (macOS: metaKey, Windows/Linux: ctrlKey) ───
58
- // Windsurf에서 Cmd+L은 Cascade 패널 토글/새 세션 생성
59
- document.dispatchEvent(new KeyboardEvent('keydown', {
60
- key: 'l', code: 'KeyL', keyCode: 76,
61
- metaKey: true, ctrlKey: false,
62
- bubbles: true, cancelable: true,
63
- }));
64
-
65
- return 'sent Cmd+L';
66
- } catch (e) {
67
- return 'error: ' + e.message;
68
- }
69
- })()
@@ -1,58 +0,0 @@
1
- /**
2
- * Windsurf v1 — open_panel
3
- *
4
- * Cascade(AI 채팅) 패널이 닫혀 있을 때 열기.
5
- *
6
- * Windsurf의 Cascade 패널은 Secondary Side Bar (#workbench.parts.auxiliarybar)에 위치.
7
- * 닫혀 있으면 offsetWidth === 0.
8
- * Cmd+L 단축키로 열 수 있음 (WINDSURF.md §2.5).
9
- *
10
- * 반환: 'visible' | 'opened' | 'error: ...'
11
- * 최종 확인: Windsurf 1.108.x (2026-03-10)
12
- */
13
- (() => {
14
- try {
15
- // ─── 1. Cascade 패널이 이미 열려 있는지 확인 ───
16
- const cascade = document.querySelector('#windsurf\\.cascadePanel') ||
17
- document.querySelector('.chat-client-root');
18
- const sidebar = document.getElementById('workbench.parts.auxiliarybar');
19
-
20
- // 패널이 존재하고 보이면 이미 열린 상태
21
- if (cascade && cascade.offsetWidth > 0 && cascade.offsetHeight > 0) {
22
- return 'visible';
23
- }
24
- if (sidebar && sidebar.offsetWidth > 0 && sidebar.offsetHeight > 0 && cascade) {
25
- return 'visible';
26
- }
27
-
28
- // ─── 2. Toggle 버튼 클릭 시도 ───
29
- const toggleBtns = Array.from(document.querySelectorAll('li.action-item a, button, [role="button"]'));
30
- for (const btn of toggleBtns) {
31
- const label = (btn.getAttribute('aria-label') || '').toLowerCase();
32
- if (label.includes('toggle cascade') || label.includes('toggle secondary') ||
33
- label.includes('toggle auxiliary') || label.includes('cascade')) {
34
- if (btn.offsetWidth > 0 || btn.offsetHeight > 0) {
35
- btn.click();
36
- return 'opened (toggle)';
37
- }
38
- }
39
- }
40
-
41
- // ─── 3. Cmd+L 단축키 폴백 (Windsurf 공식 단축키) ───
42
- // keyCode: 76, modifiers: 4 (Meta/Cmd)
43
- document.dispatchEvent(new KeyboardEvent('keydown', {
44
- key: 'l', code: 'KeyL', keyCode: 76,
45
- metaKey: true, ctrlKey: false,
46
- bubbles: true, cancelable: true,
47
- }));
48
- document.dispatchEvent(new KeyboardEvent('keyup', {
49
- key: 'l', code: 'KeyL', keyCode: 76,
50
- metaKey: true, ctrlKey: false,
51
- bubbles: true, cancelable: true,
52
- }));
53
-
54
- return 'opened (Cmd+L)';
55
- } catch (e) {
56
- return 'error: ' + e.message;
57
- }
58
- })()
@@ -1,297 +0,0 @@
1
- /**
2
- * Windsurf v1 — read_chat (v1 — Cascade DOM + Fiber)
3
- *
4
- * Windsurf는 VS Code 포크, 채팅 UI를 "Cascade"라고 부릅니다.
5
- *
6
- * DOM 구조:
7
- * #windsurf.cascadePanel → .chat-client-root
8
- * 스크롤: .cascade-scrollbar
9
- * 메시지 리스트: .cascade-scrollbar .pb-20 > .flex.flex-col > .flex.flex-col.gap-2\.5
10
- * 사용자 메시지: hasProse=false, hasWhitespace=true
11
- * AI 메시지: [class*="prose"] (prose-sm)
12
- * 피드백 UI: .mark-js-ignore (무시)
13
- * 입력: [data-lexical-editor="true"]
14
- *
15
- * Fiber props:
16
- * cascadeId: 세션 ID
17
- * isRunning: 생성 중 여부
18
- * hasPendingTerminalCommand: 승인 대기
19
- * copyableText: AI 응답 마크다운 원본
20
- *
21
- * 최종 확인: Windsurf (2026-03-06)
22
- */
23
- (() => {
24
- try {
25
- // ─── 1. 컨테이너 ───
26
- const cascade = document.querySelector('#windsurf\\.cascadePanel')
27
- || document.querySelector('.chat-client-root');
28
- if (!cascade) {
29
- return { id: 'no_cascade', status: 'idle', title: 'No Cascade', messages: [], inputContent: '', activeModal: null };
30
- }
31
-
32
- // ─── 2. Fiber에서 cascadeId, isRunning 추출 (턴 요소에서 탐색) ───
33
- let cascadeId = 'cascade';
34
- let isRunning = false;
35
- let hasPendingCmd = false;
36
- try {
37
- // 턴 요소에서 Fiber 탐색 (cascadePanel 루트보다 깊이 6에서 cascadeId 발견)
38
- const scrollArea = cascade.querySelector('.cascade-scrollbar');
39
- const gapEls = scrollArea ? scrollArea.querySelectorAll('[class*="gap-2"]') : [];
40
- let firstTurn = null;
41
- for (const el of gapEls) {
42
- if (el.children.length >= 1 && el.closest('.cascade-scrollbar')) {
43
- firstTurn = el.children[0]; break;
44
- }
45
- }
46
- const fiberTarget = firstTurn || cascade;
47
- const fk = Object.keys(fiberTarget).find(k => k.startsWith('__reactFiber'));
48
- if (fk) {
49
- let fiber = fiberTarget[fk];
50
- for (let d = 0; d < 50 && fiber; d++) {
51
- const p = fiber.memoizedProps || fiber.pendingProps || {};
52
- if (p.cascadeId && typeof p.cascadeId === 'string') cascadeId = p.cascadeId;
53
- if (p.isRunning === true) isRunning = true;
54
- if (p.hasPendingTerminalCommand === true) hasPendingCmd = true;
55
- fiber = fiber.return;
56
- }
57
- }
58
- } catch (_) { }
59
-
60
- // ─── 3. 상태 감지 ───
61
- let status = 'idle';
62
- if (isRunning) status = 'generating';
63
-
64
- // Signal A: Stop 버튼
65
- if (status === 'idle') {
66
- const allBtns = Array.from(document.querySelectorAll('button'));
67
- const stopBtn = allBtns.find(b => {
68
- if (b.offsetWidth === 0) return false;
69
- const label = (b.getAttribute('aria-label') || '').toLowerCase();
70
- const text = (b.textContent || '').trim().toLowerCase();
71
- return label.includes('stop') || label === 'cancel generation'
72
- || text === 'stop' || text === 'stop generating';
73
- });
74
- if (stopBtn) status = 'generating';
75
- }
76
-
77
- // Signal B: 입력창 placeholder
78
- if (status === 'idle') {
79
- const editor = cascade.querySelector('[data-lexical-editor="true"]');
80
- if (editor) {
81
- const ph = (editor.getAttribute('placeholder') || '').toLowerCase();
82
- if (ph.includes('wait') || ph.includes('generating')) status = 'generating';
83
- }
84
- }
85
-
86
- const title = document.title.split(' \u2014 ')[0].trim() || 'Cascade';
87
-
88
- // ─── 4. HTML → Markdown 변환기 ───
89
- function htmlToMd(node) {
90
- if (node.nodeType === 3) return node.textContent || '';
91
- if (node.nodeType !== 1) return '';
92
- const tag = node.tagName;
93
- if (tag === 'STYLE' || tag === 'SCRIPT' || tag === 'SVG') return '';
94
- if (tag === 'TABLE') {
95
- const rows = Array.from(node.querySelectorAll('tr'));
96
- if (rows.length === 0) return '';
97
- const table = rows.map(tr =>
98
- Array.from(tr.querySelectorAll('th, td')).map(cell => (cell.textContent || '').trim().replace(/\|/g, '\\|'))
99
- );
100
- const colCount = Math.max(...table.map(r => r.length));
101
- const header = table[0] || [];
102
- const sep = Array(colCount).fill('---');
103
- const body = table.slice(1);
104
- let md = '| ' + header.join(' | ') + ' |\n';
105
- md += '| ' + sep.join(' | ') + ' |\n';
106
- for (const row of body) {
107
- while (row.length < colCount) row.push('');
108
- md += '| ' + row.join(' | ') + ' |\n';
109
- }
110
- return '\n' + md + '\n';
111
- }
112
- if (tag === 'UL') return '\n' + Array.from(node.children).map(li => '- ' + childrenToMd(li).trim()).join('\n') + '\n';
113
- if (tag === 'OL') return '\n' + Array.from(node.children).map((li, i) => (i + 1) + '. ' + childrenToMd(li).trim()).join('\n') + '\n';
114
- if (tag === 'LI') return childrenToMd(node);
115
- if (tag === 'H1') return '\n# ' + childrenToMd(node).trim() + '\n';
116
- if (tag === 'H2') return '\n## ' + childrenToMd(node).trim() + '\n';
117
- if (tag === 'H3') return '\n### ' + childrenToMd(node).trim() + '\n';
118
- if (tag === 'H4') return '\n#### ' + childrenToMd(node).trim() + '\n';
119
- if (tag === 'STRONG' || tag === 'B') return '**' + childrenToMd(node).trim() + '**';
120
- if (tag === 'EM' || tag === 'I') return '*' + childrenToMd(node).trim() + '*';
121
- if (tag === 'PRE') {
122
- const codeEl = node.querySelector('code');
123
- const lang = codeEl ? (codeEl.className.match(/language-(\w+)/)?.[1] || '') : '';
124
- const code = (codeEl || node).textContent || '';
125
- return '\n```' + lang + '\n' + code.trim() + '\n```\n';
126
- }
127
- if (tag === 'CODE') {
128
- if (node.parentElement && node.parentElement.tagName === 'PRE') return node.textContent || '';
129
- return '`' + (node.textContent || '').trim() + '`';
130
- }
131
- if (tag === 'BLOCKQUOTE') return '\n> ' + childrenToMd(node).trim().replace(/\n/g, '\n> ') + '\n';
132
- if (tag === 'A') return '[' + childrenToMd(node).trim() + '](' + (node.getAttribute('href') || '') + ')';
133
- if (tag === 'BR') return '\n';
134
- if (tag === 'P') return '\n' + childrenToMd(node).trim() + '\n';
135
- return childrenToMd(node);
136
- }
137
- function childrenToMd(node) {
138
- return Array.from(node.childNodes).map(htmlToMd).join('');
139
- }
140
-
141
- function getCleanMd(el) {
142
- const clone = el.cloneNode(true);
143
- clone.querySelectorAll('button, [role="button"], style, script, svg, .codicon, [class*="feedback"]').forEach(n => n.remove());
144
- clone.querySelectorAll('*').forEach(child => {
145
- if (!child.parentNode) return;
146
- const t = (child.textContent || '').trim();
147
- if (t.length > 60) return;
148
- const low = t.toLowerCase();
149
- if (/^(analyzed\s+\d|edited\s+\d|ran\s+\S|terminal\s|reading|searching)/i.test(low)) child.remove();
150
- });
151
- let md = htmlToMd(clone);
152
- md = md.replace(/\n{3,}/g, '\n\n').trim();
153
- return md;
154
- }
155
-
156
- // ─── 5. 메시지 수집 ───
157
- const collected = [];
158
- const seenHashes = new Set();
159
-
160
- const scrollArea = cascade.querySelector('.cascade-scrollbar');
161
- if (!scrollArea) {
162
- return { id: cascadeId, status, title, messages: [], inputContent: '', activeModal: null };
163
- }
164
-
165
- // 메시지 리스트 컨테이너 찾기: .gap-2.5 중 자식 2개 이상
166
- let msgContainer = null;
167
- const gapEls = scrollArea.querySelectorAll('[class*="gap-2"]');
168
- for (const el of gapEls) {
169
- if (el.children.length >= 2 && el.closest('.cascade-scrollbar')) {
170
- msgContainer = el; break;
171
- }
172
- }
173
-
174
- if (msgContainer) {
175
- const turns = Array.from(msgContainer.children);
176
- for (const turn of turns) {
177
- // .mark-js-ignore = 피드백 UI → 무시
178
- if ((turn.className || '').includes('mark-js-ignore')) continue;
179
- if (turn.offsetHeight < 10) continue;
180
-
181
- // 역할 판별: .prose = AI, 아니면 user
182
- const proseEl = turn.querySelector('[class*="prose"]');
183
- const role = proseEl ? 'assistant' : 'user';
184
-
185
- let text = '';
186
- if (role === 'assistant') {
187
- // AI: Fiber copyableText가 있으면 사용 (이미 마크다운!)
188
- try {
189
- const fk = Object.keys(turn).find(k => k.startsWith('__reactFiber'));
190
- if (fk) {
191
- let fiber = turn[fk];
192
- for (let d = 0; d < 20 && fiber; d++) {
193
- const p = fiber.memoizedProps || {};
194
- if (p.copyableText && typeof p.copyableText === 'string' && p.copyableText.length > 5) {
195
- text = p.copyableText;
196
- break;
197
- }
198
- fiber = fiber.return;
199
- }
200
- }
201
- } catch (_) { }
202
-
203
- // Fiber에 없으면 HTML→Markdown
204
- if (!text) {
205
- const mdRoot = proseEl || turn;
206
- text = getCleanMd(mdRoot);
207
- }
208
- } else {
209
- // 사용자: whitespace-pre-wrap 요소에서 텍스트 추출
210
- const whitespace = turn.querySelector('[class*="whitespace"]');
211
- text = (whitespace || turn).innerText?.trim() || '';
212
- }
213
-
214
- if (!text || text.length < 1) continue;
215
-
216
- const hash = role + ':' + text.slice(0, 200);
217
- if (seenHashes.has(hash)) continue;
218
- seenHashes.add(hash);
219
- collected.push({ role, text, el: turn });
220
- }
221
- }
222
-
223
- // DOM 순서 정렬
224
- collected.sort((a, b) => {
225
- const pos = a.el.compareDocumentPosition(b.el);
226
- if (pos & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
227
- if (pos & Node.DOCUMENT_POSITION_PRECEDING) return 1;
228
- return 0;
229
- });
230
-
231
- // 최신 30개만
232
- const trimmed = collected.length > 30 ? collected.slice(-30) : collected;
233
-
234
- const final = trimmed.map((m, i) => ({
235
- id: 'msg_' + i,
236
- role: m.role,
237
- content: m.text.length > 6000 ? m.text.slice(0, 6000) + '\n[... truncated]' : m.text,
238
- index: i,
239
- kind: 'standard'
240
- }));
241
-
242
- // ─── 6. 입력창 ───
243
- const editor = cascade.querySelector('[data-lexical-editor="true"]')
244
- || cascade.querySelector('[contenteditable="true"][role="textbox"]')
245
- || cascade.querySelector('textarea:not(.xterm-helper-textarea)');
246
- const inputContent = editor ? (editor.innerText || editor.value || '').trim() : '';
247
-
248
- // ─── 7. 모달/승인 감지 ───
249
- let activeModal = null;
250
- try {
251
- // Fiber: hasPendingTerminalCommand
252
- if (hasPendingCmd) {
253
- const allBtns = Array.from(document.querySelectorAll('button')).filter(b => b.offsetWidth > 0);
254
- const approvalBtns = allBtns.filter(b => {
255
- const t = (b.textContent || '').trim().toLowerCase();
256
- return /^(run|reject|skip|approve|allow|deny|cancel|accept)\b/i.test(t);
257
- });
258
- const btnTexts = [...new Set(approvalBtns.map(b => (b.textContent || '').trim()).filter(t => t.length < 40))];
259
- activeModal = { message: 'Terminal command pending', buttons: btnTexts.length > 0 ? btnTexts : ['Run', 'Reject'] };
260
- }
261
-
262
- // Dialog 폴백
263
- if (!activeModal) {
264
- const dialog = document.querySelector('.monaco-dialog-box, [role="dialog"]');
265
- if (dialog && dialog.offsetWidth > 80) {
266
- const msg = (dialog.querySelector('.dialog-message') || dialog).innerText?.trim() || '';
267
- const buttons = Array.from(dialog.querySelectorAll('.monaco-button, button'))
268
- .map(b => (b.innerText || '').trim()).filter(t => t.length > 0 && t.length < 30);
269
- if (msg || buttons.length > 0) {
270
- activeModal = { message: msg.slice(0, 300), buttons };
271
- }
272
- }
273
- }
274
-
275
- // 인라인 승인 버튼
276
- if (!activeModal) {
277
- const allBtns = Array.from(document.querySelectorAll('button')).filter(b => b.offsetWidth > 0);
278
- const approvalBtns = allBtns.filter(b => {
279
- const t = (b.textContent || '').trim().toLowerCase();
280
- if (t.length > 40) return false;
281
- return /^(run|reject|skip|approve|allow|deny)\b/i.test(t)
282
- || t === 'always allow' || t === 'always deny';
283
- });
284
- if (approvalBtns.length >= 2) {
285
- const btnTexts = [...new Set(approvalBtns.map(b => (b.textContent || '').trim()))];
286
- activeModal = { message: '', buttons: btnTexts };
287
- }
288
- }
289
-
290
- if (activeModal) status = 'waiting_approval';
291
- } catch (_) { activeModal = null; }
292
-
293
- return { id: cascadeId, status, title, messages: final, inputContent, activeModal };
294
- } catch (e) {
295
- return { id: 'error', status: 'error', error: e.message, messages: [] };
296
- }
297
- })()