@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
package/README.md CHANGED
@@ -1,45 +1,961 @@
1
1
  # @graphty/remote-logger
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ Remote logging client and server for browser debugging. Send console logs from browsers to a terminal-based log server for easy debugging of web applications.
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ ## Why Remote Logging?
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ Browser applications run in a sandbox - their `console.log()` output appears in browser DevTools but is not accessible to CLI tools, terminal sessions, or AI assistants. Remote logging bridges this gap by sending browser logs to a server where they can be viewed, searched, and analyzed.
8
8
 
9
- ## Purpose
9
+ **Use cases where remote logging shines:**
10
10
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@graphty/remote-logger`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
11
+ - **Storybook & Component Development** - See console output without switching to browser DevTools
12
+ - **Mobile Web Apps** - Phones and tablets require USB debugging to access DevTools
13
+ - **VR/AR Applications** - You can't see a browser console while wearing a headset
14
+ - **Embedded Devices** - Kiosks, smart displays, and IoT devices without keyboard access
15
+ - **CI/CD & Automated Testing** - Capture browser logs during headless test runs
16
+ - **LLM-Assisted Debugging** - AI assistants can read, interpret, and act on logs without requiring user interaction with browser DevTools
15
17
 
16
- ## What is OIDC Trusted Publishing?
18
+ ## Features
17
19
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
20
+ - **Browser Client**: Lightweight client for sending logs from browser to server
21
+ - **Log Server**: HTTPS/HTTP server with colored terminal output and REST API
22
+ - **MCP Server**: Model Context Protocol server for Claude Code integration
23
+ - **Console Capture UI**: Floating widget to copy/download/view browser console logs
24
+ - **Batching & Retry**: Efficient log delivery with automatic retry on failure
25
+ - **Session Tracking**: Unique session IDs for correlating logs across page loads
26
+ - **Project Markers**: Filter logs by git worktree or project name
27
+ - **Throttling**: Configurable rate limiting for high-frequency log messages
28
+ - **File Logging**: JSONL file streaming organized by project marker
29
+ - **Log Retention**: Automatic cleanup of old logs (configurable, default 7 days)
19
30
 
20
- ## Setup Instructions
31
+ ## Installation
21
32
 
22
- To properly configure OIDC trusted publishing for this package:
33
+ ```bash
34
+ npm install @graphty/remote-logger
35
+ # or
36
+ pnpm add @graphty/remote-logger
37
+ ```
23
38
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
39
+ ## Quick Start
28
40
 
29
- ## DO NOT USE THIS PACKAGE
41
+ ### 1. Start the Log Server
30
42
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
43
+ ```bash
44
+ # Using npx
45
+ npx remote-log-server --port 9080
36
46
 
37
- ## More Information
47
+ # Or via CLI after installation
48
+ remote-log-server --port 9080
49
+ ```
38
50
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
51
+ ### 2. Add Client to Your Application
42
52
 
43
- ---
53
+ ```typescript
54
+ import { RemoteLogClient } from "@graphty/remote-logger";
55
+
56
+ // Create client pointing to your log server
57
+ const logger = new RemoteLogClient({
58
+ serverUrl: "http://localhost:9080",
59
+ sessionPrefix: "myapp",
60
+ });
61
+
62
+ // Log messages (batched and sent automatically)
63
+ logger.log("INFO", "Application started");
64
+ logger.log("DEBUG", "Loading user data", { userId: 123 });
65
+ logger.log("ERROR", "Failed to fetch", { error: "Network error" });
66
+
67
+ // Flush immediately when needed (e.g., before page unload)
68
+ await logger.flush();
69
+
70
+ // Clean up when done
71
+ await logger.close();
72
+ ```
73
+
74
+ ### 3. View Logs in Terminal
75
+
76
+ Logs appear in the server terminal with colors and session info:
77
+
78
+ ```
79
+ 10:30:15 [myapp-abc123] INFO Application started
80
+ 10:30:15 [myapp-abc123] DEBUG Loading user data
81
+ 10:30:16 [myapp-abc123] ERROR Failed to fetch
82
+ ```
83
+
84
+ Log levels are displayed with the following colors:
85
+ | Level | Color |
86
+ |-------|-------|
87
+ | ERROR | White text on red background |
88
+ | WARN/WARNING | Bold text on yellow background |
89
+ | INFO | Blue |
90
+ | DEBUG | Cyan |
91
+ | TRACE | Dim/gray |
92
+ | LOG (default) | Green |
93
+
94
+ ## CLI Reference
95
+
96
+ ```
97
+ Usage:
98
+ npx remote-log-server [options]
99
+
100
+ Options:
101
+ --port, -p <port> Port to listen on (default: 9080)
102
+ --host, -h <host> Hostname to bind to (default: localhost)
103
+ --cert, -c <path> Path to SSL certificate file (enables HTTPS)
104
+ --key, -k <path> Path to SSL private key file (enables HTTPS)
105
+ --log-file, -l <path> Write logs to file (JSONL format)
106
+ --quiet, -q Suppress startup banner
107
+ --mcp-only Start only MCP server (no HTTP)
108
+ --http-only Start only HTTP server (no MCP)
109
+ --help Show help message
110
+
111
+ Protocol:
112
+ HTTP is used by default. To use HTTPS, provide both --cert and --key.
113
+
114
+ Examples:
115
+ npx remote-log-server # Dual mode: HTTP + MCP (default)
116
+ npx remote-log-server --port 9080 # HTTP on port 9080 + MCP
117
+ npx remote-log-server --mcp-only # MCP only (for Claude Code)
118
+ npx remote-log-server --http-only # HTTP only (legacy mode)
119
+ npx remote-log-server --cert cert.pem --key key.pem # Use HTTPS with custom certs
120
+ ```
121
+
122
+ ### Environment Variables
123
+
124
+ | Variable | Default | Description |
125
+ |----------|---------|-------------|
126
+ | `REMOTE_LOG_RETENTION_DAYS` | `7` | Number of days to retain logs before cleanup |
127
+
128
+ ## API Reference
129
+
130
+ ### RemoteLogClient
131
+
132
+ The browser-side client for sending logs.
133
+
134
+ ```typescript
135
+ import { RemoteLogClient, createRemoteLogClient } from "@graphty/remote-logger";
136
+
137
+ // Using constructor
138
+ const client = new RemoteLogClient(options);
139
+
140
+ // Using factory function
141
+ const client = createRemoteLogClient(options);
142
+ ```
143
+
144
+ #### Options
145
+
146
+ | Option | Type | Default | Description |
147
+ |--------|------|---------|-------------|
148
+ | `serverUrl` | `string` | required | URL of the log server |
149
+ | `sessionPrefix` | `string` | `"session"` | Prefix for session ID |
150
+ | `batchIntervalMs` | `number` | `1000` | Interval between batch sends |
151
+ | `maxRetries` | `number` | `3` | Max retry attempts on failure |
152
+ | `retryDelayMs` | `number` | `1000` | Base delay between retries (uses exponential backoff) |
153
+ | `throttlePatterns` | `ThrottlePattern[]` | `[]` | Patterns to throttle (see below) |
154
+ | `projectMarker` | `string` | auto | Project identifier for filtering (auto-detected from Vite globals) |
155
+ | `worktreePath` | `string` | auto | Full worktree path for debugging (auto-detected from Vite globals) |
156
+
157
+ #### Throttling High-Frequency Logs
158
+
159
+ Use throttle patterns to prevent log flooding from high-frequency events:
160
+
161
+ ```typescript
162
+ const logger = new RemoteLogClient({
163
+ serverUrl: "http://localhost:9080",
164
+ throttlePatterns: [
165
+ // Only send "Rendering frame" once per second
166
+ { pattern: /Rendering frame/, intervalMs: 1000 },
167
+ // Only send mouse position updates every 500ms
168
+ { pattern: /Mouse position:/, intervalMs: 500 },
169
+ ],
170
+ });
171
+ ```
172
+
173
+ #### Methods
174
+
175
+ | Method | Description |
176
+ |--------|-------------|
177
+ | `log(level, message, data?)` | Log a message with optional data object |
178
+ | `flush(): Promise<void>` | Immediately send pending logs to server |
179
+ | `close(): Promise<void>` | Flush remaining logs and stop accepting new ones |
180
+
181
+ #### Properties
182
+
183
+ | Property | Type | Description |
184
+ |----------|------|-------------|
185
+ | `sessionId` | `string` (readonly) | Unique session identifier in format `{prefix}-{timestamp}-{random}` |
186
+
187
+ ### startLogServer
188
+
189
+ Start the log server programmatically.
190
+
191
+ ```typescript
192
+ import { startLogServer } from "@graphty/remote-logger/server";
193
+
194
+ const server = startLogServer({
195
+ port: 9080,
196
+ host: "localhost",
197
+ useHttp: true,
198
+ quiet: false,
199
+ });
200
+ ```
201
+
202
+ #### Options
203
+
204
+ | Option | Type | Default | Description |
205
+ |--------|------|---------|-------------|
206
+ | `port` | `number` | `9080` | Port to listen on |
207
+ | `host` | `string` | `"localhost"` | Hostname to bind to |
208
+ | `certPath` | `string` | - | Path to SSL certificate |
209
+ | `keyPath` | `string` | - | Path to SSL private key |
210
+ | `logFile` | `string` | - | Path for file logging |
211
+ | `useHttp` | `boolean` | `false` | Use HTTP instead of HTTPS |
212
+ | `quiet` | `boolean` | `false` | Suppress output |
213
+
214
+ ### REST API Endpoints
215
+
216
+ | Endpoint | Method | Description |
217
+ |----------|--------|-------------|
218
+ | `/log` | POST | Receive logs from client |
219
+ | `/logs` | GET | Get all logs by session |
220
+ | `/logs/recent` | GET | Get recent logs (`?n=50&errors=true`) |
221
+ | `/logs/errors` | GET | Get error-level logs only |
222
+ | `/logs/clear` | POST | Clear all stored logs |
223
+ | `/health` | GET | Health check |
224
+
225
+ #### POST /log
226
+
227
+ Receive log entries from clients. This is the endpoint used by `RemoteLogClient`.
228
+
229
+ **Request body:**
230
+ ```json
231
+ {
232
+ "sessionId": "myapp-abc123-xyz789",
233
+ "logs": [
234
+ {
235
+ "time": "2024-01-15T10:30:00.000Z",
236
+ "level": "INFO",
237
+ "message": "User logged in",
238
+ "data": { "userId": 123 }
239
+ }
240
+ ]
241
+ }
242
+ ```
243
+
244
+ **Response:**
245
+ ```json
246
+ { "success": true }
247
+ ```
248
+
249
+ #### GET /logs
250
+
251
+ Returns all logs grouped by session.
252
+
253
+ **Response:**
254
+ ```json
255
+ {
256
+ "myapp-abc123": [
257
+ { "time": "2024-01-15T10:30:00Z", "level": "INFO", "message": "Hello" }
258
+ ],
259
+ "myapp-def456": [
260
+ { "time": "2024-01-15T10:31:00Z", "level": "DEBUG", "message": "Debug msg" }
261
+ ]
262
+ }
263
+ ```
264
+
265
+ #### GET /logs/recent
266
+
267
+ Returns recent logs across all sessions, sorted by time.
268
+
269
+ **Query parameters:**
270
+ - `n` (optional): Number of logs to return (default: 50)
271
+ - `errors` (optional): Set to `true` to return only error-level logs
272
+
273
+ **Response:**
274
+ ```json
275
+ {
276
+ "total": 150,
277
+ "showing": 50,
278
+ "logs": [
279
+ { "sessionId": "myapp-abc123", "time": "...", "level": "INFO", "message": "..." }
280
+ ]
281
+ }
282
+ ```
283
+
284
+ #### GET /logs/errors
285
+
286
+ Returns only error-level logs across all sessions.
287
+
288
+ **Response:**
289
+ ```json
290
+ {
291
+ "total": 5,
292
+ "logs": [
293
+ { "sessionId": "myapp-abc123", "time": "...", "level": "ERROR", "message": "..." }
294
+ ]
295
+ }
296
+ ```
297
+
298
+ #### POST /logs/clear
299
+
300
+ Clears all stored logs from memory.
301
+
302
+ **Response:**
303
+ ```json
304
+ { "success": true }
305
+ ```
306
+
307
+ #### GET /health
308
+
309
+ Health check endpoint for monitoring.
310
+
311
+ **Response:**
312
+ ```json
313
+ { "status": "ok", "sessions": 3 }
314
+ ```
315
+
316
+ ## MCP Server (Claude Code Integration)
317
+
318
+ The remote-logger includes a Model Context Protocol (MCP) server that allows Claude Code to directly query and manage logs. This enables AI-assisted debugging by letting Claude Code see browser console output in real-time.
319
+
320
+ ### Setup with Claude Code
321
+
322
+ Add the following to your Claude Code MCP configuration (`~/.config/claude-code/mcp.json` or project settings):
323
+
324
+ ```json
325
+ {
326
+ "mcpServers": {
327
+ "remote-logger": {
328
+ "command": "npx",
329
+ "args": ["remote-log-server", "--mcp-only"]
330
+ }
331
+ }
332
+ }
333
+ ```
334
+
335
+ Or if installed globally:
336
+
337
+ ```json
338
+ {
339
+ "mcpServers": {
340
+ "remote-logger": {
341
+ "command": "remote-log-server",
342
+ "args": ["--mcp-only"]
343
+ }
344
+ }
345
+ }
346
+ ```
347
+
348
+ ### Dual Mode (HTTP + MCP)
349
+
350
+ By default, the server runs in dual mode with both HTTP and MCP interfaces sharing the same log storage. This allows browsers to send logs via HTTP while Claude Code queries them via MCP.
351
+
352
+ ```bash
353
+ # Start dual server (HTTP + MCP)
354
+ npx remote-log-server --port 9080
355
+ ```
356
+
357
+ ### MCP Tools
358
+
359
+ The MCP server provides 9 tools for log management:
360
+
361
+ #### `logs_get_recent`
362
+
363
+ Get recent logs from the server, sorted by time (oldest first).
364
+
365
+ **Parameters:**
366
+ | Parameter | Type | Default | Description |
367
+ |-----------|------|---------|-------------|
368
+ | `count` | `number` | `50` | Number of logs to return (max 500) |
369
+ | `projectMarker` | `string` | - | Filter by project marker |
370
+ | `workingDirectory` | `string` | - | Derive marker from path (e.g., `/path/.worktrees/my-branch`) |
371
+ | `level` | `string` | - | Filter by log level (ERROR, WARN, INFO, DEBUG) |
372
+ | `since` | `string` | - | Only logs after this ISO timestamp |
373
+
374
+ **Example usage in Claude Code:**
375
+ > "Show me the last 20 logs from the graphty-element project"
376
+
377
+ #### `logs_status`
378
+
379
+ Get the status of the remote log server.
380
+
381
+ **Returns:**
382
+ - Server status, uptime, session count, log count, error count, memory usage
383
+ - HTTP endpoint configuration (port, host, protocol, full URL for browser clients)
384
+ - Retention settings (how long logs are kept before automatic cleanup)
385
+
386
+ **Example usage:**
387
+ > "What is the status of the remote logger?"
388
+ > "What URL should I use to configure the browser client?"
389
+ > "How long are logs retained?"
390
+
391
+ #### `logs_list_sessions`
392
+
393
+ List all logging sessions with their metadata.
394
+
395
+ **Parameters:**
396
+ | Parameter | Type | Description |
397
+ |-----------|------|-------------|
398
+ | `projectMarker` | `string` | Filter by project marker |
399
+ | `hasErrors` | `boolean` | Only show sessions with errors |
400
+
401
+ **Returns:** Array of sessions with:
402
+ - `sessionId`, `projectMarker`, `worktreePath`, `pageUrl`
403
+ - `firstLogTime`, `lastLogTime`, `logCount`, `errorCount`
404
+
405
+ **Example usage:**
406
+ > "List all logging sessions that have errors"
407
+
408
+ #### `logs_receive`
409
+
410
+ Store logs from a browser or application session.
411
+
412
+ **Parameters:**
413
+ | Parameter | Type | Required | Description |
414
+ |-----------|------|----------|-------------|
415
+ | `sessionId` | `string` | Yes | Unique session identifier |
416
+ | `logs` | `array` | Yes | Array of log entries |
417
+ | `projectMarker` | `string` | No | Project identifier |
418
+ | `worktreePath` | `string` | No | Full worktree path |
419
+ | `pageUrl` | `string` | No | Browser page URL |
420
+
421
+ #### `logs_get_all`
422
+
423
+ Get all logs grouped by session.
424
+
425
+ **Parameters:**
426
+ | Parameter | Type | Description |
427
+ |-----------|------|-------------|
428
+ | `projectMarker` | `string` | Filter by project marker |
429
+
430
+ **Returns:** Object mapping session IDs to log arrays
431
+
432
+ #### `logs_get_errors`
433
+
434
+ Get only ERROR level logs.
435
+
436
+ **Parameters:**
437
+ | Parameter | Type | Description |
438
+ |-----------|------|-------------|
439
+ | `projectMarker` | `string` | Filter by project marker |
440
+ | `since` | `string` | Only errors after this timestamp |
441
+
442
+ **Example usage:**
443
+ > "Show me all errors from the current project"
444
+
445
+ #### `logs_clear`
446
+
447
+ Clear logs from the server.
448
+
449
+ **Parameters:**
450
+ | Parameter | Type | Required | Description |
451
+ |-----------|------|----------|-------------|
452
+ | `confirm` | `boolean` | Yes | Must be `true` to proceed |
453
+ | `projectMarker` | `string` | No | Only clear this project's logs |
454
+ | `sessionId` | `string` | No | Only clear this session's logs |
455
+
456
+ **Example usage:**
457
+ > "Clear all logs for the remote-logging project, confirm"
458
+
459
+ #### `logs_search`
460
+
461
+ Search logs by text pattern.
462
+
463
+ **Parameters:**
464
+ | Parameter | Type | Default | Description |
465
+ |-----------|------|---------|-------------|
466
+ | `query` | `string` | required | Search text or regex pattern |
467
+ | `regex` | `boolean` | `false` | Treat query as regex |
468
+ | `projectMarker` | `string` | - | Filter by project |
469
+ | `level` | `string` | - | Filter by log level |
470
+ | `limit` | `number` | `100` | Max results (max 1000) |
471
+
472
+ **Example usage:**
473
+ > "Search the logs for 'connection failed'"
474
+ > "Search logs for any network errors using regex 'network|timeout|connection'"
475
+
476
+ #### `logs_get_file_path`
477
+
478
+ Get the file path to the JSONL log file for a project.
479
+
480
+ **Parameters:**
481
+ | Parameter | Type | Description |
482
+ |-----------|------|-------------|
483
+ | `projectMarker` | `string` | Project marker |
484
+ | `workingDirectory` | `string` | Derive marker from path |
485
+
486
+ **Returns:** File path, existence status, and size
487
+
488
+ **Example usage:**
489
+ > "Get the log file path for this project so I can grep it"
490
+
491
+ This tool is useful for accessing logs via file-based tools like `Grep` or `Read` when you need more advanced searching capabilities.
492
+
493
+ ### Project Markers
494
+
495
+ Project markers allow you to filter logs by project, which is especially useful in monorepos or when working with multiple projects simultaneously.
496
+
497
+ Markers are determined in the following priority:
498
+ 1. Explicit `projectMarker` parameter
499
+ 2. Derived from `workingDirectory` path (extracts from `.worktrees/` or uses basename)
500
+ 3. Extracted from `sessionId` prefix (e.g., `graphty-element-123-abc` → `graphty-element`)
501
+ 4. Default: `"default"`
502
+
503
+ ### JSONL File Organization
504
+
505
+ Logs are streamed to JSONL files organized by project marker:
506
+
507
+ ```
508
+ {tmpdir}/remote-logger/
509
+ ├── graphty-element/
510
+ │ └── logs.jsonl
511
+ ├── remote-logging/
512
+ │ └── logs.jsonl
513
+ └── default/
514
+ └── logs.jsonl
515
+ ```
516
+
517
+ ## ConsoleCaptureUI
518
+
519
+ A floating UI widget that captures all console output (`log`, `error`, `warn`, `info`, `debug`) and provides a menu to copy, download, view, or clear the captured logs.
520
+
521
+ ```typescript
522
+ import { initConsoleCaptureUI, ConsoleCaptureUI } from "@graphty/remote-logger/ui";
523
+
524
+ // Initialize the UI (adds floating button to page)
525
+ const ui = initConsoleCaptureUI();
526
+
527
+ // Or use the class directly
528
+ const ui = new ConsoleCaptureUI();
529
+
530
+ // All console methods are now captured
531
+ console.log("This is captured");
532
+ console.error("This too");
533
+
534
+ // Access captured logs programmatically
535
+ const logsText = ui.getLogs();
536
+
537
+ // Later, clean up (restores original console methods)
538
+ ui.destroy();
539
+ ```
540
+
541
+ #### Widget Features
542
+
543
+ The floating button (📋) appears in the top-right corner of the page. Clicking it reveals a menu with:
544
+
545
+ | Button | Action |
546
+ |--------|--------|
547
+ | 📋 Copy Logs | Copy all captured logs to clipboard |
548
+ | 💾 Download | Download logs as a timestamped text file |
549
+ | 🗑️ Clear | Clear all captured logs |
550
+ | 👁️ Show Logs | Open a modal to view and select logs |
551
+
552
+ #### Instance Methods
553
+
554
+ | Method | Description |
555
+ |--------|-------------|
556
+ | `getLogs(): string` | Get all captured logs as formatted text |
557
+ | `clearLogs(): void` | Clear captured logs |
558
+ | `copyLogs(): Promise<void>` | Copy logs to clipboard |
559
+ | `downloadLogs(): void` | Download logs as text file |
560
+ | `destroy(): void` | Restore console methods and remove UI |
561
+
562
+ #### Global Methods
563
+
564
+ When initialized, `window.__console__` is exposed for programmatic access:
565
+
566
+ ```typescript
567
+ // Available globally after initConsoleCaptureUI()
568
+ window.__console__.copy(); // Copy to clipboard
569
+ window.__console__.download(); // Download as file
570
+ window.__console__.clear(); // Clear logs
571
+ window.__console__.get(); // Get logs as string
572
+ window.__console__.logs; // Raw log array
573
+ ```
574
+
575
+ #### Log Format
576
+
577
+ Captured logs are formatted as:
578
+ ```
579
+ [2024-01-15T10:30:00.000Z] [INFO] User logged in
580
+ [2024-01-15T10:30:01.000Z] [ERROR] Failed to connect
581
+ ```
582
+
583
+ ## Integration Examples
584
+
585
+ ### Basic Browser Integration
586
+
587
+ ```typescript
588
+ import { RemoteLogClient } from "@graphty/remote-logger";
589
+
590
+ // Create a logger instance
591
+ const logger = new RemoteLogClient({
592
+ serverUrl: "http://localhost:9080",
593
+ sessionPrefix: "myapp",
594
+ });
595
+
596
+ // Wrap console methods to also send to remote server
597
+ const originalLog = console.log;
598
+ console.log = (...args) => {
599
+ originalLog.apply(console, args);
600
+ logger.log("LOG", args.map(String).join(" "));
601
+ };
602
+
603
+ // Flush before page unload
604
+ window.addEventListener("beforeunload", () => {
605
+ logger.flush();
606
+ });
607
+ ```
608
+
609
+ ### React/Vue/Angular Error Boundary
610
+
611
+ ```typescript
612
+ import { RemoteLogClient } from "@graphty/remote-logger";
613
+
614
+ const logger = new RemoteLogClient({
615
+ serverUrl: "http://localhost:9080",
616
+ sessionPrefix: "react-app",
617
+ });
618
+
619
+ // Global error handler
620
+ window.onerror = (message, source, lineno, colno, error) => {
621
+ logger.log("ERROR", String(message), {
622
+ source,
623
+ lineno,
624
+ colno,
625
+ stack: error?.stack,
626
+ });
627
+ };
628
+
629
+ // Unhandled promise rejections
630
+ window.onunhandledrejection = (event) => {
631
+ logger.log("ERROR", "Unhandled rejection", {
632
+ reason: String(event.reason),
633
+ });
634
+ };
635
+ ```
636
+
637
+ ### Vite Integration (Automatic Project Markers)
638
+
639
+ Use the Vite plugin to automatically inject project markers into your browser builds:
640
+
641
+ ```typescript
642
+ // vite.config.ts
643
+ import { defineConfig } from "vite";
644
+ import { remoteLoggerPlugin } from "@graphty/remote-logger/vite";
645
+
646
+ export default defineConfig({
647
+ plugins: [remoteLoggerPlugin()],
648
+ });
649
+ ```
650
+
651
+ The plugin automatically:
652
+ - Detects if you're in a git worktree (e.g., `.worktrees/my-feature`) and uses the worktree name as the marker
653
+ - Falls back to the project directory basename for regular projects
654
+ - Injects `__REMOTE_LOG_PROJECT_MARKER__` and `__REMOTE_LOG_WORKTREE_PATH__` globals
655
+
656
+ The `RemoteLogClient` automatically reads these globals when available:
657
+
658
+ ```typescript
659
+ // These are injected by the Vite plugin
660
+ declare const __REMOTE_LOG_PROJECT_MARKER__: string | undefined;
661
+ declare const __REMOTE_LOG_WORKTREE_PATH__: string | undefined;
662
+
663
+ // Client reads them automatically
664
+ const client = new RemoteLogClient({
665
+ serverUrl: "http://localhost:9080",
666
+ // projectMarker and worktreePath are auto-detected!
667
+ });
668
+ ```
669
+
670
+ ### Usage with graphty-element
671
+
672
+ Add URL parameter to enable remote logging in Storybook:
673
+
674
+ ```
675
+ ?graphty-element-remote-log=http://localhost:9080
676
+ ```
677
+
678
+ ### Node.js Custom Server Integration
679
+
680
+ ```typescript
681
+ import { startLogServer, clearLogs } from "@graphty/remote-logger/server";
682
+ import type { Server } from "http";
683
+
684
+ // Start server and store reference
685
+ const server: Server = startLogServer({
686
+ port: 9080,
687
+ useHttp: true,
688
+ quiet: true, // Suppress banner for programmatic use
689
+ logFile: "./logs/debug.jsonl",
690
+ });
691
+
692
+ // Clear logs periodically
693
+ setInterval(() => {
694
+ clearLogs();
695
+ }, 3600000); // Every hour
696
+
697
+ // Graceful shutdown
698
+ process.on("SIGTERM", () => {
699
+ server.close(() => {
700
+ process.exit(0);
701
+ });
702
+ });
703
+ ```
704
+
705
+ ### Combining RemoteLogClient with ConsoleCaptureUI
706
+
707
+ ```typescript
708
+ import { RemoteLogClient } from "@graphty/remote-logger";
709
+ import { initConsoleCaptureUI } from "@graphty/remote-logger/ui";
710
+
711
+ // Initialize console capture for local viewing
712
+ const ui = initConsoleCaptureUI();
713
+
714
+ // Also send to remote server
715
+ const remoteLogger = new RemoteLogClient({
716
+ serverUrl: "http://localhost:9080",
717
+ sessionPrefix: "dual-logging",
718
+ });
719
+
720
+ // Hook into captured logs
721
+ const originalLog = console.log;
722
+ console.log = (...args) => {
723
+ // ConsoleCaptureUI already captures this
724
+ originalLog.apply(console, args);
725
+ // Also send to remote
726
+ remoteLogger.log("LOG", args.map(String).join(" "));
727
+ };
728
+ ```
729
+
730
+ ## HTTPS Certificates
731
+
732
+ ### Auto-generated Self-Signed Cert
733
+
734
+ By default, the server generates a self-signed certificate. You'll need to accept the certificate warning in your browser.
735
+
736
+ ### Using Let's Encrypt or Custom Certs
737
+
738
+ ```bash
739
+ npx remote-log-server \
740
+ --cert /path/to/fullchain.pem \
741
+ --key /path/to/privkey.pem \
742
+ --host yourdomain.com
743
+ ```
744
+
745
+ ## File Logging
746
+
747
+ Write logs to a JSONL file for later analysis:
748
+
749
+ ```bash
750
+ npx remote-log-server --log-file ./logs/debug.jsonl
751
+ ```
752
+
753
+ Each line contains a JSON object:
754
+ ```json
755
+ {"time":"2024-01-15T10:30:00Z","sessionId":"myapp-abc123","level":"INFO","message":"Hello"}
756
+ ```
757
+
758
+ ## TypeScript
759
+
760
+ Full TypeScript support with type definitions included.
761
+
762
+ ```typescript
763
+ // Client types
764
+ import type {
765
+ LogEntry,
766
+ RemoteLogClientOptions,
767
+ ThrottlePattern
768
+ } from "@graphty/remote-logger";
769
+
770
+ // Server types (from server entry point)
771
+ import type {
772
+ LogServerOptions,
773
+ ParseArgsResult,
774
+ GeneratedCert
775
+ } from "@graphty/remote-logger/server";
776
+ ```
777
+
778
+ ### Type Definitions
779
+
780
+ ```typescript
781
+ interface LogEntry {
782
+ time: string; // ISO 8601 timestamp
783
+ level: string; // Log level (INFO, DEBUG, WARN, ERROR, etc.)
784
+ message: string; // Log message
785
+ data?: Record<string, unknown>; // Optional additional data
786
+ }
787
+
788
+ interface ThrottlePattern {
789
+ pattern: RegExp; // Pattern to match log messages
790
+ intervalMs: number; // Minimum interval between matching messages
791
+ }
792
+
793
+ interface RemoteLogClientOptions {
794
+ serverUrl: string;
795
+ sessionPrefix?: string;
796
+ batchIntervalMs?: number;
797
+ maxRetries?: number;
798
+ retryDelayMs?: number;
799
+ throttlePatterns?: ThrottlePattern[];
800
+ projectMarker?: string; // Project identifier for filtering
801
+ worktreePath?: string; // Full path for debugging
802
+ }
803
+
804
+ interface LogServerOptions {
805
+ port?: number;
806
+ host?: string;
807
+ certPath?: string;
808
+ keyPath?: string;
809
+ logFile?: string;
810
+ useHttp?: boolean;
811
+ quiet?: boolean;
812
+ }
813
+ ```
814
+
815
+ ## Troubleshooting
816
+
817
+ ### CORS Errors
818
+
819
+ The server includes CORS headers by default (`Access-Control-Allow-Origin: *`). If you still encounter CORS issues:
820
+
821
+ 1. Ensure you're using the correct protocol (http vs https)
822
+ 2. Check that the port is correct
823
+ 3. For HTTPS, you may need to accept the self-signed certificate first by visiting the server URL directly
824
+
825
+ ### Certificate Warnings
826
+
827
+ When using auto-generated self-signed certificates:
828
+
829
+ 1. Navigate to `https://localhost:9080/health` in your browser
830
+ 2. Accept the security warning
831
+ 3. Your application should now be able to connect
832
+
833
+ ### Logs Not Appearing
834
+
835
+ 1. Check the browser console for network errors
836
+ 2. Verify the server is running: `curl http://localhost:9080/health`
837
+ 3. Check that `flush()` is being called before page unload
838
+ 4. Increase `batchIntervalMs` if logs are being sent too frequently
839
+
840
+ ### High Memory Usage on Server
841
+
842
+ The server stores all logs in memory. For long-running sessions:
843
+
844
+ 1. Use `POST /logs/clear` periodically to clear logs
845
+ 2. Or use `clearLogs()` programmatically
846
+ 3. Consider using `--log-file` to persist logs to disk and reduce memory pressure
847
+
848
+ ## Package Exports
849
+
850
+ The package provides three entry points for different use cases:
851
+
852
+ ### Main Entry (`@graphty/remote-logger`)
853
+
854
+ Browser-safe exports for the logging client:
855
+
856
+ ```typescript
857
+ import {
858
+ RemoteLogClient,
859
+ createRemoteLogClient
860
+ } from "@graphty/remote-logger";
861
+
862
+ // Types
863
+ import type {
864
+ LogEntry,
865
+ RemoteLogClientOptions,
866
+ ThrottlePattern
867
+ } from "@graphty/remote-logger";
868
+ ```
869
+
870
+ ### Server Entry (`@graphty/remote-logger/server`)
871
+
872
+ Node.js-only exports for the log server:
873
+
874
+ ```typescript
875
+ import {
876
+ startLogServer, // Start server programmatically
877
+ main, // CLI entry point
878
+ parseArgs, // Parse CLI arguments
879
+ clearLogs, // Clear stored logs
880
+ HELP_TEXT, // CLI help text
881
+
882
+ // Certificate utilities
883
+ generateSelfSignedCert,
884
+ certFilesExist,
885
+ readCertFiles,
886
+ } from "@graphty/remote-logger/server";
887
+
888
+ // Types
889
+ import type {
890
+ LogServerOptions,
891
+ LogEntry,
892
+ ParseArgsResult,
893
+ GeneratedCert,
894
+ } from "@graphty/remote-logger/server";
895
+ ```
896
+
897
+ ### UI Entry (`@graphty/remote-logger/ui`)
898
+
899
+ Browser exports for the console capture widget:
900
+
901
+ ```typescript
902
+ import {
903
+ ConsoleCaptureUI,
904
+ initConsoleCaptureUI
905
+ } from "@graphty/remote-logger/ui";
906
+ ```
907
+
908
+ ### Client Entry (`@graphty/remote-logger/client`)
909
+
910
+ Direct client-only imports (same as main entry):
911
+
912
+ ```typescript
913
+ import { RemoteLogClient } from "@graphty/remote-logger/client";
914
+ ```
915
+
916
+ ### Vite Entry (`@graphty/remote-logger/vite`)
917
+
918
+ Vite plugin for automatic project marker injection:
919
+
920
+ ```typescript
921
+ import { remoteLoggerPlugin } from "@graphty/remote-logger/vite";
922
+ ```
923
+
924
+ ## Log Retention
925
+
926
+ Logs are automatically cleaned up after a configurable retention period (default: 7 days). This applies to both in-memory logs and JSONL files.
927
+
928
+ ### Configuration
929
+
930
+ Set retention via environment variable:
931
+
932
+ ```bash
933
+ export REMOTE_LOG_RETENTION_DAYS=3
934
+ npx remote-log-server
935
+ ```
936
+
937
+ Or programmatically:
938
+
939
+ ```typescript
940
+ import { LogStorage } from "@graphty/remote-logger/server";
941
+
942
+ const storage = new LogStorage({
943
+ retentionDays: 3, // Keep logs for 3 days
944
+ cleanupIntervalMs: 3600000, // Check every hour (default)
945
+ });
946
+ ```
947
+
948
+ ### How It Works
949
+
950
+ 1. **Memory cleanup**: Individual logs older than the retention period are removed. Sessions with no remaining logs are deleted entirely.
951
+
952
+ 2. **JSONL cleanup**: Project directories whose files haven't been modified within the retention period are removed.
953
+
954
+ 3. **Automatic scheduling**: Cleanup runs automatically at the configured interval (default: 1 hour).
955
+
956
+ 4. **Graceful shutdown**: Call `storage.stopCleanupTimer()` when shutting down to prevent memory leaks.
957
+
958
+ ## License
959
+
960
+ MIT
44
961
 
45
- **Maintained for OIDC setup purposes only**