@adhdev/daemon-core 0.6.53 → 0.6.55

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 (164) hide show
  1. package/dist/index.d.ts +76 -34
  2. package/dist/index.js +714 -271
  3. package/dist/index.js.map +1 -1
  4. package/package.json +1 -1
  5. package/providers/_builtin/_helpers/index.js +26 -26
  6. package/providers/_builtin/cli/aider-cli/provider.json +37 -0
  7. package/providers/_builtin/cli/aider-cli/scripts/1.0/detect_status.js +20 -0
  8. package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_approval.js +10 -0
  9. package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_output.js +49 -0
  10. package/providers/_builtin/cli/aider-cli/scripts/1.0/scripts.js +7 -0
  11. package/providers/_builtin/cli/claude-cli/provider.json +9 -2
  12. package/providers/_builtin/cli/claude-cli/scripts/1.0/detect_status.js +31 -0
  13. package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_approval.js +38 -0
  14. package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_output.js +164 -0
  15. package/providers/_builtin/cli/claude-cli/scripts/1.0/scripts.js +42 -0
  16. package/providers/_builtin/cli/codex-cli/provider.json +9 -2
  17. package/providers/_builtin/cli/codex-cli/scripts/1.0/detect_status.js +20 -0
  18. package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_approval.js +15 -0
  19. package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_output.js +68 -0
  20. package/providers/_builtin/cli/codex-cli/scripts/1.0/scripts.js +11 -0
  21. package/providers/_builtin/cli/cursor-cli/provider.json +37 -0
  22. package/providers/_builtin/cli/cursor-cli/scripts/1.0/detect_status.js +19 -0
  23. package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_approval.js +10 -0
  24. package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_output.js +48 -0
  25. package/providers/_builtin/cli/cursor-cli/scripts/1.0/scripts.js +7 -0
  26. package/providers/_builtin/cli/gemini-cli/provider.json +9 -2
  27. package/providers/_builtin/cli/gemini-cli/scripts/1.0/detect_status.js +26 -0
  28. package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_approval.js +22 -0
  29. package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_output.js +71 -0
  30. package/providers/_builtin/cli/gemini-cli/scripts/1.0/scripts.js +12 -0
  31. package/providers/_builtin/cli/github-copilot-cli/provider.json +37 -0
  32. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/detect_status.js +19 -0
  33. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_approval.js +9 -0
  34. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_output.js +48 -0
  35. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/scripts.js +7 -0
  36. package/providers/_builtin/cli/goose-cli/provider.json +37 -0
  37. package/providers/_builtin/cli/goose-cli/scripts/1.0/detect_status.js +20 -0
  38. package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_approval.js +10 -0
  39. package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_output.js +48 -0
  40. package/providers/_builtin/cli/goose-cli/scripts/1.0/scripts.js +7 -0
  41. package/providers/_builtin/cli/opencode-cli/provider.json +37 -0
  42. package/providers/_builtin/cli/opencode-cli/scripts/1.0/detect_status.js +15 -0
  43. package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_approval.js +9 -0
  44. package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_output.js +48 -0
  45. package/providers/_builtin/cli/opencode-cli/scripts/1.0/scripts.js +7 -0
  46. package/providers/_builtin/extension/cline/scripts/1.0/focus_editor.js +5 -5
  47. package/providers/_builtin/extension/cline/scripts/1.0/list_chats.js +11 -11
  48. package/providers/_builtin/extension/cline/scripts/1.0/list_models.js +6 -6
  49. package/providers/_builtin/extension/cline/scripts/1.0/list_modes.js +5 -5
  50. package/providers/_builtin/extension/cline/scripts/1.0/new_session.js +12 -12
  51. package/providers/_builtin/extension/cline/scripts/1.0/open_panel.js +7 -7
  52. package/providers/_builtin/extension/cline/scripts/1.0/read_chat.js +29 -29
  53. package/providers/_builtin/extension/cline/scripts/1.0/resolve_action.js +19 -19
  54. package/providers/_builtin/extension/cline/scripts/1.0/send_message.js +15 -15
  55. package/providers/_builtin/extension/cline/scripts/1.0/set_mode.js +4 -4
  56. package/providers/_builtin/extension/cline/scripts/1.0/set_model.js +4 -4
  57. package/providers/_builtin/extension/cline/scripts/1.0/switch_session.js +21 -21
  58. package/providers/_builtin/extension/codex/scripts/1.0/explore_controls_webview.js +2 -2
  59. package/providers/_builtin/extension/codex/scripts/1.0/list_models.js +1 -1
  60. package/providers/_builtin/extension/codex/scripts/1.0/list_modes.js +1 -1
  61. package/providers/_builtin/extension/codex/scripts/1.0/new_session.js +2 -2
  62. package/providers/_builtin/extension/codex/scripts/1.0/read_chat.js +6 -6
  63. package/providers/_builtin/extension/codex/scripts/1.0/resolve_action.js +3 -3
  64. package/providers/_builtin/extension/codex/scripts/1.0/set_model.js +1 -1
  65. package/providers/_builtin/ide/antigravity/scripts/1.0/focus_editor.js +2 -2
  66. package/providers/_builtin/ide/antigravity/scripts/1.0/list_chats.js +19 -19
  67. package/providers/_builtin/ide/antigravity/scripts/1.0/list_models.js +1 -1
  68. package/providers/_builtin/ide/antigravity/scripts/1.0/list_modes.js +1 -1
  69. package/providers/_builtin/ide/antigravity/scripts/1.0/new_session.js +17 -17
  70. package/providers/_builtin/ide/antigravity/scripts/1.0/read_chat.js +41 -41
  71. package/providers/_builtin/ide/antigravity/scripts/1.0/resolve_action.js +6 -6
  72. package/providers/_builtin/ide/antigravity/scripts/1.0/send_message.js +13 -13
  73. package/providers/_builtin/ide/antigravity/scripts/1.0/set_model.js +1 -1
  74. package/providers/_builtin/ide/antigravity/scripts/1.0/switch_session.js +13 -13
  75. package/providers/_builtin/ide/cursor/scripts/1.0/dismiss_notification.js +3 -3
  76. package/providers/_builtin/ide/cursor/scripts/1.0/focus_editor.js +1 -1
  77. package/providers/_builtin/ide/cursor/scripts/1.0/list_models.js +12 -12
  78. package/providers/_builtin/ide/cursor/scripts/1.0/list_modes.js +5 -5
  79. package/providers/_builtin/ide/cursor/scripts/1.0/list_notifications.js +2 -2
  80. package/providers/_builtin/ide/cursor/scripts/1.0/list_sessions.js +5 -5
  81. package/providers/_builtin/ide/cursor/scripts/1.0/new_session.js +1 -1
  82. package/providers/_builtin/ide/cursor/scripts/1.0/open_panel.js +3 -3
  83. package/providers/_builtin/ide/cursor/scripts/1.0/read_chat.js +9 -9
  84. package/providers/_builtin/ide/cursor/scripts/1.0/resolve_action.js +4 -4
  85. package/providers/_builtin/ide/cursor/scripts/1.0/send_message.js +5 -5
  86. package/providers/_builtin/ide/cursor/scripts/1.0/set_mode.js +4 -4
  87. package/providers/_builtin/ide/cursor/scripts/1.0/set_model.js +12 -12
  88. package/providers/_builtin/ide/cursor/scripts/1.0/switch_session.js +2 -2
  89. package/providers/_builtin/ide/kiro/scripts/1.0/focus_editor.js +2 -2
  90. package/providers/_builtin/ide/kiro/scripts/1.0/open_panel.js +7 -7
  91. package/providers/_builtin/ide/kiro/scripts/1.0/resolve_action.js +3 -3
  92. package/providers/_builtin/ide/kiro/scripts/1.0/send_message.js +4 -4
  93. package/providers/_builtin/ide/kiro/scripts/1.0/webview_list_sessions.js +2 -2
  94. package/providers/_builtin/ide/kiro/scripts/1.0/webview_new_session.js +5 -5
  95. package/providers/_builtin/ide/kiro/scripts/1.0/webview_read_chat.js +13 -13
  96. package/providers/_builtin/ide/kiro/scripts/1.0/webview_resolve_action.js +1 -1
  97. package/providers/_builtin/ide/kiro/scripts/1.0/webview_send_message.js +8 -8
  98. package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_mode.js +1 -1
  99. package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_model.js +1 -1
  100. package/providers/_builtin/ide/kiro/scripts/1.0/webview_switch_session.js +3 -3
  101. package/providers/_builtin/ide/pearai/.tmp/after_rich.json +157 -0
  102. package/providers/_builtin/ide/pearai/.tmp/after_rich_raw.json +161 -0
  103. package/providers/_builtin/ide/pearai/.tmp/after_switch.json +592 -0
  104. package/providers/_builtin/ide/pearai/.tmp/after_switch_raw.json +596 -0
  105. package/providers/_builtin/ide/pearai/.tmp/home_dump_raw.json +176 -0
  106. package/providers/_builtin/ide/pearai/.tmp/items_raw.json +778 -0
  107. package/providers/_builtin/ide/pearai/.tmp/webview_dump.json +157 -0
  108. package/providers/_builtin/ide/pearai/.tmp/webview_dump_raw.json +161 -0
  109. package/providers/_builtin/ide/pearai/provider.json +1 -3
  110. package/providers/_builtin/ide/pearai/scripts/1.0/focus_editor.js +12 -16
  111. package/providers/_builtin/ide/pearai/scripts/1.0/list_models.js +45 -0
  112. package/providers/_builtin/ide/pearai/scripts/1.0/list_modes.js +44 -0
  113. package/providers/_builtin/ide/pearai/scripts/1.0/list_sessions.js +82 -27
  114. package/providers/_builtin/ide/pearai/scripts/1.0/new_session.js +26 -43
  115. package/providers/_builtin/ide/pearai/scripts/1.0/open_panel.js +10 -33
  116. package/providers/_builtin/ide/pearai/scripts/1.0/read_chat.js +169 -0
  117. package/providers/_builtin/ide/pearai/scripts/1.0/resolve_action.js +47 -41
  118. package/providers/_builtin/ide/pearai/scripts/1.0/scripts.js +36 -7
  119. package/providers/_builtin/ide/pearai/scripts/1.0/send_message.js +97 -22
  120. package/providers/_builtin/ide/pearai/scripts/1.0/set_mode.js +51 -0
  121. package/providers/_builtin/ide/pearai/scripts/1.0/set_model.js +54 -0
  122. package/providers/_builtin/ide/pearai/scripts/1.0/switch_session.js +81 -0
  123. package/providers/_builtin/ide/trae/scripts/1.0/focus_editor.js +2 -2
  124. package/providers/_builtin/ide/trae/scripts/1.0/list_chats.js +2 -2
  125. package/providers/_builtin/ide/trae/scripts/1.0/new_session.js +4 -4
  126. package/providers/_builtin/ide/trae/scripts/1.0/open_panel.js +6 -6
  127. package/providers/_builtin/ide/trae/scripts/1.0/read_chat.js +13 -13
  128. package/providers/_builtin/ide/trae/scripts/1.0/resolve_action.js +3 -3
  129. package/providers/_builtin/ide/trae/scripts/1.0/send_message.js +11 -11
  130. package/providers/_builtin/ide/trae/scripts/1.0/switch_session.js +2 -2
  131. package/providers/_builtin/ide/windsurf/scripts/1.0/focus_editor.js +6 -6
  132. package/providers/_builtin/ide/windsurf/scripts/1.0/list_chats.js +4 -4
  133. package/providers/_builtin/ide/windsurf/scripts/1.0/list_sessions.js +6 -6
  134. package/providers/_builtin/ide/windsurf/scripts/1.0/new_session.js +9 -9
  135. package/providers/_builtin/ide/windsurf/scripts/1.0/open_panel.js +6 -6
  136. package/providers/_builtin/ide/windsurf/scripts/1.0/resolve_action.js +8 -8
  137. package/providers/_builtin/ide/windsurf/scripts/1.0/switch_session.js +8 -8
  138. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/focus_editor.js +6 -6
  139. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_chats.js +12 -12
  140. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/new_session.js +15 -15
  141. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/open_panel.js +10 -10
  142. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/read_chat.js +33 -33
  143. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/resolve_action.js +6 -6
  144. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/send_message.js +16 -16
  145. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/switch_session.js +7 -7
  146. package/providers/_builtin/registry.json +76 -3
  147. package/src/cli-adapters/provider-cli-adapter.ts +267 -251
  148. package/src/cli-adapters/terminal-screen.ts +268 -0
  149. package/src/commands/chat-commands.ts +41 -15
  150. package/src/commands/cli-manager.ts +4 -2
  151. package/src/daemon/dev-server.ts +245 -35
  152. package/src/providers/acp-provider-instance.ts +1 -1
  153. package/src/providers/cli-provider-instance.ts +21 -8
  154. package/src/providers/provider-loader.ts +3 -2
  155. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_models.js +0 -43
  156. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_modes.js +0 -35
  157. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_sessions.js +0 -62
  158. package/providers/_builtin/ide/pearai/scripts/1.0/webview_new_session.js +0 -49
  159. package/providers/_builtin/ide/pearai/scripts/1.0/webview_read_chat.js +0 -92
  160. package/providers/_builtin/ide/pearai/scripts/1.0/webview_resolve_action.js +0 -59
  161. package/providers/_builtin/ide/pearai/scripts/1.0/webview_send_message.js +0 -72
  162. package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_mode.js +0 -36
  163. package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_model.js +0 -36
  164. package/providers/_builtin/ide/pearai/scripts/1.0/webview_switch_session.js +0 -34
@@ -1,38 +1,93 @@
1
1
  /**
2
- * PearAI — list_sessions (IDE 메인 프레임에서 실행)
3
- *
4
- * 히스토리 패널 토글 버튼을 클릭하여 히스토리 뷰를 오픈합니다.
5
- * 히스토리 뷰가 열리면 webviewListSessions로 항목을 읽을 수 있습니다.
2
+ * PearAI — webview_list_sessions (webview iframe runs inside)
3
+ *
4
+ * PearAI(Roo Code/Cline based) Session list extract.
5
+ * history task-item Tasks .
6
6
  */
7
7
  (() => {
8
8
  try {
9
- // Panel title bar에서 히스토리 관련 버튼 찾기
10
- const actionBtns = document.querySelectorAll('.action-item a.action-label, .action-item .action-label');
11
- for (const btn of actionBtns) {
12
- const title = (btn.getAttribute('title') || '').toLowerCase();
13
- const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
14
- const cls = btn.className || '';
15
-
16
- if (title.includes('history') || title.includes('히스토리') ||
17
- ariaLabel.includes('history') || ariaLabel.includes('히스토리') ||
18
- cls.includes('codicon-history')) {
19
- btn.click();
20
- return JSON.stringify({ toggled: true, method: 'panelAction', title: btn.getAttribute('title') });
21
- }
22
- }
9
+ const sessions = [];
10
+ const seen = new Set();
11
+
12
+ const pushSession = (session) => {
13
+ if (!session || !session.id || seen.has(session.id)) return;
14
+ seen.add(session.id);
15
+ sessions.push({
16
+ id: session.id,
17
+ title: (session.title || '').trim().slice(0, 120),
18
+ active: Boolean(session.active),
19
+ index: typeof session.index === 'number' ? session.index : sessions.length,
20
+ });
21
+ };
22
+
23
+ // ─── History items: data-testid="task-item-*" ───
24
+ const taskItems = document.querySelectorAll('[data-testid^="task-item-"]');
25
+
26
+ if (taskItems.length > 0) {
27
+ for (let i = 0; i < taskItems.length; i++) {
28
+ const item = taskItems[i];
29
+ if (!item) continue;
30
+
31
+ const testId = item.getAttribute('data-testid') || '';
32
+ const taskId = testId.replace('task-item-', '');
33
+
34
+ // Extract title from full text
35
+ const fullText = (item.textContent || '').trim();
23
36
 
24
- // Broader search
25
- const allBtns = document.querySelectorAll('a[title], button[title]');
26
- for (const btn of allBtns) {
27
- const title = (btn.getAttribute('title') || '').toLowerCase();
28
- if (title.includes('history') || title.includes('task history')) {
29
- btn.click();
30
- return JSON.stringify({ toggled: true, method: 'titleBtn', title: btn.getAttribute('title') });
37
+ // structure: "MARCH 16, 1:31 AM 173 B test123 Tokens:10.4k 229"
38
+ // strategy: Tokens: before last with text title use
39
+ let title = '';
40
+
41
+ // Extract date
42
+ // title extract: (B/kB) , Tokens: before
43
+ const titleMatch = fullText.match(/[AP]M[\d.\s]*[kMG]?B\s*(.*?)(?:Tokens:|$)/s);
44
+ if (titleMatch && titleMatch[1]) {
45
+ title = titleMatch[1].trim();
46
+ }
47
+
48
+ // fallback: first 80 chars
49
+ if (!title) {
50
+ title = fullText.substring(0, 80);
51
+ }
52
+
53
+ pushSession({
54
+ id: taskId || `task-${i}`,
55
+ title,
56
+ active: item.getAttribute('aria-selected') === 'true' || item.classList.contains('active'),
57
+ index: i,
58
+ });
31
59
  }
32
60
  }
33
61
 
34
- return JSON.stringify({ toggled: false, error: 'History toggle button not found' });
62
+ // ─── Tasks ───
63
+ const cards = Array.from(document.querySelectorAll('div')).filter((card) => {
64
+ const className = String(card.className || '');
65
+ const text = (card.textContent || '').trim();
66
+ return className.includes('bg-vscode-editor-background')
67
+ && className.includes('cursor-pointer')
68
+ && className.includes('overflow-hidden')
69
+ && !!card.querySelector('[data-testid="copy-prompt-button"]')
70
+ && /↑\s*\d|↓\s*\d/i.test(text)
71
+ && /MARCH|APRIL|MAY|JUNE|JULY|AUGUST|SEPTEMBER|OCTOBER|NOVEMBER|DECEMBER|JANUARY|FEBRUARY/i.test(text);
72
+ });
73
+
74
+ cards.forEach((card, index) => {
75
+ const text = (card.textContent || '').trim();
76
+ const prompt = card.querySelector('.text-vscode-foreground');
77
+ const title = (prompt?.textContent || text)
78
+ .replace(/\s*↑\s*\d[\d.,kKmM]*\s*↓\s*\d[\d.,kKmM]*/g, '')
79
+ .trim();
80
+
81
+ pushSession({
82
+ id: card.getAttribute('data-testid') || `card-${index}`,
83
+ title,
84
+ active: false,
85
+ index,
86
+ });
87
+ });
88
+
89
+ return JSON.stringify({ sessions, note: sessions.length ? undefined : 'No sessions found' });
35
90
  } catch (e) {
36
- return JSON.stringify({ toggled: false, error: e.message });
91
+ return JSON.stringify({ sessions: [], error: String(e.message || e) });
37
92
  }
38
93
  })()
@@ -1,55 +1,38 @@
1
1
  /**
2
- * PearAI — new_session (IDE 메인 프레임에서 실행)
3
- *
4
- * Panel title bar의 "+" 버튼(New Task)을 찾아 클릭합니다.
5
- * PearAI(Roo Code 기반)에서 새 태스크 버튼은 webview 바깥의 VS Code panel 헤더에 위치합니다.
2
+ * PearAI — webview_new_session
6
3
  */
7
4
  (() => {
8
5
  try {
9
- // Strategy 1: Find the codicon-add / plus button in panel title actions
10
- const actionBtns = document.querySelectorAll('.panel .title .actions-container .action-item a, .pane-header .actions-container .action-item a, .title-actions .action-item a');
11
- for (const btn of actionBtns) {
12
- const title = btn.getAttribute('title') || '';
13
- const ariaLabel = btn.getAttribute('aria-label') || '';
14
- const cls = btn.className || '';
15
-
16
- if (title.toLowerCase().includes('new task') ||
17
- title.toLowerCase().includes('new chat') ||
18
- ariaLabel.toLowerCase().includes('new task') ||
19
- ariaLabel.toLowerCase().includes('new chat') ||
20
- cls.includes('codicon-add') ||
21
- cls.includes('codicon-plus')) {
22
- btn.click();
23
- return JSON.stringify({ created: true, method: 'panelAction', title: title || ariaLabel });
24
- }
6
+ const click = (element) => {
7
+ if (!element) return false;
8
+ element.scrollIntoView({ block: 'center' });
9
+ element.focus?.();
10
+ element.click?.();
11
+ return true;
12
+ };
13
+
14
+ const closeTask = Array.from(document.querySelectorAll('button[title], button[aria-label]')).find((button) =>
15
+ /close task and start a new one/i.test(button.getAttribute('title') || '')
16
+ || /close task and start a new one/i.test(button.getAttribute('aria-label') || '')
17
+ );
18
+ if (click(closeTask)) {
19
+ return JSON.stringify({ created: true, method: 'close-task' });
25
20
  }
26
21
 
27
- // Strategy 2: Broader search for action items with "+" or "new"
28
- const allActions = document.querySelectorAll('.action-item a.action-label');
29
- for (const a of allActions) {
30
- const title = (a.getAttribute('title') || '').toLowerCase();
31
- const cls = a.className || '';
32
- if ((title.includes('new') && title.includes('task')) ||
33
- (title.includes('plus') || cls.includes('codicon-add'))) {
34
- a.click();
35
- return JSON.stringify({ created: true, method: 'actionLabel', title: a.getAttribute('title') });
36
- }
22
+ const startNewTask = Array.from(document.querySelectorAll('button, [role="button"], div.cursor-pointer')).find((element) =>
23
+ /start new task|new task|new chat/i.test((element.textContent || '').trim())
24
+ );
25
+ if (click(startNewTask)) {
26
+ return JSON.stringify({ created: true, method: 'start-new-task' });
37
27
  }
38
28
 
39
- // Strategy 3: Use keybinding (Cmd+Shift+P -> "new task")
40
- // Simulate keyboard shortcut for Roo Code: typically there's a command
41
- // registered as roo-cline.plusButtonClicked or similar
42
- const allBtns = document.querySelectorAll('a[title], button[title]');
43
- const matches = [];
44
- for (const btn of allBtns) {
45
- const t = btn.getAttribute('title') || '';
46
- if (t.toLowerCase().includes('new') || t.toLowerCase().includes('plus') || t === '+') {
47
- matches.push({ tag: btn.tagName, title: t, cls: (btn.className || '').substring(0, 60) });
48
- }
29
+ const cards = document.querySelectorAll('[data-testid="copy-prompt-button"]');
30
+ if (cards.length > 0) {
31
+ return JSON.stringify({ created: true, method: 'already-home' });
49
32
  }
50
33
 
51
- return JSON.stringify({ created: false, error: 'New Task button not found in panel', candidates: matches.slice(0, 5) });
52
- } catch (e) {
53
- return JSON.stringify({ created: false, error: e.message });
34
+ return JSON.stringify({ created: false, error: 'new session control not found' });
35
+ } catch (error) {
36
+ return JSON.stringify({ created: false, error: String(error && error.message || error) });
54
37
  }
55
38
  })()
@@ -1,46 +1,23 @@
1
1
  /**
2
2
  * PearAI — open_panel
3
- *
4
- * PearAI 채팅 패널 열기.
5
- * "Toggle PearAI Side Bar (⌘;)" 버튼으로 열기.
6
- *
7
- * 반환: 'visible' | 'opened' | 'error: ...'
8
3
  */
9
4
  (() => {
10
5
  try {
11
- // 1. 이미 열려 있는지 확인
12
6
  const sidebar = document.getElementById('workbench.parts.auxiliarybar');
13
7
  if (sidebar && sidebar.offsetWidth > 0 && sidebar.offsetHeight > 0) {
14
- return 'visible';
8
+ return JSON.stringify({ opened: true, visible: true });
15
9
  }
16
10
 
17
- // 2. Toggle 버튼 클릭 시도
18
- const toggleBtns = Array.from(document.querySelectorAll('li.action-item a, button, [role="button"]'));
19
- for (const btn of toggleBtns) {
20
- const label = (btn.getAttribute('aria-label') || '').toLowerCase();
21
- if (label.includes('toggle pearai') || label.includes('toggle secondary') ||
22
- label.includes('toggle auxiliary')) {
23
- if (btn.offsetWidth > 0 || btn.offsetHeight > 0) {
24
- btn.click();
25
- return 'opened (toggle)';
26
- }
27
- }
28
- }
11
+ const toggle = Array.from(document.querySelectorAll('a[aria-label], button[aria-label], [role="button"][aria-label]'))
12
+ .find((element) => /toggle pearai side bar|toggle pearai|toggle auxiliary/i.test(element.getAttribute('aria-label') || ''));
29
13
 
30
- // 3. Cmd+; 단축키 폴백 (PearAI 기본 단축키)
31
- document.dispatchEvent(new KeyboardEvent('keydown', {
32
- key: ';', code: 'Semicolon', keyCode: 186,
33
- metaKey: true, ctrlKey: false,
34
- bubbles: true, cancelable: true,
35
- }));
36
- document.dispatchEvent(new KeyboardEvent('keyup', {
37
- key: ';', code: 'Semicolon', keyCode: 186,
38
- metaKey: true, ctrlKey: false,
39
- bubbles: true, cancelable: true,
40
- }));
14
+ if (!toggle) {
15
+ return JSON.stringify({ opened: false, error: 'toggle not found' });
16
+ }
41
17
 
42
- return 'opened (⌘;)';
43
- } catch (e) {
44
- return 'error: ' + e.message;
18
+ toggle.click();
19
+ return JSON.stringify({ opened: true });
20
+ } catch (error) {
21
+ return JSON.stringify({ opened: false, error: String(error && error.message || error) });
45
22
  }
46
23
  })()
@@ -0,0 +1,169 @@
1
+ /**
2
+ * PearAI — webview_read_chat
3
+ */
4
+ (() => {
5
+ try {
6
+ const normalize = (value) => String(value || '').replace(/\r/g, '').replace(/\u00a0/g, ' ');
7
+ const collapse = (value) => normalize(value).replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n').trim();
8
+ const fence = '```';
9
+
10
+ const markdownFromNode = (node, depth = 0) => {
11
+ if (!node || depth > 20) return '';
12
+ if (node.nodeType === Node.TEXT_NODE) return node.nodeValue || '';
13
+ if (node.nodeType !== Node.ELEMENT_NODE) return '';
14
+
15
+ const tag = node.tagName.toLowerCase();
16
+ const children = () => Array.from(node.childNodes).map((child) => markdownFromNode(child, depth + 1)).join('');
17
+
18
+ if (tag === 'br') return '\n';
19
+ if (tag === 'hr') return '\n---\n\n';
20
+ if (tag === 'strong' || tag === 'b') return `**${children().trim()}**`;
21
+ if (tag === 'em' || tag === 'i') return `*${children().trim()}*`;
22
+ if (tag === 'code' && node.parentElement?.tagName?.toLowerCase() !== 'pre') return `\`${node.textContent || ''}\``;
23
+ if (tag === 'pre') {
24
+ const code = normalize(node.textContent || '').replace(/^\n+|\n+$/g, '');
25
+ const lang = Array.from(node.querySelectorAll('code')).map((codeNode) => {
26
+ const match = String(codeNode.className || '').match(/language-([\w-]+)/);
27
+ return match ? match[1] : '';
28
+ }).find(Boolean) || '';
29
+ return `\n\n${fence}${lang}\n${code}\n${fence}\n\n`;
30
+ }
31
+ if (tag === 'a') {
32
+ const text = collapse(children()) || collapse(node.textContent || '');
33
+ const href = node.getAttribute('href') || '';
34
+ return href ? `[${text}](${href})` : text;
35
+ }
36
+ if (tag === 'li') return `- ${collapse(children())}\n`;
37
+ if (tag === 'ul' || tag === 'ol') return `\n${Array.from(node.children).map((child) => markdownFromNode(child, depth + 1)).join('')}\n`;
38
+ if (tag === 'p') return `${children().trim()}\n\n`;
39
+ if (tag === 'table') {
40
+ const rows = Array.from(node.querySelectorAll('tr')).map((row) => Array.from(row.children).map((cell) => collapse(markdownFromNode(cell, depth + 1)) || collapse(cell.textContent || '')));
41
+ if (!rows.length) return '';
42
+ const header = rows[0];
43
+ const divider = header.map(() => '---');
44
+ const body = rows.slice(1);
45
+ return `\n| ${header.join(' | ')} |\n| ${divider.join(' | ')} |\n${body.map((row) => `| ${row.join(' | ')} |`).join('\n')}\n\n`;
46
+ }
47
+ if (tag === 'button') return '';
48
+ return children();
49
+ };
50
+
51
+ const title = collapse(
52
+ document.querySelector('.font-bold + .ml-1')?.textContent
53
+ || document.querySelector('.font-bold')?.nextElementSibling?.textContent
54
+ || ''
55
+ ).replace(/^Task:\s*/i, '');
56
+ const input = document.querySelector('textarea[placeholder*="Type your task" i]') || document.querySelector('textarea');
57
+ const inputContent = input ? input.value || '' : '';
58
+
59
+ const rawItems = Array.from(document.querySelectorAll('[data-item-index]')).map((element) => ({
60
+ element,
61
+ text: collapse(element.innerText || element.textContent || ''),
62
+ })).filter((item) => item.text);
63
+
64
+ const messages = [];
65
+ let activeModal = null;
66
+
67
+ if (title) {
68
+ messages.push({ role: 'user', content: title, index: messages.length });
69
+ }
70
+
71
+ const significant = rawItems.filter((item) => !/^API Request(?:\n|$)/i.test(item.text) && !/^Initial Checkpoint(?:\n|$)/i.test(item.text));
72
+
73
+ for (let itemIndex = 0; itemIndex < significant.length; itemIndex += 1) {
74
+ const item = significant[itemIndex];
75
+ const { element, text } = item;
76
+
77
+ if (/^Thinking$/i.test(text)) continue;
78
+ if (element.querySelector('.codicon-trash')) {
79
+ messages.push({ role: 'user', content: text, index: messages.length });
80
+ continue;
81
+ }
82
+
83
+ if (element.querySelector('.codicon-terminal') || /^Run Command:/i.test(text)) {
84
+ const command = collapse(element.querySelector('.font-mono')?.textContent || text.replace(/^Run Command:\s*/i, ''));
85
+ messages.push({
86
+ role: 'assistant',
87
+ content: command ? `${fence}sh\n${command}\n${fence}` : 'Run Command',
88
+ kind: 'terminal',
89
+ meta: { label: 'Run Command' },
90
+ index: messages.length,
91
+ });
92
+ continue;
93
+ }
94
+
95
+ if (element.querySelector('.text-muted-foreground') && text.startsWith('...')) {
96
+ messages.push({
97
+ role: 'assistant',
98
+ content: text.replace(/^\.\.\.\s*/, ''),
99
+ kind: 'thought',
100
+ meta: { label: 'Thinking' },
101
+ index: messages.length,
102
+ });
103
+ continue;
104
+ }
105
+
106
+ if (element.querySelector('.codicon-question') || /^Agent has a question:/i.test(text)) {
107
+ const contentNode = element.querySelector('.sc-fkSzgi') || element;
108
+ let content = collapse(markdownFromNode(contentNode));
109
+ const actions = Array.from(element.querySelectorAll('button[aria-label]')).map((button) => collapse(button.getAttribute('aria-label') || button.textContent || '')).filter(Boolean);
110
+ if (actions.length) {
111
+ content = `${content}\n\n${actions.map((action) => `- ${action}`).join('\n')}`.trim();
112
+ if (itemIndex === significant.length - 1) {
113
+ activeModal = { title: 'Agent has a question', actions };
114
+ }
115
+ }
116
+ messages.push({ role: 'assistant', content, index: messages.length });
117
+ continue;
118
+ }
119
+
120
+ if (element.querySelector('.codicon-check') && /^Task Completed/i.test(text)) {
121
+ const contentNode = element.querySelector('.sc-fkSzgi') || element;
122
+ const content = collapse(markdownFromNode(contentNode).replace(/^Task Completed\s*/i, ''));
123
+ messages.push({ role: 'assistant', content, index: messages.length });
124
+ continue;
125
+ }
126
+
127
+ const markdownNode = element.querySelector('.sc-fkSzgi') || element;
128
+ const content = collapse(markdownFromNode(markdownNode));
129
+ if (content) {
130
+ messages.push({ role: 'assistant', content, index: messages.length });
131
+ }
132
+ }
133
+
134
+ let status = 'idle';
135
+ const visibleButtons = Array.from(document.querySelectorAll('button')).filter((button) => {
136
+ const rect = button.getBoundingClientRect();
137
+ return rect.width > 0 && rect.height > 0;
138
+ });
139
+
140
+ const actionButtons = visibleButtons
141
+ .map((button) => collapse(button.textContent || button.getAttribute('aria-label') || ''))
142
+ .filter((text) => /approve|accept|allow|run|save|reject|deny|abort/i.test(text));
143
+ if (!activeModal && actionButtons.length >= 2) {
144
+ activeModal = { title: 'Action Required', actions: actionButtons };
145
+ }
146
+ if (activeModal?.actions?.length) {
147
+ status = 'waiting_approval';
148
+ }
149
+
150
+ const generatingIndicators = [
151
+ ...visibleButtons.map((button) => collapse(button.textContent || button.getAttribute('aria-label') || '')),
152
+ collapse(document.body.innerText || ''),
153
+ ].join('\n');
154
+ if (/cancel|stop generating|streaming|responding/i.test(generatingIndicators)) {
155
+ status = activeModal?.actions?.length ? 'waiting_approval' : 'generating';
156
+ }
157
+
158
+ return JSON.stringify({
159
+ id: 'pearai-agent',
160
+ title: title || undefined,
161
+ status,
162
+ messages,
163
+ inputContent: inputContent || undefined,
164
+ activeModal: activeModal || undefined,
165
+ });
166
+ } catch (error) {
167
+ return JSON.stringify({ id: 'pearai-agent', status: 'error', messages: [], error: String(error && error.message || error) });
168
+ }
169
+ })()
@@ -1,54 +1,60 @@
1
1
  /**
2
- * PearAI — resolve_action
2
+ * PearAI — webview_resolve_action
3
3
  *
4
- * 승인/거부 버튼 찾기 + 좌표 반환.
5
- * PearAI의 approval 다이얼로그는 메인 DOM에 표시됨.
4
+ * PearAI Agent(Roo Code based)renders approve/reject button inside webview.
5
+ * button click() event .
6
6
  *
7
- * 파라미터: ${ BUTTON_TEXT }
7
+ * Parameter: ${ BUTTON_TEXT }
8
8
  */
9
9
  (() => {
10
- const want = ${ BUTTON_TEXT };
11
- const wantNorm = (want || '').replace(/\s+/g, ' ').trim().toLowerCase();
10
+ try {
11
+ const doc = document.getElementById("active-frame")?.contentDocument || document;
12
+ const want = ${ BUTTON_TEXT };
13
+ const wantNorm = (want || '').replace(/\s+/g, ' ').trim().toLowerCase();
12
14
 
13
- function norm(t) { return (t || '').replace(/\s+/g, ' ').trim().toLowerCase(); }
15
+ function norm(t) { return (t || '').replace(/\s+/g, ' ').trim().toLowerCase(); }
14
16
 
15
- function matches(el) {
16
- const t = norm(el.textContent);
17
- if (!t || t.length > 80) return false;
18
- if (t === wantNorm) return true;
19
- if (t.indexOf(wantNorm) === 0) return true;
20
- if (wantNorm.indexOf(t) >= 0 && t.length > 2) return true;
21
- if (/^(run|approve|allow|accept|yes)\b/.test(wantNorm)) {
22
- if (/^(run|allow|accept|approve)\b/.test(t)) return true;
17
+ function matches(el) {
18
+ const t = norm(el.textContent);
19
+ if (!t || t.length > 80) return false;
20
+ if (t === wantNorm) return true;
21
+ if (t.indexOf(wantNorm) === 0) return true;
22
+ if (wantNorm.indexOf(t) >= 0 && t.length > 2) return true;
23
+ if (/^(run|approve|allow|accept|yes)\b/.test(wantNorm)) {
24
+ if (/^(run|allow|accept|approve|save)\b/.test(t)) return true;
25
+ }
26
+ if (/^(reject|deny|no|abort)\b/.test(wantNorm)) {
27
+ if (/^(reject|deny)\b/.test(t)) return true;
28
+ }
29
+ return false;
23
30
  }
24
- if (/^(reject|deny|no|abort)\b/.test(wantNorm)) {
25
- if (/^(reject|deny)\b/.test(t)) return true;
26
- }
27
- return false;
28
- }
29
31
 
30
- const sel = 'button, [role="button"], .monaco-button';
31
- const allBtns = [...document.querySelectorAll(sel)].filter(b => {
32
- if (!b.offsetWidth || !b.getBoundingClientRect().height) return false;
33
- const rect = b.getBoundingClientRect();
34
- return rect.y > 0 && rect.y < window.innerHeight;
35
- });
32
+ const sel = 'button, [role="button"], .vsc-button';
33
+ const allBtns = [...doc.querySelectorAll(sel)].filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
36
34
 
37
- let found = null;
38
- for (let i = allBtns.length - 1; i >= 0; i--) {
39
- if (matches(allBtns[i])) { found = allBtns[i]; break; }
40
- }
35
+ let found = null;
36
+ for (let i = allBtns.length - 1; i >= 0; i--) {
37
+ if (matches(allBtns[i])) { found = allBtns[i]; break; }
38
+ }
41
39
 
42
- if (found) {
43
- const rect = found.getBoundingClientRect();
44
- return JSON.stringify({
45
- found: true,
46
- text: found.textContent?.trim()?.substring(0, 40),
47
- x: Math.round(rect.x + rect.width / 2),
48
- y: Math.round(rect.y + rect.height / 2),
49
- w: Math.round(rect.width),
50
- h: Math.round(rect.height)
51
- });
40
+ if (found) {
41
+ found.focus?.();
42
+ const rect = found.getBoundingClientRect();
43
+ const x = rect.left + rect.width / 2;
44
+ const y = rect.top + rect.height / 2;
45
+ for (const type of ['pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click']) {
46
+ found.dispatchEvent(new PointerEvent(type, {
47
+ bubbles: true, cancelable: true, view: window,
48
+ clientX: x, clientY: y, pointerId: 1, pointerType: 'mouse'
49
+ }));
50
+ }
51
+ return JSON.stringify({
52
+ resolved: true,
53
+ clicked: found.textContent || wantNorm
54
+ });
55
+ }
56
+ return JSON.stringify({ resolved: false, error: 'Button not found: ' + wantNorm });
57
+ } catch (e) {
58
+ return JSON.stringify({ resolved: false, error: e.message });
52
59
  }
53
- return JSON.stringify({ found: false, want: wantNorm });
54
60
  })()
@@ -25,36 +25,61 @@ function withParams(name, params) {
25
25
  // For legacy scripts checking MESSAGE, interpolate them manually
26
26
  if (script.includes('${ MESSAGE }')) {
27
27
  const msg = params?.MESSAGE || params?.text || '';
28
- return script.replace(/\$\{ MESSAGE \}/g, JSON.stringify(msg));
28
+ script = script.replace(/\$\{ MESSAGE \}/g, JSON.stringify(msg));
29
29
  }
30
30
  if (script.includes('${ BUTTON_TEXT }')) {
31
31
  const btn = params?.BUTTON_TEXT || params?.buttonText || '';
32
- return script.replace(/\$\{ BUTTON_TEXT \}/g, JSON.stringify(btn));
32
+ script = script.replace(/\$\{ BUTTON_TEXT \}/g, JSON.stringify(btn));
33
+ }
34
+ if (script.includes('${ MODE }')) {
35
+ const mode = params?.mode || '';
36
+ script = script.replace(/\$\{ MODE \}/g, JSON.stringify(mode));
37
+ }
38
+ if (script.includes('${ MODEL }')) {
39
+ const model = params?.model || '';
40
+ script = script.replace(/\$\{ MODEL \}/g, JSON.stringify(model));
41
+ }
42
+ if (script.includes('${ INDEX }')) {
43
+ const index = params?.index ?? 0;
44
+ script = script.replace(/\$\{ INDEX \}/g, JSON.stringify(index));
45
+ }
46
+ if (script.includes('${ TITLE }')) {
47
+ const title = params?.title || '';
48
+ script = script.replace(/\$\{ TITLE \}/g, JSON.stringify(title));
49
+ }
50
+
51
+ if (!script.includes('${')) {
52
+ return script;
33
53
  }
34
54
 
35
55
  return `(${script})(${JSON.stringify(params)})`;
36
56
  }
37
57
 
38
- // ─── Core (no params — IIFE) ───
58
+ module.exports.readChat = () => load('read_chat.js');
59
+ module.exports.webviewReadChat = module.exports.readChat;
39
60
 
40
- module.exports.readChat = () => load('read_chat.js') || load('webview_read_chat.js');
41
61
  module.exports.sendMessage = (params) => {
42
62
  let s = load('send_message.js');
43
- if (!s) s = load('webview_send_message.js');
44
63
  if (!s) return null;
45
- // Legacy template substitution fallback
46
64
  if (s.includes('${ MESSAGE }')) {
47
65
  const msg = params?.MESSAGE || params?.text || params || '';
48
66
  return s.replace(/\$\{ MESSAGE \}/g, JSON.stringify(msg));
49
67
  }
50
- return withParams('send_message.js', params) || withParams('webview_send_message.js', params);
68
+ return withParams('send_message.js', params);
51
69
  };
70
+ module.exports.webviewSendMessage = module.exports.sendMessage;
71
+
52
72
  module.exports.listSessions = () => load('list_sessions.js');
73
+ module.exports.webviewListSessions = module.exports.listSessions;
53
74
  module.exports.newSession = () => load('new_session.js');
75
+ module.exports.webviewNewSession = module.exports.newSession;
54
76
  module.exports.focusEditor = () => load('focus_editor.js');
77
+ module.exports.webviewFocusEditor = module.exports.focusEditor;
55
78
  module.exports.openPanel = () => load('open_panel.js');
56
79
  module.exports.listModels = () => load('list_models.js');
80
+ module.exports.webviewListModels = module.exports.listModels;
57
81
  module.exports.listModes = () => load('list_modes.js');
82
+ module.exports.webviewListModes = module.exports.listModes;
58
83
 
59
84
  // ─── With params (function expression) ───
60
85
 
@@ -63,6 +88,7 @@ module.exports.switchSession = (params) => {
63
88
  const title = typeof params === 'string' ? params : params?.title || null;
64
89
  return withParams('switch_session.js', { index, title });
65
90
  };
91
+ module.exports.webviewSwitchSession = module.exports.switchSession;
66
92
 
67
93
  module.exports.resolveAction = (params) => {
68
94
  const action = typeof params === 'string' ? params : params?.action || 'approve';
@@ -70,13 +96,16 @@ module.exports.resolveAction = (params) => {
70
96
  || (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : action);
71
97
  return withParams('resolve_action.js', { buttonText, BUTTON_TEXT: buttonText });
72
98
  };
99
+ module.exports.webviewResolveAction = module.exports.resolveAction;
73
100
 
74
101
  module.exports.setModel = (params) => {
75
102
  const model = typeof params === 'string' ? params : params?.model;
76
103
  return withParams('set_model.js', { model });
77
104
  };
105
+ module.exports.webviewSetModel = module.exports.setModel;
78
106
 
79
107
  module.exports.setMode = (params) => {
80
108
  const mode = typeof params === 'string' ? params : params?.mode;
81
109
  return withParams('set_mode.js', { mode });
82
110
  };
111
+ module.exports.webviewSetMode = module.exports.setMode;