@graphty/remote-logger 0.0.1 → 1.2.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.
Files changed (138) hide show
  1. package/README.md +944 -28
  2. package/bin/remote-log-server.js +3 -0
  3. package/dist/client/RemoteLogClient.d.ts +116 -0
  4. package/dist/client/RemoteLogClient.d.ts.map +1 -0
  5. package/dist/client/RemoteLogClient.js +269 -0
  6. package/dist/client/RemoteLogClient.js.map +1 -0
  7. package/dist/client/index.d.ts +7 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +6 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/client/types.d.ts +60 -0
  12. package/dist/client/types.d.ts.map +1 -0
  13. package/dist/client/types.js +6 -0
  14. package/dist/client/types.js.map +1 -0
  15. package/dist/index.d.ts +22 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +23 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/mcp/index.d.ts +9 -0
  20. package/dist/mcp/index.d.ts.map +1 -0
  21. package/dist/mcp/index.js +9 -0
  22. package/dist/mcp/index.js.map +1 -0
  23. package/dist/mcp/mcp-server.d.ts +32 -0
  24. package/dist/mcp/mcp-server.d.ts.map +1 -0
  25. package/dist/mcp/mcp-server.js +270 -0
  26. package/dist/mcp/mcp-server.js.map +1 -0
  27. package/dist/mcp/tools/index.d.ts +14 -0
  28. package/dist/mcp/tools/index.d.ts.map +1 -0
  29. package/dist/mcp/tools/index.js +14 -0
  30. package/dist/mcp/tools/index.js.map +1 -0
  31. package/dist/mcp/tools/logs-clear.d.ts +76 -0
  32. package/dist/mcp/tools/logs-clear.d.ts.map +1 -0
  33. package/dist/mcp/tools/logs-clear.js +58 -0
  34. package/dist/mcp/tools/logs-clear.js.map +1 -0
  35. package/dist/mcp/tools/logs-get-all.d.ts +60 -0
  36. package/dist/mcp/tools/logs-get-all.d.ts.map +1 -0
  37. package/dist/mcp/tools/logs-get-all.js +50 -0
  38. package/dist/mcp/tools/logs-get-all.js.map +1 -0
  39. package/dist/mcp/tools/logs-get-errors.d.ts +65 -0
  40. package/dist/mcp/tools/logs-get-errors.d.ts.map +1 -0
  41. package/dist/mcp/tools/logs-get-errors.js +46 -0
  42. package/dist/mcp/tools/logs-get-errors.js.map +1 -0
  43. package/dist/mcp/tools/logs-get-file-path.d.ts +75 -0
  44. package/dist/mcp/tools/logs-get-file-path.d.ts.map +1 -0
  45. package/dist/mcp/tools/logs-get-file-path.js +90 -0
  46. package/dist/mcp/tools/logs-get-file-path.js.map +1 -0
  47. package/dist/mcp/tools/logs-get-recent.d.ts +89 -0
  48. package/dist/mcp/tools/logs-get-recent.d.ts.map +1 -0
  49. package/dist/mcp/tools/logs-get-recent.js +74 -0
  50. package/dist/mcp/tools/logs-get-recent.js.map +1 -0
  51. package/dist/mcp/tools/logs-list-sessions.d.ts +64 -0
  52. package/dist/mcp/tools/logs-list-sessions.d.ts.map +1 -0
  53. package/dist/mcp/tools/logs-list-sessions.js +48 -0
  54. package/dist/mcp/tools/logs-list-sessions.js.map +1 -0
  55. package/dist/mcp/tools/logs-receive.d.ts +150 -0
  56. package/dist/mcp/tools/logs-receive.d.ts.map +1 -0
  57. package/dist/mcp/tools/logs-receive.js +68 -0
  58. package/dist/mcp/tools/logs-receive.js.map +1 -0
  59. package/dist/mcp/tools/logs-search.d.ts +91 -0
  60. package/dist/mcp/tools/logs-search.d.ts.map +1 -0
  61. package/dist/mcp/tools/logs-search.js +68 -0
  62. package/dist/mcp/tools/logs-search.js.map +1 -0
  63. package/dist/mcp/tools/logs-status.d.ts +45 -0
  64. package/dist/mcp/tools/logs-status.d.ts.map +1 -0
  65. package/dist/mcp/tools/logs-status.js +45 -0
  66. package/dist/mcp/tools/logs-status.js.map +1 -0
  67. package/dist/server/dual-server.d.ts +76 -0
  68. package/dist/server/dual-server.d.ts.map +1 -0
  69. package/dist/server/dual-server.js +214 -0
  70. package/dist/server/dual-server.js.map +1 -0
  71. package/dist/server/index.d.ts +12 -0
  72. package/dist/server/index.d.ts.map +1 -0
  73. package/dist/server/index.js +12 -0
  74. package/dist/server/index.js.map +1 -0
  75. package/dist/server/jsonl-writer.d.ts +93 -0
  76. package/dist/server/jsonl-writer.d.ts.map +1 -0
  77. package/dist/server/jsonl-writer.js +205 -0
  78. package/dist/server/jsonl-writer.js.map +1 -0
  79. package/dist/server/log-server.d.ts +126 -0
  80. package/dist/server/log-server.d.ts.map +1 -0
  81. package/dist/server/log-server.js +589 -0
  82. package/dist/server/log-server.js.map +1 -0
  83. package/dist/server/log-storage.d.ts +301 -0
  84. package/dist/server/log-storage.d.ts.map +1 -0
  85. package/dist/server/log-storage.js +408 -0
  86. package/dist/server/log-storage.js.map +1 -0
  87. package/dist/server/marker-utils.d.ts +69 -0
  88. package/dist/server/marker-utils.d.ts.map +1 -0
  89. package/dist/server/marker-utils.js +118 -0
  90. package/dist/server/marker-utils.js.map +1 -0
  91. package/dist/server/self-signed-cert.d.ts +30 -0
  92. package/dist/server/self-signed-cert.d.ts.map +1 -0
  93. package/dist/server/self-signed-cert.js +83 -0
  94. package/dist/server/self-signed-cert.js.map +1 -0
  95. package/dist/ui/ConsoleCaptureUI.d.ts +118 -0
  96. package/dist/ui/ConsoleCaptureUI.d.ts.map +1 -0
  97. package/dist/ui/ConsoleCaptureUI.js +571 -0
  98. package/dist/ui/ConsoleCaptureUI.js.map +1 -0
  99. package/dist/ui/index.d.ts +15 -0
  100. package/dist/ui/index.d.ts.map +1 -0
  101. package/dist/ui/index.js +15 -0
  102. package/dist/ui/index.js.map +1 -0
  103. package/dist/vite/index.d.ts +8 -0
  104. package/dist/vite/index.d.ts.map +1 -0
  105. package/dist/vite/index.js +8 -0
  106. package/dist/vite/index.js.map +1 -0
  107. package/dist/vite/plugin.d.ts +42 -0
  108. package/dist/vite/plugin.d.ts.map +1 -0
  109. package/dist/vite/plugin.js +46 -0
  110. package/dist/vite/plugin.js.map +1 -0
  111. package/package.json +90 -7
  112. package/src/client/RemoteLogClient.ts +328 -0
  113. package/src/client/index.ts +7 -0
  114. package/src/client/types.ts +62 -0
  115. package/src/index.ts +28 -0
  116. package/src/mcp/index.ts +25 -0
  117. package/src/mcp/mcp-server.ts +364 -0
  118. package/src/mcp/tools/index.ts +69 -0
  119. package/src/mcp/tools/logs-clear.ts +86 -0
  120. package/src/mcp/tools/logs-get-all.ts +78 -0
  121. package/src/mcp/tools/logs-get-errors.ts +71 -0
  122. package/src/mcp/tools/logs-get-file-path.ts +121 -0
  123. package/src/mcp/tools/logs-get-recent.ts +104 -0
  124. package/src/mcp/tools/logs-list-sessions.ts +71 -0
  125. package/src/mcp/tools/logs-receive.ts +96 -0
  126. package/src/mcp/tools/logs-search.ts +95 -0
  127. package/src/mcp/tools/logs-status.ts +69 -0
  128. package/src/server/dual-server.ts +308 -0
  129. package/src/server/index.ts +54 -0
  130. package/src/server/jsonl-writer.ts +277 -0
  131. package/src/server/log-server.ts +763 -0
  132. package/src/server/log-storage.ts +651 -0
  133. package/src/server/marker-utils.ts +144 -0
  134. package/src/server/self-signed-cert.ts +93 -0
  135. package/src/ui/ConsoleCaptureUI.ts +649 -0
  136. package/src/ui/index.ts +15 -0
  137. package/src/vite/index.ts +8 -0
  138. package/src/vite/plugin.ts +59 -0
@@ -0,0 +1,589 @@
1
+ /**
2
+ * Remote Log Server - A standalone HTTP/HTTPS log server for remote debugging.
3
+ *
4
+ * Features:
5
+ * - HTTPS with auto-generated self-signed certs or custom certs
6
+ * - Receives logs from browser via POST /log
7
+ * - Pretty terminal output with colors
8
+ * - REST API for querying logs
9
+ * - Optional file logging for Claude Code to read
10
+ *
11
+ * Usage:
12
+ * npx remote-log-server --port 9080
13
+ * npx remote-log-server --cert /path/to/cert.crt --key /path/to/key.key
14
+ */
15
+ import * as fs from "fs";
16
+ import * as http from "http";
17
+ import * as https from "https";
18
+ import * as os from "os";
19
+ import * as path from "path";
20
+ import { URL } from "url";
21
+ import { JsonlWriter } from "./jsonl-writer.js";
22
+ import { LogStorage } from "./log-storage.js";
23
+ import { certFilesExist, readCertFiles } from "./self-signed-cert.js";
24
+ // Shared log storage instance
25
+ let sharedStorage = null;
26
+ // Shared JSONL writer instance
27
+ let sharedJsonlWriter = null;
28
+ /**
29
+ * Get the shared LogStorage instance, creating it if needed.
30
+ * Creates a JsonlWriter for JSONL file streaming by default.
31
+ * @returns The shared LogStorage instance
32
+ */
33
+ export function getLogStorage() {
34
+ if (!sharedStorage) {
35
+ // Create JSONL writer for file streaming
36
+ const jsonlBaseDir = path.join(os.tmpdir(), "remote-logger");
37
+ sharedJsonlWriter = new JsonlWriter(jsonlBaseDir);
38
+ // Create storage with JSONL writer
39
+ sharedStorage = new LogStorage({ jsonlWriter: sharedJsonlWriter });
40
+ }
41
+ return sharedStorage;
42
+ }
43
+ /**
44
+ * Get the shared JsonlWriter instance.
45
+ * @returns The shared JsonlWriter instance or null if not initialized
46
+ */
47
+ export function getJsonlWriter() {
48
+ return sharedJsonlWriter;
49
+ }
50
+ /**
51
+ * Set the shared LogStorage instance (for testing or external injection).
52
+ * @param storage - The LogStorage instance to use
53
+ */
54
+ export function setLogStorage(storage) {
55
+ sharedStorage = storage;
56
+ }
57
+ // ANSI color codes for terminal output
58
+ const colors = {
59
+ reset: "\x1b[0m",
60
+ bright: "\x1b[1m",
61
+ dim: "\x1b[2m",
62
+ red: "\x1b[31m",
63
+ green: "\x1b[32m",
64
+ yellow: "\x1b[33m",
65
+ blue: "\x1b[34m",
66
+ magenta: "\x1b[35m",
67
+ cyan: "\x1b[36m",
68
+ white: "\x1b[37m",
69
+ bgRed: "\x1b[41m",
70
+ bgYellow: "\x1b[43m",
71
+ };
72
+ // File stream for log file
73
+ let logFileStream = null;
74
+ /**
75
+ * Clear all stored logs.
76
+ * Useful for testing.
77
+ */
78
+ export function clearLogs() {
79
+ getLogStorage().clear();
80
+ }
81
+ /**
82
+ * Format log level for terminal output with colors.
83
+ * @param level - The log level string
84
+ * @returns Colored and formatted log level string
85
+ */
86
+ function formatLogLevel(level) {
87
+ switch (level.toUpperCase()) {
88
+ case "ERROR":
89
+ return `${colors.bgRed}${colors.white} ERROR ${colors.reset}`;
90
+ case "WARN":
91
+ case "WARNING":
92
+ return `${colors.bgYellow}${colors.bright} WARN ${colors.reset}`;
93
+ case "INFO":
94
+ return `${colors.blue} INFO ${colors.reset}`;
95
+ case "DEBUG":
96
+ return `${colors.cyan} DEBUG ${colors.reset}`;
97
+ case "TRACE":
98
+ return `${colors.dim} TRACE ${colors.reset}`;
99
+ case "LOG":
100
+ default:
101
+ return `${colors.green} LOG ${colors.reset}`;
102
+ }
103
+ }
104
+ /**
105
+ * Display a log entry in the terminal.
106
+ * @param sessionId - The session ID for this log entry
107
+ * @param log - The log entry to display
108
+ * @param quiet - If true, suppress terminal output
109
+ */
110
+ function displayLog(sessionId, log, quiet) {
111
+ if (!quiet) {
112
+ const time = new Date(log.time).toLocaleTimeString();
113
+ const level = formatLogLevel(log.level);
114
+ const session = `${colors.cyan}[${sessionId.substring(0, 12)}]${colors.reset}`;
115
+ // Truncate very long messages for display
116
+ let { message } = log;
117
+ if (message.length > 1000) {
118
+ message = `${message.substring(0, 1000)}... [truncated]`;
119
+ }
120
+ // eslint-disable-next-line no-console
121
+ console.log(`${time} ${session} ${level} ${message}`);
122
+ }
123
+ // Write to log file if configured
124
+ if (logFileStream) {
125
+ const logLine = JSON.stringify({
126
+ time: log.time,
127
+ sessionId,
128
+ level: log.level,
129
+ message: log.message,
130
+ });
131
+ logFileStream.write(`${logLine}\n`);
132
+ }
133
+ }
134
+ /**
135
+ * Handle incoming HTTP request.
136
+ * @param req - The incoming HTTP request
137
+ * @param res - The HTTP response object
138
+ * @param host - The server hostname
139
+ * @param port - The server port number
140
+ * @param useHttps - Whether HTTPS is being used
141
+ * @param quiet - If true, suppress terminal output
142
+ * @param logReceiveOnly - If true, only serve /log POST and /health GET endpoints
143
+ */
144
+ function handleRequest(req, res, host, port, useHttps, quiet, logReceiveOnly = false) {
145
+ // CORS headers
146
+ res.setHeader("Access-Control-Allow-Origin", "*");
147
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
148
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
149
+ if (req.method === "OPTIONS") {
150
+ res.writeHead(204);
151
+ res.end();
152
+ return;
153
+ }
154
+ const url = req.url ?? "/";
155
+ const protocol = useHttps ? "https" : "http";
156
+ // Handle log endpoint - receive logs from browser
157
+ if (url === "/log" && req.method === "POST") {
158
+ let body = "";
159
+ req.on("data", (chunk) => {
160
+ body += chunk.toString();
161
+ });
162
+ req.on("end", () => {
163
+ try {
164
+ const data = JSON.parse(body);
165
+ const { sessionId, logs, projectMarker, worktreePath, pageUrl } = data;
166
+ const storage = getLogStorage();
167
+ const isNewSession = !storage.hasSession(sessionId);
168
+ // Show new session banner
169
+ if (isNewSession && !quiet) {
170
+ // eslint-disable-next-line no-console
171
+ console.log(`\n${colors.bright}${colors.magenta}═══════════════════════════════════════════════════════════${colors.reset}`);
172
+ // eslint-disable-next-line no-console
173
+ console.log(`${colors.bright}${colors.magenta} NEW SESSION: ${sessionId}${colors.reset}`);
174
+ // eslint-disable-next-line no-console
175
+ console.log(`${colors.bright}${colors.magenta}═══════════════════════════════════════════════════════════${colors.reset}\n`);
176
+ }
177
+ // Add logs to storage
178
+ storage.addLogs(sessionId, logs, { projectMarker, worktreePath, pageUrl });
179
+ // Display each log in terminal
180
+ for (const log of logs) {
181
+ displayLog(sessionId, log, quiet);
182
+ }
183
+ res.writeHead(200, { "Content-Type": "application/json" });
184
+ res.end(JSON.stringify({ success: true }));
185
+ }
186
+ catch (error) {
187
+ if (!quiet) {
188
+ console.error("Error parsing log data:", error);
189
+ }
190
+ res.writeHead(400, { "Content-Type": "application/json" });
191
+ res.end(JSON.stringify({ error: "Invalid JSON" }));
192
+ }
193
+ });
194
+ return;
195
+ }
196
+ // Health check endpoint (always available)
197
+ if (url === "/health" && req.method === "GET") {
198
+ const health = getLogStorage().getHealth();
199
+ res.writeHead(200, { "Content-Type": "application/json" });
200
+ res.end(JSON.stringify({ status: health.status, sessions: health.sessionCount }));
201
+ return;
202
+ }
203
+ // In logReceiveOnly mode, only /log and /health are available
204
+ if (logReceiveOnly) {
205
+ res.writeHead(404, { "Content-Type": "application/json" });
206
+ res.end(JSON.stringify({ error: "Not found (log receive only mode)" }));
207
+ return;
208
+ }
209
+ // Handle logs viewer endpoint - GET all logs
210
+ if (url === "/logs" && req.method === "GET") {
211
+ const allLogs = getLogStorage().getAllLogsBySession();
212
+ res.writeHead(200, { "Content-Type": "application/json" });
213
+ res.end(JSON.stringify(allLogs, null, 2));
214
+ return;
215
+ }
216
+ // Handle recent logs endpoint - GET last N logs across all sessions
217
+ if (url.startsWith("/logs/recent") && req.method === "GET") {
218
+ const urlObj = new URL(url, `${protocol}://${host}:${port}`);
219
+ const count = parseInt(urlObj.searchParams.get("n") ?? "50", 10);
220
+ const errorsOnly = urlObj.searchParams.get("errors") === "true";
221
+ const storage = getLogStorage();
222
+ const filter = errorsOnly ? { level: "ERROR" } : {};
223
+ const recentLogs = storage.getRecentLogs(count, filter);
224
+ const totalLogs = storage.getLogs(filter).length;
225
+ res.writeHead(200, { "Content-Type": "application/json" });
226
+ res.end(JSON.stringify({
227
+ total: totalLogs,
228
+ showing: recentLogs.length,
229
+ logs: recentLogs,
230
+ }, null, 2));
231
+ return;
232
+ }
233
+ // Handle errors-only endpoint
234
+ if (url === "/logs/errors" && req.method === "GET") {
235
+ const errorLogs = getLogStorage().getErrors();
236
+ res.writeHead(200, { "Content-Type": "application/json" });
237
+ res.end(JSON.stringify({
238
+ total: errorLogs.length,
239
+ logs: errorLogs,
240
+ }, null, 2));
241
+ return;
242
+ }
243
+ // Handle clear logs endpoint
244
+ if (url === "/logs/clear" && req.method === "POST") {
245
+ getLogStorage().clear();
246
+ if (!quiet) {
247
+ // eslint-disable-next-line no-console
248
+ console.log(`\n${colors.yellow}Logs cleared${colors.reset}\n`);
249
+ }
250
+ res.writeHead(200, { "Content-Type": "application/json" });
251
+ res.end(JSON.stringify({ success: true }));
252
+ return;
253
+ }
254
+ // Default: 404
255
+ res.writeHead(404, { "Content-Type": "application/json" });
256
+ res.end(JSON.stringify({ error: "Not found" }));
257
+ }
258
+ /**
259
+ * Print startup banner.
260
+ * @param host - The server hostname
261
+ * @param port - The server port number
262
+ * @param useHttps - Whether HTTPS is being used
263
+ */
264
+ function printBanner(host, port, useHttps) {
265
+ const protocol = useHttps ? "https" : "http";
266
+ // eslint-disable-next-line no-console
267
+ console.log("");
268
+ // eslint-disable-next-line no-console
269
+ console.log(`${colors.bright}${colors.cyan}════════════════════════════════════════════════════════════${colors.reset}`);
270
+ // eslint-disable-next-line no-console
271
+ console.log(`${colors.bright}${colors.cyan} Remote Log Server${colors.reset}`);
272
+ // eslint-disable-next-line no-console
273
+ console.log(`${colors.bright}${colors.cyan}════════════════════════════════════════════════════════════${colors.reset}`);
274
+ // eslint-disable-next-line no-console
275
+ console.log("");
276
+ // eslint-disable-next-line no-console
277
+ console.log(`${colors.green}Server running at:${colors.reset} ${colors.bright}${protocol}://${host}:${port}/${colors.reset}`);
278
+ // eslint-disable-next-line no-console
279
+ console.log("");
280
+ // eslint-disable-next-line no-console
281
+ console.log(`${colors.yellow}API Endpoints:${colors.reset}`);
282
+ // eslint-disable-next-line no-console
283
+ console.log(` ${colors.cyan}POST /log ${colors.reset} - Receive logs from browser`);
284
+ // eslint-disable-next-line no-console
285
+ console.log(` ${colors.cyan}GET /logs ${colors.reset} - Get all logs as JSON`);
286
+ // eslint-disable-next-line no-console
287
+ console.log(` ${colors.cyan}GET /logs/recent ${colors.reset} - Get last 50 logs (?n=100 for more)`);
288
+ // eslint-disable-next-line no-console
289
+ console.log(` ${colors.cyan}GET /logs/errors ${colors.reset} - Get only error logs`);
290
+ // eslint-disable-next-line no-console
291
+ console.log(` ${colors.cyan}POST /logs/clear ${colors.reset} - Clear all logs`);
292
+ // eslint-disable-next-line no-console
293
+ console.log(` ${colors.cyan}GET /health ${colors.reset} - Health check`);
294
+ // eslint-disable-next-line no-console
295
+ console.log("");
296
+ // eslint-disable-next-line no-console
297
+ console.log(`${colors.dim}Remote logs will appear below:${colors.reset}`);
298
+ // eslint-disable-next-line no-console
299
+ console.log(`${colors.cyan}────────────────────────────────────────────────────────────${colors.reset}`);
300
+ }
301
+ /**
302
+ * Create a log server with shared storage.
303
+ * The server is not started - call server.listen() to start it.
304
+ * @param options - Server configuration options
305
+ * @returns The server instance
306
+ */
307
+ export function createLogServer(options) {
308
+ const { port, host, storage, quiet = true, logReceiveOnly = false, certPath, keyPath, } = options;
309
+ // Set the shared storage
310
+ setLogStorage(storage);
311
+ let server;
312
+ // Use HTTPS only if valid certificate files are provided
313
+ const useHttps = certPath && keyPath && certFilesExist(certPath, keyPath);
314
+ if (useHttps) {
315
+ // HTTPS server with provided certificates
316
+ const { cert, key } = readCertFiles(certPath, keyPath);
317
+ if (!quiet) {
318
+ // eslint-disable-next-line no-console
319
+ console.log(`${colors.green}Using SSL certificates from: ${certPath}${colors.reset}`);
320
+ }
321
+ server = https.createServer({ cert, key }, (req, res) => {
322
+ handleRequest(req, res, host, port, true, quiet, logReceiveOnly);
323
+ });
324
+ }
325
+ else {
326
+ // HTTP server (default - no self-signed certs as browsers reject them)
327
+ server = http.createServer((req, res) => {
328
+ handleRequest(req, res, host, port, false, quiet, logReceiveOnly);
329
+ });
330
+ }
331
+ return { server };
332
+ }
333
+ /**
334
+ * Start the log server.
335
+ * @param options - Server configuration options
336
+ * @returns The HTTP or HTTPS server instance
337
+ */
338
+ export function startLogServer(options = {}) {
339
+ const port = options.port ?? 9080;
340
+ const host = options.host ?? "localhost";
341
+ const quiet = options.quiet ?? false;
342
+ // Set up log file if specified
343
+ if (options.logFile) {
344
+ logFileStream = fs.createWriteStream(options.logFile, { flags: "a" });
345
+ if (!quiet) {
346
+ // eslint-disable-next-line no-console
347
+ console.log(`${colors.green}Writing logs to: ${options.logFile}${colors.reset}`);
348
+ }
349
+ }
350
+ // Determine SSL configuration
351
+ // Use HTTPS only if valid certificate files are provided
352
+ let server;
353
+ let useHttps = false;
354
+ const { certPath, keyPath } = options;
355
+ if (certPath && keyPath && certFilesExist(certPath, keyPath)) {
356
+ // HTTPS server with provided certificates
357
+ useHttps = true;
358
+ const { cert, key } = readCertFiles(certPath, keyPath);
359
+ if (!quiet) {
360
+ // eslint-disable-next-line no-console
361
+ console.log(`${colors.green}Using SSL certificates from: ${certPath}${colors.reset}`);
362
+ }
363
+ server = https.createServer({ cert, key }, (req, res) => {
364
+ handleRequest(req, res, host, port, true, quiet);
365
+ });
366
+ }
367
+ else {
368
+ // HTTP server (default - no self-signed certs as browsers reject them)
369
+ server = http.createServer((req, res) => {
370
+ handleRequest(req, res, host, port, false, quiet);
371
+ });
372
+ }
373
+ // Start listening
374
+ server.listen(port, host, () => {
375
+ if (!quiet) {
376
+ printBanner(host, port, useHttps);
377
+ }
378
+ });
379
+ // Handle graceful shutdown
380
+ process.on("SIGINT", () => {
381
+ // eslint-disable-next-line no-console
382
+ console.log(`\n${colors.yellow}Shutting down...${colors.reset}`);
383
+ if (logFileStream) {
384
+ logFileStream.end();
385
+ }
386
+ // Close JSONL writer to flush pending writes
387
+ const jsonlWriter = getJsonlWriter();
388
+ if (jsonlWriter) {
389
+ void jsonlWriter.close();
390
+ }
391
+ server.close(() => {
392
+ process.exit(0);
393
+ });
394
+ });
395
+ return server;
396
+ }
397
+ /**
398
+ * Help text displayed when --help is passed.
399
+ */
400
+ export const HELP_TEXT = `
401
+ Remote Log Server - Remote logging for browser debugging
402
+
403
+ Usage:
404
+ npx remote-log-server [options]
405
+ npx @graphty/remote-logger [options]
406
+
407
+ Options:
408
+ --port, -p <port> Port to listen on (default: 9080)
409
+ --host, -h <host> Hostname to bind to (default: localhost)
410
+ --cert, -c <path> Path to SSL certificate file (enables HTTPS)
411
+ --key, -k <path> Path to SSL private key file (enables HTTPS)
412
+ --log-file, -l <path> Write logs to file
413
+ --mcp-only Start only MCP server (no HTTP)
414
+ --http-only Start only HTTP server (legacy mode)
415
+ --mcp Alias for --mcp-only (deprecated)
416
+ --quiet, -q Suppress startup banner
417
+ --help Show this help message
418
+
419
+ Protocol:
420
+ HTTP is used by default. To use HTTPS, provide both --cert and --key.
421
+
422
+ Modes:
423
+ Default (no flags) Dual mode: HTTP + MCP running together
424
+ --mcp-only MCP only: For Claude Code integration
425
+ --http-only HTTP only: Legacy mode for browser debugging
426
+
427
+ Examples:
428
+ npx remote-log-server # Start dual mode (HTTP + MCP)
429
+ npx remote-log-server --port 9085 # Custom port
430
+ npx remote-log-server --mcp-only # MCP server only (for Claude Code)
431
+ npx remote-log-server --http-only # HTTP server only (legacy)
432
+ npx remote-log-server --cert cert.crt --key key.key # Use HTTPS with custom certs
433
+ npx remote-log-server --log-file ./tmp/logs.jsonl # Also write to file
434
+ `;
435
+ /**
436
+ * Parse command line arguments into LogServerOptions.
437
+ * This is separated from main() to enable testing.
438
+ * @param args - Array of command line arguments (excluding node and script name)
439
+ * @returns ParseArgsResult with options, help flag, or error
440
+ */
441
+ export function parseArgs(args) {
442
+ const options = {};
443
+ for (let i = 0; i < args.length; i++) {
444
+ const arg = args[i];
445
+ const nextArg = args[i + 1];
446
+ switch (arg) {
447
+ case "--port":
448
+ case "-p":
449
+ options.port = parseInt(nextArg, 10);
450
+ i++;
451
+ break;
452
+ case "--host":
453
+ case "-h":
454
+ options.host = nextArg;
455
+ i++;
456
+ break;
457
+ case "--cert":
458
+ case "-c":
459
+ options.certPath = nextArg;
460
+ i++;
461
+ break;
462
+ case "--key":
463
+ case "-k":
464
+ options.keyPath = nextArg;
465
+ i++;
466
+ break;
467
+ case "--log-file":
468
+ case "-l":
469
+ options.logFile = nextArg;
470
+ i++;
471
+ break;
472
+ case "--mcp":
473
+ // Legacy alias for --mcp-only. Only set mcpOnly now.
474
+ options.mcpOnly = true;
475
+ break;
476
+ case "--mcp-only":
477
+ options.mcpOnly = true;
478
+ break;
479
+ case "--http-only":
480
+ options.httpOnly = true;
481
+ break;
482
+ case "--quiet":
483
+ case "-q":
484
+ options.quiet = true;
485
+ break;
486
+ case "--help":
487
+ return { options, showHelp: true };
488
+ default:
489
+ return { options, showHelp: false, error: `Unknown option: ${arg}` };
490
+ }
491
+ }
492
+ return { options, showHelp: false };
493
+ }
494
+ /**
495
+ * Parse command line arguments and start the server.
496
+ */
497
+ export async function main() {
498
+ const args = process.argv.slice(2);
499
+ const result = parseArgs(args);
500
+ if (result.showHelp) {
501
+ // eslint-disable-next-line no-console
502
+ console.log(HELP_TEXT);
503
+ process.exit(0);
504
+ }
505
+ if (result.error) {
506
+ console.error(result.error);
507
+ process.exit(1);
508
+ }
509
+ const { options } = result;
510
+ // Determine mode: mcp-only, http-only, or dual (default)
511
+ // All modes now use createDualServer with different options
512
+ const { createDualServer } = await import("./dual-server.js");
513
+ if (options.mcpOnly) {
514
+ // MCP-only mode: HTTP only serves /log endpoint, MCP enabled
515
+ const dualServer = await createDualServer({
516
+ httpPort: options.port ?? 9080,
517
+ httpHost: options.host ?? "localhost",
518
+ httpEnabled: true,
519
+ mcpEnabled: true,
520
+ quiet: options.quiet ?? false,
521
+ logReceiveOnly: true, // Only serve /log and /health endpoints
522
+ certPath: options.certPath,
523
+ keyPath: options.keyPath,
524
+ });
525
+ // Handle graceful shutdown
526
+ process.on("SIGINT", () => {
527
+ // eslint-disable-next-line no-console
528
+ console.log("\nShutting down...");
529
+ void dualServer.shutdown().then(() => {
530
+ process.exit(0);
531
+ });
532
+ });
533
+ if (!options.quiet) {
534
+ // eslint-disable-next-line no-console
535
+ console.log("MCP mode: Log receive endpoint and MCP tools running");
536
+ }
537
+ }
538
+ else if (options.httpOnly) {
539
+ // HTTP-only mode: All HTTP endpoints, no MCP
540
+ const dualServer = await createDualServer({
541
+ httpPort: options.port ?? 9080,
542
+ httpHost: options.host ?? "localhost",
543
+ httpEnabled: true,
544
+ mcpEnabled: false,
545
+ quiet: options.quiet ?? false,
546
+ certPath: options.certPath,
547
+ keyPath: options.keyPath,
548
+ logFile: options.logFile,
549
+ });
550
+ // Handle graceful shutdown
551
+ process.on("SIGINT", () => {
552
+ // eslint-disable-next-line no-console
553
+ console.log("\nShutting down...");
554
+ void dualServer.shutdown().then(() => {
555
+ process.exit(0);
556
+ });
557
+ });
558
+ if (!options.quiet) {
559
+ // eslint-disable-next-line no-console
560
+ console.log("HTTP-only mode: All HTTP endpoints running");
561
+ }
562
+ }
563
+ else {
564
+ // Dual mode (default): All HTTP endpoints and MCP
565
+ const dualServer = await createDualServer({
566
+ httpPort: options.port ?? 9080,
567
+ httpHost: options.host ?? "localhost",
568
+ httpEnabled: true,
569
+ mcpEnabled: true,
570
+ quiet: options.quiet ?? false,
571
+ certPath: options.certPath,
572
+ keyPath: options.keyPath,
573
+ logFile: options.logFile,
574
+ });
575
+ // Handle graceful shutdown
576
+ process.on("SIGINT", () => {
577
+ // eslint-disable-next-line no-console
578
+ console.log("\nShutting down...");
579
+ void dualServer.shutdown().then(() => {
580
+ process.exit(0);
581
+ });
582
+ });
583
+ if (!options.quiet) {
584
+ // eslint-disable-next-line no-console
585
+ console.log("Dual mode: HTTP and MCP servers running");
586
+ }
587
+ }
588
+ }
589
+ //# sourceMappingURL=log-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-server.js","sourceRoot":"","sources":["../../src/server/log-server.ts"],"names":[],"mappings":"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"}