btcp-browser-agent 0.1.0 → 0.1.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.
- package/package.json +8 -9
- package/packages/core/dist/actions.d.ts +97 -0
- package/packages/core/dist/actions.js +940 -0
- package/packages/core/dist/errors.d.ts +138 -0
- package/packages/core/dist/errors.js +157 -0
- package/packages/core/dist/index.d.ts +120 -0
- package/packages/core/dist/index.js +134 -0
- package/packages/core/dist/ref-map.d.ts +16 -0
- package/packages/core/dist/ref-map.js +91 -0
- package/packages/core/dist/snapshot.d.ts +37 -0
- package/packages/core/dist/snapshot.js +751 -0
- package/packages/core/dist/types.d.ts +396 -0
- package/packages/core/dist/types.js +7 -0
- package/packages/extension/dist/background.d.ts +227 -0
- package/packages/extension/dist/background.js +737 -0
- package/packages/extension/dist/content.d.ts +18 -0
- package/packages/extension/dist/content.js +149 -0
- package/packages/extension/dist/index.d.ts +228 -0
- package/packages/extension/dist/index.js +350 -0
- package/packages/extension/dist/session-manager.d.ts +87 -0
- package/packages/extension/dist/session-manager.js +322 -0
- package/packages/extension/{src/session-types.ts → dist/session-types.d.ts} +113 -144
- package/packages/extension/dist/session-types.js +5 -0
- package/packages/extension/dist/types.d.ts +88 -0
- package/packages/extension/dist/types.js +7 -0
- package/CLAUDE.md +0 -230
- package/SKILL.md +0 -143
- package/SNAPSHOT_IMPROVEMENTS.md +0 -302
- package/USAGE.md +0 -146
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/docs/browser-cli-design.md +0 -500
- package/examples/chrome-extension/CHANGELOG.md +0 -210
- package/examples/chrome-extension/DEBUG.md +0 -231
- package/examples/chrome-extension/ERROR_FIXED.md +0 -147
- package/examples/chrome-extension/QUICK_TEST.md +0 -189
- package/examples/chrome-extension/README.md +0 -149
- package/examples/chrome-extension/SESSION_ONLY_MODE.md +0 -305
- package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +0 -97
- package/examples/chrome-extension/build.js +0 -43
- package/examples/chrome-extension/manifest.json +0 -37
- package/examples/chrome-extension/package-lock.json +0 -1063
- package/examples/chrome-extension/package.json +0 -21
- package/examples/chrome-extension/popup.html +0 -195
- package/examples/chrome-extension/src/background.ts +0 -12
- package/examples/chrome-extension/src/content.ts +0 -7
- package/examples/chrome-extension/src/popup.ts +0 -303
- package/examples/chrome-extension/src/scenario-google-github.ts +0 -389
- package/examples/chrome-extension/test-page.html +0 -127
- package/examples/chrome-extension/tests/README.md +0 -206
- package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +0 -380
- package/examples/chrome-extension/tsconfig.json +0 -14
- package/examples/snapshots/README.md +0 -207
- package/examples/snapshots/amazon-com-detail.html +0 -9528
- package/examples/snapshots/amazon-com-detail.snapshot.txt +0 -997
- package/examples/snapshots/convert-snapshots.ts +0 -97
- package/examples/snapshots/edition-cnn-com.html +0 -13292
- package/examples/snapshots/edition-cnn-com.snapshot.txt +0 -562
- package/examples/snapshots/github-com-microsoft-vscode.html +0 -2916
- package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +0 -455
- package/examples/snapshots/google-search.html +0 -20012
- package/examples/snapshots/google-search.snapshot.txt +0 -195
- package/examples/snapshots/metadata.json +0 -86
- package/examples/snapshots/npr-org-templates.html +0 -2031
- package/examples/snapshots/npr-org-templates.snapshot.txt +0 -224
- package/examples/snapshots/stackoverflow-com.html +0 -5216
- package/examples/snapshots/stackoverflow-com.snapshot.txt +0 -2404
- package/examples/snapshots/test-all-mode.html +0 -46
- package/examples/snapshots/test-all-mode.snapshot.txt +0 -5
- package/examples/snapshots/validate.test.ts +0 -296
- package/packages/cli/package.json +0 -42
- package/packages/cli/src/__tests__/cli.test.ts +0 -434
- package/packages/cli/src/__tests__/errors.test.ts +0 -226
- package/packages/cli/src/__tests__/executor.test.ts +0 -275
- package/packages/cli/src/__tests__/formatter.test.ts +0 -260
- package/packages/cli/src/__tests__/parser.test.ts +0 -288
- package/packages/cli/src/__tests__/suggestions.test.ts +0 -255
- package/packages/cli/src/commands/back.ts +0 -22
- package/packages/cli/src/commands/check.ts +0 -33
- package/packages/cli/src/commands/clear.ts +0 -33
- package/packages/cli/src/commands/click.ts +0 -32
- package/packages/cli/src/commands/closetab.ts +0 -31
- package/packages/cli/src/commands/eval.ts +0 -41
- package/packages/cli/src/commands/fill.ts +0 -30
- package/packages/cli/src/commands/focus.ts +0 -33
- package/packages/cli/src/commands/forward.ts +0 -22
- package/packages/cli/src/commands/goto.ts +0 -34
- package/packages/cli/src/commands/help.ts +0 -162
- package/packages/cli/src/commands/hover.ts +0 -34
- package/packages/cli/src/commands/index.ts +0 -129
- package/packages/cli/src/commands/newtab.ts +0 -35
- package/packages/cli/src/commands/press.ts +0 -40
- package/packages/cli/src/commands/reload.ts +0 -25
- package/packages/cli/src/commands/screenshot.ts +0 -27
- package/packages/cli/src/commands/scroll.ts +0 -64
- package/packages/cli/src/commands/select.ts +0 -35
- package/packages/cli/src/commands/snapshot.ts +0 -21
- package/packages/cli/src/commands/tab.ts +0 -32
- package/packages/cli/src/commands/tabs.ts +0 -26
- package/packages/cli/src/commands/text.ts +0 -27
- package/packages/cli/src/commands/title.ts +0 -17
- package/packages/cli/src/commands/type.ts +0 -38
- package/packages/cli/src/commands/uncheck.ts +0 -33
- package/packages/cli/src/commands/url.ts +0 -17
- package/packages/cli/src/commands/wait.ts +0 -54
- package/packages/cli/src/errors.ts +0 -164
- package/packages/cli/src/executor.ts +0 -68
- package/packages/cli/src/formatter.ts +0 -215
- package/packages/cli/src/index.ts +0 -257
- package/packages/cli/src/parser.ts +0 -195
- package/packages/cli/src/suggestions.ts +0 -207
- package/packages/cli/src/terminal/Terminal.ts +0 -365
- package/packages/cli/src/terminal/index.ts +0 -5
- package/packages/cli/src/types.ts +0 -155
- package/packages/cli/tsconfig.json +0 -20
- package/packages/core/package.json +0 -35
- package/packages/core/src/actions.ts +0 -1210
- package/packages/core/src/errors.ts +0 -296
- package/packages/core/src/index.test.ts +0 -638
- package/packages/core/src/index.ts +0 -220
- package/packages/core/src/ref-map.ts +0 -107
- package/packages/core/src/snapshot.ts +0 -873
- package/packages/core/src/types.ts +0 -536
- package/packages/core/tsconfig.json +0 -23
- package/packages/extension/README.md +0 -129
- package/packages/extension/package.json +0 -43
- package/packages/extension/src/background.ts +0 -888
- package/packages/extension/src/content.ts +0 -172
- package/packages/extension/src/index.ts +0 -579
- package/packages/extension/src/session-manager.ts +0 -385
- package/packages/extension/src/types.ts +0 -162
- package/packages/extension/tsconfig.json +0 -28
- package/src/index.ts +0 -64
- package/tsconfig.build.json +0 -12
- package/tsconfig.json +0 -26
- package/vitest.config.ts +0 -13
|
@@ -1,389 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google → GitHub → Star Scenario
|
|
3
|
-
* AI Agent workflow demonstration that can be run from the popup
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Client } from '../../../packages/extension/src/index.js';
|
|
7
|
-
|
|
8
|
-
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
9
|
-
|
|
10
|
-
interface LogCallback {
|
|
11
|
-
(message: string, type?: 'info' | 'success' | 'error' | 'warning'): void;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Find an element in the snapshot tree based on criteria
|
|
16
|
-
* Snapshot format: "- ROLE "label" [attributes] [@ref:N]"
|
|
17
|
-
*/
|
|
18
|
-
function findElement(tree: string, criteria: {
|
|
19
|
-
role?: string;
|
|
20
|
-
name?: string;
|
|
21
|
-
nameContains?: string;
|
|
22
|
-
type?: string;
|
|
23
|
-
}): string | null {
|
|
24
|
-
const lines = tree.split('\n');
|
|
25
|
-
|
|
26
|
-
for (const line of lines) {
|
|
27
|
-
const refMatch = line.match(/@ref:(\d+)/);
|
|
28
|
-
if (!refMatch) continue;
|
|
29
|
-
|
|
30
|
-
const ref = `@ref:${refMatch[1]}`;
|
|
31
|
-
let matches = true;
|
|
32
|
-
|
|
33
|
-
// Match role (uppercase in snapshot: BUTTON, TEXTBOX, LINK, etc.)
|
|
34
|
-
if (criteria.role) {
|
|
35
|
-
const roleUpper = criteria.role.toUpperCase();
|
|
36
|
-
if (!line.includes(roleUpper)) matches = false;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Match exact name in quotes: "Search"
|
|
40
|
-
if (criteria.name) {
|
|
41
|
-
const namePattern = `"${criteria.name}"`;
|
|
42
|
-
if (!line.includes(namePattern)) matches = false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Match name contains (case-insensitive)
|
|
46
|
-
if (criteria.nameContains) {
|
|
47
|
-
const quotedTextMatch = line.match(/"([^"]+)"/);
|
|
48
|
-
if (!quotedTextMatch || !quotedTextMatch[1].toLowerCase().includes(criteria.nameContains.toLowerCase())) {
|
|
49
|
-
matches = false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Match type attribute: [type=search]
|
|
54
|
-
if (criteria.type) {
|
|
55
|
-
const typePattern = `type=${criteria.type}`;
|
|
56
|
-
if (!line.includes(typePattern)) matches = false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (matches) return ref;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Find first link containing specific domain
|
|
67
|
-
* Looks for LINK role with domain in the line
|
|
68
|
-
*/
|
|
69
|
-
function findLinkByDomain(tree: string, domain: string): string | null {
|
|
70
|
-
const lines = tree.split('\n');
|
|
71
|
-
|
|
72
|
-
for (const line of lines) {
|
|
73
|
-
// Check for LINK role (uppercase in snapshot)
|
|
74
|
-
if (!line.includes("LINK")) continue;
|
|
75
|
-
|
|
76
|
-
const refMatch = line.match(/@ref:(\d+)/);
|
|
77
|
-
if (!refMatch) continue;
|
|
78
|
-
|
|
79
|
-
// Check if domain appears anywhere in the line (case-insensitive)
|
|
80
|
-
if (line.toLowerCase().includes(domain.toLowerCase())) {
|
|
81
|
-
return `@ref:${refMatch[1]}`;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Run the Google → GitHub → Star scenario
|
|
90
|
-
*/
|
|
91
|
-
export async function runGoogleGithubScenario(client: Client, log: LogCallback): Promise<void> {
|
|
92
|
-
const TOTAL_STEPS = 15;
|
|
93
|
-
let currentStep = 0;
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
// Step 1: Navigate to Google
|
|
97
|
-
currentStep++;
|
|
98
|
-
log(`[${currentStep}/${TOTAL_STEPS}] Navigating to Google...`, 'info');
|
|
99
|
-
await client.navigate('https://www.google.com');
|
|
100
|
-
log('✅ Loaded Google', 'success');
|
|
101
|
-
await sleep(1500);
|
|
102
|
-
|
|
103
|
-
// Step 2: Take snapshot
|
|
104
|
-
currentStep++;
|
|
105
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🤔 Taking snapshot to analyze page...`, 'info');
|
|
106
|
-
const snapshot1 = await client.snapshot({ format: 'tree' });
|
|
107
|
-
log(`✅ Found ${snapshot1.split('\n').length} elements`, 'success');
|
|
108
|
-
log(`\n📸 SNAPSHOT (Google Homepage - first 30 lines):\n${snapshot1.split('\n').slice(0, 30).join('\n')}\n... (${snapshot1.split('\n').length - 30} more lines)`, 'info');
|
|
109
|
-
await sleep(500);
|
|
110
|
-
|
|
111
|
-
// Step 3: Find search input
|
|
112
|
-
currentStep++;
|
|
113
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🔍 Analyzing snapshot for search box...`, 'info');
|
|
114
|
-
log(`💭 Thinking: Trying role=combobox first...`, 'info');
|
|
115
|
-
let searchInput = findElement(snapshot1, { role: 'combobox' });
|
|
116
|
-
if (!searchInput) {
|
|
117
|
-
log(`💭 Thinking: Not found. Trying role=searchbox...`, 'info');
|
|
118
|
-
searchInput = findElement(snapshot1, { role: 'searchbox' });
|
|
119
|
-
}
|
|
120
|
-
if (!searchInput) {
|
|
121
|
-
log(`💭 Thinking: Not found. Trying textbox with "search" in name...`, 'info');
|
|
122
|
-
searchInput = findElement(snapshot1, { role: 'textbox', nameContains: 'search' });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (!searchInput) {
|
|
126
|
-
throw new Error('Could not find search input');
|
|
127
|
-
}
|
|
128
|
-
log(`✅ Found search box: ${searchInput}`, 'success');
|
|
129
|
-
await sleep(500);
|
|
130
|
-
|
|
131
|
-
// Step 4: Type search query
|
|
132
|
-
currentStep++;
|
|
133
|
-
log(`[${currentStep}/${TOTAL_STEPS}] Typing "btcp-cowork"...`, 'info');
|
|
134
|
-
await client.type(searchInput, 'btcp-cowork');
|
|
135
|
-
log('✅ Query typed', 'success');
|
|
136
|
-
await sleep(500);
|
|
137
|
-
|
|
138
|
-
// Step 5: Submit search
|
|
139
|
-
currentStep++;
|
|
140
|
-
log(`[${currentStep}/${TOTAL_STEPS}] Submitting search...`, 'info');
|
|
141
|
-
log(`💭 Thinking: Looking for Google Search button...`, 'info');
|
|
142
|
-
|
|
143
|
-
// Look for the actual "Google Search" button
|
|
144
|
-
const searchButton = findElement(snapshot1, { role: 'button', name: 'Google Search' });
|
|
145
|
-
|
|
146
|
-
if (!searchButton) {
|
|
147
|
-
log('⚠️ Google Search button not found, trying Enter key...', 'warning');
|
|
148
|
-
// Click the search input first to ensure focus
|
|
149
|
-
await client.click(searchInput);
|
|
150
|
-
await sleep(300);
|
|
151
|
-
await client.execute({
|
|
152
|
-
id: crypto.randomUUID(),
|
|
153
|
-
action: 'press',
|
|
154
|
-
key: 'Enter',
|
|
155
|
-
});
|
|
156
|
-
} else {
|
|
157
|
-
log(`💭 Thinking: Found button ${searchButton}, clicking it...`, 'info');
|
|
158
|
-
await client.click(searchButton);
|
|
159
|
-
}
|
|
160
|
-
log('✅ Search submitted', 'success');
|
|
161
|
-
await sleep(3000); // Increased wait time for results to load
|
|
162
|
-
|
|
163
|
-
// Step 6: Wait and verify results loaded
|
|
164
|
-
currentStep++;
|
|
165
|
-
log(`[${currentStep}/${TOTAL_STEPS}] Checking results page...`, 'info');
|
|
166
|
-
const currentUrl = await client.getUrl();
|
|
167
|
-
if (!currentUrl.includes('google.com/search')) {
|
|
168
|
-
log('⚠️ URL may not be results page', 'warning');
|
|
169
|
-
} else {
|
|
170
|
-
log('✅ On results page', 'success');
|
|
171
|
-
}
|
|
172
|
-
await sleep(1000);
|
|
173
|
-
|
|
174
|
-
// Step 7: Take snapshot of results
|
|
175
|
-
currentStep++;
|
|
176
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🤔 Taking snapshot of search results...`, 'info');
|
|
177
|
-
const snapshot2 = await client.snapshot({ format: 'tree' });
|
|
178
|
-
log(`✅ Found ${snapshot2.split('\n').length} elements`, 'success');
|
|
179
|
-
|
|
180
|
-
// Show links found in snapshot
|
|
181
|
-
const linkLines = snapshot2.split('\n').filter(line => line.includes('LINK') && line.includes('@ref:'));
|
|
182
|
-
log(`\n📸 SNAPSHOT (Links found - first 10):\n${linkLines.slice(0, 10).join('\n')}`, 'info');
|
|
183
|
-
await sleep(500);
|
|
184
|
-
|
|
185
|
-
// Step 8: Find GitHub/BTCP link
|
|
186
|
-
currentStep++;
|
|
187
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🔍 Searching for BTCP repository link...`, 'info');
|
|
188
|
-
log(`💭 Thinking: Scanning ${linkLines.length} links...`, 'info');
|
|
189
|
-
|
|
190
|
-
// Try to find browser-tool-calling-protocol link first
|
|
191
|
-
let githubLink = findLinkByDomain(snapshot2, 'browser-tool-calling-protocol');
|
|
192
|
-
|
|
193
|
-
if (!githubLink) {
|
|
194
|
-
log(`💭 Thinking: No BTCP link found, trying github.com...`, 'info');
|
|
195
|
-
githubLink = findLinkByDomain(snapshot2, 'github.com');
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (!githubLink) {
|
|
199
|
-
// Fallback: try to find first search result (skip navigation links)
|
|
200
|
-
log(`💭 Thinking: Trying first search result...`, 'info');
|
|
201
|
-
const lines = snapshot2.split('\n');
|
|
202
|
-
for (const line of lines) {
|
|
203
|
-
// Skip navigation links (Images, Videos, News, etc.)
|
|
204
|
-
if (line.includes('LINK') && !line.includes('Images') && !line.includes('Videos') &&
|
|
205
|
-
!line.includes('News') && !line.includes('Shopping') && !line.includes('AI Mode')) {
|
|
206
|
-
const refMatch = line.match(/@ref:(\d+)/);
|
|
207
|
-
if (refMatch && parseInt(refMatch[1]) >= 18) { // Start from ref:18 which is first result
|
|
208
|
-
githubLink = `@ref:${refMatch[1]}`;
|
|
209
|
-
log(`💭 Thinking: Found first result: ${line.substring(0, 80)}...`, 'info');
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (!githubLink) {
|
|
217
|
-
throw new Error('No GitHub links found in results');
|
|
218
|
-
}
|
|
219
|
-
log(`✅ Found link: ${githubLink}`, 'success');
|
|
220
|
-
await sleep(500);
|
|
221
|
-
|
|
222
|
-
// Step 9: Click GitHub link
|
|
223
|
-
currentStep++;
|
|
224
|
-
log(`[${currentStep}/${TOTAL_STEPS}] Navigating to GitHub...`, 'info');
|
|
225
|
-
await client.click(githubLink);
|
|
226
|
-
log('✅ Clicked link', 'success');
|
|
227
|
-
await sleep(3000);
|
|
228
|
-
|
|
229
|
-
// Step 10: Verify on GitHub
|
|
230
|
-
currentStep++;
|
|
231
|
-
log(`[${currentStep}/${TOTAL_STEPS}] Verifying GitHub page...`, 'info');
|
|
232
|
-
const githubUrl = await client.getUrl();
|
|
233
|
-
if (!githubUrl.includes('github.com')) {
|
|
234
|
-
log('⚠️ May not be on GitHub', 'warning');
|
|
235
|
-
} else {
|
|
236
|
-
log('✅ On GitHub repository page', 'success');
|
|
237
|
-
}
|
|
238
|
-
await sleep(1000);
|
|
239
|
-
|
|
240
|
-
// Step 11: Initial encounter & assessment
|
|
241
|
-
currentStep++;
|
|
242
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🤔 Taking snapshot to understand page structure...`, 'info');
|
|
243
|
-
const snapshot3 = await client.snapshot({ format: 'tree' });
|
|
244
|
-
const totalLines = snapshot3.split('\n').length;
|
|
245
|
-
const snapshotHeader = snapshot3.split('\n').find(line => line.startsWith('SNAPSHOT:')) || '';
|
|
246
|
-
const refsMatch = snapshotHeader.match(/refs=(\d+)/);
|
|
247
|
-
const totalRefs = refsMatch ? parseInt(refsMatch[1]) : 0;
|
|
248
|
-
|
|
249
|
-
log(`📸 Snapshot captured: ${totalLines} lines, ${totalRefs} interactive elements`, 'success');
|
|
250
|
-
log(`💭 Thinking: This is a large page - processing all ${totalRefs} elements would be inefficient`, 'info');
|
|
251
|
-
log(`💭 Thinking: Strategy: Preview first 100 lines to understand page structure`, 'info');
|
|
252
|
-
|
|
253
|
-
const preview = snapshot3.split('\n').slice(0, 100).join('\n');
|
|
254
|
-
log(`\n📸 PREVIEW (first 100 lines):\n${preview}`, 'info');
|
|
255
|
-
await sleep(1000);
|
|
256
|
-
|
|
257
|
-
// Step 12: Strategic analysis
|
|
258
|
-
currentStep++;
|
|
259
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🧠 Analyzing preview for patterns...`, 'info');
|
|
260
|
-
log(`💭 Thinking: I see BUTTON elements, LINK elements, navigation structure`, 'info');
|
|
261
|
-
log(`💭 Thinking: My goal: Find star button`, 'info');
|
|
262
|
-
log(`💭 Thinking: Question: Does "star" appear in the preview?`, 'info');
|
|
263
|
-
|
|
264
|
-
const hasStarInPreview = preview.toLowerCase().includes('star');
|
|
265
|
-
if (hasStarInPreview) {
|
|
266
|
-
log(`💭 Thinking: Result: Yes, star references found in preview`, 'success');
|
|
267
|
-
} else {
|
|
268
|
-
log(`💭 Thinking: Result: No star in preview - need to search full page`, 'info');
|
|
269
|
-
}
|
|
270
|
-
await sleep(500);
|
|
271
|
-
|
|
272
|
-
// Step 13: Formulate filtering strategy
|
|
273
|
-
currentStep++;
|
|
274
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🎯 Decision point - How to narrow down to star button?`, 'info');
|
|
275
|
-
log(`💭 Thinking: Option A: Use grep filter for "star" keyword → Fast, targeted`, 'info');
|
|
276
|
-
log(`💭 Thinking: Option B: Use role=button filter → Gets all buttons, still large`, 'info');
|
|
277
|
-
log(`💭 Thinking: Option C: Combine filters: grep="star" + analyze results`, 'info');
|
|
278
|
-
log(`💭 Thinking: Choosing Option A: grep filter is most efficient`, 'success');
|
|
279
|
-
log(`💭 Thinking: Executing: snapshot({ grep: { pattern: 'star', ignoreCase: true } })`, 'info');
|
|
280
|
-
await sleep(500);
|
|
281
|
-
|
|
282
|
-
// Step 14: Execute filtered snapshot
|
|
283
|
-
currentStep++;
|
|
284
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🔍 Taking filtered snapshot with grep="star"...`, 'info');
|
|
285
|
-
const filteredSnapshot = await client.snapshot({
|
|
286
|
-
format: 'tree',
|
|
287
|
-
grep: { pattern: 'star', ignoreCase: true }
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
const filteredLines = filteredSnapshot.split('\n').filter(line => line.includes('@ref:'));
|
|
291
|
-
log(`✅ Filtered snapshot: ${filteredLines.length} matching elements (reduced from ${totalRefs} refs)`, 'success');
|
|
292
|
-
log(`\n📸 FILTERED RESULTS:\n${filteredLines.join('\n')}`, 'info');
|
|
293
|
-
await sleep(1000);
|
|
294
|
-
|
|
295
|
-
// Step 15: Intelligent element selection
|
|
296
|
-
currentStep++;
|
|
297
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🧩 Analyzing filtered results...`, 'info');
|
|
298
|
-
log(`💭 Thinking: The grep filter returned ${filteredLines.length} elements with "star"`, 'info');
|
|
299
|
-
log(`💭 Thinking: Now I need to identify which one is the star action button`, 'info');
|
|
300
|
-
|
|
301
|
-
// Analyze what grep returned - purely use the filtered snapshot
|
|
302
|
-
log(`💭 Thinking: Examining each filtered element:`, 'info');
|
|
303
|
-
for (const line of filteredLines.slice(0, 5)) {
|
|
304
|
-
log(` ${line}`, 'info');
|
|
305
|
-
}
|
|
306
|
-
if (filteredLines.length > 5) {
|
|
307
|
-
log(` ... and ${filteredLines.length - 5} more`, 'info');
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Use findElement helper on the already-filtered snapshot
|
|
311
|
-
log(`💭 Thinking: Using findElement to locate button with "star" in name`, 'info');
|
|
312
|
-
let starButton = findElement(filteredSnapshot, { role: 'button', nameContains: 'star' });
|
|
313
|
-
|
|
314
|
-
// Check if we found "Unstar" instead (means already starred)
|
|
315
|
-
const hasUnstar = filteredSnapshot.toLowerCase().includes('"unstar"');
|
|
316
|
-
|
|
317
|
-
if (hasUnstar) {
|
|
318
|
-
log(`💭 Thinking: Found "Unstar" button → repo already starred`, 'info');
|
|
319
|
-
log(`⚠️ Repository already starred (Unstar button present)`, 'warning');
|
|
320
|
-
log(`ℹ️ Scenario completed - repo is already starred`, 'info');
|
|
321
|
-
starButton = findElement(filteredSnapshot, { role: 'button', nameContains: 'unstar' });
|
|
322
|
-
} else if (starButton) {
|
|
323
|
-
log(`💭 Thinking: Found "Star" button → need to click it to star`, 'success');
|
|
324
|
-
log(`💭 Thinking: Decision: Click ${starButton} "Star" button`, 'success');
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (!starButton) {
|
|
328
|
-
log('⚠️ Could not find star button (may need login)', 'warning');
|
|
329
|
-
log('ℹ️ Scenario completed up to GitHub navigation', 'info');
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
log(`✅ Selected element: ${starButton}`, 'success');
|
|
334
|
-
await sleep(500);
|
|
335
|
-
|
|
336
|
-
// Step 16: Execute action (only if not already starred)
|
|
337
|
-
if (!hasUnstar) {
|
|
338
|
-
currentStep++;
|
|
339
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🎯 Clicking star button...`, 'info');
|
|
340
|
-
await client.click(starButton);
|
|
341
|
-
log('✅ Star button clicked', 'success');
|
|
342
|
-
log('⏳ Waiting for UI update...', 'info');
|
|
343
|
-
await sleep(2000);
|
|
344
|
-
} else {
|
|
345
|
-
currentStep++;
|
|
346
|
-
log(`[${currentStep}/${TOTAL_STEPS}] ⏭️ Skipping star action (already starred)`, 'info');
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Step 17: Verification
|
|
350
|
-
currentStep++;
|
|
351
|
-
log(`[${currentStep}/${TOTAL_STEPS}] 🔍 Verifying action succeeded...`, 'info');
|
|
352
|
-
log(`💭 Thinking: Taking verification snapshot with grep="star"...`, 'info');
|
|
353
|
-
|
|
354
|
-
const finalUrl = await client.getUrl();
|
|
355
|
-
if (finalUrl.includes('login')) {
|
|
356
|
-
log('⚠️ Redirected to login - authentication required', 'warning');
|
|
357
|
-
log('ℹ️ In production, agent would handle OAuth flow', 'info');
|
|
358
|
-
} else {
|
|
359
|
-
const verifySnapshot = await client.snapshot({
|
|
360
|
-
format: 'tree',
|
|
361
|
-
grep: { pattern: 'star', ignoreCase: true }
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
const hasUnstar = verifySnapshot.toLowerCase().includes('"unstar"');
|
|
365
|
-
log(`💭 Thinking: Checking if "Unstar" now appears (indicates starring succeeded)`, 'info');
|
|
366
|
-
|
|
367
|
-
if (hasUnstar) {
|
|
368
|
-
log('✅ Success! Button changed from "Star" to "Unstar"', 'success');
|
|
369
|
-
log('🎉 Repository successfully starred!', 'success');
|
|
370
|
-
} else {
|
|
371
|
-
log('✅ Star action completed', 'success');
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
currentStep++;
|
|
376
|
-
log(`[${currentStep}/${TOTAL_STEPS}] ✨ Scenario complete!`, 'success');
|
|
377
|
-
log('───────────────────────────', 'info');
|
|
378
|
-
log('Summary:', 'info');
|
|
379
|
-
log('• Searched Google for "btcp-cowork"', 'info');
|
|
380
|
-
log('• Found and clicked GitHub link', 'info');
|
|
381
|
-
log('• Navigated to repository', 'info');
|
|
382
|
-
log('• Attempted to star repository', 'info');
|
|
383
|
-
log('───────────────────────────', 'info');
|
|
384
|
-
|
|
385
|
-
} catch (error) {
|
|
386
|
-
log(`❌ Scenario failed: ${error instanceof Error ? error.message : String(error)}`, 'error');
|
|
387
|
-
throw error;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>BTCP Extension Test Page</title>
|
|
6
|
-
<style>
|
|
7
|
-
body {
|
|
8
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
9
|
-
max-width: 800px;
|
|
10
|
-
margin: 50px auto;
|
|
11
|
-
padding: 20px;
|
|
12
|
-
line-height: 1.6;
|
|
13
|
-
}
|
|
14
|
-
.card {
|
|
15
|
-
background: #f8f9fa;
|
|
16
|
-
border: 2px solid #dee2e6;
|
|
17
|
-
border-radius: 8px;
|
|
18
|
-
padding: 20px;
|
|
19
|
-
margin: 20px 0;
|
|
20
|
-
}
|
|
21
|
-
.success { border-color: #28a745; background: #d4edda; }
|
|
22
|
-
.info { border-color: #17a2b8; background: #d1ecf1; }
|
|
23
|
-
.warning { border-color: #ffc107; background: #fff3cd; }
|
|
24
|
-
h1 { color: #2563eb; }
|
|
25
|
-
h2 { margin-top: 0; }
|
|
26
|
-
code {
|
|
27
|
-
background: #e9ecef;
|
|
28
|
-
padding: 2px 6px;
|
|
29
|
-
border-radius: 3px;
|
|
30
|
-
font-family: 'Courier New', monospace;
|
|
31
|
-
}
|
|
32
|
-
ol { padding-left: 20px; }
|
|
33
|
-
li { margin: 10px 0; }
|
|
34
|
-
</style>
|
|
35
|
-
</head>
|
|
36
|
-
<body>
|
|
37
|
-
<h1>🧪 BTCP Extension Test Page</h1>
|
|
38
|
-
|
|
39
|
-
<div class="card info">
|
|
40
|
-
<h2>Purpose</h2>
|
|
41
|
-
<p>This page helps you test the BTCP Browser Agent extension. Use this as your "active tab" when testing session creation.</p>
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
<div class="card success">
|
|
45
|
-
<h2>✅ You're Ready to Test!</h2>
|
|
46
|
-
<p>This page is loaded successfully. Now follow these steps:</p>
|
|
47
|
-
<ol>
|
|
48
|
-
<li>Make sure this tab is <strong>active</strong> (you're viewing it now)</li>
|
|
49
|
-
<li>Click the <strong>BTCP Browser Agent extension icon</strong> in your Chrome toolbar</li>
|
|
50
|
-
<li>In the popup, click <strong>"Start New Session"</strong></li>
|
|
51
|
-
<li>You should see this tab get added to a <strong>blue tab group</strong> labeled "BTCP Session 1"</li>
|
|
52
|
-
</ol>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<div class="card warning">
|
|
56
|
-
<h2>⚠️ Troubleshooting</h2>
|
|
57
|
-
<p><strong>If the button doesn't work:</strong></p>
|
|
58
|
-
<ol>
|
|
59
|
-
<li>Open Chrome DevTools on the popup (right-click popup → Inspect)</li>
|
|
60
|
-
<li>Check the Console tab for error messages</li>
|
|
61
|
-
<li>Also check the Background Service Worker console:
|
|
62
|
-
<ul>
|
|
63
|
-
<li>Go to <code>chrome://extensions</code></li>
|
|
64
|
-
<li>Find "BTCP Browser Agent"</li>
|
|
65
|
-
<li>Click "service worker" link</li>
|
|
66
|
-
<li>Check console for errors</li>
|
|
67
|
-
</ul>
|
|
68
|
-
</li>
|
|
69
|
-
</ol>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
<div class="card info">
|
|
73
|
-
<h2>📋 Expected Behavior</h2>
|
|
74
|
-
<p><strong>When you start a session:</strong></p>
|
|
75
|
-
<ul>
|
|
76
|
-
<li>✅ This tab should be added to a blue tab group</li>
|
|
77
|
-
<li>✅ The group should be labeled "BTCP Session 1"</li>
|
|
78
|
-
<li>✅ The popup should show:
|
|
79
|
-
<ul>
|
|
80
|
-
<li>Blue session status box</li>
|
|
81
|
-
<li>Session name: "BTCP Session 1"</li>
|
|
82
|
-
<li>Tab count: "1 tab"</li>
|
|
83
|
-
<li>"Close Session" button (red)</li>
|
|
84
|
-
</ul>
|
|
85
|
-
</li>
|
|
86
|
-
</ul>
|
|
87
|
-
|
|
88
|
-
<p><strong>When you click "New Tab" in the popup:</strong></p>
|
|
89
|
-
<ul>
|
|
90
|
-
<li>✅ A new tab should open</li>
|
|
91
|
-
<li>✅ It should automatically join the "BTCP Session 1" group</li>
|
|
92
|
-
<li>✅ Tab count should update to "2 tabs"</li>
|
|
93
|
-
</ul>
|
|
94
|
-
|
|
95
|
-
<p><strong>When you click "Close Session":</strong></p>
|
|
96
|
-
<ul>
|
|
97
|
-
<li>✅ All tabs in the group should close at once</li>
|
|
98
|
-
<li>✅ This includes this test page!</li>
|
|
99
|
-
</ul>
|
|
100
|
-
</div>
|
|
101
|
-
|
|
102
|
-
<div class="card">
|
|
103
|
-
<h2>🔍 Quick Debug Check</h2>
|
|
104
|
-
<p>Open the Console (F12 → Console tab) and run this:</p>
|
|
105
|
-
<pre><code>chrome.tabGroups.query({}).then(groups =>
|
|
106
|
-
console.log('Active groups:', groups.length, groups)
|
|
107
|
-
);</code></pre>
|
|
108
|
-
<p>This shows all active tab groups in your browser.</p>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<div class="card info">
|
|
112
|
-
<h2>📚 More Help</h2>
|
|
113
|
-
<p>For detailed debugging instructions, see:</p>
|
|
114
|
-
<ul>
|
|
115
|
-
<li><code>DEBUG.md</code> - Full debugging guide</li>
|
|
116
|
-
<li><code>QUICK_TEST.md</code> - Quick console tests</li>
|
|
117
|
-
</ul>
|
|
118
|
-
<p>Both files are in the extension directory.</p>
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
<script>
|
|
122
|
-
console.log('BTCP Test Page loaded');
|
|
123
|
-
console.log('Tab ID:', chrome?.runtime?.id || 'N/A');
|
|
124
|
-
console.log('Ready for testing!');
|
|
125
|
-
</script>
|
|
126
|
-
</body>
|
|
127
|
-
</html>
|