@pablovitasso/szkrabok 1.0.16 → 1.0.18

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/README.md CHANGED
@@ -80,20 +80,19 @@ session_manage { "action": "open", "sessionName": "my-session" }
80
80
  browser.run_test { "sessionName": "my-session", "files": ["automation/example.spec.js"] }
81
81
  ```
82
82
 
83
- ### Bebok (CLI)
83
+ ### CLI
84
84
 
85
- `bebok` is the human/shell interface calls the same handlers as MCP tools:
85
+ `szkrabok` is both the MCP server and the CLI. With no arguments it starts the MCP server; with a subcommand it runs the CLI:
86
86
 
87
87
  ```bash
88
- bebok open <profile> # Launch browser, print CDP endpoint, stay alive
89
- bebok session list # Show all sessions (active + stored)
90
- bebok session inspect <id> # Dump cookie/localStorage counts
91
- bebok session delete <id> # Delete a session
92
- bebok session cleanup --days 30 # Delete sessions unused for N days
93
- bebok endpoint <sessionName> # Print CDP + WS endpoints
94
-
95
- szkrabok detect-browser # List usable Chrome/Chromium installations
96
- szkrabok install-browser # Install Playwright's Chromium
88
+ szkrabok open <profile> # Launch browser, print CDP endpoint, stay alive
89
+ szkrabok session list # Show all sessions (active + stored)
90
+ szkrabok session inspect <id> # Dump cookie/localStorage counts
91
+ szkrabok session delete <id> # Delete a session
92
+ szkrabok session cleanup --days 30 # Delete sessions unused for N days
93
+ szkrabok endpoint <sessionName> # Print CDP + WS endpoints
94
+ szkrabok detect-browser # List usable Chrome/Chromium installations
95
+ szkrabok install-browser # Install Playwright's Chromium
97
96
  ```
98
97
 
99
98
  ---
@@ -102,7 +101,7 @@ szkrabok install-browser # Install Playwright's Chromium
102
101
 
103
102
  * **`@pablovitasso/szkrabok/runtime`** (`packages/runtime/`): Browser bootstrap, stealth, session pool, MCP client (`mcpConnect`, `spawnClient`, codegen).
104
103
  * **Config**: `szkrabok.config.toml` (defaults) deep-merged with `szkrabok.config.local.toml` (machine-specific, gitignored).
105
- * **Release**: `npm run release:patch` bumps version, then `npm publish --access public`.
104
+ * **Release**: `npm run deps:update` updates dependencies, `npm run release:patch` bumps version + tags, then `npm run release:publish`.
106
105
 
107
106
  ---
108
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pablovitasso/szkrabok",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Production-grade MCP browser automation layer with persistent sessions and stealth capabilities",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -18,8 +18,7 @@
18
18
  "README.md"
19
19
  ],
20
20
  "bin": {
21
- "szkrabok": "src/index.js",
22
- "bebok": "src/cli.js"
21
+ "szkrabok": "src/index.js"
23
22
  },
24
23
  "engines": {
25
24
  "node": ">=20.0.0"
@@ -37,8 +36,9 @@
37
36
  "format:check": "prettier --check \"{src,tests}/**/*.{js,json,md}\" \"*.{js,json,md}\"",
38
37
  "codegen:mcp": "node packages/runtime/mcp-client/codegen/generate-mcp-tools.mjs",
39
38
  "prepack": "git describe --exact-match --tags HEAD 2>/dev/null || (echo 'ERROR: HEAD is not tagged. Run npm run release:patch or release:minor first.' && exit 1)",
40
- "release:patch": "npm version patch --workspaces --include-workspace-root --ignore-scripts && node scripts/release-commit.js && node scripts/release-reminder.js",
41
- "release:minor": "npm version minor --workspaces --include-workspace-root --ignore-scripts && node scripts/release-commit.js && node scripts/release-reminder.js",
39
+ "release:patch": "npm version patch --workspaces --include-workspace-root --ignore-scripts --no-git-tag-version && node scripts/release-commit.js",
40
+ "release:minor": "npm version minor --workspaces --include-workspace-root --ignore-scripts --no-git-tag-version && node scripts/release-commit.js",
41
+ "deps:update": "npx npm-check-updates -u --workspaces && npm install",
42
42
  "release:publish": "node scripts/release-publish.js",
43
43
  "test": "npm run test:self && npm run test:auto",
44
44
  "test:node": "node --test tests/node/*.test.js",
@@ -68,26 +68,26 @@
68
68
  "url": "git+https://github.com/PabloVitasso/szkrabok.git"
69
69
  },
70
70
  "dependencies": {
71
- "@modelcontextprotocol/sdk": "^1.0.4",
71
+ "@modelcontextprotocol/sdk": "^1.27.1",
72
72
  "dotenv": "^17.3.1",
73
- "playwright": "^1.49.1",
73
+ "playwright": "^1.58.2",
74
74
  "playwright-core": "^1.58.2",
75
75
  "playwright-extra": "^4.3.6",
76
- "puppeteer": "^24.34.0",
76
+ "puppeteer": "^24.39.0",
77
77
  "puppeteer-extra-plugin-stealth": "^2.11.2",
78
78
  "smol-toml": "^1.6.0",
79
- "zod": "^3.24.1"
79
+ "zod": "^4.3.6"
80
80
  },
81
81
  "devDependencies": {
82
- "@eslint/js": "^9.17.0",
83
- "@types/puppeteer": "^5.4.7",
84
- "ajv": "^8.17.1",
82
+ "@eslint/js": "^10.0.1",
83
+ "@types/puppeteer": "^7.0.4",
84
+ "ajv": "^8.18.0",
85
85
  "ajv-formats": "^3.0.1",
86
- "eslint": "^9.17.0",
87
- "eslint-config-prettier": "^9.1.0",
86
+ "eslint": "^10.0.3",
87
+ "eslint-config-prettier": "^10.1.8",
88
88
  "eslint-plugin-node": "^11.1.0",
89
- "globals": "^15.13.0",
90
- "prettier": "^3.4.2",
89
+ "globals": "^17.4.0",
90
+ "prettier": "^3.8.1",
91
91
  "puppeteer-extra": "^3.3.6"
92
92
  },
93
93
  "puppeteer": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@szkrabok/runtime",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "szkrabok — browser bootstrap, stealth, session pool, MCP client.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -18,7 +18,7 @@
18
18
  "node": ">=20.0.0"
19
19
  },
20
20
  "dependencies": {
21
- "@modelcontextprotocol/sdk": ">=1.0.0",
21
+ "@modelcontextprotocol/sdk": ">=1.27.1",
22
22
  "chrome-launcher": "*",
23
23
  "playwright": "*",
24
24
  "playwright-core": "*",
@@ -3,9 +3,23 @@ import { readFileSync } from 'node:fs';
3
3
  import { resolve, dirname } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
 
6
- const pkg = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'));
6
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
7
+ const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
8
+ const v = pkg.version;
7
9
 
8
- execSync(
9
- `git add package.json package-lock.json packages/runtime/package.json && git commit -m "chore: release ${pkg.version}"`,
10
- { stdio: 'inherit' }
11
- );
10
+ const run = cmd => execSync(cmd, { cwd: root, stdio: 'inherit' });
11
+
12
+ // Stage all version-bumped files
13
+ run('git add package.json package-lock.json packages/runtime/package.json');
14
+
15
+ // Single release commit
16
+ run(`git commit -m "chore: release ${v}"`);
17
+
18
+ // Tag on this commit (not the npm version bump commit)
19
+ run(`git tag v${v}`);
20
+
21
+ // Push commit and tag together
22
+ run('git push');
23
+ run(`git push origin v${v}`);
24
+
25
+ console.log(`\nReleased v${v}. Run: npm run release:publish`);
@@ -3,9 +3,12 @@ import { readFileSync } from 'node:fs';
3
3
  import { resolve, dirname } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
 
6
- const pkg = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'));
6
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
7
+ const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
7
8
  const v = pkg.version;
8
9
 
10
+ const run = cmd => execSync(cmd, { cwd: root, stdio: 'inherit' });
11
+
9
12
  try {
10
13
  execSync('npm whoami', { stdio: 'pipe' });
11
14
  } catch {
@@ -14,5 +17,5 @@ try {
14
17
  }
15
18
 
16
19
  console.log(`Publishing @pablovitasso/szkrabok@${v} to npm...`);
17
- execSync('npm publish --access public', { stdio: 'inherit' });
20
+ run('npm publish --access public');
18
21
  console.log(`\nDone. https://www.npmjs.com/package/@pablovitasso/szkrabok`);
package/src/cli.js CHANGED
@@ -1,16 +1,18 @@
1
- #!/usr/bin/env node
2
-
3
1
  import { program } from 'commander';
4
2
  import path from 'node:path';
5
3
  import fs from 'node:fs/promises';
4
+
6
5
  import { list, deleteSession, endpoint } from './tools/szkrabok_session.js';
7
6
 
8
7
  const SESSIONS_DIR = path.join(process.cwd(), 'sessions');
9
8
 
10
- program
11
- .name('bebok')
12
- .description('szkrabok CLI')
13
- .version('2.0.0');
9
+ /* ---------- lazy runtime ---------- */
10
+
11
+ let runtime;
12
+ const getRuntime = async () => {
13
+ if (!runtime) runtime = await import('#runtime');
14
+ return runtime;
15
+ };
14
16
 
15
17
  /* ---------- helpers ---------- */
16
18
 
@@ -22,175 +24,254 @@ const readJson = async file => {
22
24
  }
23
25
  };
24
26
 
25
- const shutdownHandler = handle => async () => {
27
+ const safe = fn => async (...args) => {
26
28
  try {
27
- await handle.close();
28
- } finally {
29
- process.exit(0);
29
+ await fn(...args);
30
+ } catch (err) {
31
+ console.error(err?.message ?? err);
32
+ process.exit(1);
30
33
  }
31
34
  };
32
35
 
33
- /* ---------- session command ---------- */
36
+ const attachShutdown = handle => {
37
+ let closing = false;
38
+
39
+ const shutdown = async () => {
40
+ if (closing) return;
41
+ closing = true;
42
+
43
+ try {
44
+ await handle.close();
45
+ } finally {
46
+ process.exit(0);
47
+ }
48
+ };
49
+
50
+ process.once('SIGINT', shutdown);
51
+ process.once('SIGTERM', shutdown);
52
+ };
53
+
54
+ /* ---------- program ---------- */
34
55
 
35
56
  program
36
- .command('session')
37
- .description('Session management')
38
- .argument('<action>', 'list | inspect | delete | cleanup')
39
- .argument('[id]', 'Session ID')
40
- .option('--days <days>', 'For cleanup: delete sessions older than N days', '30')
41
- .action(async (action, id, options) => {
42
- const actions = {
43
- list: async () => {
44
- const { sessions } = await list();
45
- console.table(
46
- sessions.map(s => ({
47
- ID: s.id,
48
- Active: s.active ? 'yes' : 'no',
49
- Preset: s.preset ?? 'N/A',
50
- Label: s.label ?? 'N/A',
51
- }))
52
- );
53
- },
54
-
55
- inspect: async () => {
56
- if (!id) throw new Error('Session ID required');
57
-
58
- const dir = path.join(SESSIONS_DIR, id);
59
- const [meta, state] = await Promise.all([
60
- readJson(path.join(dir, 'meta.json')),
61
- readJson(path.join(dir, 'state.json')),
62
- ]);
63
-
64
- if (!meta || !state) throw new Error(`Session ${id} not found or incomplete`);
65
-
66
- console.log('=== METADATA ===');
67
- console.log(JSON.stringify(meta, null, 2));
68
- console.log('\n=== COOKIES ===');
69
- console.log(state.cookies?.length ?? 0, 'cookies');
70
- console.log('\n=== LOCALSTORAGE ===');
71
- for (const origin of state.origins ?? []) {
72
- console.log(origin.origin, ':', origin.localStorage?.length ?? 0, 'items');
73
- }
74
- },
75
-
76
- delete: async () => {
77
- if (!id) throw new Error('Session ID required');
78
- await deleteSession({ sessionName: id });
79
- console.log(`Session ${id} deleted`);
80
- },
81
-
82
- cleanup: async () => {
83
- const days = Number(options.days) || 30;
84
- const cutoff = Date.now() - days * 86400000;
85
-
86
- let entries;
87
- try {
88
- entries = await fs.readdir(SESSIONS_DIR, { withFileTypes: true });
89
- } catch {
90
- console.log('No sessions directory found');
91
- return;
92
- }
93
-
94
- await Promise.all(
95
- entries
96
- .filter(e => e.isDirectory())
97
- .map(async e => {
98
- const meta = await readJson(path.join(SESSIONS_DIR, e.name, 'meta.json'));
99
- if (meta?.lastUsed && meta.lastUsed < cutoff) {
100
- await deleteSession({ sessionName: e.name });
101
- console.log(`Deleted old session: ${e.name}`);
102
- }
103
- })
57
+ .name('szkrabok')
58
+ .description('szkrabok CLI')
59
+ .version('1.0.16');
60
+
61
+ /* ---------- init ---------- */
62
+
63
+ program
64
+ .command('init')
65
+ .description('Scaffold minimal config')
66
+ .action(
67
+ safe(async () => {
68
+ const { init } = await import('./tools/scaffold.js');
69
+
70
+ const result = await init({
71
+ dir: process.cwd(),
72
+ preset: 'minimal',
73
+ install: false,
74
+ });
75
+
76
+ if (result.created.length)
77
+ console.error(`Created: ${result.created.join(', ')}`);
78
+
79
+ if (result.merged.length)
80
+ console.error(`Merged: ${result.merged.join(', ')}`);
81
+
82
+ if (result.skipped.length)
83
+ console.error(`Skipped: ${result.skipped.join(', ')}`);
84
+
85
+ for (const w of result.warnings)
86
+ console.error(`Warning: ${w}`);
87
+
88
+ console.error(
89
+ 'Done. Run "szkrabok install-browser" if Chromium is not installed.'
90
+ );
91
+ })
92
+ );
93
+
94
+ /* ---------- session ---------- */
95
+
96
+ const session = program.command('session').description('Session management');
97
+
98
+ session
99
+ .command('list')
100
+ .action(
101
+ safe(async () => {
102
+ const { sessions } = await list();
103
+
104
+ console.table(
105
+ sessions.map(s => ({
106
+ ID: s.id,
107
+ Active: s.active ? 'yes' : 'no',
108
+ Preset: s.preset ?? 'N/A',
109
+ Label: s.label ?? 'N/A',
110
+ }))
111
+ );
112
+ })
113
+ );
114
+
115
+ session
116
+ .command('inspect <id>')
117
+ .action(
118
+ safe(async id => {
119
+ const dir = path.join(SESSIONS_DIR, id);
120
+
121
+ const [meta, state] = await Promise.all([
122
+ readJson(path.join(dir, 'meta.json')),
123
+ readJson(path.join(dir, 'state.json')),
124
+ ]);
125
+
126
+ if (!meta || !state)
127
+ throw new Error(`Session ${id} not found`);
128
+
129
+ console.log('=== METADATA ===');
130
+ console.log(JSON.stringify(meta, null, 2));
131
+
132
+ console.log('\n=== COOKIES ===');
133
+ console.log(state.cookies?.length ?? 0, 'cookies');
134
+
135
+ console.log('\n=== LOCALSTORAGE ===');
136
+
137
+ for (const origin of state.origins ?? []) {
138
+ console.log(
139
+ origin.origin,
140
+ ':',
141
+ origin.localStorage?.length ?? 0,
142
+ 'items'
104
143
  );
105
- },
106
- };
144
+ }
145
+ })
146
+ );
107
147
 
108
- const fn = actions[action];
109
- if (!fn) {
110
- console.error(`Unknown action: ${action}. Use: list | inspect | delete | cleanup`);
111
- process.exit(1);
112
- }
148
+ session
149
+ .command('delete <id>')
150
+ .action(
151
+ safe(async id => {
152
+ await deleteSession({ sessionName: id });
153
+ console.log(`Session ${id} deleted`);
154
+ })
155
+ );
113
156
 
114
- try {
115
- await fn();
116
- } catch (err) {
117
- console.error(err.message);
118
- process.exit(1);
119
- }
120
- });
157
+ session
158
+ .command('cleanup')
159
+ .option('--days <days>', 'delete sessions older than N days', '30')
160
+ .action(
161
+ safe(async options => {
162
+ const days = Number(options.days) || 30;
163
+ const cutoff = Date.now() - days * 86400000;
164
+
165
+ let entries;
166
+
167
+ try {
168
+ entries = await fs.readdir(SESSIONS_DIR, { withFileTypes: true });
169
+ } catch {
170
+ console.log('No sessions directory');
171
+ return;
172
+ }
173
+
174
+ await Promise.all(
175
+ entries
176
+ .filter(e => e.isDirectory())
177
+ .map(async e => {
178
+ const meta = await readJson(
179
+ path.join(SESSIONS_DIR, e.name, 'meta.json')
180
+ );
121
181
 
122
- /* ---------- open command ---------- */
182
+ if (meta?.lastUsed && meta.lastUsed < cutoff) {
183
+ await deleteSession({ sessionName: e.name });
184
+ console.log(`Deleted: ${e.name}`);
185
+ }
186
+ })
187
+ );
188
+ })
189
+ );
190
+
191
+ /* ---------- open ---------- */
123
192
 
124
193
  program
125
194
  .command('open <profile>')
126
- .description(
127
- 'Launch a browser session with stealth + persistence. Prints CDP endpoint. Runs until Ctrl-C.'
128
- )
129
- .option('--preset <preset>', 'TOML preset name')
130
- .option('--headless', 'Run headless')
131
- .action(async (profile, options) => {
132
- const { launch } = await import('#runtime');
133
-
134
- const handle = await launch({
135
- profile,
136
- preset: options.preset,
137
- headless: options.headless ?? undefined,
138
- reuse: false,
139
- });
195
+ .description('Launch persistent browser and print CDP endpoint')
196
+ .option('--preset <preset>')
197
+ .option('--headless')
198
+ .action(
199
+ safe(async (profile, options) => {
200
+ const { launch } = await getRuntime();
140
201
 
141
- console.log(handle.cdpEndpoint);
202
+ const handle = await launch({
203
+ profile,
204
+ preset: options.preset,
205
+ headless: options.headless ?? undefined,
206
+ reuse: false,
207
+ });
142
208
 
143
- const shutdown = shutdownHandler(handle);
144
- process.on('SIGINT', shutdown);
145
- process.on('SIGTERM', shutdown);
209
+ console.log(handle.cdpEndpoint);
146
210
 
147
- await new Promise(() => {});
148
- });
211
+ attachShutdown(handle);
149
212
 
150
- /* ---------- endpoint command ---------- */
213
+ await new Promise(() => {});
214
+ })
215
+ );
216
+
217
+ /* ---------- endpoint ---------- */
151
218
 
152
219
  program
153
220
  .command('endpoint <sessionName>')
154
- .description('Print CDP and WS endpoints for a running session')
155
- .action(async sessionName => {
156
- try {
221
+ .description('Print CDP and WS endpoints')
222
+ .action(
223
+ safe(async sessionName => {
157
224
  const result = await endpoint({ sessionName });
225
+
158
226
  console.log(`CDP: ${result.cdpEndpoint}`);
159
- if (result.wsEndpoint) console.log(`WS: ${result.wsEndpoint}`);
160
- } catch (err) {
161
- console.error(err.message);
162
- process.exit(1);
163
- }
164
- });
165
227
 
166
- /* ---------- detect-browser command ---------- */
228
+ if (result.wsEndpoint)
229
+ console.log(`WS: ${result.wsEndpoint}`);
230
+ })
231
+ );
232
+
233
+ /* ---------- detect browser ---------- */
167
234
 
168
235
  program
169
236
  .command('detect-browser')
170
- .description('Detect usable Chrome/Chromium browsers')
171
- .action(async () => {
172
- const { findChromiumPath } = await import('#runtime');
173
- const path = await findChromiumPath();
174
- if (!path) {
175
- console.log('No usable Chrome/Chromium browser found.\n');
176
- console.log(' szkrabok install-browser');
177
- console.log(' https://www.google.com/chrome/\n');
178
- process.exit(1);
179
- }
180
- console.log(path);
181
- console.log('\nRecommended configuration:\n\n[default]');
182
- console.log(`executablePath = "${path}"`);
183
- });
237
+ .description('Detect Chrome/Chromium')
238
+ .action(
239
+ safe(async () => {
240
+ const { findChromiumPath } = await getRuntime();
184
241
 
185
- /* ---------- install-browser command ---------- */
242
+ const chromiumPath = await findChromiumPath();
243
+
244
+ if (!chromiumPath) {
245
+ console.log('No Chromium detected\n');
246
+ console.log(' szkrabok install-browser');
247
+ process.exit(1);
248
+ }
249
+
250
+ console.log(chromiumPath);
251
+
252
+ console.log('\nRecommended config:\n');
253
+ console.log('[default]');
254
+ console.log(`executablePath = "${chromiumPath}"`);
255
+ })
256
+ );
257
+
258
+ /* ---------- install browser ---------- */
186
259
 
187
260
  program
188
261
  .command('install-browser')
189
- .description('Install Chromium browser via Playwright')
190
- .action(async () => {
191
- const { spawn } = await import('node:child_process');
192
- const proc = spawn('npx', ['playwright', 'install', 'chromium'], { stdio: 'inherit' });
193
- proc.on('close', code => process.exit(code ?? 0));
262
+ .description('Install Chromium via Playwright')
263
+ .action(() => {
264
+ import('node:child_process').then(({ spawn }) => {
265
+ const proc = spawn('npx', ['playwright', 'install', 'chromium'], {
266
+ stdio: 'inherit',
267
+ });
268
+
269
+ proc.on('close', code => process.exit(code ?? 0));
270
+ });
194
271
  });
195
272
 
196
- program.parse();
273
+ /* ---------- export ---------- */
274
+
275
+ export async function runCli() {
276
+ await program.parseAsync(process.argv);
277
+ }
package/src/index.js CHANGED
@@ -1,39 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import 'dotenv/config';
3
- import { createServer } from './server.js';
4
- import { log, logError } from './utils/logger.js';
5
3
 
6
- // Parse CLI args
4
+ const CLI_COMMANDS = new Set(['session', 'open', 'endpoint', 'detect-browser', 'install-browser', 'init']);
7
5
  const args = process.argv.slice(2);
6
+ const firstArg = args[0];
8
7
 
9
- if (args.includes('init')) {
10
- const { init } = await import('./tools/scaffold.js');
11
- const result = await init({ dir: process.cwd(), preset: 'minimal', install: false });
12
- if (result.created.length) console.error(`Created: ${result.created.join(', ')}`);
13
- if (result.merged.length) console.error(`Merged: ${result.merged.join(', ')}`);
14
- if (result.skipped.length) console.error(`Skipped (already exists): ${result.skipped.join(', ')}`);
15
- if (result.warnings.length) result.warnings.forEach(w => console.error(`Warning: ${w}`));
16
- console.error('Done. Run "szkrabok --setup" if Chromium is not yet installed.');
17
- process.exit(0);
18
- }
19
-
20
- if (args.includes('--setup')) {
21
- const { execSync } = await import('node:child_process');
22
- console.log('Installing Playwright Chromium browser...');
23
- try {
24
- execSync('npx playwright install chromium', { stdio: 'inherit' });
25
- console.log('Browser installed successfully.');
26
- } catch {
27
- console.error('Browser install failed. Run manually: npx playwright install chromium');
28
- process.exit(1);
29
- }
8
+ // --- CLI mode ---
9
+ if (firstArg && (CLI_COMMANDS.has(firstArg) || firstArg === '--setup' || firstArg === '--help' || firstArg === '-h' || firstArg === '--version' || firstArg === '-V')) {
10
+ const { runCli } = await import('./cli.js');
11
+ await runCli();
30
12
  process.exit(0);
31
13
  }
32
14
 
15
+ // --- MCP server mode ---
33
16
  if (args.includes('--no-headless') || args.includes('--headful')) {
34
17
  process.env.HEADLESS = 'false';
35
18
  }
36
19
 
20
+ const { createServer } = await import('./server.js');
21
+ const { log, logError } = await import('./utils/logger.js');
22
+
37
23
  const server = createServer();
38
24
 
39
25
  process.on('SIGINT', async () => {
@@ -1,13 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { resolve, dirname } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
-
5
- const pkg = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'));
6
- const v = pkg.version;
7
-
8
- console.log(`
9
- Version bumped to ${v}.
10
-
11
- Next steps:
12
- npm run release:publish
13
- `);