@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/src/init.mjs
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* browsermonitor init –
|
|
3
|
-
*
|
|
4
|
-
* Called by:
|
|
5
|
-
* - `browsermonitor init` subcommand (explicit)
|
|
6
|
-
* - Auto-init on first run when .browsermonitor/ does not exist
|
|
7
|
-
*
|
|
8
|
-
* What it does:
|
|
9
|
-
* 1. Creates .browsermonitor/ directory structure
|
|
10
|
-
* 2. Creates settings.json with defaults (prompts for URL if TTY)
|
|
11
|
-
* 3. Updates CLAUDE.md, AGENTS.md, memory.md with Browser Monitor section
|
|
12
|
-
* 4. Suggests adding .browsermonitor/ to .gitignore
|
|
2
|
+
* browsermonitor init – creates settings.json with defaults, updates agent files.
|
|
13
3
|
*/
|
|
14
4
|
|
|
15
5
|
import fs from 'fs';
|
|
16
6
|
import path from 'path';
|
|
17
7
|
import { fileURLToPath } from 'url';
|
|
18
8
|
import {
|
|
19
|
-
DEFAULT_SETTINGS,
|
|
20
9
|
ensureDirectories,
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
loadSettings,
|
|
11
|
+
DEFAULT_SETTINGS,
|
|
23
12
|
} from './settings.mjs';
|
|
13
|
+
import { C } from './utils/colors.mjs';
|
|
14
|
+
import { printBulletBox } from './templates/section-heading.mjs';
|
|
24
15
|
|
|
25
16
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
17
|
|
|
@@ -31,132 +22,86 @@ const TEMPLATE_PATH = path.resolve(__dirname, 'agents.llm/browser-monitor-sectio
|
|
|
31
22
|
|
|
32
23
|
/**
|
|
33
24
|
* Replace existing tagged block or append template to a doc file.
|
|
34
|
-
* Section is identified by BEGIN/END tags.
|
|
35
|
-
* @param {string} hostDir
|
|
36
|
-
* @param {string} docFilename - e.g. 'CLAUDE.md', 'AGENTS.md', 'memory.md'
|
|
37
|
-
* @param {string} templateContent - full block including BEGIN and END tags
|
|
38
|
-
* @returns {boolean} true if file was updated
|
|
39
25
|
*/
|
|
40
26
|
function replaceOrAppendSection(hostDir, docFilename, templateContent) {
|
|
41
27
|
const hostPath = path.join(hostDir, docFilename);
|
|
42
|
-
if (!fs.existsSync(hostPath)) return
|
|
28
|
+
if (!fs.existsSync(hostPath)) return null;
|
|
43
29
|
|
|
44
30
|
const content = fs.readFileSync(hostPath, 'utf8');
|
|
45
31
|
const trimmedTemplate = templateContent.trimEnd();
|
|
46
32
|
const beginIndex = content.indexOf(BEGIN_TAG_PREFIX);
|
|
47
33
|
|
|
48
34
|
let newContent;
|
|
35
|
+
let action;
|
|
49
36
|
if (beginIndex === -1) {
|
|
50
37
|
newContent = content.trimEnd() + '\n\n' + trimmedTemplate + '\n';
|
|
51
|
-
|
|
38
|
+
action = 'appended';
|
|
52
39
|
} else {
|
|
53
40
|
const endTagStartIndex = content.indexOf(END_TAG_PREFIX, beginIndex);
|
|
54
|
-
if (endTagStartIndex === -1)
|
|
55
|
-
console.error(`[browsermonitor] ${docFilename}: BEGIN tag found but no END tag; skipping`);
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
41
|
+
if (endTagStartIndex === -1) return null;
|
|
58
42
|
const afterEndComment = content.indexOf('-->', endTagStartIndex) + 3;
|
|
59
43
|
const lineEnd = content.indexOf('\n', afterEndComment);
|
|
60
44
|
const endIndex = lineEnd === -1 ? content.length : lineEnd + 1;
|
|
61
45
|
newContent = content.slice(0, beginIndex) + trimmedTemplate + '\n' + content.slice(endIndex);
|
|
62
|
-
|
|
46
|
+
action = 'replaced';
|
|
63
47
|
}
|
|
64
48
|
|
|
65
49
|
try {
|
|
66
50
|
fs.writeFileSync(hostPath, newContent);
|
|
67
|
-
return
|
|
68
|
-
} catch
|
|
69
|
-
|
|
70
|
-
return false;
|
|
51
|
+
return action;
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
71
54
|
}
|
|
72
55
|
}
|
|
73
56
|
|
|
74
|
-
/**
|
|
75
|
-
* Prompt user for default URL (stdin line read).
|
|
76
|
-
* @param {string} defaultValue
|
|
77
|
-
* @returns {Promise<string>}
|
|
78
|
-
*/
|
|
79
|
-
function askDefaultUrl(defaultValue) {
|
|
80
|
-
return new Promise((resolve) => {
|
|
81
|
-
process.stdout.write(` Default URL [${defaultValue}]: `);
|
|
82
|
-
process.stdin.resume();
|
|
83
|
-
process.stdin.setEncoding('utf8');
|
|
84
|
-
process.stdin.once('data', (chunk) => {
|
|
85
|
-
process.stdin.pause();
|
|
86
|
-
const trimmed = chunk.toString().trim().split('\n')[0].trim();
|
|
87
|
-
resolve(trimmed || defaultValue);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Suggest adding .browsermonitor/ to .gitignore if not already present.
|
|
94
|
-
* @param {string} projectRoot
|
|
95
|
-
*/
|
|
96
|
-
function suggestGitignore(projectRoot) {
|
|
97
|
-
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
98
|
-
if (!fs.existsSync(gitignorePath)) return;
|
|
99
|
-
|
|
100
|
-
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
101
|
-
if (content.includes('.browsermonitor')) return;
|
|
102
|
-
|
|
103
|
-
console.log(`[browsermonitor] Tip: add .browsermonitor/ to your .gitignore`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
57
|
/**
|
|
107
58
|
* Run browsermonitor initialization.
|
|
108
|
-
* @param {string} projectRoot - Absolute path to the project
|
|
109
|
-
* @param {Object} [options]
|
|
110
|
-
* @param {boolean} [options.askForUrl=true] - Prompt for default URL
|
|
111
|
-
* @param {boolean} [options.updateAgentFiles=true] - Update CLAUDE.md/AGENTS.md/memory.md
|
|
112
59
|
*/
|
|
113
|
-
export async function runInit(projectRoot,
|
|
114
|
-
|
|
60
|
+
export async function runInit(projectRoot, config = {}) {
|
|
61
|
+
// Merge: explicit config > saved settings > defaults
|
|
62
|
+
const saved = loadSettings(projectRoot);
|
|
63
|
+
config = { ...DEFAULT_SETTINGS, ...saved, ...config };
|
|
64
|
+
const { updateAgentFiles = true } = config;
|
|
115
65
|
|
|
116
|
-
console.log('');
|
|
117
|
-
console.log('========================================');
|
|
118
|
-
console.log(' Browser Monitor - Setup');
|
|
119
|
-
console.log('========================================');
|
|
120
|
-
console.log('');
|
|
121
|
-
console.log(`[browsermonitor] Project: ${projectRoot}`);
|
|
122
|
-
console.log('');
|
|
123
|
-
|
|
124
|
-
// 1. Create directory structure
|
|
125
66
|
ensureDirectories(projectRoot);
|
|
126
|
-
console.log('[browsermonitor] Created .browsermonitor/ directory structure');
|
|
127
67
|
|
|
128
|
-
//
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
131
|
-
let
|
|
132
|
-
|
|
133
|
-
|
|
68
|
+
// Update agent files (render template with settings values)
|
|
69
|
+
const agentUpdates = [];
|
|
70
|
+
if (updateAgentFiles && fs.existsSync(TEMPLATE_PATH)) {
|
|
71
|
+
let templateContent = fs.readFileSync(TEMPLATE_PATH, 'utf8');
|
|
72
|
+
templateContent = templateContent
|
|
73
|
+
.replace(/\{\{DEFAULT_URL\}\}/g, config.defaultUrl)
|
|
74
|
+
.replace(/\{\{HTTP_PORT\}\}/g, String(config.httpPort));
|
|
75
|
+
for (const docFile of ['CLAUDE.md', 'AGENTS.md', 'memory.md']) {
|
|
76
|
+
const action = replaceOrAppendSection(projectRoot, docFile, templateContent);
|
|
77
|
+
if (action) agentUpdates.push(`${action} ${C.cyan}${docFile}${C.reset}`);
|
|
134
78
|
}
|
|
135
|
-
const settings = { ...DEFAULT_SETTINGS, defaultUrl };
|
|
136
|
-
saveSettings(projectRoot, settings);
|
|
137
|
-
console.log(`[browsermonitor] Created settings.json (defaultUrl: ${defaultUrl})`);
|
|
138
|
-
} else {
|
|
139
|
-
console.log('[browsermonitor] settings.json already exists, skipping');
|
|
140
79
|
}
|
|
141
80
|
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
replaceOrAppendSection(projectRoot, 'AGENTS.md', templateContent);
|
|
150
|
-
replaceOrAppendSection(projectRoot, 'memory.md', templateContent);
|
|
81
|
+
// Gitignore check
|
|
82
|
+
let gitignoreHint = null;
|
|
83
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
84
|
+
if (fs.existsSync(gitignorePath)) {
|
|
85
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
86
|
+
if (!content.includes('.browsermonitor')) {
|
|
87
|
+
gitignoreHint = `${C.yellow}Tip:${C.reset} add ${C.cyan}.browsermonitor/${C.reset} to .gitignore`;
|
|
151
88
|
}
|
|
152
89
|
}
|
|
153
90
|
|
|
154
|
-
//
|
|
155
|
-
|
|
91
|
+
// Display results
|
|
92
|
+
const lines = [
|
|
93
|
+
`${C.cyan}Project:${C.reset} ${projectRoot}`,
|
|
94
|
+
`${C.green}Created${C.reset} .browsermonitor/`,
|
|
95
|
+
];
|
|
96
|
+
if (config.defaultUrl) {
|
|
97
|
+
lines[1] += ` → ${C.cyan}${config.defaultUrl}${C.reset}`;
|
|
98
|
+
}
|
|
99
|
+
if (agentUpdates.length > 0) {
|
|
100
|
+
lines.push(`${C.green}Agent docs:${C.reset} ${agentUpdates.join(', ')}`);
|
|
101
|
+
}
|
|
102
|
+
if (gitignoreHint) lines.push(gitignoreHint);
|
|
156
103
|
|
|
157
104
|
console.log('');
|
|
158
|
-
|
|
159
|
-
console.log(' browsermonitor - Interactive menu (o=open, j=join, q=quit)');
|
|
160
|
-
console.log(' browsermonitor --open - Launch Chrome at default URL');
|
|
105
|
+
printBulletBox(lines);
|
|
161
106
|
console.log('');
|
|
162
107
|
}
|
package/src/intro.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { printCliCommandsTable } from './templates/cli-commands.mjs';
|
|
|
8
8
|
|
|
9
9
|
const TITLE = 'Browser Monitor';
|
|
10
10
|
const TAGLINE = 'Browser console, network & DOM capture for debugging and LLM workflows';
|
|
11
|
-
const NPM_URL = 'https://www.npmjs.com/package/browsermonitor';
|
|
11
|
+
const NPM_URL = 'https://www.npmjs.com/package/@romanmatena/browsermonitor';
|
|
12
12
|
const GITHUB_URL = 'https://github.com/romanmatena/browsermonitor';
|
|
13
13
|
|
|
14
14
|
export function printAppIntro() {
|
package/src/monitor/README.md
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
# Monitor submodule
|
|
2
2
|
|
|
3
|
-
Sdílené moduly pro režimy join
|
|
3
|
+
Sdílené moduly pro režimy join a open.
|
|
4
4
|
|
|
5
|
-
- **
|
|
5
|
+
- **open-mode.mjs** – spuštění nového Chrome.
|
|
6
|
+
- **join-mode.mjs** – připojení k běžícímu Chrome.
|
|
7
|
+
- **page-monitoring.mjs** – připojení console/network listenerů na stránku.
|
|
6
8
|
- **tab-selection.mjs** – výběr tabu (askUserToSelectPage, ensureKeypressEvents).
|
|
7
|
-
- **interactive-mode.mjs** – interaktivní menu (o = open, j = join, q = quit), výběr projektového adresáře, výběr Chrome instance.
|
|
8
|
-
- **index.mjs** – re-exporty pro přehled API.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## shared/
|
|
11
|
+
|
|
12
|
+
Společné utility používané oběma režimy:
|
|
13
|
+
|
|
14
|
+
- **user-page-filter.mjs** – filtruje interní Chrome stránky (chrome://, devtools://, extension://).
|
|
15
|
+
- **monitoring-wrapper.mjs** – factory pro setupPageMonitoring s vazbou na session state.
|
|
16
|
+
- **help.mjs** – periodický help reminder + full in-session help (h key).
|
|
17
|
+
- **http-state-setup.mjs** – napojení sharedHttpState callbacků na mode-local state.
|
|
18
|
+
- **tab-switching.mjs** – interaktivní přepínání tabů (t key).
|
|
19
|
+
- **cleanup.mjs** – cleanup funkce + signal handlery (SIGINT, SIGTERM, uncaughtException).
|
|
20
|
+
- **keyboard-handler.mjs** – keyboard input handler (d, c, q, k, s, p, t, h).
|
|
21
|
+
- **index.mjs** – barrel re-exporty všech shared modulů.
|
|
22
|
+
|
|
23
|
+
Veřejné API (`runJoinMode`, `runOpenMode`) se importuje přímo z jednotlivých souborů v `cli.mjs`.
|