@everydaydevopsio/pilot 0.5.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.
- package/.ai-agent-bridge.yaml +10 -0
- package/.dockerignore +9 -0
- package/CLAUDE.md +61 -0
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/browser.d.ts +100 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +654 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli/init.d.ts +4 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +56 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/skill-template.d.ts +2 -0
- package/dist/cli/skill-template.d.ts.map +1 -0
- package/dist/cli/skill-template.js +114 -0
- package/dist/cli/skill-template.js.map +1 -0
- package/dist/commands/click.d.ts +21 -0
- package/dist/commands/click.d.ts.map +1 -0
- package/dist/commands/click.js +64 -0
- package/dist/commands/click.js.map +1 -0
- package/dist/commands/evaluate.d.ts +14 -0
- package/dist/commands/evaluate.d.ts.map +1 -0
- package/dist/commands/evaluate.js +28 -0
- package/dist/commands/evaluate.js.map +1 -0
- package/dist/commands/navigate.d.ts +19 -0
- package/dist/commands/navigate.d.ts.map +1 -0
- package/dist/commands/navigate.js +78 -0
- package/dist/commands/navigate.js.map +1 -0
- package/dist/commands/page_info.d.ts +8 -0
- package/dist/commands/page_info.d.ts.map +1 -0
- package/dist/commands/page_info.js +13 -0
- package/dist/commands/page_info.js.map +1 -0
- package/dist/commands/screenshot.d.ts +18 -0
- package/dist/commands/screenshot.d.ts.map +1 -0
- package/dist/commands/screenshot.js +37 -0
- package/dist/commands/screenshot.js.map +1 -0
- package/dist/commands/tabs.d.ts +10 -0
- package/dist/commands/tabs.d.ts.map +1 -0
- package/dist/commands/tabs.js +15 -0
- package/dist/commands/tabs.js.map +1 -0
- package/dist/commands/type.d.ts +14 -0
- package/dist/commands/type.d.ts.map +1 -0
- package/dist/commands/type.js +61 -0
- package/dist/commands/type.js.map +1 -0
- package/dist/commands/wait.d.ts +17 -0
- package/dist/commands/wait.d.ts.map +1 -0
- package/dist/commands/wait.js +61 -0
- package/dist/commands/wait.js.map +1 -0
- package/dist/mcp/console-buffer.d.ts +28 -0
- package/dist/mcp/console-buffer.d.ts.map +1 -0
- package/dist/mcp/console-buffer.js +68 -0
- package/dist/mcp/console-buffer.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +74 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +18 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +46 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/browser.d.ts +5 -0
- package/dist/mcp/tools/browser.d.ts.map +1 -0
- package/dist/mcp/tools/browser.js +435 -0
- package/dist/mcp/tools/browser.js.map +1 -0
- package/dist/mcp/tools/errors.d.ts +4 -0
- package/dist/mcp/tools/errors.d.ts.map +1 -0
- package/dist/mcp/tools/errors.js +117 -0
- package/dist/mcp/tools/errors.js.map +1 -0
- package/dist/mcp/tools/names.d.ts +7 -0
- package/dist/mcp/tools/names.d.ts.map +1 -0
- package/dist/mcp/tools/names.js +24 -0
- package/dist/mcp/tools/names.js.map +1 -0
- package/dist/util/config.d.ts +34 -0
- package/dist/util/config.d.ts.map +1 -0
- package/dist/util/config.js +53 -0
- package/dist/util/config.js.map +1 -0
- package/dist/util/logger.d.ts +4 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +16 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/viewport.d.ts +105 -0
- package/dist/viewport.d.ts.map +1 -0
- package/dist/viewport.js +145 -0
- package/dist/viewport.js.map +1 -0
- package/package.json +74 -0
- package/smoke/mcp-smoke.ts +161 -0
- package/src/browser.ts +798 -0
- package/src/cli/init.ts +62 -0
- package/src/cli/skill-template.ts +113 -0
- package/src/commands/click.ts +93 -0
- package/src/commands/evaluate.ts +45 -0
- package/src/commands/navigate.ts +105 -0
- package/src/commands/page_info.ts +21 -0
- package/src/commands/screenshot.ts +72 -0
- package/src/commands/tabs.ts +35 -0
- package/src/commands/type.ts +77 -0
- package/src/commands/wait.ts +90 -0
- package/src/mcp/console-buffer.ts +94 -0
- package/src/mcp/index.ts +107 -0
- package/src/mcp/server.ts +67 -0
- package/src/mcp/tools/browser.ts +605 -0
- package/src/mcp/tools/errors.ts +158 -0
- package/src/mcp/tools/names.ts +25 -0
- package/src/util/config.ts +71 -0
- package/src/util/logger.ts +18 -0
- package/src/viewport.ts +204 -0
- package/tsconfig.json +24 -0
package/.dockerignore
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code for working in this repository.
|
|
4
|
+
|
|
5
|
+
## Repository Facts
|
|
6
|
+
|
|
7
|
+
- Canonical GitHub repo: `everydaydevopsio/pilot`
|
|
8
|
+
- Default branch: `main`
|
|
9
|
+
- Primary package manager: `pnpm`
|
|
10
|
+
- Version-file locations: `.nvmrc`, `package.json` (`packageManager` field)
|
|
11
|
+
- Primary CI workflows: `ci.yml`, `lint.yml`, `smoke.yml`, `e2e.yml`
|
|
12
|
+
- Primary release/publish workflow: `publish.yml`
|
|
13
|
+
- Build: `pnpm run build` — Test: `pnpm run test` — Lint: `pnpm run lint` — Coverage: `pnpm run test:coverage`
|
|
14
|
+
- Coverage threshold: 50%
|
|
15
|
+
|
|
16
|
+
## Publishing
|
|
17
|
+
|
|
18
|
+
This repository publishes to **npmjs** under the `@everydaydevopsio` scope.
|
|
19
|
+
|
|
20
|
+
- Registry: `https://registry.npmjs.org`
|
|
21
|
+
- Package name: `@everydaydevopsio/pilot`
|
|
22
|
+
- Authentication uses `NODE_AUTH_TOKEN` secret (npmjs automation token)
|
|
23
|
+
- Publish job has `id-token: write` for provenance
|
|
24
|
+
- Publish with `npm publish --access public --provenance`
|
|
25
|
+
|
|
26
|
+
## Installed agent rules
|
|
27
|
+
|
|
28
|
+
Created by [Ballast](https://github.com/everydaydevopsio/ballast) v5.9.2. Do not edit this section.
|
|
29
|
+
|
|
30
|
+
Read and follow these rule files in `.claude/rules/` when they apply:
|
|
31
|
+
|
|
32
|
+
- `.claude/rules/local-dev-badges.md` — Add standard badges (CI, Release, License, GitHub Release, npm) to the top of README.md
|
|
33
|
+
- `.claude/rules/local-dev-env.md` — Local development environment specialist - reproducible dev setup, DX, and documentation
|
|
34
|
+
- `.claude/rules/local-dev-license.md` — License setup - ensure LICENSE file, package.json license field, and README reference (default MIT; overridable in AGENTS.md/CLAUDE.md)
|
|
35
|
+
- `.claude/rules/local-dev-mcp.md` — Optional: use GitHub MCP and issues MCP (Jira/Linear/GitHub) for local-dev context
|
|
36
|
+
- `.claude/rules/docs.md` — Documentation specialist - GitHub Markdown docs by default, or maintain existing Docusaurus sites with publish-docs automation
|
|
37
|
+
- `.claude/rules/cicd.md` — CI/CD specialist - pipeline design, quality gates, and deployment
|
|
38
|
+
- `.claude/rules/observability.md` — Observability specialist - logging, tracing, metrics, and SLOs
|
|
39
|
+
- `.claude/rules/publishing-api.md` — REST API publishing specialist - Docker CD with Kubernetes health probes and Helm chart update
|
|
40
|
+
- `.claude/rules/publishing-apps.md` — App publishing specialist - npmjs for Node apps, PyPI for Python apps, GitHub Releases for Go apps
|
|
41
|
+
- `.claude/rules/publishing-apt.md` — APT/deb package publishing specialist - GoReleaser nfpms and GitHub Releases
|
|
42
|
+
- `.claude/rules/publishing-brew.md` — Homebrew tap publishing specialist - GoReleaser brews block and tap repo setup
|
|
43
|
+
- `.claude/rules/publishing-cli.md` — CLI publishing specialist - GoReleaser for Go, npmjs for Node, PyPI for Python
|
|
44
|
+
- `.claude/rules/publishing-libraries.md` — Library publishing specialist - npmjs for TypeScript, PyPI for Python, GitHub tags/releases for Go
|
|
45
|
+
- `.claude/rules/publishing-sdks.md` — SDK publishing specialist - npmjs for TypeScript SDKs, PyPI for Python SDKs, GitHub tags/releases for Go SDKs
|
|
46
|
+
- `.claude/rules/publishing-web.md` — Web app publishing specialist - Docker to GHCR/Docker Hub with Helm chart CD on push to main
|
|
47
|
+
- `.claude/rules/typescript-linting.md` — TypeScript linting specialist - implements comprehensive linting and code formatting for TypeScript/JavaScript projects
|
|
48
|
+
- `.claude/rules/typescript-logging.md` — Centralized logging specialist - configures Pino with Fluentd for Node/Next.js, and pino-browser to /api/logs
|
|
49
|
+
- `.claude/rules/typescript-testing.md` — Testing specialist - sets up Jest (default) or Vitest for Vite projects, 50% coverage, and test step in build GitHub Action
|
|
50
|
+
- `.claude/rules/git-hooks.md` — Git hook specialist - configure pre-commit, pre-push, and Husky workflows that match the repository layout
|
|
51
|
+
- `.claude/rules/tasks-task-system.md` — Task system integration - use {{taskSystem}} for work items and configure the MCP server
|
|
52
|
+
- `.claude/rules/tasks-todo.md` — Branch-local TODO tracking - manage tasks/TODO.md and triage before PR
|
|
53
|
+
|
|
54
|
+
## Installed skills
|
|
55
|
+
|
|
56
|
+
Created by [Ballast](https://github.com/everydaydevopsio/ballast) v5.9.2. Do not edit this section.
|
|
57
|
+
|
|
58
|
+
Read and use these skill files in `.claude/skills/` when they are relevant:
|
|
59
|
+
|
|
60
|
+
- `.claude/skills/github-health-check.skill` — Run a comprehensive GitHub repository health check. Use this skill whenever the user asks to: check GitHub health, audit the repo, check CI status, review open PRs, merge Dependabot PRs, check code coverage, check GitHub Code Quality, check GitHub security feature enablement, check security advisories, check Dependabot alerts, check code scanning alerts, check secret scanning alerts, check Snyk integration, keep GitHub in good shape, or any variation of "how is the repo doing". Also trigger for: "check dependabot PRs", "any PRs to merge", "check branch status", "repo health", "GitHub status check", "what needs attention in GitHub", "tidy up GitHub".
|
|
61
|
+
- `.claude/skills/owasp-security-scan.skill` — Run OWASP-aligned security scans across Go, TypeScript, and Python codebases. Use this skill whenever the user asks to: scan for security vulnerabilities, run OWASP checks, audit dependencies, find CVEs, check for injection flaws, run SAST or SCA analysis, review code security, or harden their app against the OWASP Top 10. Also trigger for phrases like "security audit", "check my code for vulns", "are my dependencies safe", or any mention of gosec, bandit, semgrep, or npm audit in a security context. Covers Go, TypeScript/JavaScript, and Python with language-specific tools plus cross-language Semgrep rulesets.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# pilot
|
|
2
|
+
|
|
3
|
+
[](https://github.com/everydaydevopsio/pilot/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/everydaydevopsio/pilot/actions/workflows/e2e.yml)
|
|
5
|
+
[](https://github.com/everydaydevopsio/pilot/actions/workflows/smoke.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/everydaydevopsio/pilot/releases)
|
|
8
|
+
[](https://www.npmjs.com/package/@everydaydevopsio/pilot)
|
|
9
|
+
|
|
10
|
+
A lightweight Node.js/TypeScript MCP server that gives AI agents DevTools-grade control over a running Chrome instance. Connects to Chrome via the Chrome DevTools Protocol (CDP) and exposes MCP tools for screenshots, navigation, clicks, typing, JavaScript evaluation, and live console/network event monitoring.
|
|
11
|
+
|
|
12
|
+
Use pilot to open a URL and watch for errors — from any AI agent that speaks MCP.
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
- **Node.js**: Use the version in `.nvmrc`. Supported: Node 22 (LTS) or 24 (Active LTS).
|
|
17
|
+
- [nvm](https://github.com/nvm-sh/nvm) (Node Version Manager)
|
|
18
|
+
- [pnpm](https://pnpm.io) package manager (managed via Corepack)
|
|
19
|
+
- [pre-commit](https://pre-commit.com) for Git hooks (optional but recommended)
|
|
20
|
+
|
|
21
|
+
### Install nvm
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
After installation, restart your shell (or `source` your shell profile) so the `nvm` command is available. See the [nvm repository](https://github.com/nvm-sh/nvm) for the latest install script and platform-specific notes.
|
|
28
|
+
|
|
29
|
+
### Install dependencies
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
nvm install # installs the version from .nvmrc (Node 24)
|
|
33
|
+
nvm use
|
|
34
|
+
|
|
35
|
+
# Enable Corepack and activate the pnpm version pinned in package.json
|
|
36
|
+
corepack enable
|
|
37
|
+
corepack prepare --activate
|
|
38
|
+
|
|
39
|
+
pnpm install
|
|
40
|
+
|
|
41
|
+
# Optional: Install Git hooks
|
|
42
|
+
pre-commit install
|
|
43
|
+
pre-commit install --hook-type pre-push
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Corepack ships with Node.js and uses the `packageManager` field in `package.json` to pin the pnpm version, so every contributor and CI run uses the same one.
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Build
|
|
52
|
+
pnpm run build
|
|
53
|
+
|
|
54
|
+
# Run as MCP server (stdio)
|
|
55
|
+
pnpm start
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### With Docker
|
|
59
|
+
|
|
60
|
+
To use the MCP server from a Docker container, pass `-i` so stdin stays open for stdio communication:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
docker build -t pilot .
|
|
64
|
+
claude mcp add pilot -- docker run -i --rm pilot
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Claude Code Integration
|
|
68
|
+
|
|
69
|
+
Add the MCP server to Claude Code:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Via npx (no install required)
|
|
73
|
+
claude mcp add pilot -- npx @everydaydevopsio/pilot
|
|
74
|
+
|
|
75
|
+
# Or from a local build
|
|
76
|
+
claude mcp add pilot -- node /path/to/pilot/dist/mcp/index.js
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Or add to `.mcp.json` in your project:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"pilot": {
|
|
85
|
+
"type": "stdio",
|
|
86
|
+
"command": "npx",
|
|
87
|
+
"args": ["@everydaydevopsio/pilot"]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## MCP Tools
|
|
94
|
+
|
|
95
|
+
**Browser Lifecycle:**
|
|
96
|
+
|
|
97
|
+
| Tool | Description |
|
|
98
|
+
| --------------- | ------------- |
|
|
99
|
+
| `browser_start` | Launch Chrome |
|
|
100
|
+
| `browser_stop` | Stop Chrome |
|
|
101
|
+
|
|
102
|
+
**Browser Control:**
|
|
103
|
+
|
|
104
|
+
| Tool | Description |
|
|
105
|
+
| ------------------------- | ------------------------------------------------ |
|
|
106
|
+
| `browser_screenshot` | Capture viewport or full page screenshot |
|
|
107
|
+
| `browser_navigate` | Navigate to URL and wait for load |
|
|
108
|
+
| `browser_click` | Click element by CSS selector or coordinates |
|
|
109
|
+
| `browser_type` | Type text into focused element or selector |
|
|
110
|
+
| `browser_evaluate` | Execute JavaScript and return result |
|
|
111
|
+
| `browser_wait` | Wait for selector, network idle, or fixed delay |
|
|
112
|
+
| `browser_page_info` | Get current URL, title, and ready state |
|
|
113
|
+
| `browser_viewport_resize` | Resize the viewport to new dimensions at runtime |
|
|
114
|
+
|
|
115
|
+
**Error Monitoring:**
|
|
116
|
+
|
|
117
|
+
| Tool | Description |
|
|
118
|
+
| -------------------------- | -------------------------------------------- |
|
|
119
|
+
| `browser_get_console_logs` | Get buffered console messages with filters |
|
|
120
|
+
| `browser_get_errors` | Get console errors (and optionally warnings) |
|
|
121
|
+
| `browser_clear_errors` | Clear the console message buffer |
|
|
122
|
+
|
|
123
|
+
## Configuration
|
|
124
|
+
|
|
125
|
+
All configuration via environment variables.
|
|
126
|
+
|
|
127
|
+
| Env var | Default | Description |
|
|
128
|
+
| ------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
129
|
+
| `PILOT_CDP_PORT` | `9222` | CDP port when connecting to an existing Chrome (ignored when `browser_start` launches Chrome) |
|
|
130
|
+
| `PILOT_CDP_HOST` | `127.0.0.1` | CDP host when connecting to an existing Chrome (ignored when `browser_start` launches Chrome) |
|
|
131
|
+
| `PILOT_LOG_LEVEL` | `info` | Pino log level |
|
|
132
|
+
| `PILOT_CHROME_PATH` | (auto) | Path to Chrome executable |
|
|
133
|
+
| `PILOT_HEADLESS` | `true` | Run Chrome headless |
|
|
134
|
+
| `PILOT_MCP_BUFFER_SIZE` | `1000` | Console message buffer size |
|
|
135
|
+
| `PILOT_PROFILE_NAME` | `profile1` | Persistent browser profile name. Profiles are stored under `$XDG_DATA_HOME/pilot/<name>` (default `~/.local/share/pilot/<name>`). |
|
|
136
|
+
| `PILOT_RESPONSIVE` | (preset) | Responsive viewport mode. When `true`, the page uses real window dimensions and reflows on resize. Desktop presets default to `true`; mobile/tablet presets leave this unset (locked viewport). Set to `false` to lock the viewport with `setDeviceMetricsOverride`. |
|
|
137
|
+
| `PILOT_CHROME_NO_SANDBOX` | (auto) | Force `--no-sandbox` on/off. Accepts `true`/`1` or `false`/`0`. When unset, the flag is auto-applied only when running as root on Linux. See [Chrome sandbox](#chrome-sandbox) below. |
|
|
138
|
+
|
|
139
|
+
> **Tip — seeing the browser window:** By default Chrome runs headless (no visible window). To watch the browser while the agent works, ask the AI agent: _"set headless to false"_ (or _"run Chrome with a visible window"_). The agent will set `PILOT_HEADLESS=false` before calling `browser_start`, and a Chrome window will appear on your desktop.
|
|
140
|
+
|
|
141
|
+
### Responsive viewport mode
|
|
142
|
+
|
|
143
|
+
Desktop presets (`desktop`, `desktop-small`) default to **responsive mode**. In responsive mode, the page uses the real browser window dimensions and reflows naturally when the window is resized — just like a normal browser. This is useful for testing responsive websites where you want the layout to react to window changes.
|
|
144
|
+
|
|
145
|
+
Mobile and tablet presets use a **locked viewport** (via `setDeviceMetricsOverride`) to emulate exact device dimensions regardless of the actual window size.
|
|
146
|
+
|
|
147
|
+
To lock the viewport on desktop (the old behavior), set `responsive: false` in `browser_start` or `PILOT_RESPONSIVE=false`.
|
|
148
|
+
|
|
149
|
+
#### Resizing at runtime
|
|
150
|
+
|
|
151
|
+
Use `browser_viewport_resize` to change the viewport dimensions while the browser is running:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
browser_viewport_resize({ width: 1024, height: 768 })
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This sets both the window size and the rendering viewport, and disables responsive mode so the page stays locked at the specified dimensions. Useful for testing specific breakpoints or device sizes without restarting the browser.
|
|
158
|
+
|
|
159
|
+
### Chrome sandbox
|
|
160
|
+
|
|
161
|
+
The Chrome renderer sandbox is the primary defense against a compromised page (or page content reaching the agent via prompt injection) running code with the privileges of this process. An AI agent that visits arbitrary URLs is precisely the case where the sandbox matters most, so the server keeps it enabled by default.
|
|
162
|
+
|
|
163
|
+
`--no-sandbox` is auto-applied only when the server is running as **root** on Linux — the most common case where Chrome's user-namespace sandbox fails to initialize. In every other case (non-root user, macOS, Windows, non-root inside a container) the sandbox stays on.
|
|
164
|
+
|
|
165
|
+
Override the auto-detection with `PILOT_CHROME_NO_SANDBOX`:
|
|
166
|
+
|
|
167
|
+
- `PILOT_CHROME_NO_SANDBOX=true` — force the flag on (e.g. an environment where the sandbox cannot work and you have accepted the risk).
|
|
168
|
+
- `PILOT_CHROME_NO_SANDBOX=false` — force the flag off, even when running as root.
|
|
169
|
+
|
|
170
|
+
When the flag is applied, the server emits a `warn`-level log on launch so operators can see that the agent is browsing without the renderer sandbox. The safest Docker setup is to run the container as a non-root user with a working Chrome sandbox helper, rather than relying on `--no-sandbox`.
|
|
171
|
+
|
|
172
|
+
## Testing
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Unit tests
|
|
176
|
+
pnpm run test
|
|
177
|
+
|
|
178
|
+
# With coverage (50% threshold enforced)
|
|
179
|
+
pnpm run test:coverage
|
|
180
|
+
|
|
181
|
+
# MCP E2E tests (requires Chrome installed)
|
|
182
|
+
pnpm run test:e2e:mcp
|
|
183
|
+
|
|
184
|
+
# MCP E2E tests via Docker (no local Chrome needed)
|
|
185
|
+
pnpm run test:e2e:mcp:docker
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Project Structure
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
src/
|
|
192
|
+
├── browser.ts # CDP connection + reconnect logic
|
|
193
|
+
├── cli/ # CLI commands
|
|
194
|
+
│ ├── init.ts # Init command (creates skill)
|
|
195
|
+
│ └── skill-template.ts # SKILL.md template
|
|
196
|
+
├── commands/ # CDP command implementations
|
|
197
|
+
│ ├── screenshot.ts
|
|
198
|
+
│ ├── navigate.ts
|
|
199
|
+
│ ├── click.ts
|
|
200
|
+
│ ├── type.ts
|
|
201
|
+
│ ├── evaluate.ts
|
|
202
|
+
│ ├── wait.ts
|
|
203
|
+
│ └── page_info.ts
|
|
204
|
+
├── mcp/ # MCP server (sole entry point)
|
|
205
|
+
│ ├── index.ts # Entry point (stdio)
|
|
206
|
+
│ ├── server.ts # MCP server setup
|
|
207
|
+
│ ├── console-buffer.ts # Console message buffer
|
|
208
|
+
│ └── tools/
|
|
209
|
+
│ ├── browser.ts # Browser control tools
|
|
210
|
+
│ └── errors.ts # Error monitoring tools
|
|
211
|
+
└── util/
|
|
212
|
+
├── config.ts # Configuration loading
|
|
213
|
+
└── logger.ts # Pino logger setup
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Claude Code Skill
|
|
217
|
+
|
|
218
|
+
The `init` command creates a Claude Code skill in your project that automates the browser debugging workflow.
|
|
219
|
+
|
|
220
|
+
### Initialize the Skill
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Using npx (no installation required)
|
|
224
|
+
npx @everydaydevopsio/pilot init
|
|
225
|
+
|
|
226
|
+
# If installed globally
|
|
227
|
+
pilot init
|
|
228
|
+
|
|
229
|
+
# Overwrite existing skill
|
|
230
|
+
pilot init --force
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This creates `.claude/skills/debug-browser/SKILL.md` in your project.
|
|
234
|
+
|
|
235
|
+
### Using the Skill
|
|
236
|
+
|
|
237
|
+
In Claude Code, say **"debug in browser"** or use **/debug-browser**. The skill will:
|
|
238
|
+
|
|
239
|
+
1. Add the MCP server to your Claude Code session
|
|
240
|
+
2. Call `browser_start` to launch Chrome
|
|
241
|
+
3. Spawn a background sub-agent to watch for console errors
|
|
242
|
+
|
|
243
|
+
### Error Watching Workflow
|
|
244
|
+
|
|
245
|
+
1. Ask Claude: "Use pilot to open localhost:3000 and watch for errors"
|
|
246
|
+
2. Claude clears the error buffer and tells you to proceed
|
|
247
|
+
3. You interact with the app in Chrome
|
|
248
|
+
4. Claude periodically checks for errors and can fix them in your source code
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Client } from 'chrome-remote-interface';
|
|
2
|
+
import type { Config } from './util/config.js';
|
|
3
|
+
import { type ViewportConfig } from './viewport.js';
|
|
4
|
+
export type BrowserEventCallback = (event: string, data: unknown) => void;
|
|
5
|
+
export interface TabInfo {
|
|
6
|
+
targetId: string;
|
|
7
|
+
url: string;
|
|
8
|
+
title: string;
|
|
9
|
+
active: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface BrowserState {
|
|
12
|
+
client: Client | null;
|
|
13
|
+
targetId: string | null;
|
|
14
|
+
url: string | null;
|
|
15
|
+
connected: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface LaunchOptions {
|
|
18
|
+
headless?: boolean;
|
|
19
|
+
chromePath?: string;
|
|
20
|
+
profileName?: string;
|
|
21
|
+
viewport?: string;
|
|
22
|
+
viewportWidth?: number;
|
|
23
|
+
viewportHeight?: number;
|
|
24
|
+
deviceScaleFactor?: number;
|
|
25
|
+
responsive?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export type SandboxDecision = {
|
|
28
|
+
disable: false;
|
|
29
|
+
} | {
|
|
30
|
+
disable: true;
|
|
31
|
+
reason: 'env_override' | 'root_user';
|
|
32
|
+
};
|
|
33
|
+
export declare function sandboxDecision(): SandboxDecision;
|
|
34
|
+
export declare function shouldDisableSandbox(): boolean;
|
|
35
|
+
export declare const PROFILE_NAME_RE: RegExp;
|
|
36
|
+
export declare function resolveUserDataDir(profileName: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Extract the PID from a Chrome SingletonLock symlink target.
|
|
39
|
+
* On Linux, Chrome writes the symlink target as "hostname-pid".
|
|
40
|
+
* Returns the PID if extraction succeeds, or null otherwise.
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractLockPid(lockPath: string): {
|
|
43
|
+
pid: number;
|
|
44
|
+
lockHost: string;
|
|
45
|
+
} | null;
|
|
46
|
+
/**
|
|
47
|
+
* Check whether a process with the given PID is still running.
|
|
48
|
+
* Returns true if the process exists (even if we lack permission to signal it).
|
|
49
|
+
* Returns false only when the OS confirms the process does not exist (ESRCH).
|
|
50
|
+
*/
|
|
51
|
+
export declare function isProcessAlive(pid: number): boolean;
|
|
52
|
+
export declare function isProfileLocked(userDataDir: string): boolean;
|
|
53
|
+
export declare class BrowserManager {
|
|
54
|
+
private readonly config;
|
|
55
|
+
private client;
|
|
56
|
+
private targetId;
|
|
57
|
+
private currentUrl;
|
|
58
|
+
private retryTimer;
|
|
59
|
+
private retryMs;
|
|
60
|
+
private destroyed;
|
|
61
|
+
private intentionalClose;
|
|
62
|
+
private eventCallback;
|
|
63
|
+
private pendingNetworkRequests;
|
|
64
|
+
private networkIdleTimer;
|
|
65
|
+
private networkIdleResolvers;
|
|
66
|
+
private chromeProcess;
|
|
67
|
+
private launchedCdpPort;
|
|
68
|
+
private viewportConfig;
|
|
69
|
+
private launchedUserDataDir;
|
|
70
|
+
constructor(config: Config);
|
|
71
|
+
setEventCallback(cb: BrowserEventCallback): void;
|
|
72
|
+
private emit;
|
|
73
|
+
getState(): BrowserState;
|
|
74
|
+
getClient(): Client | null;
|
|
75
|
+
isConnected(): boolean;
|
|
76
|
+
isLaunched(): boolean;
|
|
77
|
+
getViewportConfig(): ViewportConfig | null;
|
|
78
|
+
setViewportConfig(config: ViewportConfig): void;
|
|
79
|
+
static findChromeExecutable(override?: string): string;
|
|
80
|
+
static findFreePort(): Promise<number>;
|
|
81
|
+
launch(opts?: LaunchOptions): Promise<{
|
|
82
|
+
headless: boolean;
|
|
83
|
+
viewport: string;
|
|
84
|
+
}>;
|
|
85
|
+
private waitForChromeReady;
|
|
86
|
+
connect(): Promise<void>;
|
|
87
|
+
private enableDomains;
|
|
88
|
+
private attachEventListeners;
|
|
89
|
+
private checkNetworkIdle;
|
|
90
|
+
waitForNetworkIdle(timeoutMs?: number): Promise<void>;
|
|
91
|
+
private getCdpConnectionInfo;
|
|
92
|
+
listTabs(): Promise<TabInfo[]>;
|
|
93
|
+
createTab(url?: string): Promise<TabInfo>;
|
|
94
|
+
closeTab(targetId: string): Promise<void>;
|
|
95
|
+
switchTab(targetId: string): Promise<void>;
|
|
96
|
+
private scheduleReconnect;
|
|
97
|
+
private cleanupUserDataDir;
|
|
98
|
+
destroy(): Promise<void>;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAOtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;AAE1E,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,eAAe,GACzB;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAAA;CAAE,CAAC;AAE/E,wBAAgB,eAAe,IAAI,eAAe,CAuBjD;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,eAAO,MAAM,eAAe,QAAgC,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAS9D;AAiBD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,GACf;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAe1C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWnD;AAwBD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAsC5D;AAED,qBAAa,cAAc;IAiBb,OAAO,CAAC,QAAQ,CAAC,MAAM;IAhBnC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,oBAAoB,CAAyB;IACrD,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,mBAAmB,CAAuB;gBAErB,MAAM,EAAE,MAAM;IAI3C,gBAAgB,CAAC,EAAE,EAAE,oBAAoB,GAAG,IAAI;IAIhD,OAAO,CAAC,IAAI;IAIZ,QAAQ,IAAI,YAAY;IASxB,SAAS,IAAI,MAAM,GAAG,IAAI;IAI1B,WAAW,IAAI,OAAO;IAItB,UAAU,IAAI,OAAO;IAIrB,iBAAiB,IAAI,cAAc,GAAG,IAAI;IAI1C,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAI/C,MAAM,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM;WAmCzC,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAWtC,MAAM,CACV,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;YAuHrC,kBAAkB;IAkB1B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAgDhB,aAAa;IAa3B,OAAO,CAAC,oBAAoB;IAgG5B,OAAO,CAAC,gBAAgB;IAWxB,kBAAkB,CAAC,SAAS,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBpD,OAAO,CAAC,oBAAoB;IAOtB,QAAQ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAa9B,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAezC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ChD,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,kBAAkB;IAepB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA+C/B"}
|