noctrace 0.4.0 → 0.4.2

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.
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "noctrace",
3
+ "version": "0.4.0",
4
+ "description": "Chrome DevTools Network-tab-style waterfall visualizer for Claude Code agent workflows",
5
+ "author": {
6
+ "name": "Nyktora Group LLC",
7
+ "url": "https://nyktora.com"
8
+ },
9
+ "homepage": "https://nyktora.github.io/noctrace/",
10
+ "repository": "https://github.com/nyktora/noctrace",
11
+ "license": "MIT",
12
+ "keywords": ["devtools", "waterfall", "observability", "timeline", "context-health"]
13
+ }
package/.mcp.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "noctrace": {
4
+ "command": "node",
5
+ "args": ["${CLAUDE_PLUGIN_ROOT}/bin/noctrace-mcp.js"],
6
+ "env": {
7
+ "NODE_ENV": "production"
8
+ }
9
+ }
10
+ }
11
+ }
package/README.md CHANGED
@@ -37,7 +37,13 @@ npm install -g noctrace
37
37
  noctrace
38
38
  ```
39
39
 
40
- Requires Node.js 20+. That's it. No config, no hooks, no API keys.
40
+ ### As a Claude Code Plugin
41
+
42
+ ```bash
43
+ claude plugin install nyktora/noctrace
44
+ ```
45
+
46
+ Requires Node.js 20+. That's it. No config required. Optional hooks for real-time events.
41
47
 
42
48
  ## Features
43
49
 
@@ -54,6 +60,9 @@ Requires Node.js 20+. That's it. No config, no hooks, no API keys.
54
60
  - **Detail panel** — click any row for full tool input/output, resizable
55
61
  - **Re-read detection** — flags duplicate file reads that waste context
56
62
  - **Dark theme** — Catppuccin Mocha palette
63
+ - **Session export** — share sessions as standalone offline HTML files
64
+ - **Hooks integration** — optional real-time event streaming from Claude Code
65
+ - **Context Drift Rate** — detect accelerating token growth before context rot hits
57
66
 
58
67
  ![Noctrace waterfall timeline](docs/screenshots/noctrace-waterfall.png)
59
68
 
@@ -89,7 +98,7 @@ Click any row to inspect the full tool input and output. Two-column layout shows
89
98
  4. Parses tool_use/tool_result pairs into a waterfall timeline
90
99
  5. Watches active session files for real-time updates via WebSocket
91
100
 
92
- No hooks to install. No config files. No cloud. Everything stays local.
101
+ No config files. No cloud. Everything stays local. Optional hooks for richer real-time data.
93
102
 
94
103
  ## Configuration
95
104
 
@@ -98,6 +107,11 @@ No hooks to install. No config files. No cloud. Everything stays local.
98
107
  | `PORT` | `4117` | Server port (auto-increments if busy) |
99
108
  | `CLAUDE_HOME` | `~/.claude` | Override Claude home directory |
100
109
 
110
+ | CLI Flag | Description |
111
+ |----------|-------------|
112
+ | `--install-hooks` | Configure Claude Code to push real-time events to noctrace |
113
+ | `--uninstall-hooks` | Remove noctrace hooks from Claude Code |
114
+
101
115
  ## Development
102
116
 
103
117
  ```bash
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Minimal MCP server wrapper for the noctrace plugin.
4
+ *
5
+ * Starts the noctrace Express server as a side effect and speaks just enough
6
+ * MCP (JSON-RPC 2.0 over stdio) to stay alive as a Claude Code managed process.
7
+ * Exposes a single `open_dashboard` tool so Claude can tell the user the URL.
8
+ */
9
+ import { createInterface } from 'node:readline';
10
+
11
+ const VERSION = '0.4.0';
12
+ let serverPort = null;
13
+ let browserOpened = false;
14
+
15
+ // Start the Express server (lazy import to avoid loading before needed)
16
+ async function boot() {
17
+ process.env.NOCTRACE_NO_AUTOSTART = '1';
18
+ const { startServer } = await import('../dist/server/server/index.js');
19
+ serverPort = await startServer();
20
+
21
+ // Open browser once on first start
22
+ if (!browserOpened) {
23
+ const open = (await import('open')).default;
24
+ await open(`http://localhost:${serverPort}`);
25
+ browserOpened = true;
26
+ }
27
+ }
28
+
29
+ // JSON-RPC response helper
30
+ function respond(id, result) {
31
+ const msg = JSON.stringify({ jsonrpc: '2.0', id, result });
32
+ process.stdout.write(`${msg}\n`);
33
+ }
34
+
35
+ // Handle incoming JSON-RPC messages from Claude Code
36
+ function handleMessage(line) {
37
+ let msg;
38
+ try {
39
+ msg = JSON.parse(line);
40
+ } catch {
41
+ return; // ignore malformed input
42
+ }
43
+
44
+ const { id, method, params } = msg;
45
+
46
+ if (method === 'initialize') {
47
+ respond(id, {
48
+ protocolVersion: '2024-11-05',
49
+ capabilities: { tools: {} },
50
+ serverInfo: { name: 'noctrace', version: VERSION },
51
+ });
52
+ return;
53
+ }
54
+
55
+ if (method === 'notifications/initialized') {
56
+ // No response needed for notifications
57
+ return;
58
+ }
59
+
60
+ if (method === 'tools/list') {
61
+ respond(id, {
62
+ tools: [
63
+ {
64
+ name: 'open_dashboard',
65
+ description: 'Open the noctrace waterfall dashboard in the browser',
66
+ inputSchema: { type: 'object', properties: {}, required: [] },
67
+ },
68
+ ],
69
+ });
70
+ return;
71
+ }
72
+
73
+ if (method === 'tools/call') {
74
+ const toolName = params?.name;
75
+ if (toolName === 'open_dashboard') {
76
+ const url = `http://localhost:${serverPort ?? 4117}`;
77
+ // Open browser
78
+ import('open').then((m) => m.default(url)).catch(() => {});
79
+ respond(id, {
80
+ content: [{ type: 'text', text: `Noctrace dashboard: ${url}` }],
81
+ });
82
+ return;
83
+ }
84
+ // Unknown tool
85
+ respond(id, {
86
+ content: [{ type: 'text', text: `Unknown tool: ${toolName}` }],
87
+ isError: true,
88
+ });
89
+ return;
90
+ }
91
+
92
+ // Unknown method — respond with empty result to avoid hanging
93
+ if (id !== undefined) {
94
+ respond(id, {});
95
+ }
96
+ }
97
+
98
+ // Main
99
+ async function main() {
100
+ await boot();
101
+
102
+ const rl = createInterface({ input: process.stdin });
103
+ rl.on('line', handleMessage);
104
+
105
+ // Keep alive until stdin closes (Claude Code manages our lifecycle)
106
+ rl.on('close', () => {
107
+ process.exit(0);
108
+ });
109
+ }
110
+
111
+ main().catch((err) => {
112
+ console.error('[noctrace-mcp] Fatal:', err.message);
113
+ process.exit(1);
114
+ });
package/bin/noctrace.js CHANGED
@@ -178,6 +178,7 @@ if (args.includes('--uninstall-hooks')) {
178
178
  }
179
179
 
180
180
  // Default: start the server and open the browser
181
+ process.env.NOCTRACE_NO_AUTOSTART = '1';
181
182
  const { startServer } = await import('../dist/server/server/index.js');
182
183
  const open = (await import('open')).default;
183
184
  const port = await startServer();