@adhdev/daemon-core 0.5.7 → 0.5.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.5.7",
3
+ "version": "0.5.16",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -61,40 +61,50 @@
61
61
  "spawn": {
62
62
  "command": "claude",
63
63
  "args": [],
64
- "shell": false,
64
+ "shell": true,
65
65
  "env": {}
66
66
  },
67
67
  "patterns": {
68
68
  "prompt": [
69
- {},
70
- {},
71
- {},
72
- {},
73
- {},
74
- {},
75
- {}
69
+ { "source": "Type your message", "flags": "i" },
70
+ { "source": "^>\\s*$", "flags": "m" },
71
+ { "source": "[›❯]\\s*[\\r\\n]", "flags": "" },
72
+ { "source": "[›❯]\\s*$", "flags": "m" },
73
+ { "source": "for\\s*shortcuts", "flags": "i" },
74
+ { "source": "\\?\\s*for\\s*help", "flags": "i" },
75
+ { "source": "Press enter", "flags": "i" }
76
76
  ],
77
77
  "generating": [
78
- {},
79
- {},
80
- {},
81
- {},
82
- {}
78
+ { "source": "[\\u2800-\\u28ff]", "flags": "" },
79
+ { "source": "esc to (cancel|interrupt|stop)", "flags": "i" },
80
+ { "source": "generating\\.\\.\\.", "flags": "i" },
81
+ { "source": "Claude is (?:thinking|processing|working)", "flags": "i" },
82
+ { "source": "Flummoxing", "flags": "i" }
83
83
  ],
84
84
  "approval": [
85
- {},
86
- {},
87
- {},
88
- {},
89
- {},
90
- {},
91
- {},
92
- {},
93
- {}
85
+ { "source": "Allow\\s*once", "flags": "i" },
86
+ { "source": "Always\\s*allow", "flags": "i" },
87
+ { "source": "\\(y/n\\)", "flags": "i" },
88
+ { "source": "\\[Y/n\\]", "flags": "i" },
89
+ { "source": "Run\\s*this\\s*command", "flags": "i" },
90
+ { "source": "Allow\\s*tool", "flags": "i" },
91
+ { "source": "Yes,?\\s*don'?t\\s*ask", "flags": "i" },
92
+ { "source": "Deny", "flags": "i" },
93
+ { "source": "Do you want to proceed", "flags": "i" }
94
94
  ],
95
95
  "ready": [
96
- {},
97
- {}
96
+ { "source": "for\\s*shortcuts", "flags": "i" },
97
+ { "source": "[›❯]\\s*$", "flags": "m" }
98
+ ],
99
+ "dialog": [
100
+ { "source": "Quick safety check", "flags": "i" },
101
+ { "source": "Is this a project", "flags": "i" },
102
+ { "source": "Enter to confirm", "flags": "i" }
98
103
  ]
104
+ },
105
+ "approvalKeys": {
106
+ "0": "1",
107
+ "1": "2",
108
+ "2": "3"
99
109
  }
100
110
  }
@@ -65,29 +65,36 @@
65
65
  },
66
66
  "patterns": {
67
67
  "prompt": [
68
- {},
69
- {},
70
- {}
68
+ { "source": "\\?\\s*for\\s*shortcuts", "flags": "i" },
69
+ { "source": "^>\\s*$", "flags": "m" },
70
+ { "source": "[›❯]\\s*$", "flags": "m" },
71
+ { "source": "sandbox", "flags": "i" },
72
+ { "source": "Type your message", "flags": "i" }
71
73
  ],
72
74
  "generating": [
73
- {},
74
- {},
75
- {},
76
- {},
77
- {},
78
- {}
75
+ { "source": "[\\u2800-\\u28ff]", "flags": "" },
76
+ { "source": "[▀▄▌▐░▒▓█]", "flags": "" },
77
+ { "source": "Thinking", "flags": "i" },
78
+ { "source": "Generating", "flags": "i" },
79
+ { "source": "esc to (cancel|interrupt|stop)", "flags": "i" }
79
80
  ],
80
81
  "approval": [
81
- {},
82
- {},
83
- {},
84
- {},
85
- {},
86
- {}
82
+ { "source": "Allow\\s*once", "flags": "i" },
83
+ { "source": "Always\\s*allow", "flags": "i" },
84
+ { "source": "\\(y/n\\)", "flags": "i" },
85
+ { "source": "\\[Y/n\\]", "flags": "i" },
86
+ { "source": "Run\\s*this\\s*command", "flags": "i" },
87
+ { "source": "Deny", "flags": "i" },
88
+ { "source": "auto-?approve", "flags": "i" }
87
89
  ],
88
90
  "ready": [
89
- {},
90
- {}
91
+ { "source": "\\?\\s*for\\s*shortcuts", "flags": "i" },
92
+ { "source": "sandbox", "flags": "i" }
91
93
  ]
94
+ },
95
+ "approvalKeys": {
96
+ "0": "y",
97
+ "1": "a",
98
+ "2": "n"
92
99
  }
93
100
  }
@@ -63,6 +63,27 @@
63
63
  "label": "Long Generation Threshold (sec)",
64
64
  "min": 30,
65
65
  "max": 600
66
+ },
67
+ "showThinking": {
68
+ "type": "boolean",
69
+ "default": true,
70
+ "public": true,
71
+ "label": "Show Thinking",
72
+ "description": "Display AI thinking/reasoning process in chat"
73
+ },
74
+ "showToolCalls": {
75
+ "type": "boolean",
76
+ "default": true,
77
+ "public": true,
78
+ "label": "Show Tool Calls",
79
+ "description": "Display tool call summaries (Searched, Analyzed, Edited, etc.)"
80
+ },
81
+ "showTerminal": {
82
+ "type": "boolean",
83
+ "default": true,
84
+ "public": true,
85
+ "label": "Show Terminal",
86
+ "description": "Display terminal command execution and output"
66
87
  }
67
88
  }
68
89
  }
@@ -1,17 +1,15 @@
1
1
  /**
2
2
  * Antigravity v1 — resolve_action
3
- *
4
- * 버튼 찾기 + 좌표 반환 (CDP Input.dispatchMouseEvent로 클릭)
3
+ *
4
+ * 스크롤 최하단 scrollIntoView .click()
5
5
  * 파라미터: ${BUTTON_TEXT}
6
- *
7
- * 핵심: viewport 안에 보이는 버튼 중 마지막(최신) 매칭 우선
8
6
  */
9
7
  (() => {
10
8
  const want = ${ BUTTON_TEXT };
11
9
  const wantNorm = (want || '').replace(/\s+/g, ' ').trim().toLowerCase();
12
-
10
+
13
11
  function norm(t) { return (t || '').replace(/\s+/g, ' ').trim().toLowerCase(); }
14
-
12
+
15
13
  function matches(el) {
16
14
  const raw = (el.textContent || '').trim();
17
15
  const t = norm(raw);
@@ -35,15 +33,16 @@
35
33
  }
36
34
  return false;
37
35
  }
38
-
36
+
37
+ // 1. 채팅 패널 스크롤을 최하단으로
38
+ const conv = document.querySelector('.antigravity-agent-side-panel') || document.querySelector('#conversation');
39
+ const scrollEl = conv ? (conv.querySelector('.overflow-y-auto') || conv) : null;
40
+ if (scrollEl) scrollEl.scrollTop = scrollEl.scrollHeight;
41
+
42
+ // 2. viewport 필터 없이 DOM에 있는 모든 visible 버튼 검색
39
43
  const sel = 'button, [role="button"]';
40
- const allBtns = [...document.querySelectorAll(sel)].filter(b => {
41
- if (!b.offsetWidth || !b.getBoundingClientRect().height) return false;
42
- const rect = b.getBoundingClientRect();
43
- // viewport 안에 보이는 것만 (y > 0, y < window.innerHeight)
44
- return rect.y > 0 && rect.y < window.innerHeight;
45
- });
46
-
44
+ const allBtns = [...document.querySelectorAll(sel)].filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
45
+
47
46
  // 마지막(최신) 매칭 우선 — 역순 검색
48
47
  let found = null;
49
48
  for (let i = allBtns.length - 1; i >= 0; i--) {
@@ -52,17 +51,13 @@
52
51
  break;
53
52
  }
54
53
  }
55
-
54
+
56
55
  if (found) {
57
- const rect = found.getBoundingClientRect();
58
- return JSON.stringify({
59
- found: true,
60
- text: found.textContent?.trim()?.substring(0, 40),
61
- x: Math.round(rect.x + rect.width / 2),
62
- y: Math.round(rect.y + rect.height / 2),
63
- w: Math.round(rect.width),
64
- h: Math.round(rect.height)
65
- });
56
+ const text = found.textContent?.trim()?.substring(0, 40);
57
+ // 버튼이 화면에 보이도록 스크롤 후 클릭
58
+ try { found.scrollIntoView({ block: 'nearest' }); } catch (_) {}
59
+ try { found.click(); } catch (_) {}
60
+ return JSON.stringify({ resolved: true, clicked: text });
66
61
  }
67
62
  return JSON.stringify({ found: false, want: wantNorm });
68
63
  })()
@@ -155,7 +155,7 @@
155
155
  const hash = 'user:' + text.slice(0, 200);
156
156
  if (seenHashes.has(hash)) continue;
157
157
  seenHashes.add(hash);
158
- collected.push({ role: 'user', text, el });
158
+ collected.push({ role: 'user', text, el, kind: 'standard' });
159
159
  }
160
160
  }
161
161
 
@@ -164,6 +164,8 @@
164
164
  for (const ab of assistantBlocks) {
165
165
  if (ab.offsetHeight < 10) continue;
166
166
  if (ab.closest('[class*="max-h-"][class*="overflow-y-auto"]')) continue;
167
+ // Thought 내부의 블록은 제외 (thinking으로 별도 수집)
168
+ if (ab.closest('.isolate')?.querySelector('button')?.textContent?.startsWith('Thought for')) continue;
167
169
 
168
170
  let text = getCleanMd(ab);
169
171
  if (!text || text.length < 2) continue;
@@ -172,7 +174,66 @@
172
174
  const hash = 'assistant:' + text.slice(0, 200);
173
175
  if (seenHashes.has(hash)) continue;
174
176
  seenHashes.add(hash);
175
- collected.push({ role: 'assistant', text, el: ab });
177
+ collected.push({ role: 'assistant', text, el: ab, kind: 'standard' });
178
+ }
179
+
180
+ // ─── Thought 수집 (AI 사고 과정) ───
181
+ const thoughtBtns = scroll.querySelectorAll('button');
182
+ for (const btn of thoughtBtns) {
183
+ const label = (btn.textContent || '').trim();
184
+ if (!label.startsWith('Thought for')) continue;
185
+ const sibling = btn.nextElementSibling;
186
+ if (!sibling) continue;
187
+ // 실제 thinking 텍스트는 sibling 내부의 .leading-relaxed.select-text에 있음
188
+ const contentEl = sibling.querySelector('.leading-relaxed.select-text');
189
+ if (!contentEl) continue;
190
+ const clone = contentEl.cloneNode(true);
191
+ clone.querySelectorAll('button, svg, style, script, [role="button"]').forEach(n => n.remove());
192
+ const thinkText = (clone.innerText || clone.textContent || '').trim();
193
+ if (!thinkText || thinkText.length < 5) continue;
194
+ const hash = 'think:' + thinkText.slice(0, 200);
195
+ if (seenHashes.has(hash)) continue;
196
+ seenHashes.add(hash);
197
+ // 순수 텍스트만 전달 (마크다운 포맷은 프론트엔드에서 처리)
198
+ collected.push({ role: 'assistant', text: thinkText.slice(0, 3000), el: btn, kind: 'thought', meta: { label } });
199
+ }
200
+
201
+ // ─── Terminal/Tool Call 수집 (명령 실행 결과) ───
202
+ const termHeaders = scroll.querySelectorAll('div.mb-1.px-2.py-1');
203
+ for (const h of termHeaders) {
204
+ const spanEl = h.querySelector('span');
205
+ const label = (spanEl?.textContent || '').trim();
206
+ if (!label.match(/^(Ran|Running) command/i)) continue;
207
+ const parent = h.parentElement;
208
+ if (!parent) continue;
209
+ const pre = parent.querySelector('pre');
210
+ const cmdText = (pre?.textContent || '').trim();
211
+ if (!cmdText || cmdText.length < 2) continue;
212
+ const hash = 'term:' + cmdText.slice(0, 200);
213
+ if (seenHashes.has(hash)) continue;
214
+ seenHashes.add(hash);
215
+ // 순수 텍스트만 전달 (라벨/아이콘은 프론트엔드에서 처리)
216
+ const isRunning = label.startsWith('Running');
217
+ collected.push({ role: 'assistant', text: cmdText.slice(0, 3000), el: h, kind: 'terminal', meta: { label, isRunning } });
218
+ }
219
+
220
+ // ─── Tool Call 요약 수집 (Searched, Analyzed, Edited 등) ───
221
+ const toolDivs = scroll.querySelectorAll('div[data-tooltip-id]');
222
+ for (const td of toolDivs) {
223
+ const cls = (td.className || '').toString();
224
+ if (!cls.includes('cursor-pointer') || !cls.includes('text-sm')) continue;
225
+ // span 단위로 읽어서 공백으로 연결 (textContent는 "SearchedDevServer"처럼 붙음)
226
+ const spans = td.querySelectorAll('span');
227
+ const text = spans.length > 0
228
+ ? Array.from(spans).map(s => (s.textContent || '').trim()).filter(Boolean).join(' ')
229
+ : (td.textContent || '').trim();
230
+ if (!text.match(/^(Searched|Analyzed|Edited|Read|Viewed|Created|Listed|Checked)/)) continue;
231
+ if (text.length > 120) continue;
232
+ const hash = 'tool:' + text;
233
+ if (seenHashes.has(hash)) continue;
234
+ seenHashes.add(hash);
235
+ // 간결하게 한 줄 요약
236
+ collected.push({ role: 'assistant', text: text, el: td, kind: 'tool' });
176
237
  }
177
238
 
178
239
  // 3. DOM 순서 정렬
@@ -183,15 +244,16 @@
183
244
  return 0;
184
245
  });
185
246
 
186
- // 최신 30개만 유지 (대화 로드 시 수백 개 수집 방지)
187
- const trimmed = collected.length > 30 ? collected.slice(-30) : collected;
247
+ // 최신 50개만 유지 (thinking/tool_use 포함으로 늘림)
248
+ const trimmed = collected.length > 50 ? collected.slice(-50) : collected;
188
249
 
189
250
  const final = trimmed.map((m, i) => ({
190
251
  id: 'msg_' + i,
191
252
  role: m.role,
192
253
  content: m.text.length > 6000 ? m.text.slice(0, 6000) + '\n[... truncated]' : m.text,
193
254
  index: i,
194
- kind: 'standard',
255
+ kind: m.kind || 'standard',
256
+ meta: m.meta || undefined,
195
257
  vsc_history: true
196
258
  }));
197
259
 
@@ -1,17 +1,15 @@
1
1
  /**
2
2
  * Antigravity v1 — resolve_action
3
- *
4
- * 버튼 찾기 + 좌표 반환 (CDP Input.dispatchMouseEvent로 클릭)
3
+ *
4
+ * 스크롤 최하단 scrollIntoView .click()
5
5
  * 파라미터: ${BUTTON_TEXT}
6
- *
7
- * 핵심: viewport 안에 보이는 버튼 중 마지막(최신) 매칭 우선
8
6
  */
9
7
  (() => {
10
8
  const want = ${ BUTTON_TEXT };
11
9
  const wantNorm = (want || '').replace(/\s+/g, ' ').trim().toLowerCase();
12
-
10
+
13
11
  function norm(t) { return (t || '').replace(/\s+/g, ' ').trim().toLowerCase(); }
14
-
12
+
15
13
  function matches(el) {
16
14
  const raw = (el.textContent || '').trim();
17
15
  const t = norm(raw);
@@ -35,15 +33,16 @@
35
33
  }
36
34
  return false;
37
35
  }
38
-
36
+
37
+ // 1. 채팅 패널 스크롤을 최하단으로
38
+ const conv = document.querySelector('.antigravity-agent-side-panel') || document.querySelector('#conversation');
39
+ const scrollEl = conv ? (conv.querySelector('.overflow-y-auto') || conv) : null;
40
+ if (scrollEl) scrollEl.scrollTop = scrollEl.scrollHeight;
41
+
42
+ // 2. viewport 필터 없이 DOM에 있는 모든 visible 버튼 검색
39
43
  const sel = 'button, [role="button"]';
40
- const allBtns = [...document.querySelectorAll(sel)].filter(b => {
41
- if (!b.offsetWidth || !b.getBoundingClientRect().height) return false;
42
- const rect = b.getBoundingClientRect();
43
- // viewport 안에 보이는 것만 (y > 0, y < window.innerHeight)
44
- return rect.y > 0 && rect.y < window.innerHeight;
45
- });
46
-
44
+ const allBtns = [...document.querySelectorAll(sel)].filter(b => b.offsetWidth > 0 && b.offsetHeight > 0);
45
+
47
46
  // 마지막(최신) 매칭 우선 — 역순 검색
48
47
  let found = null;
49
48
  for (let i = allBtns.length - 1; i >= 0; i--) {
@@ -52,17 +51,13 @@
52
51
  break;
53
52
  }
54
53
  }
55
-
54
+
56
55
  if (found) {
57
- const rect = found.getBoundingClientRect();
58
- return JSON.stringify({
59
- found: true,
60
- text: found.textContent?.trim()?.substring(0, 40),
61
- x: Math.round(rect.x + rect.width / 2),
62
- y: Math.round(rect.y + rect.height / 2),
63
- w: Math.round(rect.width),
64
- h: Math.round(rect.height)
65
- });
56
+ const text = found.textContent?.trim()?.substring(0, 40);
57
+ // 버튼이 화면에 보이도록 스크롤 후 클릭
58
+ try { found.scrollIntoView({ block: 'nearest' }); } catch (_) {}
59
+ try { found.click(); } catch (_) {}
60
+ return JSON.stringify({ resolved: true, clicked: text });
66
61
  }
67
62
  return JSON.stringify({ found: false, want: wantNorm });
68
63
  })()