btcp-browser-agent 0.1.0

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 (117) hide show
  1. package/CLAUDE.md +230 -0
  2. package/LICENSE +21 -0
  3. package/README.md +309 -0
  4. package/SKILL.md +143 -0
  5. package/SNAPSHOT_IMPROVEMENTS.md +302 -0
  6. package/USAGE.md +146 -0
  7. package/dist/index.d.ts +34 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +35 -0
  10. package/dist/index.js.map +1 -0
  11. package/docs/browser-cli-design.md +500 -0
  12. package/examples/chrome-extension/CHANGELOG.md +210 -0
  13. package/examples/chrome-extension/DEBUG.md +231 -0
  14. package/examples/chrome-extension/ERROR_FIXED.md +147 -0
  15. package/examples/chrome-extension/QUICK_TEST.md +189 -0
  16. package/examples/chrome-extension/README.md +149 -0
  17. package/examples/chrome-extension/SESSION_ONLY_MODE.md +305 -0
  18. package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +97 -0
  19. package/examples/chrome-extension/build.js +43 -0
  20. package/examples/chrome-extension/manifest.json +37 -0
  21. package/examples/chrome-extension/package-lock.json +1063 -0
  22. package/examples/chrome-extension/package.json +21 -0
  23. package/examples/chrome-extension/popup.html +195 -0
  24. package/examples/chrome-extension/src/background.ts +12 -0
  25. package/examples/chrome-extension/src/content.ts +7 -0
  26. package/examples/chrome-extension/src/popup.ts +303 -0
  27. package/examples/chrome-extension/src/scenario-google-github.ts +389 -0
  28. package/examples/chrome-extension/test-page.html +127 -0
  29. package/examples/chrome-extension/tests/README.md +206 -0
  30. package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +380 -0
  31. package/examples/chrome-extension/tsconfig.json +14 -0
  32. package/examples/snapshots/README.md +207 -0
  33. package/examples/snapshots/amazon-com-detail.html +9528 -0
  34. package/examples/snapshots/amazon-com-detail.snapshot.txt +997 -0
  35. package/examples/snapshots/convert-snapshots.ts +97 -0
  36. package/examples/snapshots/edition-cnn-com.html +13292 -0
  37. package/examples/snapshots/edition-cnn-com.snapshot.txt +562 -0
  38. package/examples/snapshots/github-com-microsoft-vscode.html +2916 -0
  39. package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +455 -0
  40. package/examples/snapshots/google-search.html +20012 -0
  41. package/examples/snapshots/google-search.snapshot.txt +195 -0
  42. package/examples/snapshots/metadata.json +86 -0
  43. package/examples/snapshots/npr-org-templates.html +2031 -0
  44. package/examples/snapshots/npr-org-templates.snapshot.txt +224 -0
  45. package/examples/snapshots/stackoverflow-com.html +5216 -0
  46. package/examples/snapshots/stackoverflow-com.snapshot.txt +2404 -0
  47. package/examples/snapshots/test-all-mode.html +46 -0
  48. package/examples/snapshots/test-all-mode.snapshot.txt +5 -0
  49. package/examples/snapshots/validate.test.ts +296 -0
  50. package/package.json +65 -0
  51. package/packages/cli/package.json +42 -0
  52. package/packages/cli/src/__tests__/cli.test.ts +434 -0
  53. package/packages/cli/src/__tests__/errors.test.ts +226 -0
  54. package/packages/cli/src/__tests__/executor.test.ts +275 -0
  55. package/packages/cli/src/__tests__/formatter.test.ts +260 -0
  56. package/packages/cli/src/__tests__/parser.test.ts +288 -0
  57. package/packages/cli/src/__tests__/suggestions.test.ts +255 -0
  58. package/packages/cli/src/commands/back.ts +22 -0
  59. package/packages/cli/src/commands/check.ts +33 -0
  60. package/packages/cli/src/commands/clear.ts +33 -0
  61. package/packages/cli/src/commands/click.ts +32 -0
  62. package/packages/cli/src/commands/closetab.ts +31 -0
  63. package/packages/cli/src/commands/eval.ts +41 -0
  64. package/packages/cli/src/commands/fill.ts +30 -0
  65. package/packages/cli/src/commands/focus.ts +33 -0
  66. package/packages/cli/src/commands/forward.ts +22 -0
  67. package/packages/cli/src/commands/goto.ts +34 -0
  68. package/packages/cli/src/commands/help.ts +162 -0
  69. package/packages/cli/src/commands/hover.ts +34 -0
  70. package/packages/cli/src/commands/index.ts +129 -0
  71. package/packages/cli/src/commands/newtab.ts +35 -0
  72. package/packages/cli/src/commands/press.ts +40 -0
  73. package/packages/cli/src/commands/reload.ts +25 -0
  74. package/packages/cli/src/commands/screenshot.ts +27 -0
  75. package/packages/cli/src/commands/scroll.ts +64 -0
  76. package/packages/cli/src/commands/select.ts +35 -0
  77. package/packages/cli/src/commands/snapshot.ts +21 -0
  78. package/packages/cli/src/commands/tab.ts +32 -0
  79. package/packages/cli/src/commands/tabs.ts +26 -0
  80. package/packages/cli/src/commands/text.ts +27 -0
  81. package/packages/cli/src/commands/title.ts +17 -0
  82. package/packages/cli/src/commands/type.ts +38 -0
  83. package/packages/cli/src/commands/uncheck.ts +33 -0
  84. package/packages/cli/src/commands/url.ts +17 -0
  85. package/packages/cli/src/commands/wait.ts +54 -0
  86. package/packages/cli/src/errors.ts +164 -0
  87. package/packages/cli/src/executor.ts +68 -0
  88. package/packages/cli/src/formatter.ts +215 -0
  89. package/packages/cli/src/index.ts +257 -0
  90. package/packages/cli/src/parser.ts +195 -0
  91. package/packages/cli/src/suggestions.ts +207 -0
  92. package/packages/cli/src/terminal/Terminal.ts +365 -0
  93. package/packages/cli/src/terminal/index.ts +5 -0
  94. package/packages/cli/src/types.ts +155 -0
  95. package/packages/cli/tsconfig.json +20 -0
  96. package/packages/core/package.json +35 -0
  97. package/packages/core/src/actions.ts +1210 -0
  98. package/packages/core/src/errors.ts +296 -0
  99. package/packages/core/src/index.test.ts +638 -0
  100. package/packages/core/src/index.ts +220 -0
  101. package/packages/core/src/ref-map.ts +107 -0
  102. package/packages/core/src/snapshot.ts +873 -0
  103. package/packages/core/src/types.ts +536 -0
  104. package/packages/core/tsconfig.json +23 -0
  105. package/packages/extension/README.md +129 -0
  106. package/packages/extension/package.json +43 -0
  107. package/packages/extension/src/background.ts +888 -0
  108. package/packages/extension/src/content.ts +172 -0
  109. package/packages/extension/src/index.ts +579 -0
  110. package/packages/extension/src/session-manager.ts +385 -0
  111. package/packages/extension/src/session-types.ts +144 -0
  112. package/packages/extension/src/types.ts +162 -0
  113. package/packages/extension/tsconfig.json +28 -0
  114. package/src/index.ts +64 -0
  115. package/tsconfig.build.json +12 -0
  116. package/tsconfig.json +26 -0
  117. package/vitest.config.ts +13 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * eval command - Execute JavaScript in page context
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { InvalidArgumentsError } from '../errors.js';
7
+
8
+ export const evalCommand: CommandHandler = {
9
+ name: 'eval',
10
+ description: 'Execute JavaScript in the page context',
11
+ usage: 'eval <code>',
12
+ examples: [
13
+ 'eval document.title',
14
+ 'eval "window.scrollTo(0, 0)"',
15
+ 'eval "document.querySelectorAll(\'a\').length"',
16
+ ],
17
+
18
+ async execute(client, args) {
19
+ if (args.length === 0) {
20
+ throw new InvalidArgumentsError('JavaScript code required', 'eval <code>');
21
+ }
22
+
23
+ const script = args.join(' ');
24
+
25
+ const response = await client.execute({
26
+ id: `cmd_${Date.now()}`,
27
+ action: 'evaluate',
28
+ script,
29
+ } as any);
30
+
31
+ if (response.success) {
32
+ const result = (response as any).data?.result;
33
+ return {
34
+ success: true,
35
+ data: result !== undefined ? String(result) : '(undefined)',
36
+ };
37
+ }
38
+
39
+ return { success: false, error: response.error };
40
+ },
41
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * fill command - Fill an input field
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { InvalidArgumentsError } from '../errors.js';
7
+
8
+ export const fillCommand: CommandHandler = {
9
+ name: 'fill',
10
+ description: 'Fill an input field (sets value directly)',
11
+ usage: 'fill <selector> <value>',
12
+ examples: ['fill @ref:1 "john@example.com"', 'fill #email test@test.com'],
13
+
14
+ async execute(client, args) {
15
+ if (args.length < 2) {
16
+ throw new InvalidArgumentsError('Selector and value required', 'fill <selector> <value>');
17
+ }
18
+
19
+ const selector = args[0];
20
+ const value = args.slice(1).join(' ');
21
+
22
+ const response = await client.fill(selector, value);
23
+
24
+ if (response.success) {
25
+ return { success: true, message: `Filled: ${selector}` };
26
+ }
27
+
28
+ return { success: false, error: response.error };
29
+ },
30
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * focus command - Focus an element
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { InvalidArgumentsError } from '../errors.js';
7
+
8
+ export const focusCommand: CommandHandler = {
9
+ name: 'focus',
10
+ description: 'Focus an element',
11
+ usage: 'focus <selector>',
12
+ examples: ['focus @ref:1', 'focus #input'],
13
+
14
+ async execute(client, args) {
15
+ if (args.length === 0) {
16
+ throw new InvalidArgumentsError('Selector required', 'focus <selector>');
17
+ }
18
+
19
+ const selector = args[0];
20
+
21
+ const response = await client.execute({
22
+ id: `cmd_${Date.now()}`,
23
+ action: 'focus',
24
+ selector,
25
+ } as any);
26
+
27
+ if (response.success) {
28
+ return { success: true, message: `Focused: ${selector}` };
29
+ }
30
+
31
+ return { success: false, error: response.error };
32
+ },
33
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * forward command - Go forward in browser history
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+
7
+ export const forwardCommand: CommandHandler = {
8
+ name: 'forward',
9
+ description: 'Go forward in browser history',
10
+ usage: 'forward',
11
+ examples: ['forward'],
12
+
13
+ async execute(client) {
14
+ const response = await client.forward();
15
+
16
+ if (response.success) {
17
+ return { success: true, message: 'Navigated forward' };
18
+ }
19
+
20
+ return { success: false, error: response.error };
21
+ },
22
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * goto command - Navigate to a URL
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { InvalidArgumentsError } from '../errors.js';
7
+
8
+ export const gotoCommand: CommandHandler = {
9
+ name: 'goto',
10
+ description: 'Navigate to a URL',
11
+ usage: 'goto <url>',
12
+ examples: ['goto https://example.com', 'goto github.com'],
13
+
14
+ async execute(client, args) {
15
+ if (args.length === 0) {
16
+ throw new InvalidArgumentsError('URL required', 'goto <url>');
17
+ }
18
+
19
+ let url = args[0];
20
+
21
+ // Add https:// if no protocol specified
22
+ if (!url.match(/^https?:\/\//i)) {
23
+ url = `https://${url}`;
24
+ }
25
+
26
+ const response = await client.navigate(url);
27
+
28
+ if (response.success) {
29
+ return { success: true, message: `Navigated to ${url}` };
30
+ }
31
+
32
+ return { success: false, error: response.error };
33
+ },
34
+ };
@@ -0,0 +1,162 @@
1
+ /**
2
+ * help command - Show help information
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { formatCommandHelp } from '../formatter.js';
7
+ import { commands } from './index.js';
8
+ import { commandCategories, findSimilarCommands } from '../suggestions.js';
9
+
10
+ /**
11
+ * Format categorized help
12
+ */
13
+ function formatCategorizedHelp(): string {
14
+ let output = 'BTCP Browser CLI - Available Commands\n';
15
+ output += '═'.repeat(40) + '\n\n';
16
+
17
+ for (const [, category] of Object.entries(commandCategories)) {
18
+ output += `▸ ${category.name}\n`;
19
+ output += ` ${category.description}\n\n`;
20
+
21
+ for (const cmdName of category.commands) {
22
+ const cmd = commands[cmdName];
23
+ if (cmd) {
24
+ const padding = ' '.repeat(Math.max(0, 12 - cmdName.length));
25
+ output += ` ${cmdName}${padding}${cmd.description}\n`;
26
+ }
27
+ }
28
+ output += '\n';
29
+ }
30
+
31
+ output += '─'.repeat(40) + '\n';
32
+ output += 'Tips:\n';
33
+ output += ' • Type "help <command>" for detailed usage\n';
34
+ output += ' • Type "help category <name>" for category commands\n';
35
+ output += ' • Use @ref:N selectors from snapshot output\n';
36
+ output += ' • Comments start with # in multi-line input\n';
37
+
38
+ return output;
39
+ }
40
+
41
+ /**
42
+ * Format category-specific help
43
+ */
44
+ function formatCategoryHelp(categoryKey: string): string | null {
45
+ const category = commandCategories[categoryKey as keyof typeof commandCategories];
46
+ if (!category) return null;
47
+
48
+ let output = `${category.name}\n`;
49
+ output += '─'.repeat(30) + '\n';
50
+ output += `${category.description}\n\n`;
51
+ output += 'Commands:\n\n';
52
+
53
+ for (const cmdName of category.commands) {
54
+ const cmd = commands[cmdName];
55
+ if (cmd) {
56
+ output += ` ${cmd.usage}\n`;
57
+ output += ` ${cmd.description}\n`;
58
+ if (cmd.examples && cmd.examples.length > 0) {
59
+ output += ` Example: ${cmd.examples[0]}\n`;
60
+ }
61
+ output += '\n';
62
+ }
63
+ }
64
+
65
+ return output;
66
+ }
67
+
68
+ /**
69
+ * Format quick reference
70
+ */
71
+ function formatQuickRef(): string {
72
+ let output = 'Quick Reference\n';
73
+ output += '═'.repeat(40) + '\n\n';
74
+
75
+ output += 'Common Workflow:\n';
76
+ output += ' goto <url> Navigate to page\n';
77
+ output += ' snapshot See page elements\n';
78
+ output += ' click @ref:N Click element\n';
79
+ output += ' type @ref:N "..." Type into input\n';
80
+ output += ' fill @ref:N "..." Fill input field\n\n';
81
+
82
+ output += 'Selectors:\n';
83
+ output += ' @ref:5 Element ref from snapshot\n';
84
+ output += ' #id CSS ID selector\n';
85
+ output += ' .class CSS class selector\n';
86
+ output += ' button Tag name selector\n\n';
87
+
88
+ output += 'Multi-line:\n';
89
+ output += ' Commands can be separated by newlines\n';
90
+ output += ' Lines starting with # are comments\n';
91
+ output += ' Execution stops on first error\n';
92
+
93
+ return output;
94
+ }
95
+
96
+ export const helpCommand: CommandHandler = {
97
+ name: 'help',
98
+ description: 'Show help information',
99
+ usage: 'help [command|category <name>|quick]',
100
+ examples: [
101
+ 'help',
102
+ 'help goto',
103
+ 'help category navigation',
104
+ 'help quick',
105
+ ],
106
+
107
+ async execute(_client, args) {
108
+ if (args.length === 0) {
109
+ return { success: true, data: formatCategorizedHelp() };
110
+ }
111
+
112
+ const first = args[0].toLowerCase();
113
+
114
+ // Quick reference
115
+ if (first === 'quick' || first === 'ref') {
116
+ return { success: true, data: formatQuickRef() };
117
+ }
118
+
119
+ // Category help
120
+ if (first === 'category' || first === 'cat') {
121
+ if (args.length < 2) {
122
+ const categories = Object.keys(commandCategories).join(', ');
123
+ return {
124
+ success: true,
125
+ data: `Available categories: ${categories}\n\nUsage: help category <name>`,
126
+ };
127
+ }
128
+ const categoryHelp = formatCategoryHelp(args[1].toLowerCase());
129
+ if (categoryHelp) {
130
+ return { success: true, data: categoryHelp };
131
+ }
132
+ const categories = Object.keys(commandCategories).join(', ');
133
+ return {
134
+ success: false,
135
+ error: `Unknown category: ${args[1]}\n\nAvailable: ${categories}`,
136
+ };
137
+ }
138
+
139
+ // Command help
140
+ const cmdName = first;
141
+ const cmd = commands[cmdName];
142
+
143
+ if (cmd) {
144
+ return { success: true, data: formatCommandHelp(cmd) };
145
+ }
146
+
147
+ // Suggest similar commands
148
+ const similar = findSimilarCommands(cmdName);
149
+ if (similar.length > 0) {
150
+ const suggestions = similar.map((s) => ` ${s}`).join('\n');
151
+ return {
152
+ success: false,
153
+ error: `Unknown command: ${cmdName}\n\nDid you mean:\n${suggestions}\n\nType "help" for all commands`,
154
+ };
155
+ }
156
+
157
+ return {
158
+ success: false,
159
+ error: `Unknown command: ${cmdName}\n\nType "help" to see available commands`,
160
+ };
161
+ },
162
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * hover command - Hover over an element
3
+ */
4
+
5
+ import type { CommandHandler, CommandClient } from '../types.js';
6
+ import { InvalidArgumentsError } from '../errors.js';
7
+
8
+ export const hoverCommand: CommandHandler = {
9
+ name: 'hover',
10
+ description: 'Hover over an element',
11
+ usage: 'hover <selector>',
12
+ examples: ['hover @ref:5', 'hover .menu-item'],
13
+
14
+ async execute(client, args) {
15
+ if (args.length === 0) {
16
+ throw new InvalidArgumentsError('Selector required', 'hover <selector>');
17
+ }
18
+
19
+ const selector = args[0];
20
+
21
+ // Use execute for hover since it may not be in the simplified client interface
22
+ const response = await client.execute({
23
+ id: `cmd_${Date.now()}`,
24
+ action: 'hover',
25
+ selector,
26
+ } as any);
27
+
28
+ if (response.success) {
29
+ return { success: true, message: `Hovered: ${selector}` };
30
+ }
31
+
32
+ return { success: false, error: response.error };
33
+ },
34
+ };
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Command registry - exports all available commands
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+
7
+ // Navigation
8
+ import { gotoCommand } from './goto.js';
9
+ import { backCommand } from './back.js';
10
+ import { forwardCommand } from './forward.js';
11
+ import { reloadCommand } from './reload.js';
12
+ import { urlCommand } from './url.js';
13
+ import { titleCommand } from './title.js';
14
+
15
+ // Snapshot & Screenshot
16
+ import { snapshotCommand } from './snapshot.js';
17
+ import { screenshotCommand } from './screenshot.js';
18
+
19
+ // DOM Interaction
20
+ import { clickCommand } from './click.js';
21
+ import { typeCommand } from './type.js';
22
+ import { fillCommand } from './fill.js';
23
+ import { clearCommand } from './clear.js';
24
+ import { hoverCommand } from './hover.js';
25
+ import { scrollCommand } from './scroll.js';
26
+ import { pressCommand } from './press.js';
27
+ import { focusCommand } from './focus.js';
28
+ import { checkCommand } from './check.js';
29
+ import { uncheckCommand } from './uncheck.js';
30
+ import { selectCommand } from './select.js';
31
+
32
+ // Tab Management
33
+ import { tabsCommand } from './tabs.js';
34
+ import { tabCommand } from './tab.js';
35
+ import { newtabCommand } from './newtab.js';
36
+ import { closetabCommand } from './closetab.js';
37
+
38
+ // Utility
39
+ import { waitCommand } from './wait.js';
40
+ import { evalCommand } from './eval.js';
41
+ import { textCommand } from './text.js';
42
+ import { helpCommand } from './help.js';
43
+
44
+ /**
45
+ * Command registry - map of command name to handler
46
+ */
47
+ export const commands: Record<string, CommandHandler> = {
48
+ // Navigation
49
+ goto: gotoCommand,
50
+ back: backCommand,
51
+ forward: forwardCommand,
52
+ reload: reloadCommand,
53
+ url: urlCommand,
54
+ title: titleCommand,
55
+
56
+ // Snapshot & Screenshot
57
+ snapshot: snapshotCommand,
58
+ screenshot: screenshotCommand,
59
+
60
+ // DOM Interaction
61
+ click: clickCommand,
62
+ type: typeCommand,
63
+ fill: fillCommand,
64
+ clear: clearCommand,
65
+ hover: hoverCommand,
66
+ scroll: scrollCommand,
67
+ press: pressCommand,
68
+ focus: focusCommand,
69
+ check: checkCommand,
70
+ uncheck: uncheckCommand,
71
+ select: selectCommand,
72
+
73
+ // Tab Management
74
+ tabs: tabsCommand,
75
+ tab: tabCommand,
76
+ newtab: newtabCommand,
77
+ closetab: closetabCommand,
78
+
79
+ // Utility
80
+ wait: waitCommand,
81
+ eval: evalCommand,
82
+ text: textCommand,
83
+ help: helpCommand,
84
+ };
85
+
86
+ /**
87
+ * Get a command handler by name
88
+ */
89
+ export function getCommand(name: string): CommandHandler | undefined {
90
+ return commands[name.toLowerCase()];
91
+ }
92
+
93
+ /**
94
+ * Get all command handlers
95
+ */
96
+ export function getAllCommands(): CommandHandler[] {
97
+ return Object.values(commands);
98
+ }
99
+
100
+ // Re-export individual commands for direct imports
101
+ export {
102
+ gotoCommand,
103
+ backCommand,
104
+ forwardCommand,
105
+ reloadCommand,
106
+ urlCommand,
107
+ titleCommand,
108
+ snapshotCommand,
109
+ screenshotCommand,
110
+ clickCommand,
111
+ typeCommand,
112
+ fillCommand,
113
+ clearCommand,
114
+ hoverCommand,
115
+ scrollCommand,
116
+ pressCommand,
117
+ focusCommand,
118
+ checkCommand,
119
+ uncheckCommand,
120
+ selectCommand,
121
+ tabsCommand,
122
+ tabCommand,
123
+ newtabCommand,
124
+ closetabCommand,
125
+ waitCommand,
126
+ evalCommand,
127
+ textCommand,
128
+ helpCommand,
129
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * newtab command - Open a new tab
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { getFlagBool } from '../parser.js';
7
+
8
+ export const newtabCommand: CommandHandler = {
9
+ name: 'newtab',
10
+ description: 'Open a new tab',
11
+ usage: 'newtab [url] [--background]',
12
+ examples: ['newtab', 'newtab https://example.com', 'newtab github.com --background'],
13
+
14
+ async execute(client, args, flags) {
15
+ let url = args[0];
16
+
17
+ // Add https:// if URL provided without protocol
18
+ if (url && !url.match(/^https?:\/\//i)) {
19
+ url = `https://${url}`;
20
+ }
21
+
22
+ const background = getFlagBool(flags, 'background');
23
+
24
+ const result = await client.tabNew({
25
+ url,
26
+ active: !background,
27
+ });
28
+
29
+ return {
30
+ success: true,
31
+ message: `Opened new tab [${result.tabId}]${url ? `: ${url}` : ''}`,
32
+ data: result,
33
+ };
34
+ },
35
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * press command - Press a keyboard key
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { InvalidArgumentsError } from '../errors.js';
7
+
8
+ export const pressCommand: CommandHandler = {
9
+ name: 'press',
10
+ description: 'Press a keyboard key',
11
+ usage: 'press <key> [selector]',
12
+ examples: [
13
+ 'press Enter',
14
+ 'press Tab',
15
+ 'press Escape',
16
+ 'press Enter @ref:1',
17
+ ],
18
+
19
+ async execute(client, args) {
20
+ if (args.length === 0) {
21
+ throw new InvalidArgumentsError('Key required', 'press <key> [selector]');
22
+ }
23
+
24
+ const key = args[0];
25
+ const selector = args[1];
26
+
27
+ const response = await client.execute({
28
+ id: `cmd_${Date.now()}`,
29
+ action: 'press',
30
+ key,
31
+ selector,
32
+ } as any);
33
+
34
+ if (response.success) {
35
+ return { success: true, message: `Pressed: ${key}` };
36
+ }
37
+
38
+ return { success: false, error: response.error };
39
+ },
40
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * reload command - Reload the current page
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { getFlagBool } from '../parser.js';
7
+
8
+ export const reloadCommand: CommandHandler = {
9
+ name: 'reload',
10
+ description: 'Reload the current page',
11
+ usage: 'reload [--hard]',
12
+ examples: ['reload', 'reload --hard'],
13
+
14
+ async execute(client, _args, flags) {
15
+ const bypassCache = getFlagBool(flags, 'hard');
16
+ const response = await client.reload({ bypassCache });
17
+
18
+ if (response.success) {
19
+ const msg = bypassCache ? 'Hard reloaded page' : 'Reloaded page';
20
+ return { success: true, message: msg };
21
+ }
22
+
23
+ return { success: false, error: response.error };
24
+ },
25
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * screenshot command - Capture visible tab
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { getFlagString, getFlagNumber } from '../parser.js';
7
+ import { formatScreenshot } from '../formatter.js';
8
+
9
+ export const screenshotCommand: CommandHandler = {
10
+ name: 'screenshot',
11
+ description: 'Capture screenshot of visible tab',
12
+ usage: 'screenshot [--format png|jpeg] [--quality <0-100>]',
13
+ examples: ['screenshot', 'screenshot --format jpeg --quality 80'],
14
+
15
+ async execute(client, _args, flags) {
16
+ const formatFlag = getFlagString(flags, 'format');
17
+ const format = formatFlag === 'jpeg' ? 'jpeg' : 'png';
18
+ const quality = getFlagNumber(flags, 'quality');
19
+
20
+ const dataUrl = await client.screenshot({ format, quality });
21
+ return {
22
+ success: true,
23
+ message: formatScreenshot(dataUrl),
24
+ data: dataUrl,
25
+ };
26
+ },
27
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * scroll command - Scroll the page
3
+ */
4
+
5
+ import type { CommandHandler } from '../types.js';
6
+ import { getFlagNumber } from '../parser.js';
7
+
8
+ export const scrollCommand: CommandHandler = {
9
+ name: 'scroll',
10
+ description: 'Scroll the page',
11
+ usage: 'scroll <direction> [amount] | scroll <selector>',
12
+ examples: [
13
+ 'scroll down',
14
+ 'scroll up 500',
15
+ 'scroll down 200',
16
+ 'scroll @ref:5',
17
+ ],
18
+
19
+ async execute(client, args, flags) {
20
+ if (args.length === 0) {
21
+ // Default to scroll down
22
+ const response = await client.execute({
23
+ id: `cmd_${Date.now()}`,
24
+ action: 'scroll',
25
+ direction: 'down',
26
+ amount: 300,
27
+ } as any);
28
+ return response.success
29
+ ? { success: true, message: 'Scrolled down' }
30
+ : { success: false, error: response.error };
31
+ }
32
+
33
+ const first = args[0].toLowerCase();
34
+
35
+ // Check if it's a direction
36
+ if (['up', 'down', 'left', 'right'].includes(first)) {
37
+ const direction = first as 'up' | 'down' | 'left' | 'right';
38
+ const amount = args[1] ? parseInt(args[1], 10) : 300;
39
+
40
+ const response = await client.execute({
41
+ id: `cmd_${Date.now()}`,
42
+ action: 'scroll',
43
+ direction,
44
+ amount: isNaN(amount) ? 300 : amount,
45
+ } as any);
46
+
47
+ return response.success
48
+ ? { success: true, message: `Scrolled ${direction}` }
49
+ : { success: false, error: response.error };
50
+ }
51
+
52
+ // It's a selector - scroll element into view
53
+ const selector = args[0];
54
+ const response = await client.execute({
55
+ id: `cmd_${Date.now()}`,
56
+ action: 'scrollIntoView',
57
+ selector,
58
+ } as any);
59
+
60
+ return response.success
61
+ ? { success: true, message: `Scrolled to: ${selector}` }
62
+ : { success: false, error: response.error };
63
+ },
64
+ };