@romanmatena/browsermonitor 2.0.0 → 2.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.
- package/README.md +9 -9
- package/package.json +1 -1
- package/src/agents.llm/browser-monitor-section.md +6 -4
- package/src/cli.mjs +103 -105
- package/src/http-server.mjs +12 -38
- package/src/init.mjs +48 -103
- package/src/intro.mjs +1 -1
- package/src/logging/LogBuffer.mjs +1 -1
- package/src/monitor/README.md +18 -5
- package/src/monitor/join-mode.mjs +127 -335
- package/src/monitor/open-mode.mjs +141 -384
- package/src/monitor/shared/cleanup.mjs +96 -0
- package/src/monitor/shared/help.mjs +64 -0
- package/src/monitor/shared/http-state-setup.mjs +55 -0
- package/src/monitor/shared/index.mjs +11 -0
- package/src/monitor/shared/keyboard-handler.mjs +79 -0
- package/src/monitor/shared/monitoring-wrapper.mjs +39 -0
- package/src/monitor/shared/tab-switching.mjs +61 -0
- package/src/monitor/shared/user-page-filter.mjs +28 -0
- package/src/os/wsl/chrome.mjs +3 -36
- package/src/os/wsl/detect.mjs +0 -12
- package/src/os/wsl/index.mjs +0 -3
- package/src/settings.mjs +12 -10
- package/src/templates/api-help.mjs +9 -11
- package/src/templates/cli-commands.mjs +1 -1
- package/src/templates/section-heading.mjs +10 -16
- package/src/utils/ask.mjs +94 -28
- package/src/utils/chrome-instances.mjs +81 -0
- package/src/utils/chrome-profile-path.mjs +9 -4
- package/src/utils/status-line.mjs +0 -8
- package/src/monitor/index.mjs +0 -18
- package/src/monitor/interactive-mode.mjs +0 -275
- package/src/monitor.mjs +0 -39
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
# Browser Monitor
|
|
6
6
|
|
|
7
7
|
[](https://github.com/romanmatena/browsermonitor/actions/workflows/ci.yml)
|
|
8
|
-
[](https://www.npmjs.com/package/browsermonitor)
|
|
9
|
-
[](https://www.npmjs.com/package/browsermonitor)
|
|
8
|
+
[](https://www.npmjs.com/package/@romanmatena/browsermonitor)
|
|
9
|
+
[](https://www.npmjs.com/package/@romanmatena/browsermonitor)
|
|
10
10
|
[](https://nodejs.org/)
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://github.com/romanmatena/browsermonitor)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
Browser console, network, DOM, and screenshot monitoring for debugging and LLM workflows.
|
|
16
16
|
|
|
17
|
-
**[npm](https://www.npmjs.com/package/browsermonitor)** · **[GitHub](https://github.com/romanmatena/browsermonitor)**
|
|
17
|
+
**[npm](https://www.npmjs.com/package/@romanmatena/browsermonitor)** · **[GitHub](https://github.com/romanmatena/browsermonitor)**
|
|
18
18
|
|
|
19
19
|
[Installation](#installation) · [Quick Start](#quick-start) · [HTTP API](#http-api) · [Contributing](CONTRIBUTING.md)
|
|
20
20
|
|
|
@@ -46,21 +46,21 @@ Browser console, network, DOM, and screenshot monitoring for debugging and LLM w
|
|
|
46
46
|
|
|
47
47
|
## Installation
|
|
48
48
|
|
|
49
|
-
Install globally from [npm](https://www.npmjs.com/package/browsermonitor):
|
|
49
|
+
Install globally from [npm](https://www.npmjs.com/package/@romanmatena/browsermonitor):
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
# Using npm
|
|
53
|
-
npm install -g browsermonitor
|
|
53
|
+
npm install -g @romanmatena/browsermonitor
|
|
54
54
|
|
|
55
55
|
# Or pnpm
|
|
56
|
-
pnpm add -g browsermonitor
|
|
56
|
+
pnpm add -g @romanmatena/browsermonitor
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
**Note:** Chromium download is skipped — browsermonitor uses your system Chrome/Chromium. No extra 300 MB download.
|
|
60
60
|
|
|
61
|
-
**First run:** When you run `browsermonitor` in a project directory
|
|
61
|
+
**First run (interactive):** When you run `browsermonitor` for the first time in a project directory, interactive mode asks for HTTP API port, saves `settings.json`, and updates agent files (`CLAUDE.md`, `AGENTS.md`, `memory.md`). When you press `o` (open), it asks for the default URL.
|
|
62
62
|
|
|
63
|
-
**
|
|
63
|
+
**Re-init:** Run `browsermonitor init` to recreate settings and update agent files.
|
|
64
64
|
|
|
65
65
|
## Quick Start
|
|
66
66
|
|
|
@@ -74,7 +74,7 @@ browsermonitor --join=9222 # Join mode: attach to existing Chrome on port
|
|
|
74
74
|
|
|
75
75
|
| Mode | How to run | When to use |
|
|
76
76
|
|------------|--------------------------|-------------|
|
|
77
|
-
| **Interactive** | `browsermonitor` (no flags) |
|
|
77
|
+
| **Interactive** | `browsermonitor` (no flags) | First run asks HTTP port. Then menu: **o** = open Chrome (asks URL on first use), **j** = join running Chrome, **q** = quit. |
|
|
78
78
|
| **Open** | `browsermonitor --open [url]` | Launch a new Chrome and monitor it. Uses current dir for logs. |
|
|
79
79
|
| **Join** | `browsermonitor --join=PORT` | Attach to an existing Chrome with remote debugging on PORT (e.g. 9222). Port is required. |
|
|
80
80
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@romanmatena/browsermonitor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Browser console, network, DOM monitoring for debugging and LLM workflows. Captures console, network, cookies, screenshot, DOM. HTTP API for LLM/scripts. WSL+Windows, Linux, Open/Join modes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
|
|
4
4
|
**Why use this:** Do not ask the user to copy or paste content from the browser (DOM, console, network). You can obtain the current page state yourself: the project has browsermonitor; after a dump you read the generated files.
|
|
5
5
|
|
|
6
|
+
**Monitored URL:** `{{DEFAULT_URL}}`
|
|
7
|
+
|
|
6
8
|
**What to do when you need the live page (elements, console, requests):**
|
|
7
|
-
1. Trigger a dump: `curl -s http://localhost:
|
|
9
|
+
1. Trigger a dump: `curl -s http://localhost:{{HTTP_PORT}}/dump` (monitor must be running; user runs `browsermonitor` or `browsermonitor --open` / `--join=9222` to start it).
|
|
8
10
|
2. Read the written files in `.browsermonitor/.puppeteer/`:
|
|
9
11
|
- **.browsermonitor/.puppeteer/dom.html** – current page HTML (JS-modified DOM). Use this for the element tree and structure.
|
|
10
12
|
- **.browsermonitor/.puppeteer/screenshot.png** – screenshot of the current tab viewport.
|
|
11
13
|
- **.browsermonitor/.puppeteer/console.log** – browser console output.
|
|
12
14
|
- **.browsermonitor/.puppeteer/network.log** and **.browsermonitor/.puppeteer/network-log/*.json** – network requests and responses.
|
|
13
15
|
- **.browsermonitor/.puppeteer/cookies/** – cookies per domain (JSON files).
|
|
14
|
-
3. Optional: `curl -s http://localhost:
|
|
15
|
-
4. Optional: `curl -s http://localhost:
|
|
16
|
-
5. Optional: `curl -s http://localhost:
|
|
16
|
+
3. Optional: `curl -s http://localhost:{{HTTP_PORT}}/status` for buffer status.
|
|
17
|
+
4. Optional: `curl -s http://localhost:{{HTTP_PORT}}/tabs` to list tabs; `curl -s "http://localhost:{{HTTP_PORT}}/tab?index=2"` to switch tab.
|
|
18
|
+
5. Optional: `curl -s http://localhost:{{HTTP_PORT}}/clear` to clear buffers.
|
|
17
19
|
|
|
18
20
|
<!-- END browser-monitor-llm-section - LLM: do not remove this block; required for automatic section updates -->
|
package/src/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Configuration in .browsermonitor/settings.json (created on first run).
|
|
7
7
|
*
|
|
8
8
|
* Subcommands:
|
|
9
|
-
* init →
|
|
9
|
+
* init → Create .browsermonitor/, settings.json, update agent files
|
|
10
10
|
*
|
|
11
11
|
* Mode is chosen by arguments:
|
|
12
12
|
* (none) → Interactive: menu (o = open, j = join, q = quit)
|
|
@@ -21,29 +21,49 @@
|
|
|
21
21
|
* --help Show help
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import { parseArgs } from 'node:util';
|
|
25
|
+
import { runJoinMode } from './monitor/join-mode.mjs';
|
|
26
|
+
import { runOpenMode } from './monitor/open-mode.mjs';
|
|
25
27
|
import { printAppIntro } from './intro.mjs';
|
|
26
28
|
import { createHttpServer } from './http-server.mjs';
|
|
27
29
|
import { printApiHelpTable } from './templates/api-help.mjs';
|
|
28
30
|
import { printCliCommandsTable } from './templates/cli-commands.mjs';
|
|
29
|
-
import {
|
|
30
|
-
import { loadSettings, isInitialized,
|
|
31
|
+
import { printModeHeading } from './templates/section-heading.mjs';
|
|
32
|
+
import { loadSettings, getPaths, ensureDirectories, isInitialized, DEFAULT_SETTINGS, saveSettings } from './settings.mjs';
|
|
31
33
|
import { runInit } from './init.mjs';
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
import { resolveHttpPort, resolveDefaultUrl, askMode } from './utils/ask.mjs';
|
|
35
|
+
|
|
36
|
+
// ---- Parse CLI arguments ----
|
|
37
|
+
const { values: flags, positionals } = parseArgs({
|
|
38
|
+
args: process.argv.slice(2),
|
|
39
|
+
options: {
|
|
40
|
+
open: { type: 'boolean', default: false },
|
|
41
|
+
join: { type: 'string' },
|
|
42
|
+
port: { type: 'string' },
|
|
43
|
+
realtime: { type: 'boolean', default: false },
|
|
44
|
+
headless: { type: 'boolean', default: false },
|
|
45
|
+
timeout: { type: 'string', default: '0' },
|
|
46
|
+
'nav-timeout': { type: 'string' },
|
|
47
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
48
|
+
},
|
|
49
|
+
allowPositionals: true,
|
|
50
|
+
strict: false,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const subcommand = positionals[0];
|
|
54
|
+
const urlFromArgs = positionals.find((a) => /^https?:\/\//.test(a) || a.includes('localhost'));
|
|
55
|
+
const joinPort = flags.join ? parseInt(flags.join, 10) : null;
|
|
56
|
+
const httpPortFromArgs = flags.port ? parseInt(flags.port, 10) : null;
|
|
57
|
+
const hardTimeout = parseInt(flags.timeout, 10) || 0;
|
|
58
|
+
|
|
59
|
+
// Handle `browsermonitor init`
|
|
60
|
+
if (subcommand === 'init') {
|
|
61
|
+
await runInit(process.cwd());
|
|
42
62
|
process.exit(0);
|
|
43
63
|
}
|
|
44
64
|
|
|
45
65
|
// Show help
|
|
46
|
-
if (
|
|
66
|
+
if (flags.help) {
|
|
47
67
|
console.log(`
|
|
48
68
|
Browser Monitor – capture browser console, network, and DOM for debugging and LLM workflows.
|
|
49
69
|
|
|
@@ -57,29 +77,23 @@ What it does:
|
|
|
57
77
|
printCliCommandsTable({ showEntry: true, showUsage: true });
|
|
58
78
|
console.log(`
|
|
59
79
|
Subcommands:
|
|
60
|
-
init
|
|
80
|
+
init Create .browsermonitor/, settings.json with defaults, update agent files
|
|
61
81
|
|
|
62
82
|
Modes (chosen by flags; only one applies):
|
|
63
|
-
INTERACTIVE (default) No flag.
|
|
64
|
-
o = open Chrome
|
|
65
|
-
j = join running Chrome (pick instance/tab)
|
|
66
|
-
q = quit
|
|
83
|
+
INTERACTIVE (default) No flag. First run asks HTTP port and URL. Then menu:
|
|
84
|
+
o = open Chrome, j = join running Chrome, q = quit
|
|
67
85
|
|
|
68
86
|
OPEN (--open) Launch a new Chrome and monitor it. URL = first positional or config.
|
|
69
|
-
Uses current directory for logs. Good for local dev with a fresh profile.
|
|
70
87
|
|
|
71
|
-
JOIN (--join=PORT) Attach to
|
|
72
|
-
|
|
73
|
-
running (e.g. started by a script or on another machine via tunnel).
|
|
88
|
+
JOIN (--join=PORT) Attach to existing Chrome with remote debugging on PORT.
|
|
89
|
+
If PORT omitted, scans for running instances.
|
|
74
90
|
|
|
75
91
|
Options:
|
|
76
92
|
--port=PORT HTTP API port (default: from settings or 60001)
|
|
77
|
-
--realtime Write each event to files immediately (default: lazy
|
|
93
|
+
--realtime Write each event to files immediately (default: lazy)
|
|
78
94
|
--headless Run Chrome without GUI
|
|
79
|
-
--open Go directly to open mode
|
|
80
|
-
--join=PORT Go directly to join mode (PORT required)
|
|
81
95
|
--timeout=MS Hard timeout in ms; process exits after (0 = disabled)
|
|
82
|
-
--nav-timeout=MS Navigation timeout in ms (default: from settings
|
|
96
|
+
--nav-timeout=MS Navigation timeout in ms (default: from settings)
|
|
83
97
|
--help, -h Show this help
|
|
84
98
|
|
|
85
99
|
Config (.browsermonitor/settings.json):
|
|
@@ -90,67 +104,42 @@ Config (.browsermonitor/settings.json):
|
|
|
90
104
|
process.exit(0);
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
// Auto-init on first run
|
|
94
|
-
if (!isInitialized(projectRoot)) {
|
|
95
|
-
console.log('[browsermonitor] First run detected. Setting up .browsermonitor/ ...');
|
|
96
|
-
await runInit(projectRoot, { askForUrl: process.stdin.isTTY, updateAgentFiles: true });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Ensure directories exist (in case user deleted .puppeteer/ subdir)
|
|
100
|
-
ensureDirectories(projectRoot);
|
|
101
|
-
|
|
102
|
-
// Load settings from .browsermonitor/settings.json
|
|
103
|
-
const config = loadSettings(projectRoot);
|
|
104
|
-
const paths = getPaths(projectRoot);
|
|
105
|
-
|
|
106
|
-
// ---- Mode dispatch: --open | --join=PORT | interactive ----
|
|
107
|
-
const openMode = args.some((a) => a === '--open' || a.startsWith('--open='));
|
|
108
|
-
const joinArg = args.find((a) => a.startsWith('--join'));
|
|
109
|
-
let joinPort = null;
|
|
110
|
-
if (joinArg) {
|
|
111
|
-
if (joinArg === '--join' || !joinArg.includes('=')) {
|
|
112
|
-
console.error('Error: --join requires a port (e.g. --join=9222)');
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
const portStr = joinArg.split('=')[1];
|
|
116
|
-
joinPort = parseInt(portStr, 10);
|
|
117
|
-
if (Number.isNaN(joinPort) || joinPort < 1 || joinPort > 65535) {
|
|
118
|
-
console.error(`Error: invalid port for --join: ${portStr}`);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Shared options (CLI args override settings.json)
|
|
124
|
-
const realtimeMode = args.includes('--realtime') || config.realtime;
|
|
125
|
-
const headlessCli = args.includes('--headless');
|
|
126
|
-
const timeoutArg = args.find((a) => a.startsWith('--timeout='));
|
|
127
|
-
const hardTimeout = timeoutArg ? parseInt(timeoutArg.split('=')[1], 10) : 0;
|
|
128
|
-
const navTimeoutArg = args.find((a) => a.startsWith('--nav-timeout='));
|
|
129
|
-
const navigationTimeout = navTimeoutArg
|
|
130
|
-
? parseInt(navTimeoutArg.split('=')[1], 10)
|
|
131
|
-
: (config.navigationTimeout !== undefined ? config.navigationTimeout : 60_000);
|
|
132
|
-
const urlFromArgs = args.find((a) => !a.startsWith('--'));
|
|
133
|
-
const url = urlFromArgs || config.defaultUrl || 'https://localhost:4000/';
|
|
134
|
-
const headless = headlessCli || config.headless || false;
|
|
135
|
-
const ignorePatterns = config.ignorePatterns || [];
|
|
136
|
-
const outputDir = projectRoot;
|
|
137
|
-
|
|
138
|
-
const DEFAULT_HTTP_PORT = config.httpPort || 60001;
|
|
139
|
-
const portArg = args.find((a) => a === '--port' || a.startsWith('--port='));
|
|
140
|
-
let httpPortFromArgs = null;
|
|
141
|
-
if (portArg) {
|
|
142
|
-
const val = portArg.includes('=') ? portArg.split('=')[1] : '';
|
|
143
|
-
const num = parseInt(val, 10);
|
|
144
|
-
if (!Number.isNaN(num) && num >= 1 && num <= 65535) httpPortFromArgs = num;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
107
|
(async () => {
|
|
108
|
+
// 1. Intro
|
|
148
109
|
printAppIntro();
|
|
149
110
|
|
|
150
|
-
|
|
111
|
+
// 2. Project root = cwd, load existing settings (may be empty/missing)
|
|
112
|
+
const projectRoot = process.cwd();
|
|
113
|
+
ensureDirectories(projectRoot);
|
|
114
|
+
let config = loadSettings(projectRoot);
|
|
115
|
+
const paths = getPaths(projectRoot);
|
|
116
|
+
|
|
117
|
+
// 3. CLI args override settings.json
|
|
118
|
+
const realtimeMode = flags.realtime || config.realtime;
|
|
119
|
+
const navTimeoutFromArgs = flags['nav-timeout'] ? parseInt(flags['nav-timeout'], 10) : null;
|
|
120
|
+
const navigationTimeout = navTimeoutFromArgs
|
|
121
|
+
?? (config.navigationTimeout !== undefined ? config.navigationTimeout : 60_000);
|
|
122
|
+
const headless = flags.headless || config.headless || false;
|
|
123
|
+
const httpPort = await resolveHttpPort(httpPortFromArgs ?? config.httpPort, DEFAULT_SETTINGS.httpPort);
|
|
124
|
+
const url = await resolveDefaultUrl(urlFromArgs || config.defaultUrl, DEFAULT_SETTINGS.defaultUrl);
|
|
125
|
+
|
|
126
|
+
// 4. Need to initialize project (create .browsermonitor/, settings.json) before showing API info, because API port is part of config
|
|
127
|
+
if (!isInitialized(projectRoot)) {
|
|
128
|
+
saveSettings(projectRoot, { ...DEFAULT_SETTINGS, httpPort, defaultUrl: url, headless, navigationTimeout, realtime: realtimeMode });
|
|
129
|
+
config = loadSettings(projectRoot);
|
|
130
|
+
await runInit(projectRoot, config);
|
|
131
|
+
}
|
|
151
132
|
|
|
152
|
-
|
|
153
|
-
|
|
133
|
+
// 5. Show API/output info (now httpPort is known)
|
|
134
|
+
printApiHelpTable({
|
|
135
|
+
url: config.defaultUrl,
|
|
136
|
+
port: config.httpPort,
|
|
137
|
+
showApi: true,
|
|
138
|
+
showInteractive: false,
|
|
139
|
+
showOutputFiles: true,
|
|
140
|
+
noLeadingNewline: true,
|
|
141
|
+
context: paths,
|
|
142
|
+
});
|
|
154
143
|
|
|
155
144
|
const sharedHttpState = {
|
|
156
145
|
mode: 'interactive',
|
|
@@ -162,41 +151,50 @@ if (portArg) {
|
|
|
162
151
|
getAllTabs: async () => [],
|
|
163
152
|
};
|
|
164
153
|
const sharedHttpServer = createHttpServer({
|
|
165
|
-
port: httpPort,
|
|
166
|
-
defaultPort:
|
|
154
|
+
port: config.httpPort,
|
|
155
|
+
defaultPort: config.httpPort,
|
|
167
156
|
getState: () => sharedHttpState,
|
|
168
157
|
});
|
|
169
158
|
|
|
170
159
|
const commonOptions = {
|
|
171
|
-
|
|
172
|
-
outputDir,
|
|
160
|
+
outputDir: projectRoot,
|
|
173
161
|
paths,
|
|
174
|
-
|
|
162
|
+
realtime: realtimeMode,
|
|
163
|
+
ignorePatterns: config.ignorePatterns,
|
|
175
164
|
hardTimeout,
|
|
176
|
-
httpPort,
|
|
165
|
+
httpPort: config.httpPort,
|
|
166
|
+
joinPort,
|
|
177
167
|
sharedHttpState,
|
|
178
168
|
sharedHttpServer,
|
|
179
169
|
};
|
|
180
170
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
await runOpenMode(
|
|
171
|
+
// 8. Dispatch to mode
|
|
172
|
+
if (flags.open) {
|
|
173
|
+
await runOpenMode(config.defaultUrl, {
|
|
184
174
|
...commonOptions,
|
|
185
175
|
headless,
|
|
186
176
|
navigationTimeout,
|
|
187
177
|
});
|
|
188
178
|
} else if (joinPort !== null) {
|
|
189
|
-
|
|
190
|
-
await runJoinMode(joinPort, {
|
|
191
|
-
...commonOptions,
|
|
192
|
-
defaultUrl: url,
|
|
193
|
-
});
|
|
179
|
+
await runJoinMode(config.defaultUrl, commonOptions);
|
|
194
180
|
} else {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
181
|
+
// No mode flag → ask user
|
|
182
|
+
printModeHeading('Choose mode');
|
|
183
|
+
const mode = await askMode();
|
|
184
|
+
if (mode === 'q') process.exit(0);
|
|
185
|
+
|
|
186
|
+
if (mode === 'o') {
|
|
187
|
+
await runOpenMode(config.defaultUrl, {
|
|
188
|
+
...commonOptions,
|
|
189
|
+
headless,
|
|
190
|
+
navigationTimeout,
|
|
191
|
+
skipModeHeading: true,
|
|
192
|
+
});
|
|
193
|
+
} else if (mode === 'j') {
|
|
194
|
+
await runJoinMode(config.defaultUrl, {
|
|
195
|
+
...commonOptions,
|
|
196
|
+
skipModeHeading: true,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
201
199
|
}
|
|
202
200
|
})();
|
package/src/http-server.mjs
CHANGED
|
@@ -12,8 +12,8 @@ import http from 'http';
|
|
|
12
12
|
import { C, log } from './utils/colors.mjs';
|
|
13
13
|
import { getFullTimestamp } from './logging/index.mjs';
|
|
14
14
|
import { getComputedStylesFromPage } from './logging/dump.mjs';
|
|
15
|
-
import {
|
|
16
|
-
|
|
15
|
+
import { API_ENDPOINTS } from './templates/api-help.mjs';
|
|
16
|
+
|
|
17
17
|
|
|
18
18
|
/** Default timeout for Puppeteer operations (ms). */
|
|
19
19
|
const PUPPETEER_CALL_TIMEOUT_MS = 30_000;
|
|
@@ -155,7 +155,6 @@ export function createHttpServer(options) {
|
|
|
155
155
|
return;
|
|
156
156
|
}
|
|
157
157
|
try {
|
|
158
|
-
const statsBeforeDump = s.logBuffer.getStats();
|
|
159
158
|
const pages = s.getPages();
|
|
160
159
|
const page = pages.length > 0 ? pages[0] : null;
|
|
161
160
|
|
|
@@ -172,26 +171,14 @@ export function createHttpServer(options) {
|
|
|
172
171
|
success: true,
|
|
173
172
|
timestamp: getFullTimestamp(),
|
|
174
173
|
message: 'Dump completed. Read the files below.',
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
},
|
|
184
|
-
llm: {
|
|
185
|
-
instruction: 'Read or download these files to get the current browser state. Do not ask the user to copy/paste from the browser.',
|
|
186
|
-
files: [
|
|
187
|
-
{ path: s.logBuffer.DOM_HTML, what: 'Current page HTML (JS-modified DOM). Use for element tree and structure.' },
|
|
188
|
-
{ path: s.logBuffer.SCREENSHOT, what: 'Screenshot of the current tab viewport (PNG).' },
|
|
189
|
-
{ path: s.logBuffer.CONSOLE_LOG, what: 'Browser console output (logs, errors, warnings).' },
|
|
190
|
-
{ path: s.logBuffer.NETWORK_LOG, what: 'Network requests overview (one line per request with ID).' },
|
|
191
|
-
{ path: s.logBuffer.NETWORK_DIR, what: 'Directory with one JSON per request: full headers, payload, response (see IDs in network log).' },
|
|
192
|
-
{ path: s.logBuffer.COOKIES_DIR, what: 'Directory with cookies per domain (JSON files).' },
|
|
193
|
-
],
|
|
194
|
-
},
|
|
174
|
+
files: [
|
|
175
|
+
{ path: s.logBuffer.DOM_HTML, what: 'Current page HTML (JS-modified DOM). Use for element tree and structure.' },
|
|
176
|
+
{ path: s.logBuffer.SCREENSHOT, what: 'Screenshot of the current tab viewport (PNG).' },
|
|
177
|
+
{ path: s.logBuffer.CONSOLE_LOG, what: 'Browser console output (logs, errors, warnings).' },
|
|
178
|
+
{ path: s.logBuffer.NETWORK_LOG, what: 'Network requests overview (one line per request with ID).' },
|
|
179
|
+
{ path: s.logBuffer.NETWORK_DIR, what: 'Directory with one JSON per request: full headers, payload, response (see IDs in network log).' },
|
|
180
|
+
{ path: s.logBuffer.COOKIES_DIR, what: 'Directory with cookies per domain (JSON files).' },
|
|
181
|
+
],
|
|
195
182
|
}, null, 2));
|
|
196
183
|
} catch (error) {
|
|
197
184
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
@@ -200,7 +187,7 @@ export function createHttpServer(options) {
|
|
|
200
187
|
return;
|
|
201
188
|
}
|
|
202
189
|
|
|
203
|
-
// GET /status
|
|
190
|
+
// GET /status — state only (no file paths; use GET /dump for that)
|
|
204
191
|
if (req.url === '/status' && req.method === 'GET') {
|
|
205
192
|
const pages = s.getPages();
|
|
206
193
|
const collectingPaused = s.getCollectingPaused();
|
|
@@ -215,14 +202,6 @@ export function createHttpServer(options) {
|
|
|
215
202
|
if (!noBrowser) {
|
|
216
203
|
payload.collecting = collectingPaused ? 'paused' : 'running';
|
|
217
204
|
payload.stats = s.logBuffer.getStats();
|
|
218
|
-
payload.outputFiles = {
|
|
219
|
-
consoleLog: s.logBuffer.CONSOLE_LOG,
|
|
220
|
-
networkLog: s.logBuffer.NETWORK_LOG,
|
|
221
|
-
networkDir: s.logBuffer.NETWORK_DIR,
|
|
222
|
-
cookiesDir: s.logBuffer.COOKIES_DIR,
|
|
223
|
-
domHtml: s.logBuffer.DOM_HTML,
|
|
224
|
-
screenshot: s.logBuffer.SCREENSHOT,
|
|
225
|
-
};
|
|
226
205
|
} else {
|
|
227
206
|
payload.message = 'No browser. Use interactive (o/j) or --open / --join.';
|
|
228
207
|
}
|
|
@@ -500,12 +479,7 @@ export function createHttpServer(options) {
|
|
|
500
479
|
}, null, 2));
|
|
501
480
|
});
|
|
502
481
|
|
|
503
|
-
server.listen(port, host
|
|
504
|
-
const url = `http://${host}:${port}`;
|
|
505
|
-
const changed = port !== defaultPort ? ` ${C.red}(changed)${C.reset}` : '';
|
|
506
|
-
const title = `HTTP API URL: ${url}${changed}`;
|
|
507
|
-
printSectionHeading(title, ' ');
|
|
508
|
-
});
|
|
482
|
+
server.listen(port, host);
|
|
509
483
|
|
|
510
484
|
server.on('error', (err) => {
|
|
511
485
|
if (err.code === 'EADDRINUSE') {
|