llm-deep-trace 0.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +159 -0
  3. package/bin/llm-deep-trace.js +24 -0
  4. package/next.config.ts +8 -0
  5. package/package.json +56 -0
  6. package/postcss.config.mjs +5 -0
  7. package/public/banner-v2.png +0 -0
  8. package/public/file.svg +1 -0
  9. package/public/globe.svg +1 -0
  10. package/public/logo.png +0 -0
  11. package/public/next.svg +1 -0
  12. package/public/vercel.svg +1 -0
  13. package/public/window.svg +1 -0
  14. package/src/app/api/agent-config/route.ts +31 -0
  15. package/src/app/api/all-sessions/route.ts +9 -0
  16. package/src/app/api/analytics/route.ts +379 -0
  17. package/src/app/api/detect-agents/route.ts +170 -0
  18. package/src/app/api/image/route.ts +73 -0
  19. package/src/app/api/search/route.ts +28 -0
  20. package/src/app/api/session-by-key/route.ts +21 -0
  21. package/src/app/api/sessions/[sessionId]/messages/route.ts +46 -0
  22. package/src/app/api/sse/route.ts +86 -0
  23. package/src/app/favicon.ico +0 -0
  24. package/src/app/globals.css +3518 -0
  25. package/src/app/icon.svg +4 -0
  26. package/src/app/layout.tsx +20 -0
  27. package/src/app/page.tsx +5 -0
  28. package/src/components/AnalyticsDashboard.tsx +393 -0
  29. package/src/components/App.tsx +243 -0
  30. package/src/components/CopyButton.tsx +42 -0
  31. package/src/components/Logo.tsx +20 -0
  32. package/src/components/MainPanel.tsx +1128 -0
  33. package/src/components/MessageRenderer.tsx +983 -0
  34. package/src/components/SessionTree.tsx +505 -0
  35. package/src/components/SettingsPanel.tsx +160 -0
  36. package/src/components/SetupView.tsx +206 -0
  37. package/src/components/Sidebar.tsx +714 -0
  38. package/src/components/ThemeToggle.tsx +54 -0
  39. package/src/lib/client-utils.ts +360 -0
  40. package/src/lib/normalizers.ts +371 -0
  41. package/src/lib/sessions.ts +1223 -0
  42. package/src/lib/store.ts +518 -0
  43. package/src/lib/types.ts +112 -0
  44. package/src/lib/useSSE.ts +81 -0
  45. package/tsconfig.json +34 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 llm-deep-trace contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ <div align="center">
2
+ <img src="public/banner-v2.png" width="900" alt="llm-deep-trace" />
3
+ <br/><br/>
4
+ <p>Browse, search, and analyze every conversation your agents have ever had.<br/>All local. No accounts. No cloud.</p>
5
+ </div>
6
+
7
+ ---
8
+
9
+ ## What it is
10
+
11
+ You use coding agents. They leave behind session logs. Those logs are gold — decisions made, code written, reasoning traced, subagents spawned. But they're just JSONL files buried in `~/.claude/` or `~/.kimi/`.
12
+
13
+ llm-deep-trace turns those files into a proper interface: threaded conversations, subagent trees, a conversation map, analytics, live tail, and full-text search across everything.
14
+
15
+ It runs entirely on your machine. It reads your local files. That's it.
16
+
17
+ ---
18
+
19
+ ## Supported agents
20
+
21
+ | Agent | Sessions | Subagents | Notes |
22
+ |---|---|---|---|
23
+ | **Claude Code** (Anthropic) | ✓ | ✓ | Full support incl. agent teams |
24
+ | **Codex** | ✓ | — | |
25
+ | **Kimi** | ✓ | — | Think-block rendering |
26
+ | **Gemini CLI** (Google) | ✓ | — | |
27
+ | **OpenClaw** | ✓ | ✓ | |
28
+ | **Cursor** | ✓ | — | Partial — some metadata missing |
29
+ | **Aider** | ✓ | — | Chat history format |
30
+ | **Continue.dev** | ✓ | — | |
31
+ | **GitHub Copilot** | ✓ | — | |
32
+ | **Factory Droid** | ✓ | — | |
33
+ | **OpenCode** | ✓ | — | |
34
+
35
+ ---
36
+
37
+ ## Quick start
38
+
39
+ ```bash
40
+ git clone https://github.com/userFRM/llm-deep-trace
41
+ cd llm-deep-trace
42
+ npm install
43
+ npm run dev
44
+ ```
45
+
46
+ Open [http://localhost:3000](http://localhost:3000). No config needed — it finds your sessions automatically.
47
+
48
+ **Requirements:** Node.js 18+
49
+
50
+ ---
51
+
52
+ ## Features
53
+
54
+ **Session browser**
55
+ - All providers in one sidebar, grouped and searchable
56
+ - Parent sessions show subagent count; click to expand the tree
57
+ - Expand all / collapse all, archive sessions you don't need
58
+
59
+ **Conversation view**
60
+ - User messages as bubbles, assistant responses as cards
61
+ - Tool call blocks collapsed by default, color-coded by type (bash, edit, web, browser, message, spawn)
62
+ - Thinking blocks (Claude extended thinking, Kimi reasoning) as expandable cards
63
+ - Inline image thumbnails with click-to-lightbox
64
+ - Ctrl+F find with match counter and highlights
65
+ - Skip preamble toggle — jump straight to the actual work
66
+
67
+ **Subagent tree + conversation map**
68
+ - React Flow visualization of the full session graph
69
+ - Click any node to navigate to that session
70
+ - Reset view, zoom capped at 75%, padding scales with graph size
71
+
72
+ **Live tail**
73
+ - Follow an active session in real time (3s poll)
74
+ - Green pulsing indicator while tailing
75
+
76
+ **Analytics**
77
+ - Sessions per day, stacked by provider
78
+ - Provider breakdown, top tools used, token totals
79
+ - Session length distribution
80
+
81
+ **Search**
82
+ - Full-text search across all sessions and all providers
83
+
84
+ ---
85
+
86
+ ## Running remotely
87
+
88
+ llm-deep-trace reads files from the machine it runs on. If your agent sessions live on a remote server (VPS, home lab, cloud box), you have a few options:
89
+
90
+ **SSH tunnel** — forward the port to your local machine:
91
+ ```bash
92
+ ssh -L 3000:localhost:3000 user@your-server
93
+ # then open http://localhost:3000 locally
94
+ ```
95
+
96
+ **Tailscale** — start the server bound to your Tailscale IP:
97
+ ```bash
98
+ npx next start --hostname <tailscale-ip> --port 3000
99
+ # accessible at http://<tailscale-ip>:3000 from any device on your Tailscale network
100
+ ```
101
+
102
+ **VPS / cloud** — same as SSH tunnel, or bind to a private network interface. Do not expose port 3000 to the public internet — there's no auth.
103
+
104
+ In all cases: the app runs on the machine where your `~/.claude/`, `~/.kimi/`, etc. directories live.
105
+
106
+ ---
107
+
108
+ ## How to ship it (for contributors)
109
+
110
+ Right now: clone and run locally. That's the intended workflow for a local devtool.
111
+
112
+ Planned:
113
+ - `npm install -g llm-deep-trace` + `llm-deep-trace` CLI command
114
+ - Homebrew tap for Mac users who prefer it
115
+ - Docker one-liner for the server crowd
116
+
117
+ PRs welcome on any of these.
118
+
119
+ ---
120
+
121
+ ## Limitations
122
+
123
+ Being straight with you:
124
+
125
+ - **Read-only.** Browse and analyze — you can't resume or fork sessions from here yet. jazzyalex/agent-sessions does this for Codex and Claude Code.
126
+ - **Local files only.** Reads `~/.claude/`, `~/.kimi/`, etc. on the machine it runs on. Remote sessions not supported.
127
+ - **Cursor / Aider / Continue** support is partial. Session formats vary and some metadata is missing.
128
+ - **No mobile UI.** Built for desktop browsers.
129
+ - **Requires Node.js 18+.** Not a zero-dep install.
130
+
131
+ ---
132
+
133
+ ## vs alternatives
134
+
135
+ [**jazzyalex/agent-sessions**](https://github.com/jazzyalex/agent-sessions) — the closest thing. Native macOS Swift app (macOS 14+), v2.11.2, actively maintained. Supports 7 agents: Codex, Claude Code, Gemini, Copilot, Factory Droid, OpenCode, OpenClaw. Has unified search, analytics, rate limits tracker, image browser, Homebrew install, and — notably — **session resume** (reopen a session directly in your terminal). If you're on a Mac and want a native app, it's worth looking at.
136
+
137
+ Where llm-deep-trace is different:
138
+ - **Cross-platform** — runs on Mac, Linux, Windows; anything with Node.js. Not macOS-only.
139
+ - **More agents** — 11 vs 7 (adds Kimi, Aider, Continue.dev, Cursor)
140
+ - **Subagent tree** — React Flow visualization of parent → child agent relationships
141
+ - **Conversation map** — full session graph, click-to-navigate
142
+ - **Web-based** — no install, no signing, no notarization; just `npm run dev`
143
+
144
+ What they have that we don't (yet):
145
+ - Session resume (reopen past sessions in the terminal)
146
+ - Real-time rate limits tracker
147
+ - Native performance + Homebrew cask + auto-updates
148
+
149
+ ---
150
+
151
+ ## Tech stack
152
+
153
+ Next.js 16 · React 19 · TypeScript · React Flow · Zustand · highlight.js · Marked
154
+
155
+ ---
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ const { execSync, spawn } = require("child_process");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+
7
+ const pkgDir = path.join(__dirname, "..");
8
+ const nextDir = path.join(pkgDir, ".next");
9
+ const port = process.env.PORT || "8340";
10
+ const host = process.env.HOST || "0.0.0.0";
11
+
12
+ if (!fs.existsSync(nextDir)) {
13
+ console.log("llm-deep-trace: first run — building (this takes ~30s)...");
14
+ execSync("npx next build", { cwd: pkgDir, stdio: "inherit" });
15
+ }
16
+
17
+ const child = spawn(
18
+ "npx",
19
+ ["next", "start", "--hostname", host, "--port", port],
20
+ { cwd: pkgDir, stdio: "inherit" }
21
+ );
22
+ child.on("exit", (code) => process.exit(code ?? 0));
23
+ process.on("SIGINT", () => child.kill("SIGINT"));
24
+ process.on("SIGTERM", () => child.kill("SIGTERM"));
package/next.config.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { NextConfig } from "next";
2
+ import path from "path";
3
+
4
+ const nextConfig: NextConfig = {
5
+ outputFileTracingRoot: path.join(__dirname),
6
+ };
7
+
8
+ export default nextConfig;
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "llm-deep-trace",
3
+ "version": "0.1.0",
4
+ "description": "The session browser for coding agents — Claude Code, Codex, Kimi, Gemini CLI, OpenClaw, Cursor, Aider, and more.",
5
+ "keywords": [
6
+ "claude-code",
7
+ "codex",
8
+ "kimi",
9
+ "gemini",
10
+ "ai-agents",
11
+ "llm",
12
+ "session-browser",
13
+ "devtools"
14
+ ],
15
+ "homepage": "https://github.com/userFRM/llm-deep-trace",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/userFRM/llm-deep-trace"
19
+ },
20
+ "license": "MIT",
21
+ "scripts": {
22
+ "dev": "next dev",
23
+ "build": "next build",
24
+ "start": "next start",
25
+ "lint": "eslint"
26
+ },
27
+ "dependencies": {
28
+ "@xyflow/react": "^12.10.1",
29
+ "highlight.js": "^11.11.1",
30
+ "marked": "^17.0.3",
31
+ "next": "16.1.6",
32
+ "react": "19.2.3",
33
+ "react-dom": "19.2.3",
34
+ "zustand": "^5.0.11"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20",
38
+ "@types/react": "^19",
39
+ "@types/react-dom": "^19",
40
+ "eslint": "^9",
41
+ "eslint-config-next": "16.1.6",
42
+ "typescript": "^5"
43
+ },
44
+ "bin": {
45
+ "llm-deep-trace": "bin/llm-deep-trace.js"
46
+ },
47
+ "files": [
48
+ "bin/",
49
+ "src/",
50
+ "public/",
51
+ "next.config.ts",
52
+ "tsconfig.json",
53
+ "postcss.config.mjs",
54
+ "tailwind.config.ts"
55
+ ]
56
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ plugins: {},
3
+ };
4
+
5
+ export default config;
Binary file
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,31 @@
1
+ import { NextResponse, NextRequest } from "next/server";
2
+ import fs from "fs";
3
+ import path from "path";
4
+
5
+ const HOME = process.env.HOME || "/root";
6
+ const CONFIG_PATH = path.join(HOME, ".llm-deep-trace.json");
7
+
8
+ export async function GET() {
9
+ try {
10
+ if (fs.existsSync(CONFIG_PATH)) {
11
+ return NextResponse.json(JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8")));
12
+ }
13
+ } catch { /* ignore */ }
14
+ return NextResponse.json({});
15
+ }
16
+
17
+ export async function POST(req: NextRequest) {
18
+ try {
19
+ const body = await req.json();
20
+ // body: { [agentId]: { binaryPath?: string; sessionsDir?: string } }
21
+ let existing: Record<string, unknown> = {};
22
+ try {
23
+ if (fs.existsSync(CONFIG_PATH)) existing = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
24
+ } catch { /* ignore */ }
25
+ const merged = { ...existing, ...body };
26
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2), "utf8");
27
+ return NextResponse.json({ ok: true });
28
+ } catch (e) {
29
+ return NextResponse.json({ error: String(e) }, { status: 500 });
30
+ }
31
+ }
@@ -0,0 +1,9 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getAllSessions } from "@/lib/sessions";
3
+
4
+ export const dynamic = "force-dynamic";
5
+
6
+ export async function GET() {
7
+ const merged = getAllSessions();
8
+ return NextResponse.json(merged);
9
+ }