@browsers-cli/se-cli 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 (87) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +379 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +14 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/config.d.ts +17 -0
  7. package/dist/config.js +80 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/daemon/backend.d.ts +9 -0
  10. package/dist/daemon/backend.js +52 -0
  11. package/dist/daemon/backend.js.map +1 -0
  12. package/dist/daemon/server.d.ts +1 -0
  13. package/dist/daemon/server.js +341 -0
  14. package/dist/daemon/server.js.map +1 -0
  15. package/dist/daemon/tools/check.d.ts +7 -0
  16. package/dist/daemon/tools/check.js +20 -0
  17. package/dist/daemon/tools/check.js.map +1 -0
  18. package/dist/daemon/tools/click.d.ts +4 -0
  19. package/dist/daemon/tools/click.js +14 -0
  20. package/dist/daemon/tools/click.js.map +1 -0
  21. package/dist/daemon/tools/eval.d.ts +5 -0
  22. package/dist/daemon/tools/eval.js +18 -0
  23. package/dist/daemon/tools/eval.js.map +1 -0
  24. package/dist/daemon/tools/fill.d.ts +6 -0
  25. package/dist/daemon/tools/fill.js +25 -0
  26. package/dist/daemon/tools/fill.js.map +1 -0
  27. package/dist/daemon/tools/find.d.ts +5 -0
  28. package/dist/daemon/tools/find.js +84 -0
  29. package/dist/daemon/tools/find.js.map +1 -0
  30. package/dist/daemon/tools/goto.d.ts +4 -0
  31. package/dist/daemon/tools/goto.js +25 -0
  32. package/dist/daemon/tools/goto.js.map +1 -0
  33. package/dist/daemon/tools/index.d.ts +1 -0
  34. package/dist/daemon/tools/index.js +37 -0
  35. package/dist/daemon/tools/index.js.map +1 -0
  36. package/dist/daemon/tools/navigation.d.ts +4 -0
  37. package/dist/daemon/tools/navigation.js +21 -0
  38. package/dist/daemon/tools/navigation.js.map +1 -0
  39. package/dist/daemon/tools/press.d.ts +4 -0
  40. package/dist/daemon/tools/press.js +23 -0
  41. package/dist/daemon/tools/press.js.map +1 -0
  42. package/dist/daemon/tools/screenshot.d.ts +5 -0
  43. package/dist/daemon/tools/screenshot.js +57 -0
  44. package/dist/daemon/tools/screenshot.js.map +1 -0
  45. package/dist/daemon/tools/select.d.ts +5 -0
  46. package/dist/daemon/tools/select.js +13 -0
  47. package/dist/daemon/tools/select.js.map +1 -0
  48. package/dist/daemon/tools/shared.d.ts +4 -0
  49. package/dist/daemon/tools/shared.js +35 -0
  50. package/dist/daemon/tools/shared.js.map +1 -0
  51. package/dist/daemon/tools/snapshot.d.ts +6 -0
  52. package/dist/daemon/tools/snapshot.js +90 -0
  53. package/dist/daemon/tools/snapshot.js.map +1 -0
  54. package/dist/daemon/tools/title.d.ts +2 -0
  55. package/dist/daemon/tools/title.js +8 -0
  56. package/dist/daemon/tools/title.js.map +1 -0
  57. package/dist/daemon/tools/type.d.ts +4 -0
  58. package/dist/daemon/tools/type.js +9 -0
  59. package/dist/daemon/tools/type.js.map +1 -0
  60. package/dist/daemon/tools/url.d.ts +2 -0
  61. package/dist/daemon/tools/url.js +8 -0
  62. package/dist/daemon/tools/url.js.map +1 -0
  63. package/dist/minimist.d.ts +10 -0
  64. package/dist/minimist.js +52 -0
  65. package/dist/minimist.js.map +1 -0
  66. package/dist/output.d.ts +6 -0
  67. package/dist/output.js +32 -0
  68. package/dist/output.js.map +1 -0
  69. package/dist/program.d.ts +2 -0
  70. package/dist/program.js +200 -0
  71. package/dist/program.js.map +1 -0
  72. package/dist/protocol.d.ts +29 -0
  73. package/dist/protocol.js +3 -0
  74. package/dist/protocol.js.map +1 -0
  75. package/dist/registry.d.ts +19 -0
  76. package/dist/registry.js +91 -0
  77. package/dist/registry.js.map +1 -0
  78. package/dist/response.d.ts +23 -0
  79. package/dist/response.js +64 -0
  80. package/dist/response.js.map +1 -0
  81. package/dist/session.d.ts +23 -0
  82. package/dist/session.js +264 -0
  83. package/dist/session.js.map +1 -0
  84. package/dist/snapshot/aria-snapshot.d.ts +1 -0
  85. package/dist/snapshot/aria-snapshot.js +200 -0
  86. package/dist/snapshot/aria-snapshot.js.map +1 -0
  87. package/package.json +55 -0
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Session = void 0;
37
+ const net = __importStar(require("net"));
38
+ const path = __importStar(require("path"));
39
+ const child_process_1 = require("child_process");
40
+ const registry_1 = require("./registry");
41
+ const config_1 = require("./config");
42
+ class Session {
43
+ workspaceDir;
44
+ sessionName;
45
+ socketPath;
46
+ wsHash;
47
+ registry;
48
+ constructor(workspaceDir, sessionName = 'default') {
49
+ this.workspaceDir = workspaceDir;
50
+ this.sessionName = sessionName;
51
+ this.wsHash = (0, config_1.workspaceHash)(workspaceDir);
52
+ this.socketPath = (0, config_1.makeSocketPath)(this.wsHash, sessionName);
53
+ this.registry = new registry_1.Registry((0, config_1.baseDaemonDir)());
54
+ }
55
+ async canConnect() {
56
+ return new Promise((resolve) => {
57
+ const sock = net.connect(this.socketPath);
58
+ const timer = setTimeout(() => { sock.destroy(); resolve(false); }, 1000);
59
+ sock.once('connect', () => {
60
+ clearTimeout(timer);
61
+ sock.destroy();
62
+ resolve(true);
63
+ });
64
+ sock.once('error', () => { clearTimeout(timer); sock.destroy(); resolve(false); });
65
+ });
66
+ }
67
+ async startDaemon(opts = {}) {
68
+ // If a daemon is already running on this socket, verify it's responsive.
69
+ if (await this.canConnect()) {
70
+ try {
71
+ await this.sendAndClose({ method: 'ping', params: { args: [], cwd: '' } });
72
+ return; // Daemon is alive and responsive
73
+ }
74
+ catch {
75
+ // Daemon is listening but not responsive — force kill it.
76
+ const config = this.registry.loadSession(this.wsHash, this.sessionName);
77
+ if (config && config.pid) {
78
+ try {
79
+ process.kill(config.pid, 'SIGKILL');
80
+ }
81
+ catch { }
82
+ }
83
+ this.registry.deleteSession(this.wsHash, this.sessionName);
84
+ await new Promise(r => setTimeout(r, 500));
85
+ }
86
+ }
87
+ const browserName = opts.browserName || 'chrome';
88
+ const daemonScript = path.join(__dirname, 'daemon', 'server.js');
89
+ const args = [daemonScript, this.sessionName, this.socketPath, this.workspaceDir, browserName];
90
+ if (opts.headed)
91
+ args.push('--headed');
92
+ if (opts.cdpEndpoint)
93
+ args.push(`--cdp=${opts.cdpEndpoint}`);
94
+ const child = (0, child_process_1.spawn)(process.execPath, args, {
95
+ detached: true,
96
+ stdio: ['ignore', 'pipe', 'pipe'],
97
+ });
98
+ await new Promise((resolve, reject) => {
99
+ const timeout = setTimeout(() => {
100
+ child.kill();
101
+ reject(new Error('daemon start timeout'));
102
+ }, 120000);
103
+ const onStdout = (data) => {
104
+ const line = data.toString().trim();
105
+ if (line.startsWith('Daemon listening on')) {
106
+ clearTimeout(timeout);
107
+ // Detach from the child so it survives the parent's exit.
108
+ child.unref();
109
+ // Remove listeners so we don't interfere with the child's lifecycle.
110
+ child.stdout?.removeListener('data', onStdout);
111
+ child.stderr?.removeListener('data', onStderr);
112
+ child.removeListener('error', onError);
113
+ child.removeListener('exit', onExit);
114
+ // Unref the stdio pipes so they don't keep the parent's event
115
+ // loop alive (which would cause execSync-based callers to hang
116
+ // until their timeout). Do NOT destroy the pipes — destroying
117
+ // them breaks the child's stdout/stderr fd and causes the daemon
118
+ // to crash with EPIPE the next time it tries to log an error.
119
+ const stdoutSock = child.stdout;
120
+ const stderrSock = child.stderr;
121
+ stdoutSock.unref?.();
122
+ stderrSock.unref?.();
123
+ resolve();
124
+ }
125
+ };
126
+ const onStderr = (data) => {
127
+ process.stderr.write(`daemon stderr: ${data}`);
128
+ };
129
+ const onError = (err) => {
130
+ clearTimeout(timeout);
131
+ reject(err);
132
+ };
133
+ const onExit = (code, signal) => {
134
+ clearTimeout(timeout);
135
+ reject(new Error(`daemon exited early code=${code} signal=${signal}`));
136
+ };
137
+ child.stdout?.on('data', onStdout);
138
+ child.stderr?.on('data', onStderr);
139
+ child.on('error', onError);
140
+ child.on('exit', onExit);
141
+ });
142
+ // Health check: verify the daemon is actually responsive by sending a ping.
143
+ // The daemon might crash shortly after listening (e.g., during module
144
+ // loading), so we confirm it can handle at least one request.
145
+ try {
146
+ await this.sendAndClose({ method: 'ping', params: { args: [], cwd: '' } });
147
+ }
148
+ catch {
149
+ // Ping failed — the daemon may have crashed. Try one more time with
150
+ // a short delay to give it a chance to fully initialize.
151
+ await new Promise(r => setTimeout(r, 500));
152
+ await this.sendAndClose({ method: 'ping', params: { args: [], cwd: '' } });
153
+ }
154
+ }
155
+ async run(args, cwd, opts = {}) {
156
+ const msg = {
157
+ method: 'run',
158
+ params: { args, cwd, raw: opts.raw, json: opts.json },
159
+ };
160
+ // Retry on connection failures — the daemon may have crashed and
161
+ // needs to be restarted from the saved session config.
162
+ let lastErr = null;
163
+ for (let attempt = 0; attempt < 3; attempt++) {
164
+ try {
165
+ return await this.sendAndClose(msg);
166
+ }
167
+ catch (e) {
168
+ lastErr = e;
169
+ const errMsg = e.message || '';
170
+ if (errMsg.includes('daemon closed connection') || errMsg.includes('ECONNREFUSED') || errMsg.includes('connect ENOENT') || errMsg.includes('ECONNRESET') || errMsg.includes('EPIPE')) {
171
+ // Try to restart the daemon on the first connection failure.
172
+ if (attempt === 0) {
173
+ try {
174
+ const config = this.registry.loadSession(this.wsHash, this.sessionName);
175
+ if (config && config.browserName) {
176
+ await this.startDaemon({ browserName: config.browserName });
177
+ }
178
+ }
179
+ catch {
180
+ // startDaemon may fail — that's OK, we'll retry the connection
181
+ }
182
+ }
183
+ await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
184
+ continue;
185
+ }
186
+ throw e;
187
+ }
188
+ }
189
+ throw lastErr;
190
+ }
191
+ async stop() {
192
+ try {
193
+ await this.sendAndClose({ method: 'stop', params: { args: [], cwd: process.cwd() } });
194
+ }
195
+ catch {
196
+ // daemon may already be dead
197
+ }
198
+ this.registry.deleteSession(this.wsHash, this.sessionName);
199
+ // Wait for the daemon to actually exit — the 'stop' response is sent
200
+ // before shutdown() completes, so the socket might still be alive briefly.
201
+ for (let i = 0; i < 10; i++) {
202
+ if (!(await this.canConnect()))
203
+ break;
204
+ await new Promise(r => setTimeout(r, 200));
205
+ }
206
+ }
207
+ sendAndClose(msg) {
208
+ return new Promise((resolve, reject) => {
209
+ const sock = net.connect(this.socketPath);
210
+ const timeout = setTimeout(() => {
211
+ sock.destroy();
212
+ reject(new Error('daemon connection timeout'));
213
+ }, 60000);
214
+ let settled = false;
215
+ const cleanup = () => {
216
+ clearTimeout(timeout);
217
+ sock.removeAllListeners();
218
+ sock.destroy();
219
+ };
220
+ sock.once('connect', () => {
221
+ sock.write(JSON.stringify(msg) + '\n');
222
+ });
223
+ let buffer = '';
224
+ sock.on('data', (data) => {
225
+ buffer += data.toString();
226
+ if (buffer.includes('\n')) {
227
+ if (settled)
228
+ return;
229
+ settled = true;
230
+ try {
231
+ const resp = JSON.parse(buffer.split('\n')[0]);
232
+ cleanup();
233
+ resolve(resp);
234
+ }
235
+ catch (e) {
236
+ cleanup();
237
+ reject(e);
238
+ }
239
+ }
240
+ });
241
+ sock.once('error', (err) => {
242
+ if (settled)
243
+ return;
244
+ settled = true;
245
+ cleanup();
246
+ reject(err);
247
+ });
248
+ sock.once('close', () => {
249
+ if (settled)
250
+ return;
251
+ settled = true;
252
+ cleanup();
253
+ if (buffer === '' || !buffer.includes('\n')) {
254
+ reject(new Error('daemon closed connection without response'));
255
+ }
256
+ });
257
+ });
258
+ }
259
+ loadConfig() {
260
+ return this.registry.loadSession(this.wsHash, this.sessionName);
261
+ }
262
+ }
263
+ exports.Session = Session;
264
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function generateAriaSnapshotScript(): string;
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateAriaSnapshotScript = generateAriaSnapshotScript;
4
+ function generateAriaSnapshotScript() {
5
+ return `
6
+ (function() {
7
+ const INTERACTIVE_TAGS = new Set([
8
+ 'a', 'button', 'input', 'select', 'textarea',
9
+ 'summary', 'details', 'option', 'optgroup'
10
+ ]);
11
+ const INTERACTIVE_ROLES = new Set([
12
+ 'button', 'link', 'textbox', 'checkbox', 'radio', 'menuitem',
13
+ 'menuitemcheckbox', 'menuitemradio', 'tab', 'combobox',
14
+ 'option', 'searchbox', 'spinbutton', 'slider', 'switch'
15
+ ]);
16
+
17
+ const TAG_TO_ROLE = {
18
+ 'a': 'link',
19
+ 'button': 'button',
20
+ 'input': 'textbox',
21
+ 'select': 'combobox',
22
+ 'textarea': 'textbox',
23
+ 'nav': 'navigation',
24
+ 'main': 'main',
25
+ 'header': 'banner',
26
+ 'footer': 'contentinfo',
27
+ 'aside': 'complementary',
28
+ 'form': 'form',
29
+ 'search': 'search',
30
+ 'h1': 'heading', 'h2': 'heading', 'h3': 'heading',
31
+ 'h4': 'heading', 'h5': 'heading', 'h6': 'heading',
32
+ 'img': 'image',
33
+ 'ul': 'list', 'ol': 'list',
34
+ 'li': 'listitem',
35
+ 'table': 'table',
36
+ 'tr': 'row',
37
+ 'details': 'group',
38
+ 'summary': 'button',
39
+ 'dialog': 'dialog',
40
+ 'alert': 'alert',
41
+ 'menu': 'menu',
42
+ 'menubar': 'menubar',
43
+ 'toolbar': 'toolbar',
44
+ 'tablist': 'tablist',
45
+ 'tab': 'tab',
46
+ 'tabpanel': 'tabpanel',
47
+ 'option': 'option',
48
+ };
49
+
50
+ let refCounter = 0;
51
+ const lines = [];
52
+
53
+ function getRole(el) {
54
+ const explicit = el.getAttribute('role');
55
+ if (explicit) return explicit;
56
+ const tag = el.tagName.toLowerCase();
57
+ if (tag in TAG_TO_ROLE) return TAG_TO_ROLE[tag];
58
+ return null;
59
+ }
60
+
61
+ function getLabel(el, role) {
62
+ const ariaLabel = el.getAttribute('aria-label');
63
+ if (ariaLabel) return ariaLabel;
64
+
65
+ const labelledby = el.getAttribute('aria-labelledby');
66
+ if (labelledby) {
67
+ const labelEl = document.getElementById(labelledby);
68
+ if (labelEl) return labelEl.textContent.trim();
69
+ }
70
+
71
+ const tag = el.tagName.toLowerCase();
72
+ if (tag === 'input' || tag === 'textarea') {
73
+ const type = (el.type || '').toLowerCase();
74
+ if (type === 'checkbox' || type === 'radio') {
75
+ if (el.id) {
76
+ const label = document.querySelector('label[for="' + CSS.escape(el.id) + '"]');
77
+ if (label) return label.textContent.trim();
78
+ }
79
+ const parentLabel = el.closest('label');
80
+ if (parentLabel) return parentLabel.textContent.trim();
81
+ }
82
+ return el.placeholder || el.name || '';
83
+ }
84
+
85
+ if (tag === 'img') return el.alt || el.title || '';
86
+
87
+ const text = (el.textContent || '').trim();
88
+ return text ? text.slice(0, 80) : '';
89
+ }
90
+
91
+ function isInteractive(el, role) {
92
+ const tag = el.tagName.toLowerCase();
93
+ if (INTERACTIVE_TAGS.has(tag)) return true;
94
+ if (role && INTERACTIVE_ROLES.has(role)) return true;
95
+ return false;
96
+ }
97
+
98
+ function isHidden(el) {
99
+ if (el.hidden) return true;
100
+ if (el.getAttribute('aria-hidden') === 'true') return true;
101
+ if (el.style && (el.style.display === 'none' || el.style.visibility === 'hidden')) return true;
102
+ // getComputedStyle for elements that may be hidden via CSS classes
103
+ try {
104
+ const style = window.getComputedStyle(el);
105
+ if (style.display === 'none' || style.visibility === 'hidden') return true;
106
+ } catch (e) {}
107
+ return false;
108
+ }
109
+
110
+ function getAttrs(el, role) {
111
+ const attrs = [];
112
+ const tag = el.tagName.toLowerCase();
113
+ if (tag.match(/^h[1-6]$/)) {
114
+ attrs.push('level=' + tag[1]);
115
+ }
116
+ if (role === 'heading' && el.getAttribute('aria-level')) {
117
+ attrs.push('level=' + el.getAttribute('aria-level'));
118
+ }
119
+ if (el.tagName === 'INPUT') {
120
+ const type = (el.type || '').toLowerCase();
121
+ if (type === 'checkbox' && el.checked) attrs.push('checked');
122
+ if (type === 'radio' && el.checked) attrs.push('checked');
123
+ if (el.disabled) attrs.push('disabled');
124
+ }
125
+ return attrs.length ? ' [' + attrs.join(' ') + ']' : '';
126
+ }
127
+
128
+ function walk(el, level, depth) {
129
+ if (level > depth) return;
130
+ if (isHidden(el)) return;
131
+
132
+ const role = getRole(el);
133
+ if (role === 'none' || role === 'presentation') {
134
+ for (const child of el.children) walk(child, level, depth);
135
+ return;
136
+ }
137
+
138
+ const label = getLabel(el, role);
139
+ const interactive = isInteractive(el, role);
140
+
141
+ let refAttr = '';
142
+ if (interactive) {
143
+ const ref = 'e' + (++refCounter);
144
+ el.setAttribute('data-se-ref', ref);
145
+ refAttr = ' [ref=' + ref + ']';
146
+ }
147
+
148
+ const attrs = getAttrs(el, role);
149
+ const indent = ' '.repeat(level);
150
+
151
+ if (role) {
152
+ const labelPart = label ? ' "' + label + '"' : '';
153
+ lines.push(indent + '- ' + role + labelPart + attrs + refAttr);
154
+ }
155
+
156
+ // Detect iframes and output placeholder
157
+ for (const child of el.children) {
158
+ if (child.tagName === 'IFRAME') {
159
+ const src = child.src || child.getAttribute('src') || '';
160
+ const indent2 = ' '.repeat(level + 1);
161
+ lines.push(indent2 + '- iframe: ' + src);
162
+ continue;
163
+ }
164
+ walk(child, level + 1, depth);
165
+ }
166
+ // Detect open shadow roots
167
+ if (el.shadowRoot) {
168
+ const indent2 = ' '.repeat(level + 1);
169
+ lines.push(indent2 + '- shadowroot:');
170
+ for (const child of el.shadowRoot.children) {
171
+ walk(child, level + 2, depth);
172
+ }
173
+ }
174
+ }
175
+
176
+ return function generateAriaSnapshot(options) {
177
+ options = options || {};
178
+ const depth = options.depth || 50;
179
+ refCounter = 0;
180
+ lines.length = 0;
181
+
182
+ const root = options.target
183
+ ? document.querySelector('[data-se-ref="' + options.target + '"]') || document.querySelector(options.target)
184
+ : document.body;
185
+
186
+ if (!root) return '';
187
+
188
+ if (root === document.body) {
189
+ lines.push('- document:');
190
+ for (const child of root.children) walk(child, 1, depth);
191
+ } else {
192
+ walk(root, 0, depth);
193
+ }
194
+
195
+ return lines.join('\\n');
196
+ };
197
+ })()
198
+ `;
199
+ }
200
+ //# sourceMappingURL=aria-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aria-snapshot.js","sourceRoot":"","sources":["../../src/snapshot/aria-snapshot.ts"],"names":[],"mappings":";;AAAA,gEAmMC;AAnMD,SAAgB,0BAA0B;IACxC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiMR,CAAC;AACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@browsers-cli/se-cli",
3
+ "version": "0.1.0",
4
+ "description": "Selenium CLI with token-efficient browser automation for AI agents",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://se-cli.github.io/se-cli/",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/se-cli/se-cli.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/se-cli/se-cli/issues"
13
+ },
14
+ "keywords": [
15
+ "selenium",
16
+ "cli",
17
+ "webdriver",
18
+ "browser-automation",
19
+ "ai-agent",
20
+ "accessibility",
21
+ "aria"
22
+ ],
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "bin": {
27
+ "se-cli": "dist/cli.js",
28
+ "se": "dist/cli.js",
29
+ "selenium-cli": "dist/cli.js"
30
+ },
31
+ "files": [
32
+ "dist/",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "dev": "tsc --watch",
39
+ "test": "vitest run",
40
+ "test:watch": "vitest",
41
+ "lint": "tsc --noEmit"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "registry": "https://registry.npmjs.org/"
46
+ },
47
+ "dependencies": {
48
+ "selenium-webdriver": "^4.25.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.0.0",
52
+ "typescript": "^5.4.0",
53
+ "vitest": "^2.0.0"
54
+ }
55
+ }