@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/src/init.mjs CHANGED
@@ -1,26 +1,17 @@
1
1
  /**
2
- * browsermonitor init – first-run setup and agent file updates.
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
- getPaths,
22
- saveSettings,
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 false;
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
- console.log(`[browsermonitor] Appended Browser Monitor section to ${docFilename}`);
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
- console.log(`[browsermonitor] Replaced Browser Monitor section in ${docFilename}`);
46
+ action = 'replaced';
63
47
  }
64
48
 
65
49
  try {
66
50
  fs.writeFileSync(hostPath, newContent);
67
- return true;
68
- } catch (err) {
69
- console.error(`[browsermonitor] Could not write ${docFilename}:`, err.message);
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, options = {}) {
114
- const { askForUrl = true, updateAgentFiles = true } = options;
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
- // 2. Create settings.json if it doesn't exist
129
- const { settingsFile } = getPaths(projectRoot);
130
- if (!fs.existsSync(settingsFile)) {
131
- let defaultUrl = DEFAULT_SETTINGS.defaultUrl;
132
- if (askForUrl && process.stdin.isTTY) {
133
- defaultUrl = await askDefaultUrl(defaultUrl);
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
- // 3. Update agent files
143
- if (updateAgentFiles) {
144
- if (!fs.existsSync(TEMPLATE_PATH)) {
145
- console.error('[browsermonitor] Agent template not found:', TEMPLATE_PATH);
146
- } else {
147
- const templateContent = fs.readFileSync(TEMPLATE_PATH, 'utf8');
148
- replaceOrAppendSection(projectRoot, 'CLAUDE.md', templateContent);
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
- // 4. Suggest .gitignore
155
- suggestGitignore(projectRoot);
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
- console.log('[browsermonitor] Setup complete.');
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() {
@@ -30,7 +30,7 @@ export class LogBuffer {
30
30
  ignorePatterns = [],
31
31
  } = options;
32
32
 
33
- this.outputDir = outputDir;
33
+ this.outputDir = path.resolve(outputDir);
34
34
  this.lazyMode = lazyMode;
35
35
 
36
36
  if (paths) {
@@ -1,10 +1,23 @@
1
1
  # Monitor submodule
2
2
 
3
- Sdílené moduly pro režimy join, open a interactive.
3
+ Sdílené moduly pro režimy join a open.
4
4
 
5
- - **page-monitoring.mjs** – připojení console/network listenerů na stránku (sdílené pro join i open).
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
- Veřejné API (`runJoinMode`, `runOpenMode`, `runInteractiveMode`) zůstává v `../monitor.mjs` kvůli absenci cyklických závislostí.
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`.