chrome-cdp-cli 2.1.2 → 2.1.3
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/dist/cli/CLIApplication.js +10 -12
- package/dist/utils/logger.js +42 -46
- package/package.json +1 -1
|
@@ -141,6 +141,9 @@ class CLIApplication {
|
|
|
141
141
|
const title = target.title.toLowerCase();
|
|
142
142
|
return (url.startsWith("chrome-devtools://") ||
|
|
143
143
|
url.startsWith("devtools://") ||
|
|
144
|
+
url.startsWith("chrome://") ||
|
|
145
|
+
url.startsWith("chrome-extension://") ||
|
|
146
|
+
url.startsWith("chrome-untrusted://") ||
|
|
144
147
|
title.includes("devtools") ||
|
|
145
148
|
title.includes("chrome devtools"));
|
|
146
149
|
}
|
|
@@ -161,23 +164,18 @@ class CLIApplication {
|
|
|
161
164
|
const CYAN = "\x1b[36m";
|
|
162
165
|
const DIM = "\x1b[2m";
|
|
163
166
|
const CLEAR_LINE = "\x1b[2K\x1b[G";
|
|
164
|
-
const
|
|
165
|
-
const RESTORE = "\x1b[u";
|
|
167
|
+
const TOTAL_LINES = targets.length * 2 + 5;
|
|
166
168
|
const truncate = (s, max) => s.length > max ? s.substring(0, max - 1) + "…" : s;
|
|
167
169
|
const render = (first) => {
|
|
168
|
-
if (first) {
|
|
169
|
-
process.stderr.write(
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
process.stderr.write(RESTORE);
|
|
170
|
+
if (!first) {
|
|
171
|
+
process.stderr.write(`\x1b[${TOTAL_LINES}A`);
|
|
173
172
|
}
|
|
174
173
|
process.stderr.write(`${CLEAR_LINE}${BOLD}Select a Chrome page${RESET} (↑↓ navigate, Enter select, q quit)\n`);
|
|
175
174
|
process.stderr.write(`${CLEAR_LINE}${"─".repeat(54)}\n`);
|
|
176
175
|
targets.forEach((t, i) => {
|
|
177
176
|
const num = `[${i + 1}]`;
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
const url = truncate(t.url, 60);
|
|
177
|
+
const title = truncate(t.title || "(Untitled)", 50);
|
|
178
|
+
const url = truncate(t.url, 58);
|
|
181
179
|
const selected = i === cursor;
|
|
182
180
|
if (selected) {
|
|
183
181
|
process.stderr.write(`${CLEAR_LINE}${CYAN}${BOLD} ❯ ${num} ${title}${RESET}\n`);
|
|
@@ -189,8 +187,8 @@ class CLIApplication {
|
|
|
189
187
|
}
|
|
190
188
|
});
|
|
191
189
|
process.stderr.write(`${CLEAR_LINE}${"─".repeat(54)}\n`);
|
|
192
|
-
process.stderr.write(`${CLEAR_LINE}${DIM}Tip: skip this prompt with cdp -i <number> <command>${RESET}\n`
|
|
193
|
-
|
|
190
|
+
process.stderr.write(`${CLEAR_LINE}${DIM}Tip: skip this prompt with cdp -i <number> <command>${RESET}\n`);
|
|
191
|
+
process.stderr.write(`${CLEAR_LINE}${DIM} or close other tabs until only one remains.${RESET}\n`);
|
|
194
192
|
};
|
|
195
193
|
render(true);
|
|
196
194
|
process.stdin.setRawMode(true);
|
package/dist/utils/logger.js
CHANGED
|
@@ -53,7 +53,7 @@ class Logger {
|
|
|
53
53
|
maxFiles: 5,
|
|
54
54
|
enableConsole: true,
|
|
55
55
|
enableStructured: false,
|
|
56
|
-
...config
|
|
56
|
+
...config,
|
|
57
57
|
};
|
|
58
58
|
if (this.config.file) {
|
|
59
59
|
this.initializeLogFile();
|
|
@@ -74,13 +74,15 @@ class Logger {
|
|
|
74
74
|
this.rotateLogFile();
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
this.logFileHandle = fs.createWriteStream(this.config.file, {
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
this.logFileHandle = fs.createWriteStream(this.config.file, {
|
|
78
|
+
flags: "a",
|
|
79
|
+
});
|
|
80
|
+
this.logFileHandle.on("error", (error) => {
|
|
81
|
+
console.error("Log file write error:", error);
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
catch (error) {
|
|
83
|
-
console.error(
|
|
85
|
+
console.error("Failed to initialize log file:", error);
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
rotateLogFile() {
|
|
@@ -104,25 +106,29 @@ class Logger {
|
|
|
104
106
|
fs.renameSync(this.config.file, `${this.config.file}.1`);
|
|
105
107
|
}
|
|
106
108
|
this.currentFileSize = 0;
|
|
107
|
-
this.logFileHandle = fs.createWriteStream(this.config.file, {
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
this.logFileHandle = fs.createWriteStream(this.config.file, {
|
|
110
|
+
flags: "a",
|
|
111
|
+
});
|
|
112
|
+
this.logFileHandle.on("error", (error) => {
|
|
113
|
+
console.error("Log file write error:", error);
|
|
110
114
|
});
|
|
111
115
|
}
|
|
112
116
|
catch (error) {
|
|
113
|
-
console.error(
|
|
117
|
+
console.error("Failed to rotate log file:", error);
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
formatLogEntry(entry) {
|
|
117
121
|
if (this.config.enableStructured) {
|
|
118
|
-
return JSON.stringify(entry) +
|
|
122
|
+
return JSON.stringify(entry) + "\n";
|
|
119
123
|
}
|
|
120
124
|
else {
|
|
121
125
|
const timestamp = entry.timestamp;
|
|
122
126
|
const level = entry.level.padEnd(5);
|
|
123
|
-
const component = entry.component ? `[${entry.component}]` :
|
|
124
|
-
const connectionId = entry.connectionId
|
|
125
|
-
|
|
127
|
+
const component = entry.component ? `[${entry.component}]` : "";
|
|
128
|
+
const connectionId = entry.connectionId
|
|
129
|
+
? `{conn:${entry.connectionId}}`
|
|
130
|
+
: "";
|
|
131
|
+
const clientId = entry.clientId ? `{client:${entry.clientId}}` : "";
|
|
126
132
|
let message = `${timestamp} ${level} ${component}${connectionId}${clientId} ${entry.message}`;
|
|
127
133
|
if (entry.data) {
|
|
128
134
|
message += ` | Data: ${JSON.stringify(entry.data)}`;
|
|
@@ -136,7 +142,7 @@ class Logger {
|
|
|
136
142
|
if (entry.metrics) {
|
|
137
143
|
message += ` | Metrics: ${JSON.stringify(entry.metrics)}`;
|
|
138
144
|
}
|
|
139
|
-
return message +
|
|
145
|
+
return message + "\n";
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
148
|
writeLog(entry) {
|
|
@@ -145,24 +151,12 @@ class Logger {
|
|
|
145
151
|
const consoleMessage = this.config.enableStructured
|
|
146
152
|
? formattedEntry.trim()
|
|
147
153
|
: formattedEntry.trim();
|
|
148
|
-
|
|
149
|
-
case 'ERROR':
|
|
150
|
-
console.error(consoleMessage);
|
|
151
|
-
break;
|
|
152
|
-
case 'WARN':
|
|
153
|
-
console.warn(consoleMessage);
|
|
154
|
-
break;
|
|
155
|
-
case 'INFO':
|
|
156
|
-
console.info(consoleMessage);
|
|
157
|
-
break;
|
|
158
|
-
case 'DEBUG':
|
|
159
|
-
console.debug(consoleMessage);
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
154
|
+
process.stderr.write(consoleMessage + "\n");
|
|
162
155
|
}
|
|
163
156
|
if (this.logFileHandle) {
|
|
164
|
-
const entrySize = Buffer.byteLength(formattedEntry,
|
|
165
|
-
if (this.currentFileSize + entrySize >=
|
|
157
|
+
const entrySize = Buffer.byteLength(formattedEntry, "utf8");
|
|
158
|
+
if (this.currentFileSize + entrySize >=
|
|
159
|
+
(this.config.maxFileSize || 10 * 1024 * 1024)) {
|
|
166
160
|
this.rotateLogFile();
|
|
167
161
|
}
|
|
168
162
|
this.logFileHandle.write(formattedEntry);
|
|
@@ -174,7 +168,7 @@ class Logger {
|
|
|
174
168
|
timestamp: new Date().toISOString(),
|
|
175
169
|
level,
|
|
176
170
|
message,
|
|
177
|
-
component: context?.component || this.config.component
|
|
171
|
+
component: context?.component || this.config.component,
|
|
178
172
|
};
|
|
179
173
|
if (context?.connectionId)
|
|
180
174
|
entry.connectionId = context.connectionId;
|
|
@@ -188,7 +182,7 @@ class Logger {
|
|
|
188
182
|
entry.error = {
|
|
189
183
|
message: error.message,
|
|
190
184
|
stack: error.stack,
|
|
191
|
-
code: error.code
|
|
185
|
+
code: error.code,
|
|
192
186
|
};
|
|
193
187
|
}
|
|
194
188
|
return entry;
|
|
@@ -214,57 +208,59 @@ class Logger {
|
|
|
214
208
|
data = errorOrData;
|
|
215
209
|
error = undefined;
|
|
216
210
|
}
|
|
217
|
-
const entry = this.createLogEntry(
|
|
211
|
+
const entry = this.createLogEntry("ERROR", message, data, error, context);
|
|
218
212
|
this.writeLog(entry);
|
|
219
213
|
}
|
|
220
214
|
}
|
|
221
215
|
warn(message, data, context) {
|
|
222
216
|
if (this.config.level >= LogLevel.WARN) {
|
|
223
|
-
const entry = this.createLogEntry(
|
|
217
|
+
const entry = this.createLogEntry("WARN", message, data, undefined, context);
|
|
224
218
|
this.writeLog(entry);
|
|
225
219
|
}
|
|
226
220
|
}
|
|
227
221
|
info(message, data, context) {
|
|
228
222
|
if (this.config.level >= LogLevel.INFO) {
|
|
229
|
-
const entry = this.createLogEntry(
|
|
223
|
+
const entry = this.createLogEntry("INFO", message, data, undefined, context);
|
|
230
224
|
this.writeLog(entry);
|
|
231
225
|
}
|
|
232
226
|
}
|
|
233
227
|
debug(message, data, context) {
|
|
234
228
|
if (this.config.level >= LogLevel.DEBUG) {
|
|
235
|
-
const entry = this.createLogEntry(
|
|
229
|
+
const entry = this.createLogEntry("DEBUG", message, data, undefined, context);
|
|
236
230
|
this.writeLog(entry);
|
|
237
231
|
}
|
|
238
232
|
}
|
|
239
233
|
logServerEvent(event, message, data, error) {
|
|
240
|
-
const metrics = event ===
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
234
|
+
const metrics = event === "startup" || event === "shutdown"
|
|
235
|
+
? {
|
|
236
|
+
memoryUsage: process.memoryUsage(),
|
|
237
|
+
}
|
|
238
|
+
: undefined;
|
|
239
|
+
const entry = this.createLogEntry(event === "error" ? "ERROR" : "INFO", `[SERVER-${event.toUpperCase()}] ${message}`, data, error, { component: "ProxyServer", metrics });
|
|
244
240
|
this.writeLog(entry);
|
|
245
241
|
}
|
|
246
242
|
logConnectionEvent(event, connectionId, message, data, error) {
|
|
247
|
-
const entry = this.createLogEntry(error ?
|
|
243
|
+
const entry = this.createLogEntry(error ? "ERROR" : "INFO", `[CONNECTION-${event.toUpperCase()}] ${message}`, data, error, { component: "ConnectionPool", connectionId });
|
|
248
244
|
this.writeLog(entry);
|
|
249
245
|
}
|
|
250
246
|
logClientEvent(event, clientId, message, data, error) {
|
|
251
|
-
const entry = this.createLogEntry(error ?
|
|
247
|
+
const entry = this.createLogEntry(error ? "ERROR" : "INFO", `[CLIENT-${event.toUpperCase()}] ${message}`, data, error, { component: "WSProxy", clientId });
|
|
252
248
|
this.writeLog(entry);
|
|
253
249
|
}
|
|
254
250
|
logMemoryEvent(event, message, metrics) {
|
|
255
|
-
const entry = this.createLogEntry(
|
|
251
|
+
const entry = this.createLogEntry("INFO", `[MEMORY-${event.toUpperCase()}] ${message}`, undefined, undefined, { component: "MemoryManager", metrics });
|
|
256
252
|
this.writeLog(entry);
|
|
257
253
|
}
|
|
258
254
|
logAPIEvent(method, path, statusCode, duration, clientIP, error) {
|
|
259
|
-
const entry = this.createLogEntry(error ?
|
|
255
|
+
const entry = this.createLogEntry(error ? "ERROR" : "INFO", `[API] ${method} ${path} - ${statusCode} (${duration}ms)`, { clientIP, duration, statusCode }, error, { component: "ProxyAPI" });
|
|
260
256
|
this.writeLog(entry);
|
|
261
257
|
}
|
|
262
258
|
logSecurityEvent(event, message, data, error) {
|
|
263
|
-
const entry = this.createLogEntry(error ?
|
|
259
|
+
const entry = this.createLogEntry(error ? "ERROR" : "WARN", `[SECURITY-${event.toUpperCase()}] ${message}`, data, error, { component: "SecurityManager" });
|
|
264
260
|
this.writeLog(entry);
|
|
265
261
|
}
|
|
266
262
|
logPerformanceMetrics(component, metrics) {
|
|
267
|
-
const entry = this.createLogEntry(
|
|
263
|
+
const entry = this.createLogEntry("INFO", `[PERFORMANCE] ${component} metrics`, undefined, undefined, { component, metrics });
|
|
268
264
|
this.writeLog(entry);
|
|
269
265
|
}
|
|
270
266
|
close() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-cdp-cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Browser automation CLI via Chrome DevTools Protocol. Designed for developers and AI assistants - combines dedicated commands for common tasks with flexible JavaScript execution for complex scenarios. Features: element interaction, screenshots, DOM snapshots, console/network monitoring. Built-in IDE integration for Cursor and Claude.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|