@ranger-testing/ranger-cli 1.0.2 → 1.0.4
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/build/agents/ui-verifier.md +100 -0
- package/build/cli.js +23 -22
- package/build/commands/addEnv.js +13 -72
- package/build/commands/index.js +1 -0
- package/build/commands/start.js +3 -19
- package/build/commands/updateEnv.js +59 -0
- package/build/commands/useEnv.js +6 -13
- package/package.json +3 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-verifier
|
|
3
|
+
description: "Lightweight agent that opens a browser and clicks through a UI flow to verify it works. Returns immediately when bugs are found. Provide a URL to visit and a detailed summary of the functionality to be verified."
|
|
4
|
+
tools: mcp__ranger-browser__browser_navigate, mcp__ranger-browser__browser_snapshot, mcp__ranger-browser__browser_take_screenshot, mcp__ranger-browser__browser_click, mcp__ranger-browser__browser_type, mcp__ranger-browser__browser_hover, mcp__ranger-browser__browser_select_option, mcp__ranger-browser__browser_press_key, mcp__ranger-browser__browser_fill_form, mcp__ranger-browser__browser_wait_for, mcp__ranger-browser__browser_console_messages, mcp__ranger-browser__browser_network_requests, mcp__ranger-browser__browser_tabs, mcp__ranger-browser__browser_navigate_back
|
|
5
|
+
model: opus
|
|
6
|
+
color: blue
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a UI Verifier agent. Your ONLY job is to click through a UI flow and report bugs immediately when you find them.
|
|
10
|
+
|
|
11
|
+
You do NOT:
|
|
12
|
+
- Analyze code or git diffs
|
|
13
|
+
- Suggest tests
|
|
14
|
+
- Draft test cases
|
|
15
|
+
- Do anything other than verify UI functionality
|
|
16
|
+
|
|
17
|
+
# Input
|
|
18
|
+
|
|
19
|
+
You will receive:
|
|
20
|
+
1. A URL or starting point
|
|
21
|
+
2. A description of the feature/flow to verify
|
|
22
|
+
3. Expected behavior
|
|
23
|
+
|
|
24
|
+
# Your Workflow
|
|
25
|
+
|
|
26
|
+
## 1. Navigate and Take Initial Snapshot
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
browser_navigate → URL
|
|
30
|
+
browser_snapshot → see the page
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 2. Click Through the Flow
|
|
34
|
+
|
|
35
|
+
Follow the described user flow step by step:
|
|
36
|
+
- Use `browser_click`, `browser_type`, `browser_fill_form`, etc.
|
|
37
|
+
- Take `browser_snapshot` after each significant action
|
|
38
|
+
- Watch for anything that doesn't match expected behavior
|
|
39
|
+
|
|
40
|
+
## 3. Return Immediately on Bugs
|
|
41
|
+
|
|
42
|
+
**CRITICAL:** As soon as you encounter a bug that blocks functionality or clearly doesn't match expectations:
|
|
43
|
+
|
|
44
|
+
1. Take a screenshot with `browser_take_screenshot`
|
|
45
|
+
2. Check `browser_console_messages` for errors
|
|
46
|
+
3. **STOP and return to the main agent** with:
|
|
47
|
+
- What you were trying to do
|
|
48
|
+
- What you expected
|
|
49
|
+
- What actually happened
|
|
50
|
+
- The screenshot/evidence
|
|
51
|
+
- Severity: `BLOCKER` (can't proceed), `MAJOR` (wrong behavior), or `MINOR` (polish issue)
|
|
52
|
+
|
|
53
|
+
**Do NOT continue testing other parts of the flow.** The main agent needs to fix the issue first.
|
|
54
|
+
|
|
55
|
+
## 4. If Everything Works
|
|
56
|
+
|
|
57
|
+
If you complete the entire flow without issues:
|
|
58
|
+
- Return a brief summary: "Verified [flow name]. All steps completed successfully."
|
|
59
|
+
- List the key actions you took
|
|
60
|
+
|
|
61
|
+
# Example Returns
|
|
62
|
+
|
|
63
|
+
## Bug Found (return immediately)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
BUG FOUND - BLOCKER
|
|
67
|
+
|
|
68
|
+
Trying to: Submit the login form
|
|
69
|
+
Expected: Navigate to dashboard
|
|
70
|
+
Actual: Form submission does nothing, no error shown
|
|
71
|
+
|
|
72
|
+
Console errors:
|
|
73
|
+
- TypeError: Cannot read property 'submit' of undefined
|
|
74
|
+
|
|
75
|
+
Screenshot: [attached]
|
|
76
|
+
|
|
77
|
+
Recommend: Check the form submission handler
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Success
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
VERIFIED - Login Flow
|
|
84
|
+
|
|
85
|
+
All steps completed:
|
|
86
|
+
1. Navigated to /login
|
|
87
|
+
2. Entered email and password
|
|
88
|
+
3. Clicked submit
|
|
89
|
+
4. Successfully redirected to /dashboard
|
|
90
|
+
5. User name displayed correctly in header
|
|
91
|
+
|
|
92
|
+
No issues found.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
# Guidelines
|
|
96
|
+
|
|
97
|
+
- Be fast - don't over-test, just verify the described flow
|
|
98
|
+
- Be specific - exact error messages, exact steps
|
|
99
|
+
- Be visual - always include screenshots for bugs
|
|
100
|
+
- Return early - don't waste time if something is broken
|
package/build/cli.js
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import yargs from 'yargs/yargs';
|
|
3
|
-
import { addEnv, start, useEnv } from './commands/index.js';
|
|
3
|
+
import { addEnv, start, useEnv, updateEnv } from './commands/index.js';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
5
|
dotenv.config();
|
|
6
6
|
// Setup yargs CLI
|
|
7
7
|
yargs(process.argv.slice(2))
|
|
8
8
|
.version('1.0.0')
|
|
9
|
-
.command('add env <
|
|
10
|
-
return yargs
|
|
11
|
-
.positional('app-name', {
|
|
9
|
+
.command('add env <env-name>', 'Add environment configuration', (yargs) => {
|
|
10
|
+
return yargs.positional('env-name', {
|
|
12
11
|
type: 'string',
|
|
13
|
-
description: 'Name of the
|
|
12
|
+
description: 'Name of the environment (e.g., local, staging, prod)',
|
|
14
13
|
demandOption: true,
|
|
15
|
-
})
|
|
16
|
-
|
|
14
|
+
});
|
|
15
|
+
}, async (argv) => {
|
|
16
|
+
await addEnv(argv['env-name']);
|
|
17
|
+
})
|
|
18
|
+
.command('use <env-name>', 'Switch to using a specific environment', (yargs) => {
|
|
19
|
+
return yargs.positional('env-name', {
|
|
17
20
|
type: 'string',
|
|
18
|
-
description: '
|
|
19
|
-
choices: ['local', 'ci'],
|
|
21
|
+
description: 'Name of the environment',
|
|
20
22
|
demandOption: true,
|
|
21
23
|
});
|
|
22
24
|
}, async (argv) => {
|
|
23
|
-
await
|
|
25
|
+
await useEnv(argv['env-name']);
|
|
24
26
|
})
|
|
25
|
-
.command('
|
|
26
|
-
return yargs
|
|
27
|
-
.positional('app-name', {
|
|
27
|
+
.command('update env <env-name>', 'Update authentication for an existing environment', (yargs) => {
|
|
28
|
+
return yargs.positional('env-name', {
|
|
28
29
|
type: 'string',
|
|
29
|
-
description: 'Name of the
|
|
30
|
+
description: 'Name of the environment to update',
|
|
30
31
|
demandOption: true,
|
|
31
|
-
})
|
|
32
|
-
|
|
32
|
+
});
|
|
33
|
+
}, async (argv) => {
|
|
34
|
+
await updateEnv(argv['env-name']);
|
|
35
|
+
})
|
|
36
|
+
.command('start <token>', 'Initialize Ranger in your project', (yargs) => {
|
|
37
|
+
return yargs.positional('token', {
|
|
33
38
|
type: 'string',
|
|
34
|
-
description: '
|
|
35
|
-
choices: ['local', 'ci'],
|
|
39
|
+
description: 'Ranger API token with MCP access',
|
|
36
40
|
demandOption: true,
|
|
37
41
|
});
|
|
38
42
|
}, async (argv) => {
|
|
39
|
-
await
|
|
40
|
-
})
|
|
41
|
-
.command('start', 'Initialize Ranger in your project', () => { }, async () => {
|
|
42
|
-
await start();
|
|
43
|
+
await start(argv.token);
|
|
43
44
|
})
|
|
44
45
|
.demandCommand(1, 'You must specify a command')
|
|
45
46
|
.help()
|
package/build/commands/addEnv.js
CHANGED
|
@@ -3,23 +3,17 @@ import { join } from 'path';
|
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import { chromium } from 'playwright';
|
|
6
|
-
import { loadMcpConfig, saveMcpConfig, hasRangerServer,
|
|
6
|
+
import { loadMcpConfig, saveMcpConfig, hasRangerServer, setRangerBrowser, } from './utils/mcpConfig.js';
|
|
7
7
|
import { installAgent } from './utils/agents.js';
|
|
8
|
-
export async function addEnv(
|
|
9
|
-
const
|
|
10
|
-
const envDir = join(appDir, envType);
|
|
11
|
-
// Create app directory if it doesn't exist
|
|
12
|
-
if (!existsSync(appDir)) {
|
|
13
|
-
await mkdir(appDir, { recursive: true });
|
|
14
|
-
console.log(`✓ Created app directory: ${appDir}`);
|
|
15
|
-
}
|
|
8
|
+
export async function addEnv(envName) {
|
|
9
|
+
const envDir = join(process.cwd(), '.ranger', envName);
|
|
16
10
|
// Check if env already exists
|
|
17
11
|
if (existsSync(envDir)) {
|
|
18
12
|
const { overwrite } = await inquirer.prompt([
|
|
19
13
|
{
|
|
20
14
|
type: 'confirm',
|
|
21
15
|
name: 'overwrite',
|
|
22
|
-
message: `Environment "${
|
|
16
|
+
message: `Environment "${envName}" already exists. Overwrite?`,
|
|
23
17
|
default: false,
|
|
24
18
|
},
|
|
25
19
|
]);
|
|
@@ -28,23 +22,6 @@ export async function addEnv(appName, envType) {
|
|
|
28
22
|
return;
|
|
29
23
|
}
|
|
30
24
|
}
|
|
31
|
-
// Prompt for target URL
|
|
32
|
-
const { targetUrl } = await inquirer.prompt([
|
|
33
|
-
{
|
|
34
|
-
type: 'input',
|
|
35
|
-
name: 'targetUrl',
|
|
36
|
-
message: 'What is the target URL for this environment?',
|
|
37
|
-
validate: (input) => {
|
|
38
|
-
try {
|
|
39
|
-
new URL(input);
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return 'Please enter a valid URL (e.g., https://example.com)';
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
]);
|
|
48
25
|
// Prompt for auth requirement
|
|
49
26
|
const { requiresAuth } = await inquirer.prompt([
|
|
50
27
|
{
|
|
@@ -66,7 +43,7 @@ export async function addEnv(appName, envType) {
|
|
|
66
43
|
const browser = await chromium.launch({ headless: false });
|
|
67
44
|
const context = await browser.newContext();
|
|
68
45
|
const page = await context.newPage();
|
|
69
|
-
await page.goto(
|
|
46
|
+
await page.goto('about:blank');
|
|
70
47
|
// Wait for browser to be closed by user
|
|
71
48
|
storageStatePath = await new Promise((resolve) => {
|
|
72
49
|
// Save storage state when page closes (before context is destroyed)
|
|
@@ -86,8 +63,7 @@ export async function addEnv(appName, envType) {
|
|
|
86
63
|
}
|
|
87
64
|
// Write config.json
|
|
88
65
|
const config = {
|
|
89
|
-
|
|
90
|
-
targetUrl,
|
|
66
|
+
name: envName,
|
|
91
67
|
browser: {
|
|
92
68
|
isolated: true,
|
|
93
69
|
browserName: 'chromium',
|
|
@@ -109,54 +85,19 @@ export async function addEnv(appName, envType) {
|
|
|
109
85
|
console.log(`✓ Created config: ${configPath}`);
|
|
110
86
|
// Load existing .mcp.json or create new one
|
|
111
87
|
const mcpConfig = await loadMcpConfig();
|
|
112
|
-
//
|
|
88
|
+
// Check if ranger server is configured
|
|
113
89
|
if (!hasRangerServer(mcpConfig)) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
name: 'token',
|
|
118
|
-
message: 'Enter your Ranger API token:',
|
|
119
|
-
mask: '*',
|
|
120
|
-
validate: (input) => {
|
|
121
|
-
if (!input || input.trim().length === 0) {
|
|
122
|
-
return 'API token is required';
|
|
123
|
-
}
|
|
124
|
-
return true;
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
]);
|
|
128
|
-
// Validate API token
|
|
129
|
-
const mcpServerUrl = process.env.MCP_SERVER_URL ||
|
|
130
|
-
'https://mcp-server-301751771437.us-central1.run.app';
|
|
131
|
-
console.log('Validating API token...');
|
|
132
|
-
try {
|
|
133
|
-
const response = await fetch(`${mcpServerUrl}/me`, {
|
|
134
|
-
method: 'GET',
|
|
135
|
-
headers: {
|
|
136
|
-
Authorization: `Bearer ${token}`,
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
if (!response.ok) {
|
|
140
|
-
console.error(`\n❌ Authentication failed: ${response.status} ${response.statusText}`);
|
|
141
|
-
console.error('Please check your API token and try again.');
|
|
142
|
-
process.exit(1);
|
|
143
|
-
}
|
|
144
|
-
console.log('✓ API token validated successfully');
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
console.error('\n❌ Failed to connect to MCP server:', error instanceof Error ? error.message : error);
|
|
148
|
-
console.error('Please check your network connection and server URL.');
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
// Add ranger server config
|
|
152
|
-
setRangerServer(mcpConfig, token, mcpServerUrl);
|
|
90
|
+
console.error('\nRanger Tests MCP is not initialized.');
|
|
91
|
+
console.error(' To initialize, run: ranger start <token>');
|
|
92
|
+
process.exit(1);
|
|
153
93
|
}
|
|
154
|
-
//
|
|
94
|
+
// Update ranger-browser with the config path
|
|
155
95
|
setRangerBrowser(mcpConfig, configPath);
|
|
156
96
|
await saveMcpConfig(mcpConfig);
|
|
157
97
|
console.log(`✓ Updated .mcp.json configuration`);
|
|
158
98
|
// Copy browser-based agents to .claude/agents
|
|
159
99
|
await installAgent('quality-advocate');
|
|
160
100
|
await installAgent('bug-basher');
|
|
161
|
-
|
|
101
|
+
await installAgent('ui-verifier');
|
|
102
|
+
console.log(`\n✅ Environment "${envName}" configured`);
|
|
162
103
|
}
|
package/build/commands/index.js
CHANGED
package/build/commands/start.js
CHANGED
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
import { mkdir, readFile, appendFile, writeFile } from 'fs/promises';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
|
-
import inquirer from 'inquirer';
|
|
5
4
|
import { loadMcpConfig, saveMcpConfig, setRangerServer, } from './utils/mcpConfig.js';
|
|
6
5
|
import { installAgent } from './utils/agents.js';
|
|
7
|
-
export async function start() {
|
|
6
|
+
export async function start(token) {
|
|
8
7
|
console.log('\n🚀 Ranger Setup\n');
|
|
9
|
-
// Prompt for API token
|
|
10
|
-
const { token } = await inquirer.prompt([
|
|
11
|
-
{
|
|
12
|
-
type: 'password',
|
|
13
|
-
name: 'token',
|
|
14
|
-
message: 'Enter your Ranger API token:',
|
|
15
|
-
mask: '*',
|
|
16
|
-
validate: (input) => {
|
|
17
|
-
if (!input || input.trim().length === 0) {
|
|
18
|
-
return 'API token is required';
|
|
19
|
-
}
|
|
20
|
-
return true;
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
]);
|
|
24
8
|
// Validate API token
|
|
25
9
|
const mcpServerUrl = process.env.MCP_SERVER_URL ||
|
|
26
10
|
'https://mcp-server-301751771437.us-central1.run.app';
|
|
@@ -83,6 +67,6 @@ export async function start() {
|
|
|
83
67
|
// Log next steps
|
|
84
68
|
console.log('\n✅ Ranger setup complete!\n');
|
|
85
69
|
console.log('Next steps:');
|
|
86
|
-
console.log(' Add an environment
|
|
87
|
-
console.log(' ranger add env
|
|
70
|
+
console.log(' Add an environment:');
|
|
71
|
+
console.log(' ranger add env local\n');
|
|
88
72
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { writeFile, readFile } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
export async function updateEnv(envName) {
|
|
6
|
+
const envDir = join(process.cwd(), '.ranger', envName);
|
|
7
|
+
const configPath = join(envDir, 'config.json');
|
|
8
|
+
const authPath = join(envDir, 'auth.json');
|
|
9
|
+
// Check if env exists
|
|
10
|
+
if (!existsSync(envDir)) {
|
|
11
|
+
console.error(`\nEnvironment "${envName}" not found.`);
|
|
12
|
+
console.error(` Run first: ranger add env ${envName}`);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
// Check if config exists
|
|
16
|
+
if (!existsSync(configPath)) {
|
|
17
|
+
console.error(`\nConfig not found at ${configPath}`);
|
|
18
|
+
console.error(` Run first: ranger add env ${envName}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
// Load existing config
|
|
22
|
+
const configContent = await readFile(configPath, 'utf-8');
|
|
23
|
+
const config = JSON.parse(configContent);
|
|
24
|
+
// Check if existing auth state exists
|
|
25
|
+
const hasExistingAuth = existsSync(authPath);
|
|
26
|
+
console.log('\n📋 Authentication Update');
|
|
27
|
+
console.log(' A browser will open with your existing session (if any).');
|
|
28
|
+
console.log(' Update your authentication as needed.');
|
|
29
|
+
console.log(' When you are done, close the browser.\n');
|
|
30
|
+
// Launch Playwright browser with existing storage state if available
|
|
31
|
+
const browser = await chromium.launch({ headless: false });
|
|
32
|
+
const contextOptions = hasExistingAuth ? { storageState: authPath } : {};
|
|
33
|
+
const context = await browser.newContext(contextOptions);
|
|
34
|
+
const page = await context.newPage();
|
|
35
|
+
await page.goto('about:blank');
|
|
36
|
+
// Wait for browser to be closed by user
|
|
37
|
+
await new Promise((resolve) => {
|
|
38
|
+
page.on('close', async () => {
|
|
39
|
+
try {
|
|
40
|
+
console.log('Saving authentication state...');
|
|
41
|
+
await context.storageState({ path: authPath });
|
|
42
|
+
resolve();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Context may already be closed
|
|
46
|
+
resolve();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
await browser.close();
|
|
51
|
+
console.log(`\n✓ Auth state saved to: ${authPath}`);
|
|
52
|
+
// Update config to reference the auth file
|
|
53
|
+
config.browser = config.browser || {};
|
|
54
|
+
config.browser.contextOptions = config.browser.contextOptions || {};
|
|
55
|
+
config.browser.contextOptions.storageState = authPath;
|
|
56
|
+
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
57
|
+
console.log(`✓ Updated config: ${configPath}`);
|
|
58
|
+
console.log(`\n✅ Environment "${envName}" authentication updated`);
|
|
59
|
+
}
|
package/build/commands/useEnv.js
CHANGED
|
@@ -2,26 +2,19 @@ import { join } from 'path';
|
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import { loadMcpConfig, saveMcpConfig, setRangerBrowser, } from './utils/mcpConfig.js';
|
|
4
4
|
import { installAgent } from './utils/agents.js';
|
|
5
|
-
export async function useEnv(
|
|
6
|
-
const
|
|
7
|
-
const envDir = join(appDir, envType);
|
|
5
|
+
export async function useEnv(envName) {
|
|
6
|
+
const envDir = join(process.cwd(), '.ranger', envName);
|
|
8
7
|
const configPath = join(envDir, 'config.json');
|
|
9
|
-
// Check app exists
|
|
10
|
-
if (!existsSync(appDir)) {
|
|
11
|
-
console.error(`\n❌ App "${appName}" not found.`);
|
|
12
|
-
console.error(` Run first: ranger-dev add app ${appName}`);
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
8
|
// Check env exists
|
|
16
9
|
if (!existsSync(envDir)) {
|
|
17
|
-
console.error(`\n❌ Environment "${
|
|
18
|
-
console.error(` Run first: ranger
|
|
10
|
+
console.error(`\n❌ Environment "${envName}" not found.`);
|
|
11
|
+
console.error(` Run first: ranger add env ${envName}`);
|
|
19
12
|
process.exit(1);
|
|
20
13
|
}
|
|
21
14
|
// Check config exists
|
|
22
15
|
if (!existsSync(configPath)) {
|
|
23
16
|
console.error(`\n❌ Config not found at ${configPath}`);
|
|
24
|
-
console.error(` Run first: ranger
|
|
17
|
+
console.error(` Run first: ranger add env ${envName}`);
|
|
25
18
|
process.exit(1);
|
|
26
19
|
}
|
|
27
20
|
// Load and update MCP config
|
|
@@ -31,5 +24,5 @@ export async function useEnv(appName, envType) {
|
|
|
31
24
|
// Install browser-based agents if they don't exist
|
|
32
25
|
await installAgent('quality-advocate');
|
|
33
26
|
await installAgent('bug-basher');
|
|
34
|
-
console.log(`\n✅ Now using environment "${
|
|
27
|
+
console.log(`\n✅ Now using environment "${envName}"`);
|
|
35
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ranger-testing/ranger-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ranger": "./build/cli.js",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc && cp -r src/agents build/ && chmod 755 build/cli.js",
|
|
11
|
-
"dev": "tsx src/cli.ts"
|
|
11
|
+
"dev": "tsx src/cli.ts",
|
|
12
|
+
"postinstall": "npx playwright install chromium"
|
|
12
13
|
},
|
|
13
14
|
"files": ["build"],
|
|
14
15
|
"dependencies": {
|