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.
Files changed (136) hide show
  1. package/package.json +8 -9
  2. package/packages/core/dist/actions.d.ts +97 -0
  3. package/packages/core/dist/actions.js +940 -0
  4. package/packages/core/dist/errors.d.ts +138 -0
  5. package/packages/core/dist/errors.js +157 -0
  6. package/packages/core/dist/index.d.ts +120 -0
  7. package/packages/core/dist/index.js +134 -0
  8. package/packages/core/dist/ref-map.d.ts +16 -0
  9. package/packages/core/dist/ref-map.js +91 -0
  10. package/packages/core/dist/snapshot.d.ts +37 -0
  11. package/packages/core/dist/snapshot.js +751 -0
  12. package/packages/core/dist/types.d.ts +396 -0
  13. package/packages/core/dist/types.js +7 -0
  14. package/packages/extension/dist/background.d.ts +227 -0
  15. package/packages/extension/dist/background.js +737 -0
  16. package/packages/extension/dist/content.d.ts +18 -0
  17. package/packages/extension/dist/content.js +149 -0
  18. package/packages/extension/dist/index.d.ts +228 -0
  19. package/packages/extension/dist/index.js +350 -0
  20. package/packages/extension/dist/session-manager.d.ts +87 -0
  21. package/packages/extension/dist/session-manager.js +322 -0
  22. package/packages/extension/{src/session-types.ts → dist/session-types.d.ts} +113 -144
  23. package/packages/extension/dist/session-types.js +5 -0
  24. package/packages/extension/dist/types.d.ts +88 -0
  25. package/packages/extension/dist/types.js +7 -0
  26. package/CLAUDE.md +0 -230
  27. package/SKILL.md +0 -143
  28. package/SNAPSHOT_IMPROVEMENTS.md +0 -302
  29. package/USAGE.md +0 -146
  30. package/dist/index.d.ts.map +0 -1
  31. package/dist/index.js.map +0 -1
  32. package/docs/browser-cli-design.md +0 -500
  33. package/examples/chrome-extension/CHANGELOG.md +0 -210
  34. package/examples/chrome-extension/DEBUG.md +0 -231
  35. package/examples/chrome-extension/ERROR_FIXED.md +0 -147
  36. package/examples/chrome-extension/QUICK_TEST.md +0 -189
  37. package/examples/chrome-extension/README.md +0 -149
  38. package/examples/chrome-extension/SESSION_ONLY_MODE.md +0 -305
  39. package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +0 -97
  40. package/examples/chrome-extension/build.js +0 -43
  41. package/examples/chrome-extension/manifest.json +0 -37
  42. package/examples/chrome-extension/package-lock.json +0 -1063
  43. package/examples/chrome-extension/package.json +0 -21
  44. package/examples/chrome-extension/popup.html +0 -195
  45. package/examples/chrome-extension/src/background.ts +0 -12
  46. package/examples/chrome-extension/src/content.ts +0 -7
  47. package/examples/chrome-extension/src/popup.ts +0 -303
  48. package/examples/chrome-extension/src/scenario-google-github.ts +0 -389
  49. package/examples/chrome-extension/test-page.html +0 -127
  50. package/examples/chrome-extension/tests/README.md +0 -206
  51. package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +0 -380
  52. package/examples/chrome-extension/tsconfig.json +0 -14
  53. package/examples/snapshots/README.md +0 -207
  54. package/examples/snapshots/amazon-com-detail.html +0 -9528
  55. package/examples/snapshots/amazon-com-detail.snapshot.txt +0 -997
  56. package/examples/snapshots/convert-snapshots.ts +0 -97
  57. package/examples/snapshots/edition-cnn-com.html +0 -13292
  58. package/examples/snapshots/edition-cnn-com.snapshot.txt +0 -562
  59. package/examples/snapshots/github-com-microsoft-vscode.html +0 -2916
  60. package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +0 -455
  61. package/examples/snapshots/google-search.html +0 -20012
  62. package/examples/snapshots/google-search.snapshot.txt +0 -195
  63. package/examples/snapshots/metadata.json +0 -86
  64. package/examples/snapshots/npr-org-templates.html +0 -2031
  65. package/examples/snapshots/npr-org-templates.snapshot.txt +0 -224
  66. package/examples/snapshots/stackoverflow-com.html +0 -5216
  67. package/examples/snapshots/stackoverflow-com.snapshot.txt +0 -2404
  68. package/examples/snapshots/test-all-mode.html +0 -46
  69. package/examples/snapshots/test-all-mode.snapshot.txt +0 -5
  70. package/examples/snapshots/validate.test.ts +0 -296
  71. package/packages/cli/package.json +0 -42
  72. package/packages/cli/src/__tests__/cli.test.ts +0 -434
  73. package/packages/cli/src/__tests__/errors.test.ts +0 -226
  74. package/packages/cli/src/__tests__/executor.test.ts +0 -275
  75. package/packages/cli/src/__tests__/formatter.test.ts +0 -260
  76. package/packages/cli/src/__tests__/parser.test.ts +0 -288
  77. package/packages/cli/src/__tests__/suggestions.test.ts +0 -255
  78. package/packages/cli/src/commands/back.ts +0 -22
  79. package/packages/cli/src/commands/check.ts +0 -33
  80. package/packages/cli/src/commands/clear.ts +0 -33
  81. package/packages/cli/src/commands/click.ts +0 -32
  82. package/packages/cli/src/commands/closetab.ts +0 -31
  83. package/packages/cli/src/commands/eval.ts +0 -41
  84. package/packages/cli/src/commands/fill.ts +0 -30
  85. package/packages/cli/src/commands/focus.ts +0 -33
  86. package/packages/cli/src/commands/forward.ts +0 -22
  87. package/packages/cli/src/commands/goto.ts +0 -34
  88. package/packages/cli/src/commands/help.ts +0 -162
  89. package/packages/cli/src/commands/hover.ts +0 -34
  90. package/packages/cli/src/commands/index.ts +0 -129
  91. package/packages/cli/src/commands/newtab.ts +0 -35
  92. package/packages/cli/src/commands/press.ts +0 -40
  93. package/packages/cli/src/commands/reload.ts +0 -25
  94. package/packages/cli/src/commands/screenshot.ts +0 -27
  95. package/packages/cli/src/commands/scroll.ts +0 -64
  96. package/packages/cli/src/commands/select.ts +0 -35
  97. package/packages/cli/src/commands/snapshot.ts +0 -21
  98. package/packages/cli/src/commands/tab.ts +0 -32
  99. package/packages/cli/src/commands/tabs.ts +0 -26
  100. package/packages/cli/src/commands/text.ts +0 -27
  101. package/packages/cli/src/commands/title.ts +0 -17
  102. package/packages/cli/src/commands/type.ts +0 -38
  103. package/packages/cli/src/commands/uncheck.ts +0 -33
  104. package/packages/cli/src/commands/url.ts +0 -17
  105. package/packages/cli/src/commands/wait.ts +0 -54
  106. package/packages/cli/src/errors.ts +0 -164
  107. package/packages/cli/src/executor.ts +0 -68
  108. package/packages/cli/src/formatter.ts +0 -215
  109. package/packages/cli/src/index.ts +0 -257
  110. package/packages/cli/src/parser.ts +0 -195
  111. package/packages/cli/src/suggestions.ts +0 -207
  112. package/packages/cli/src/terminal/Terminal.ts +0 -365
  113. package/packages/cli/src/terminal/index.ts +0 -5
  114. package/packages/cli/src/types.ts +0 -155
  115. package/packages/cli/tsconfig.json +0 -20
  116. package/packages/core/package.json +0 -35
  117. package/packages/core/src/actions.ts +0 -1210
  118. package/packages/core/src/errors.ts +0 -296
  119. package/packages/core/src/index.test.ts +0 -638
  120. package/packages/core/src/index.ts +0 -220
  121. package/packages/core/src/ref-map.ts +0 -107
  122. package/packages/core/src/snapshot.ts +0 -873
  123. package/packages/core/src/types.ts +0 -536
  124. package/packages/core/tsconfig.json +0 -23
  125. package/packages/extension/README.md +0 -129
  126. package/packages/extension/package.json +0 -43
  127. package/packages/extension/src/background.ts +0 -888
  128. package/packages/extension/src/content.ts +0 -172
  129. package/packages/extension/src/index.ts +0 -579
  130. package/packages/extension/src/session-manager.ts +0 -385
  131. package/packages/extension/src/types.ts +0 -162
  132. package/packages/extension/tsconfig.json +0 -28
  133. package/src/index.ts +0 -64
  134. package/tsconfig.build.json +0 -12
  135. package/tsconfig.json +0 -26
  136. package/vitest.config.ts +0 -13
@@ -1,21 +0,0 @@
1
- {
2
- "name": "btcp-extension-example",
3
- "version": "1.0.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "build": "node build.js",
8
- "watch": "node build.js --watch",
9
- "clean": "rm -rf dist",
10
- "demo:scenario": "tsx tests/scenario-google-to-github-star.ts"
11
- },
12
- "dependencies": {
13
- "@btcp/browser-agent": "file:../.."
14
- },
15
- "devDependencies": {
16
- "@types/chrome": "^0.0.268",
17
- "esbuild": "^0.20.0",
18
- "tsx": "^4.7.0",
19
- "typescript": "^5.3.0"
20
- }
21
- }
@@ -1,195 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>BTCP Browser Agent</title>
6
- <style>
7
- * { box-sizing: border-box; }
8
- body {
9
- width: 400px;
10
- padding: 16px;
11
- font-family: system-ui, -apple-system, sans-serif;
12
- font-size: 14px;
13
- margin: 0;
14
- }
15
- h1 {
16
- font-size: 18px;
17
- margin: 0 0 16px 0;
18
- }
19
- .section {
20
- margin-bottom: 16px;
21
- }
22
- .section-title {
23
- font-weight: 600;
24
- margin-bottom: 8px;
25
- color: #333;
26
- }
27
- button {
28
- background: #2563eb;
29
- color: white;
30
- border: none;
31
- padding: 8px 16px;
32
- border-radius: 6px;
33
- cursor: pointer;
34
- font-size: 14px;
35
- width: 100%;
36
- margin-bottom: 8px;
37
- }
38
- button:hover { background: #1d4ed8; }
39
- button:disabled { background: #9ca3af; cursor: not-allowed; }
40
- button.secondary { background: #6b7280; }
41
- button.secondary:hover { background: #4b5563; }
42
- textarea {
43
- width: 100%;
44
- height: 100px;
45
- padding: 8px;
46
- border: 1px solid #d1d5db;
47
- border-radius: 6px;
48
- font-family: monospace;
49
- font-size: 12px;
50
- resize: vertical;
51
- }
52
- .output {
53
- background: #f3f4f6;
54
- border: 1px solid #e5e7eb;
55
- border-radius: 6px;
56
- padding: 8px;
57
- font-family: monospace;
58
- font-size: 11px;
59
- max-height: 200px;
60
- overflow: auto;
61
- white-space: pre-wrap;
62
- word-break: break-all;
63
- }
64
- .actions {
65
- display: grid;
66
- grid-template-columns: 1fr 1fr;
67
- gap: 8px;
68
- }
69
- .actions button { margin: 0; }
70
- .command-input {
71
- display: flex;
72
- gap: 8px;
73
- margin-bottom: 8px;
74
- }
75
- .command-input input {
76
- flex: 1;
77
- padding: 8px;
78
- border: 1px solid #d1d5db;
79
- border-radius: 6px;
80
- }
81
- .command-input button { width: auto; margin: 0; }
82
- .session-status {
83
- background: #eff6ff;
84
- border: 1px solid #3b82f6;
85
- border-radius: 6px;
86
- padding: 8px;
87
- margin-bottom: 8px;
88
- font-size: 12px;
89
- }
90
- .session-status.inactive {
91
- background: #f3f4f6;
92
- border-color: #9ca3af;
93
- }
94
- .session-info {
95
- display: flex;
96
- justify-content: space-between;
97
- align-items: center;
98
- margin-bottom: 4px;
99
- }
100
- .session-name {
101
- font-weight: 600;
102
- color: #2563eb;
103
- }
104
- .session-name.inactive {
105
- color: #6b7280;
106
- }
107
- .session-count {
108
- font-size: 11px;
109
- color: #6b7280;
110
- }
111
- button.danger {
112
- background: #dc2626;
113
- }
114
- button.danger:hover {
115
- background: #b91c1c;
116
- }
117
- </style>
118
- </head>
119
- <body>
120
- <h1>BTCP Browser Agent</h1>
121
-
122
- <div class="section">
123
- <div class="section-title">Session</div>
124
- <div id="sessionStatus" class="session-status inactive">
125
- <div class="session-info">
126
- <span class="session-name inactive" id="sessionName">No active session</span>
127
- <span class="session-count" id="sessionCount"></span>
128
- </div>
129
- <div style="font-size: 11px; color: #6b7280; margin-top: 4px;">
130
- ℹ️ Extension only manages tabs within the active session
131
- </div>
132
- </div>
133
- <button id="btnStartSession">Start New Session</button>
134
- <button id="btnCloseSession" class="danger" style="display: none;">Close Session</button>
135
- </div>
136
-
137
- <div class="section">
138
- <div class="section-title">AI Agent Scenario</div>
139
- <button id="btnRunScenario" style="background: #7c3aed;">🤖 Run Google → GitHub Scenario</button>
140
- </div>
141
-
142
- <div class="section">
143
- <div class="section-title">Quick Actions</div>
144
- <div class="actions">
145
- <button id="btnSnapshot">Snapshot</button>
146
- <button id="btnGetHTML">Get HTML</button>
147
- <button id="btnGetTabs">List Tabs</button>
148
- <button id="btnNewTab">New Tab</button>
149
- <button id="btnHighlight">Highlight</button>
150
- <button id="btnClearHighlight" class="secondary">Clear Highlight</button>
151
- </div>
152
- </div>
153
-
154
- <div class="section">
155
- <div class="section-title">Navigate</div>
156
- <div class="command-input">
157
- <input type="text" id="navigateUrl" placeholder="https://example.com">
158
- <button id="btnNavigate">Go</button>
159
- </div>
160
- </div>
161
-
162
- <div class="section">
163
- <div class="section-title">Click Element</div>
164
- <div class="command-input">
165
- <input type="text" id="clickSelector" placeholder="@ref:0 or #button">
166
- <button id="btnClick">Click</button>
167
- </div>
168
- </div>
169
-
170
- <div class="section">
171
- <div class="section-title">Fill Input</div>
172
- <div class="command-input">
173
- <input type="text" id="fillSelector" placeholder="@ref:1" style="width: 100px;">
174
- <input type="text" id="fillValue" placeholder="value to fill">
175
- <button id="btnFill">Fill</button>
176
- </div>
177
- </div>
178
-
179
- <div class="section">
180
- <div class="section-title">Custom Command (CLI)</div>
181
- <textarea id="commandJson" placeholder='snapshot&#10;goto https://example.com&#10;click @ref:0'></textarea>
182
- <button id="btnExecute">Execute</button>
183
- </div>
184
-
185
- <div class="section">
186
- <div class="section-title" style="display: flex; justify-content: space-between; align-items: center;">
187
- <span>Output</span>
188
- <button id="btnCopyOutput" style="width: auto; margin: 0; padding: 4px 12px; font-size: 12px;">Copy</button>
189
- </div>
190
- <div class="output" id="output">Ready...</div>
191
- </div>
192
-
193
- <script type="module" src="popup.js"></script>
194
- </body>
195
- </html>
@@ -1,12 +0,0 @@
1
- /**
2
- * Background Script - routes messages between popup and content scripts
3
- *
4
- * This single call sets up:
5
- * - BackgroundAgent for browser operations (tabs, navigation, screenshots)
6
- * - Message routing to ContentAgent in tabs
7
- */
8
- import { setupMessageListener } from '@btcp/browser-agent/extension';
9
-
10
- setupMessageListener();
11
-
12
- console.log('[BTCP] Background ready');
@@ -1,7 +0,0 @@
1
- /**
2
- * Content Script - registers DOM agent and message listener
3
- */
4
- import { createContentAgent } from '@btcp/browser-agent/extension';
5
-
6
- const agent = createContentAgent();
7
- chrome.runtime.onMessage.addListener(agent.handleMessage);
@@ -1,303 +0,0 @@
1
- /**
2
- * Popup Script - UI for controlling the browser agent
3
- */
4
- import { createClient } from '@btcp/browser-agent/extension';
5
- import { createCLI } from '@btcp/browser-agent/cli';
6
- import { runGoogleGithubScenario } from './scenario-google-github';
7
-
8
- const client = createClient();
9
- const cli = createCLI(client);
10
-
11
- // DOM elements
12
- const output = document.getElementById('output') as HTMLDivElement;
13
- const commandJson = document.getElementById('commandJson') as HTMLTextAreaElement;
14
- const sessionStatus = document.getElementById('sessionStatus') as HTMLDivElement;
15
- const sessionName = document.getElementById('sessionName') as HTMLSpanElement;
16
- const sessionCount = document.getElementById('sessionCount') as HTMLSpanElement;
17
- const btnStartSession = document.getElementById('btnStartSession') as HTMLButtonElement;
18
- const btnCloseSession = document.getElementById('btnCloseSession') as HTMLButtonElement;
19
-
20
- function log(message: unknown) {
21
- const timestamp = new Date().toLocaleTimeString();
22
- const text = typeof message === 'object' ? JSON.stringify(message, null, 2) : String(message);
23
- output.textContent = `[${timestamp}]\n${text}`;
24
- }
25
-
26
- // Session management
27
- async function updateSessionUI() {
28
- try {
29
- const { session } = await client.sessionGetCurrent();
30
- if (session) {
31
- sessionStatus.classList.remove('inactive');
32
- sessionName.classList.remove('inactive');
33
- sessionName.textContent = session.title;
34
- sessionCount.textContent = `${session.tabCount} tab${session.tabCount !== 1 ? 's' : ''}`;
35
- btnStartSession.style.display = 'none';
36
- btnCloseSession.style.display = 'block';
37
-
38
- // Enable all action buttons when session is active
39
- document.querySelectorAll('button:not(#btnStartSession)').forEach(btn => {
40
- (btn as HTMLButtonElement).disabled = false;
41
- });
42
- } else {
43
- sessionStatus.classList.add('inactive');
44
- sessionName.classList.add('inactive');
45
- sessionName.textContent = 'No active session';
46
- sessionCount.textContent = '';
47
- btnStartSession.style.display = 'block';
48
- btnCloseSession.style.display = 'none';
49
-
50
- // Disable action buttons when no session (except Start Session)
51
- document.querySelectorAll('button:not(#btnStartSession)').forEach(btn => {
52
- (btn as HTMLButtonElement).disabled = true;
53
- });
54
- }
55
- } catch (e) {
56
- console.error('Failed to update session UI:', e);
57
- }
58
- }
59
-
60
- // Session controls
61
- btnStartSession.addEventListener('click', async () => {
62
- log('Starting new session...');
63
- try {
64
- const { group } = await client.groupCreate();
65
- log({ created: group.title, groupId: group.id });
66
- await updateSessionUI();
67
- } catch (e) {
68
- log(`Error: ${e}`);
69
- }
70
- });
71
-
72
- btnCloseSession.addEventListener('click', async () => {
73
- log('Closing session...');
74
- try {
75
- const { session } = await client.sessionGetCurrent();
76
- if (session) {
77
- await client.groupDelete(session.groupId);
78
- log({ closed: session.title });
79
- await updateSessionUI();
80
- }
81
- } catch (e) {
82
- log(`Error: ${e}`);
83
- }
84
- });
85
-
86
- // Initialize popup and update session UI on load
87
- async function initializePopup() {
88
- try {
89
- // Ping background to trigger session reconnection if needed
90
- await client.popupInitialize();
91
- // Then update UI with current session state
92
- await updateSessionUI();
93
- } catch (e) {
94
- console.error('Popup initialization failed:', e);
95
- // Still update UI with whatever state exists
96
- await updateSessionUI();
97
- }
98
- }
99
-
100
- initializePopup();
101
-
102
- // AI Scenario
103
- document.getElementById('btnRunScenario')?.addEventListener('click', async () => {
104
- console.log('[DEBUG] Scenario button clicked!');
105
- const btn = document.getElementById('btnRunScenario') as HTMLButtonElement;
106
- const originalText = btn.textContent;
107
-
108
- try {
109
- console.log('[DEBUG] Starting scenario execution...');
110
- btn.disabled = true;
111
- btn.textContent = '🤖 Running scenario...';
112
- log('Starting AI Agent Scenario...\n───────────────────────────');
113
-
114
- await runGoogleGithubScenario(client, (message, type = 'info') => {
115
- console.log('[DEBUG] Scenario log:', message);
116
- const timestamp = new Date().toLocaleTimeString();
117
- const prefix = type === 'error' ? '❌' : type === 'success' ? '✅' : type === 'warning' ? '⚠️' : 'ℹ️';
118
- const currentOutput = output.textContent || '';
119
- output.textContent = currentOutput + `\n[${timestamp}] ${prefix} ${message}`;
120
- output.scrollTop = output.scrollHeight;
121
- });
122
-
123
- btn.textContent = '✅ Scenario Complete!';
124
- setTimeout(() => {
125
- btn.textContent = originalText;
126
- btn.disabled = false;
127
- }, 3000);
128
- } catch (e) {
129
- log(`Scenario failed: ${e}`);
130
- btn.textContent = '❌ Scenario Failed';
131
- setTimeout(() => {
132
- btn.textContent = originalText;
133
- btn.disabled = false;
134
- }, 3000);
135
- }
136
- });
137
-
138
- // Quick actions
139
- document.getElementById('btnSnapshot')?.addEventListener('click', async () => {
140
- log('Taking snapshot...');
141
- try {
142
- const data = await client.snapshot();
143
- log(data);
144
- } catch (e) {
145
- log(`Error: ${e}`);
146
- }
147
- });
148
-
149
- document.getElementById('btnGetHTML')?.addEventListener('click', async () => {
150
- log('Getting page HTML...');
151
- try {
152
- const data = await client.snapshot({ format: 'html' });
153
- log(data);
154
- } catch (e) {
155
- log(`Error: ${e}`);
156
- }
157
- });
158
-
159
- document.getElementById('btnGetTabs')?.addEventListener('click', async () => {
160
- log('Listing tabs...');
161
- try {
162
- const tabs = await client.tabList();
163
- log(tabs);
164
- } catch (e) {
165
- log(`Error: ${e}`);
166
- }
167
- });
168
-
169
- document.getElementById('btnNewTab')?.addEventListener('click', async () => {
170
- log('Opening new tab...');
171
- try {
172
- const result = await client.tabNew({ url: 'https://example.com' });
173
- log(result);
174
- } catch (e) {
175
- log(`Error: ${e}`);
176
- }
177
- });
178
-
179
- document.getElementById('btnHighlight')?.addEventListener('click', async () => {
180
- log('Highlighting elements...');
181
- try {
182
- const result = await client.execute({
183
- id: `cmd_${Date.now()}`,
184
- action: 'highlight'
185
- });
186
- log(result);
187
- } catch (e) {
188
- log(`Error: ${e}`);
189
- }
190
- });
191
-
192
- document.getElementById('btnClearHighlight')?.addEventListener('click', async () => {
193
- log('Clearing highlights...');
194
- try {
195
- const result = await client.execute({
196
- id: `cmd_${Date.now()}`,
197
- action: 'clearHighlight'
198
- });
199
- log(result);
200
- } catch (e) {
201
- log(`Error: ${e}`);
202
- }
203
- });
204
-
205
- // Navigate
206
- document.getElementById('btnNavigate')?.addEventListener('click', async () => {
207
- const urlInput = document.getElementById('navigateUrl') as HTMLInputElement;
208
- const url = urlInput.value.trim();
209
- if (!url) {
210
- log('Enter a URL');
211
- return;
212
- }
213
- log(`Navigating to ${url}...`);
214
- try {
215
- await client.navigate(url);
216
- log({ navigated: url });
217
- } catch (e) {
218
- log(`Error: ${e}`);
219
- }
220
- });
221
-
222
- // Click
223
- document.getElementById('btnClick')?.addEventListener('click', async () => {
224
- const selectorInput = document.getElementById('clickSelector') as HTMLInputElement;
225
- const selector = selectorInput.value.trim();
226
- if (!selector) {
227
- log('Enter a selector (e.g., @ref:0)');
228
- return;
229
- }
230
- log(`Clicking ${selector}...`);
231
- try {
232
- await client.click(selector);
233
- log({ clicked: selector });
234
- } catch (e) {
235
- log(`Error: ${e}`);
236
- }
237
- });
238
-
239
- // Fill
240
- document.getElementById('btnFill')?.addEventListener('click', async () => {
241
- const selectorInput = document.getElementById('fillSelector') as HTMLInputElement;
242
- const valueInput = document.getElementById('fillValue') as HTMLInputElement;
243
- const selector = selectorInput.value.trim();
244
- const value = valueInput.value;
245
- if (!selector) {
246
- log('Enter a selector');
247
- return;
248
- }
249
- log(`Filling ${selector}...`);
250
- try {
251
- await client.fill(selector, value);
252
- log({ filled: selector, value });
253
- } catch (e) {
254
- log(`Error: ${e}`);
255
- }
256
- });
257
-
258
- // Custom command
259
- document.getElementById('btnExecute')?.addEventListener('click', async () => {
260
- const command = commandJson.value.trim();
261
- if (!command) {
262
- log('Enter a command');
263
- return;
264
- }
265
- try {
266
- log(`Executing: ${command}...`);
267
- const result = await cli.execute(command);
268
- log(result);
269
- } catch (e) {
270
- log(`Error: ${e}`);
271
- }
272
- });
273
-
274
- // Enter key handlers
275
- document.getElementById('navigateUrl')?.addEventListener('keypress', (e) => {
276
- if (e.key === 'Enter') document.getElementById('btnNavigate')?.click();
277
- });
278
-
279
- document.getElementById('clickSelector')?.addEventListener('keypress', (e) => {
280
- if (e.key === 'Enter') document.getElementById('btnClick')?.click();
281
- });
282
-
283
- document.getElementById('fillValue')?.addEventListener('keypress', (e) => {
284
- if (e.key === 'Enter') document.getElementById('btnFill')?.click();
285
- });
286
-
287
- // Copy output
288
- document.getElementById('btnCopyOutput')?.addEventListener('click', async () => {
289
- try {
290
- const text = output.textContent || '';
291
- await navigator.clipboard.writeText(text);
292
- const btn = document.getElementById('btnCopyOutput') as HTMLButtonElement;
293
- const originalText = btn.textContent;
294
- btn.textContent = 'Copied!';
295
- setTimeout(() => {
296
- btn.textContent = originalText;
297
- }, 1500);
298
- } catch (e) {
299
- log(`Copy failed: ${e}`);
300
- }
301
- });
302
-
303
- log('Ready');