agent-session-inspector 0.1.8 → 0.1.10

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 (100) hide show
  1. package/README.md +1 -1
  2. package/VERSION +1 -1
  3. package/app/.next/BUILD_ID +1 -1
  4. package/app/.next/build-manifest.json +3 -3
  5. package/app/.next/prerender-manifest.json +3 -3
  6. package/app/.next/required-server-files.json +1 -1
  7. package/app/.next/server/app/_global-error.html +1 -1
  8. package/app/.next/server/app/_global-error.rsc +1 -1
  9. package/app/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/app/.next/server/app/_not-found/page.js.nft.json +1 -1
  13. package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/app/.next/server/app/_not-found.html +1 -1
  15. package/app/.next/server/app/_not-found.rsc +14 -14
  16. package/app/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  17. package/app/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  18. package/app/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/app/.next/server/app/api/analytics/route.js.nft.json +1 -1
  20. package/app/.next/server/app/api/logs/route.js.nft.json +1 -1
  21. package/app/.next/server/app/api/pricing/route.js.nft.json +1 -1
  22. package/app/.next/server/app/api/providers/route.js.nft.json +1 -1
  23. package/app/.next/server/app/api/search/route.js.nft.json +1 -1
  24. package/app/.next/server/app/api/sessions/[provider]/[id]/record/route.js.nft.json +1 -1
  25. package/app/.next/server/app/api/sessions/[provider]/[id]/reveal/route.js.nft.json +1 -1
  26. package/app/.next/server/app/api/sessions/[provider]/[id]/route.js.nft.json +1 -1
  27. package/app/.next/server/app/api/sessions/route.js.nft.json +1 -1
  28. package/app/.next/server/app/index.html +1 -1
  29. package/app/.next/server/app/index.rsc +16 -16
  30. package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +15 -15
  31. package/app/.next/server/app/index.segments/_full.segment.rsc +16 -16
  32. package/app/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  33. package/app/.next/server/app/page.js.nft.json +1 -1
  34. package/app/.next/server/app/page_client-reference-manifest.js +1 -1
  35. package/app/.next/server/app/sessions/[provider]/[id]/page.js.nft.json +1 -1
  36. package/app/.next/server/app/sessions/[provider]/[id]/page_client-reference-manifest.js +1 -1
  37. package/app/.next/server/chunks/[root-of-the-server]__014br-h._.js +1 -1
  38. package/app/.next/server/chunks/[root-of-the-server]__0co499t._.js +1 -1
  39. package/app/.next/server/chunks/[root-of-the-server]__0p_hyq8._.js +1 -1
  40. package/app/.next/server/chunks/[root-of-the-server]__0yxic1z._.js +2 -2
  41. package/app/.next/server/chunks/ssr/_0e8jdju._.js +7 -0
  42. package/app/.next/server/chunks/ssr/_0f8nmc3._.js +1 -1
  43. package/app/.next/server/chunks/ssr/_0gr0upx._.js +7 -0
  44. package/app/.next/server/chunks/ssr/src_app_page_tsx_1chiuah._.js +1 -1
  45. package/app/.next/server/chunks/ssr/src_app_sessions_[provider]_[id]_page_tsx_0uf635h._.js +2 -6
  46. package/app/.next/server/middleware-build-manifest.js +3 -3
  47. package/app/.next/server/pages/404.html +1 -1
  48. package/app/.next/server/pages/500.html +1 -1
  49. package/app/.next/server/server-reference-manifest.js +1 -1
  50. package/app/.next/server/server-reference-manifest.json +1 -1
  51. package/app/.next/static/chunks/0hav9to299upa.js +1 -0
  52. package/app/.next/static/chunks/1-qn722atv1by.css +1 -0
  53. package/app/.next/static/chunks/{1fe2mxakoweia.js → 18c6__lhilfeo.js} +1 -1
  54. package/app/.next/static/chunks/1bgubb_nxxbrk.js +2 -0
  55. package/app/.next/static/chunks/1gwxc9rvk6onv.js +5 -0
  56. package/app/AGENTS.md +9 -0
  57. package/app/CLAUDE.md +1 -0
  58. package/app/CONTRIBUTING.md +90 -0
  59. package/app/Dockerfile +34 -0
  60. package/app/LICENSE +21 -0
  61. package/app/README.md +369 -0
  62. package/app/bin/agent-session-inspector.mjs +185 -0
  63. package/app/components.json +25 -0
  64. package/app/docs/screenshots/analytics-dark.png +0 -0
  65. package/app/docs/screenshots/analytics.png +0 -0
  66. package/app/docs/screenshots/request-table.png +0 -0
  67. package/app/docs/screenshots/session-overview-dark.png +0 -0
  68. package/app/docs/screenshots/session-overview.png +0 -0
  69. package/app/docs/screenshots/sessions-dark.png +0 -0
  70. package/app/docs/screenshots/sessions.png +0 -0
  71. package/app/docs/screenshots/timeline-dark.png +0 -0
  72. package/app/docs/screenshots/timeline.png +0 -0
  73. package/app/docs/screenshots/token-optimizer-dark.png +0 -0
  74. package/app/docs/screenshots/token-optimizer.png +0 -0
  75. package/app/docs/social-preview.png +0 -0
  76. package/app/eslint.config.mjs +20 -0
  77. package/app/install.sh +85 -0
  78. package/app/next.config.ts +17 -0
  79. package/app/package.json +3 -3
  80. package/app/pnpm-lock.yaml +7031 -0
  81. package/app/pnpm-workspace.yaml +3 -0
  82. package/app/postcss.config.mjs +7 -0
  83. package/app/scripts/build-cli.mjs +26 -0
  84. package/app/scripts/demo-data.mjs +337 -0
  85. package/app/scripts/deploy-docker.sh +71 -0
  86. package/app/scripts/package-release.sh +86 -0
  87. package/app/server.js +1 -1
  88. package/app/tsconfig.json +34 -0
  89. package/bin/agent-session-inspector.mjs +2 -2
  90. package/cli/cli.mjs +234 -84
  91. package/package.json +1 -1
  92. package/app/.next/server/chunks/ssr/_0o294sf._.js +0 -3
  93. package/app/.next/server/chunks/ssr/_0wfo2z0._.js +0 -3
  94. package/app/.next/static/chunks/1lmw5sxsr57p6.css +0 -1
  95. package/app/.next/static/chunks/1nuneih_2_kul.js +0 -1
  96. package/app/.next/static/chunks/21ckxredfe3pr.js +0 -6
  97. package/app/.next/static/chunks/3-g9jvt_m-6_4.js +0 -1
  98. /package/app/.next/static/{muuOFZsnyOfIG_5aUuqFV → QagODMnr1on0whIZ_GMxV}/_buildManifest.js +0 -0
  99. /package/app/.next/static/{muuOFZsnyOfIG_5aUuqFV → QagODMnr1on0whIZ_GMxV}/_clientMiddlewareManifest.js +0 -0
  100. /package/app/.next/static/{muuOFZsnyOfIG_5aUuqFV → QagODMnr1on0whIZ_GMxV}/_ssgManifest.js +0 -0
@@ -0,0 +1,3 @@
1
+ allowBuilds:
2
+ esbuild: false
3
+ unrs-resolver: true
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ // Bundles src/cli into the single file the launcher loads for report commands
3
+ // (usage, stats, sessions). Output defaults to cli/cli.mjs beside bin/, which
4
+ // is where bin/agent-session-inspector.mjs looks in a checkout and in the
5
+ // packaged build alike.
6
+ import { build } from "esbuild";
7
+ import path from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+
10
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
11
+ const outfile = path.resolve(process.argv[2] ?? path.join(ROOT, "cli", "cli.mjs"));
12
+
13
+ await build({
14
+ entryPoints: [path.join(ROOT, "src", "cli", "index.ts")],
15
+ outfile,
16
+ bundle: true,
17
+ platform: "node",
18
+ format: "esm",
19
+ target: "node22",
20
+ alias: { "@": path.join(ROOT, "src") },
21
+ // Bundled CommonJS dependencies call require() for Node built-ins.
22
+ banner: {
23
+ js: 'import { createRequire as __createRequire } from "node:module";\nconst require = __createRequire(import.meta.url);',
24
+ },
25
+ logLevel: "warning",
26
+ });
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env node
2
+ // Writes a fake $HOME with synthetic Claude Code, Codex, Copilot and Gemini CLI transcripts, so the
3
+ // UI can be demoed (and README screenshots retaken) without exposing real
4
+ // sessions. Usage:
5
+ // node scripts/demo-data.mjs /tmp/asi-demo
6
+ // HOME=/tmp/asi-demo pnpm dev
7
+ import fs from "fs";
8
+ import path from "path";
9
+
10
+ const root = path.resolve(process.argv[2] ?? ".demo-home");
11
+ fs.rmSync(root, { recursive: true, force: true });
12
+
13
+ const writeJsonl = (file, rows) => {
14
+ fs.mkdirSync(path.dirname(file), { recursive: true });
15
+ fs.writeFileSync(file, rows.map((r) => JSON.stringify(r)).join("\n") + "\n");
16
+ };
17
+
18
+ const clock = (start) => {
19
+ let t = new Date(start).getTime();
20
+ return (seconds = 3) => new Date((t += seconds * 1000)).toISOString();
21
+ };
22
+
23
+ // ---------------------------------------------------------------- Claude Code
24
+
25
+ function claudeSession({ id, cwd, branch, title, start, model, turns }) {
26
+ const at = clock(start);
27
+ const base = { sessionId: id, cwd, gitBranch: branch, version: "2.1.4", entrypoint: "cli" };
28
+ const rows = [{ type: "ai-title", aiTitle: title, sessionId: id }];
29
+ let n = 0;
30
+ let parent = null;
31
+ const uid = () => `${id.slice(0, 8)}-${String(n++).padStart(4, "0")}`;
32
+ const add = (rec) => {
33
+ const uuid = uid();
34
+ rows.push({ ...base, ...rec, uuid, parentUuid: parent });
35
+ parent = uuid;
36
+ };
37
+ let cache = 18_000;
38
+ const usage = (out) => {
39
+ const u = {
40
+ input_tokens: 40 + Math.floor(Math.random() * 400),
41
+ cache_creation_input_tokens: 600 + Math.floor(Math.random() * 2500),
42
+ cache_read_input_tokens: cache,
43
+ output_tokens: out,
44
+ };
45
+ cache += u.cache_creation_input_tokens;
46
+ return u;
47
+ };
48
+
49
+ let msg = 0;
50
+ for (const turn of turns) {
51
+ const turnStart = Date.now();
52
+ add({ type: "user", timestamp: at(20), message: { role: "user", content: turn.prompt } });
53
+ for (const step of turn.steps) {
54
+ const mid = `msg_${id.slice(0, 6)}${msg++}`;
55
+ if (step.thinking) {
56
+ add({
57
+ type: "assistant",
58
+ timestamp: at(4),
59
+ message: { id: mid, role: "assistant", model, content: [{ type: "thinking", thinking: step.thinking }], usage: usage(180) },
60
+ });
61
+ }
62
+ if (step.tool) {
63
+ const toolId = `toolu_${id.slice(0, 6)}${msg}`;
64
+ add({
65
+ type: "assistant",
66
+ timestamp: at(3),
67
+ message: {
68
+ id: mid,
69
+ role: "assistant",
70
+ model,
71
+ content: [{ type: "tool_use", id: toolId, name: step.tool, input: step.input }],
72
+ usage: usage(90 + Math.floor(Math.random() * 400)),
73
+ },
74
+ });
75
+ add({
76
+ type: "user",
77
+ timestamp: at(step.seconds ?? 2),
78
+ message: {
79
+ role: "user",
80
+ content: [{ type: "tool_result", tool_use_id: toolId, content: step.result, is_error: step.error === true }],
81
+ },
82
+ });
83
+ }
84
+ if (step.text) {
85
+ add({
86
+ type: "assistant",
87
+ timestamp: at(5),
88
+ message: { id: mid, role: "assistant", model, content: [{ type: "text", text: step.text }], usage: usage(350) },
89
+ });
90
+ }
91
+ }
92
+ add({ type: "system", subtype: "turn_duration", timestamp: at(1), durationMs: 40_000 + (Date.now() - turnStart) });
93
+ }
94
+ return rows;
95
+ }
96
+
97
+ const claudeProjects = path.join(root, ".claude", "projects");
98
+
99
+ const checkoutCwd = "/Users/demo/code/acme-shop";
100
+ writeJsonl(
101
+ path.join(claudeProjects, "-Users-demo-code-acme-shop", "7f3c2a10-5b1e-4c8d-9a42-1d6e8b0f3c21.jsonl"),
102
+ claudeSession({
103
+ id: "7f3c2a10-5b1e-4c8d-9a42-1d6e8b0f3c21",
104
+ cwd: checkoutCwd,
105
+ branch: "fix/cart-total-rounding",
106
+ title: "Fix cart total rounding bug",
107
+ start: "2026-09-24T09:12:00Z",
108
+ model: "claude-opus-5-5",
109
+ turns: [
110
+ {
111
+ prompt:
112
+ "Customers are reporting the cart total is sometimes off by a cent. Can you find out why and fix it? Tests are in src/cart/__tests__.",
113
+ steps: [
114
+ { thinking: "Off-by-a-cent usually means floating point arithmetic on prices. Let me find where the total is computed." },
115
+ { tool: "Grep", input: { pattern: "total", path: "src/cart" }, result: "src/cart/total.ts:12:export function cartTotal(items: CartItem[]) {\nsrc/cart/total.ts:18: return total;\nsrc/cart/summary.tsx:31: const total = cartTotal(items);" },
116
+ { tool: "Read", input: { file_path: `${checkoutCwd}/src/cart/total.ts` }, result: "export function cartTotal(items: CartItem[]) {\n let total = 0;\n for (const item of items) {\n total += item.price * item.quantity * (1 - item.discount);\n }\n return Math.round(total * 100) / 100;\n}" },
117
+ { text: "The total sums floating-point prices and rounds once at the end, so values like `0.1 + 0.2` drift before rounding. I'll switch to integer cents and round per line item." },
118
+ { tool: "Edit", input: { file_path: `${checkoutCwd}/src/cart/total.ts`, old_string: "total += item.price * item.quantity * (1 - item.discount);", new_string: "total += Math.round(toCents(item.price) * item.quantity * (1 - item.discount));" }, result: "The file src/cart/total.ts has been updated." },
119
+ { tool: "Edit", input: { file_path: `${checkoutCwd}/src/cart/__tests__/total.test.ts`, old_string: "});", new_string: " it('does not drift on fractional prices', () => {\n expect(cartTotal([{ price: 0.1, quantity: 3, discount: 0 }])).toBe(0.3);\n });\n});" }, result: "The file src/cart/__tests__/total.test.ts has been updated." },
120
+ { tool: "Bash", input: { command: "pnpm test src/cart", description: "Run cart tests" }, seconds: 14, result: " PASS src/cart/__tests__/total.test.ts\n cartTotal\n ✓ sums line items (3 ms)\n ✓ applies discounts (1 ms)\n ✓ does not drift on fractional prices (1 ms)\n\nTest Suites: 1 passed, 1 total\nTests: 3 passed, 3 total" },
121
+ { text: "Fixed. `cartTotal` now works in integer cents and rounds each line item, so totals no longer drift by a cent. I added a regression test for fractional prices; all 3 cart tests pass." },
122
+ ],
123
+ },
124
+ {
125
+ prompt: "Nice. Does the same bug exist in the order summary on the checkout page?",
126
+ steps: [
127
+ { tool: "Read", input: { file_path: `${checkoutCwd}/src/checkout/summary.tsx` }, result: "import { cartTotal } from '../cart/total';\n\nexport function OrderSummary({ items, shipping }) {\n const subtotal = cartTotal(items);\n const total = subtotal + shipping;\n return <Money value={total} />;\n}" },
128
+ { tool: "Bash", input: { command: "pnpm test src/checkout", description: "Run checkout tests" }, seconds: 9, result: [{ type: "text", text: "Tests: 7 passed, 7 total" }] },
129
+ { text: "The checkout summary calls `cartTotal`, so it picks up the fix automatically. Shipping is already stored in cents, so there's nothing else to change there." },
130
+ ],
131
+ },
132
+ ],
133
+ }),
134
+ );
135
+
136
+ const apiCwd = "/Users/demo/code/weather-api";
137
+ writeJsonl(
138
+ path.join(claudeProjects, "-Users-demo-code-weather-api", "c1d9e4b2-8a7f-4e21-b3c5-6f0a2d9e7b14.jsonl"),
139
+ claudeSession({
140
+ id: "c1d9e4b2-8a7f-4e21-b3c5-6f0a2d9e7b14",
141
+ cwd: apiCwd,
142
+ branch: "main",
143
+ title: "Add rate limiting to forecast endpoint",
144
+ start: "2026-09-23T15:40:00Z",
145
+ model: "claude-sonnet-5",
146
+ turns: [
147
+ {
148
+ prompt: "Add a simple per-IP rate limit (60 requests/minute) to GET /forecast.",
149
+ steps: [
150
+ { tool: "Glob", input: { pattern: "src/routes/**/*.ts" }, result: "src/routes/forecast.ts\nsrc/routes/health.ts" },
151
+ // A result of typed parts: the image is counted on the timeline, not shown.
152
+ { tool: "Read", input: { file_path: `${apiCwd}/docs/rate-limit.png` }, result: [{ type: "text", text: "Diagram of the token bucket: 60 requests refill every minute." }, { type: "image", source: { type: "base64", media_type: "image/png", data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" } }] },
153
+ { tool: "Read", input: { file_path: `${apiCwd}/src/routes/forecast.ts` }, result: "router.get('/forecast', async (req, res) => {\n const data = await getForecast(req.query.city);\n res.json(data);\n});" },
154
+ { tool: "Write", input: { file_path: `${apiCwd}/src/middleware/rate-limit.ts`, content: "export function rateLimit(limit: number, windowMs: number) { /* ... */ }" }, result: "File created successfully." },
155
+ { tool: "Edit", input: { file_path: `${apiCwd}/src/routes/forecast.ts`, old_string: "router.get('/forecast',", new_string: "router.get('/forecast', rateLimit(60, 60_000)," }, result: "The file src/routes/forecast.ts has been updated." },
156
+ { tool: "Bash", input: { command: "pnpm test", description: "Run test suite" }, seconds: 11, error: true, result: "FAIL src/routes/__tests__/forecast.test.ts\n ✕ returns 429 after limit (12 ms)\n Expected: 429\n Received: 200" },
157
+ { thinking: "The limiter keys on req.ip, which is undefined behind the test client. Fall back to the socket address." },
158
+ { tool: "Edit", input: { file_path: `${apiCwd}/src/middleware/rate-limit.ts`, old_string: "const key = req.ip;", new_string: "const key = req.ip ?? req.socket.remoteAddress ?? 'unknown';" }, result: "The file src/middleware/rate-limit.ts has been updated." },
159
+ { tool: "Bash", input: { command: "pnpm test", description: "Run test suite" }, seconds: 10, result: "Tests: 18 passed, 18 total" },
160
+ { text: "Added a `rateLimit` middleware (fixed window, keyed by client IP) and applied it to `GET /forecast` at 60 requests/minute. Clients over the limit get a 429 with a `Retry-After` header. All 18 tests pass." },
161
+ ],
162
+ },
163
+ ],
164
+ }),
165
+ );
166
+
167
+ writeJsonl(
168
+ path.join(claudeProjects, "-Users-demo-code-acme-shop", "a8e2f7c3-1d4b-4f9e-8c6a-3b5d7e9f1a02.jsonl"),
169
+ claudeSession({
170
+ id: "a8e2f7c3-1d4b-4f9e-8c6a-3b5d7e9f1a02",
171
+ cwd: checkoutCwd,
172
+ branch: "main",
173
+ title: "Explain the checkout flow",
174
+ start: "2026-09-22T11:05:00Z",
175
+ model: "claude-haiku-4-5-20251001",
176
+ turns: [
177
+ {
178
+ prompt: "Give me a quick tour of how checkout works in this repo.",
179
+ steps: [
180
+ { tool: "Glob", input: { pattern: "src/checkout/**" }, result: "src/checkout/page.tsx\nsrc/checkout/summary.tsx\nsrc/checkout/payment.ts\nsrc/checkout/confirm.ts" },
181
+ { tool: "Read", input: { file_path: `${checkoutCwd}/src/checkout/page.tsx` }, result: "export default function CheckoutPage() { /* address → payment → confirm */ }" },
182
+ { text: "Checkout is a three-step flow in `src/checkout/page.tsx`: address, payment, confirm. `payment.ts` creates a payment intent, `confirm.ts` finalizes the order, and `summary.tsx` shows the running total using `cartTotal`." },
183
+ ],
184
+ },
185
+ ],
186
+ }),
187
+ );
188
+
189
+ // ---------------------------------------------------------------------- Codex
190
+
191
+ const codexId = "0199a3f2-7c41-7d20-9e8b-5a4c3b2d1e0f";
192
+ {
193
+ const at = clock("2026-09-24T17:30:00Z");
194
+ const cwd = "/Users/demo/code/cli-tools";
195
+ writeJsonl(path.join(root, ".codex", "session_index.jsonl"), [
196
+ { id: codexId, thread_name: "Add --json flag to status command" },
197
+ ]);
198
+ const tokens = (input, cached, output) => ({
199
+ type: "event_msg",
200
+ timestamp: at(1),
201
+ payload: {
202
+ type: "token_count",
203
+ info: {
204
+ total_token_usage: { input_tokens: input, cached_input_tokens: cached, output_tokens: output, total_tokens: input + output },
205
+ last_token_usage: { total_tokens: 9_000 },
206
+ model_context_window: 272_000,
207
+ },
208
+ },
209
+ });
210
+ writeJsonl(path.join(root, ".codex", "sessions", "2026", "09", "24", `rollout-2026-09-24T17-30-00-${codexId}.jsonl`), [
211
+ {
212
+ type: "session_meta",
213
+ timestamp: at(0),
214
+ payload: { id: codexId, cwd, originator: "codex_cli_rs", cli_version: "0.61.0", git: { branch: "feat/status-json", repository_url: "git@github.com:demo/cli-tools.git" } },
215
+ },
216
+ { type: "turn_context", timestamp: at(1), payload: { model: "gpt-5-codex", effort: "medium", cwd } },
217
+ { type: "event_msg", timestamp: at(1), payload: { type: "task_started", turn_id: "t1", model_context_window: 272_000 } },
218
+ { type: "event_msg", timestamp: at(2), payload: { type: "user_message", message: "Add a --json flag to `status` that prints machine-readable output." } },
219
+ { type: "event_msg", timestamp: at(4), payload: { type: "agent_reasoning", text: "Find the status command definition and its output formatter." } },
220
+ { type: "response_item", timestamp: at(1), payload: { type: "function_call", name: "shell", call_id: "c1", arguments: JSON.stringify({ command: ["rg", "-n", "fn status", "src"] }) } },
221
+ { type: "response_item", timestamp: at(2), payload: { type: "function_call_output", call_id: "c1", output: "src/commands/status.rs:14:pub fn status(args: StatusArgs) -> Result<()> {" } },
222
+ tokens(21_400, 12_800, 1_150),
223
+ { type: "event_msg", timestamp: at(8), payload: { type: "patch_apply_end", call_id: "p1", success: true, stdout: "Success. Updated the following files:\nM src/commands/status.rs\nM src/cli.rs", stderr: "", changes: { [`${cwd}/src/commands/status.rs`]: { type: "update" }, [`${cwd}/src/cli.rs`]: { type: "update" } } } },
224
+ { type: "response_item", timestamp: at(1), payload: { type: "function_call", name: "shell", call_id: "c2", arguments: JSON.stringify({ command: ["cargo", "test", "status"] }) } },
225
+ { type: "response_item", timestamp: at(18), payload: { type: "function_call_output", call_id: "c2", output: "running 4 tests\ntest status::plain_output ... ok\ntest status::json_output ... ok\n\ntest result: ok. 4 passed; 0 failed" } },
226
+ tokens(48_900, 36_100, 2_870),
227
+ { type: "event_msg", timestamp: at(4), payload: { type: "agent_message", message: "`status --json` now serializes the status struct with serde and prints it to stdout. Plain output is unchanged. Added a test for the JSON shape; all 4 status tests pass." } },
228
+ { type: "event_msg", timestamp: at(1), payload: { type: "task_complete", turn_id: "t1", duration_ms: 44_000 } },
229
+ ]);
230
+ }
231
+
232
+ // -------------------------------------------------------------------- Copilot
233
+
234
+ {
235
+ const id = "5e2b9c14-3f8a-4d61-a7e0-9c3d2b1f6a85";
236
+ const dir = path.join(root, ".copilot", "session-state", id);
237
+ const cwd = "/Users/demo/code/docs-site";
238
+ const start = "2026-09-24T12:05:00Z";
239
+ const at = clock(start);
240
+ fs.mkdirSync(dir, { recursive: true });
241
+ fs.writeFileSync(
242
+ path.join(dir, "workspace.yaml"),
243
+ [
244
+ `id: ${id}`,
245
+ `name: Fix broken links in docs sidebar`,
246
+ `cwd: ${cwd}`,
247
+ `repository: demo/docs-site`,
248
+ `branch: fix/sidebar-links`,
249
+ `created_at: ${start}`,
250
+ `updated_at: 2026-09-24T12:07:10Z`,
251
+ `host_type: cli`,
252
+ `client_name: copilot-cli`,
253
+ `user_named: true`,
254
+ ].join("\n") + "\n",
255
+ );
256
+
257
+ let n = 0;
258
+ const ev = (type, data, seconds) => ({ type, data, id: `cp-${n++}`, timestamp: at(seconds), parentId: null });
259
+ const tool = (name, args, result, seconds = 2) => {
260
+ const toolCallId = `call_${n}`;
261
+ return [
262
+ ev("tool.execution_start", { toolName: name, toolCallId, arguments: args }, 3),
263
+ ev("tool.execution_complete", { toolName: name, toolCallId, success: true, result: { content: result } }, seconds),
264
+ ];
265
+ };
266
+ writeJsonl(path.join(dir, "events.jsonl"), [
267
+ ev("session.start", { sessionId: id, selectedModel: "gpt-5.1", copilotVersion: "0.0.412", context: { cwd, branch: "fix/sidebar-links", repository: "demo/docs-site" } }, 0),
268
+ ev("user.message", { content: "Some links in the docs sidebar 404 after the folder rename. Find and fix them." }, 5),
269
+ ev("assistant.message", { content: "I'll check the sidebar config against the files that actually exist.", outputTokens: 120, inputTokens: 9_800 }, 4),
270
+ ...tool("bash", { command: "node scripts/check-links.js sidebar.json" }, "3 broken links:\n /guides/setup -> guides/setup.md (missing)\n /guides/deploy -> guides/deploy.md (missing)\n /api/auth -> api/auth.md (missing)", 6),
271
+ ...tool("glob", { pattern: "docs/**/*.md" }, "docs/getting-started/setup.md\ndocs/getting-started/deploy.md\ndocs/reference/auth.md\ndocs/index.md"),
272
+ ...tool("edit", { path: `${cwd}/sidebar.json`, old_str: '"guides/setup"', new_str: '"getting-started/setup"' }, "File updated."),
273
+ ...tool("bash", { command: "node scripts/check-links.js sidebar.json" }, "All links OK (24 checked).", 5),
274
+ ev("assistant.message", { content: "Updated three sidebar entries to the new `getting-started/` and `reference/` paths. The link checker now reports all 24 links OK.", outputTokens: 210, inputTokens: 14_600 }, 4),
275
+ ev("session.shutdown", {
276
+ totalApiDurationMs: 21_400,
277
+ totalPremiumRequests: 2,
278
+ modelMetrics: { "gpt-5.1": { usage: { inputTokens: 38_900, outputTokens: 1_640, cacheReadTokens: 27_300 } } },
279
+ }, 2),
280
+ ]);
281
+
282
+ fs.mkdirSync(path.join(root, ".copilot", "logs"), { recursive: true });
283
+ fs.writeFileSync(
284
+ path.join(root, ".copilot", "logs", "process-1758715500000-4821.log"),
285
+ `${start} [INFO] Starting Copilot CLI 0.0.412\n${start} [INFO] Session ${id} created in ${cwd}\n2026-09-24T12:07:10Z [INFO] Session ${id} shut down\n`,
286
+ );
287
+ }
288
+
289
+ // ----------------------------------------------------------------- Gemini CLI
290
+
291
+ {
292
+ const id = "7c1e4a92-5b3d-4f08-9a6e-2d8f0b3c5e71";
293
+ const cwd = "/Users/demo/code/weather-api";
294
+ const start = "2026-09-25T09:10:00Z";
295
+ const at = clock(start);
296
+ const project = path.join(root, ".gemini", "tmp", "weather-api");
297
+ const model = "gemini-3.7-flash";
298
+ fs.mkdirSync(project, { recursive: true });
299
+ fs.writeFileSync(path.join(project, ".project_root"), cwd);
300
+
301
+ const tool = (callId, name, args, output) => ({
302
+ id: callId,
303
+ name,
304
+ args,
305
+ status: "success",
306
+ timestamp: at(2),
307
+ result: [{ functionResponse: { id: callId, name, response: { output } } }],
308
+ });
309
+ const reply = (messageId, fields) => ({ id: messageId, timestamp: at(4), type: "gemini", content: "", model, ...fields });
310
+ const prompt = { id: "m1", timestamp: at(3), type: "user", content: [{ text: "Forecast responses are cached for an hour. Make the TTL configurable." }] };
311
+ const grep = reply("m2", {
312
+ thoughts: [{ subject: "Locating the cache", description: "The forecast handler should own the TTL; search for it first.", timestamp: at(1) }],
313
+ tokens: { input: 11_200, output: 140, cached: 0, thoughts: 220, tool: 0, total: 11_560 },
314
+ });
315
+ writeJsonl(path.join(project, "chats", `session-2026-09-25T09-10-${id.slice(0, 8)}.jsonl`), [
316
+ { sessionId: id, projectHash: "3f9a1c", startTime: start, lastUpdated: start },
317
+ prompt,
318
+ grep,
319
+ // The CLI writes a message again as its tool calls come in; the last copy wins.
320
+ { ...grep, toolCalls: [tool("g1", "search_file_content", { pattern: "CACHE_TTL" }, "src/forecast/cache.ts:4:const CACHE_TTL = 3600;")] },
321
+ reply("m3", {
322
+ toolCalls: [
323
+ tool("g2", "replace", { file_path: `${cwd}/src/forecast/cache.ts`, old_string: "const CACHE_TTL = 3600;", new_string: "const CACHE_TTL = Number(process.env.FORECAST_TTL ?? 3600);" }, "Successfully modified file."),
324
+ tool("g3", "run_shell_command", { command: "npm test -- forecast" }, "Tests: 12 passed, 12 total"),
325
+ ],
326
+ tokens: { input: 12_900, output: 310, cached: 10_400, thoughts: 90, tool: 0, total: 13_300 },
327
+ }),
328
+ reply("m4", {
329
+ content: "The TTL now reads `FORECAST_TTL` (seconds) and falls back to one hour. All 12 forecast tests pass.",
330
+ tokens: { input: 13_600, output: 95, cached: 12_100, thoughts: 0, tool: 0, total: 13_695 },
331
+ }),
332
+ { $set: { lastUpdated: at(0), summary: "Make forecast cache TTL configurable" } },
333
+ ]);
334
+ }
335
+
336
+ console.log(`Demo home written to ${root}`);
337
+ console.log(`Run: HOME=${root} pnpm dev`);
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ NAME=agent-session-inspector
5
+
6
+ docker build -t "$NAME" .
7
+
8
+ if docker container inspect "$NAME" >/dev/null 2>&1; then
9
+ docker rm -f "$NAME"
10
+ fi
11
+
12
+ # Mount only the transcript paths the app reads, read-only. Deliberately narrow:
13
+ # ~/.codex/auth.json, ~/.copilot/config.json, ~/.hermes/auth.json and
14
+ # ~/.gemini/oauth_creds.json hold credentials and stay out. So does Cursor's
15
+ # state.vscdb, which keeps its sign-in next to the chats: Cursor sessions are
16
+ # read from the transcripts under ~/.cursor/projects instead.
17
+ PATHS=(
18
+ ".copilot/session-state"
19
+ ".copilot/logs"
20
+ ".copilot/session-store.db"
21
+ ".copilot/session-store.db-shm"
22
+ ".copilot/session-store.db-wal"
23
+ ".claude/projects"
24
+ ".codex/sessions"
25
+ ".codex/session_index.jsonl"
26
+ ".local/share/opencode/opencode.db"
27
+ ".local/share/opencode/opencode.db-shm"
28
+ ".local/share/opencode/opencode.db-wal"
29
+ ".hermes/state.db"
30
+ ".hermes/state.db-shm"
31
+ ".hermes/state.db-wal"
32
+ ".gemini/tmp"
33
+ ".cursor/projects"
34
+ )
35
+
36
+ # Desktop apps keep their data somewhere else on each OS; inside the Linux
37
+ # container the app looks under ~/.config.
38
+ case "$(uname -s)" in
39
+ Darwin) APP_DATA="Library/Application Support" ;;
40
+ *) APP_DATA=".config" ;;
41
+ esac
42
+ APP_PATHS=(
43
+ "Code/User/workspaceStorage"
44
+ "Code/User/globalStorage/emptyWindowChatSessions"
45
+ "Code - Insiders/User/workspaceStorage"
46
+ "Code - Insiders/User/globalStorage/emptyWindowChatSessions"
47
+ "Claude/local-agent-mode-sessions"
48
+ )
49
+
50
+ mounts=()
51
+ for rel in "${PATHS[@]}"; do
52
+ if [ -e "$HOME/$rel" ]; then
53
+ mounts+=(-v "$HOME/$rel:/root/$rel:ro")
54
+ fi
55
+ done
56
+ for rel in "${APP_PATHS[@]}"; do
57
+ if [ -e "$HOME/$APP_DATA/$rel" ]; then
58
+ mounts+=(-v "$HOME/$APP_DATA/$rel:/root/.config/$rel:ro")
59
+ fi
60
+ done
61
+
62
+ if [ ${#mounts[@]} -eq 0 ]; then
63
+ echo "No agent session directories found under $HOME." >&2
64
+ exit 1
65
+ fi
66
+
67
+ # The app shows where each session is stored; tell it what the mounts are
68
+ # called out here, so the paths it shows are ones that exist on this machine.
69
+ docker run -d --name "$NAME" --restart unless-stopped --user root -e HOME=/root \
70
+ -e ASI_HOST_HOME="$HOME" -e ASI_HOST_APP_DATA="$HOME/$APP_DATA" \
71
+ "${mounts[@]}" "$NAME"
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ # Build the standalone server and stage it in dist/agent-session-inspector, the
3
+ # folder `npm publish` uploads, then pack that into
4
+ # dist/agent-session-inspector.tar.gz, the archive install.sh downloads. The
5
+ # build has no native modules, so one package runs on any OS with Node.
6
+ set -euo pipefail
7
+
8
+ NAME=agent-session-inspector
9
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
10
+ VERSION="${1:-$(node -p "require('$ROOT/package.json').version")}"
11
+ VERSION="${VERSION#v}"
12
+ OUT="$ROOT/dist"
13
+ STAGE="$OUT/$NAME"
14
+ # The server sits a level down: npm leaves a package's top-level node_modules
15
+ # out of the upload.
16
+ APP="$STAGE/app"
17
+ MODULES="$APP/node_modules"
18
+
19
+ cd "$ROOT"
20
+ # Clear the old output first, or the build traces it into the new one.
21
+ rm -rf "$OUT"
22
+ pnpm run build
23
+
24
+ mkdir -p "$APP"
25
+
26
+ # next build leaves .next/static out of the standalone folder.
27
+ cp -R .next/standalone/. "$APP/"
28
+ mkdir -p "$APP/.next"
29
+ cp -R .next/static "$APP/.next/static"
30
+
31
+ mkdir -p "$STAGE/bin"
32
+ cp "bin/$NAME.mjs" "$STAGE/bin/$NAME.mjs"
33
+ chmod +x "$STAGE/bin/$NAME.mjs"
34
+ # The report commands (usage, stats, sessions) run from their own bundle.
35
+ node scripts/build-cli.mjs "$STAGE/cli/cli.mjs"
36
+ echo "$VERSION" > "$STAGE/VERSION"
37
+ cp README.md LICENSE "$STAGE/"
38
+
39
+ # The tracer drags in sharp (unused: images are unoptimized) with its
40
+ # per-platform binaries and dependencies.
41
+ for dep in "$MODULES"/.pnpm/sharp@*/node_modules/*; do
42
+ if [ -L "$dep" ]; then
43
+ target="$(cd "$dep" 2>/dev/null && pwd -P)" || continue
44
+ rm -rf "${target%/node_modules/*}"
45
+ fi
46
+ done
47
+ rm -rf "$MODULES"/.pnpm/@img+* "$MODULES"/.pnpm/sharp@*
48
+
49
+ # npm never uploads symlinks, and pnpm's node_modules is built from them, so
50
+ # hoist every traced package into one flat node_modules.
51
+ find "$APP" -type l -delete
52
+ for dir in "$MODULES"/.pnpm/*/node_modules/* "$MODULES"/.pnpm/*/node_modules/@*/*; do
53
+ [ -d "$dir" ] || continue
54
+ name="${dir##*/node_modules/}"
55
+ case "$name" in @*/*) ;; @*) continue ;; esac
56
+ if [ -e "$MODULES/$name" ]; then
57
+ echo "error: two versions of $name in the build; a flat node_modules can hold one" >&2
58
+ exit 1
59
+ fi
60
+ mkdir -p "$(dirname "$MODULES/$name")"
61
+ mv "$dir" "$MODULES/$name"
62
+ done
63
+ rm -rf "$MODULES/.pnpm"
64
+
65
+ if find "$STAGE" -name '*.node' | grep -q .; then
66
+ echo "error: native module in build; the package would not be portable:" >&2
67
+ find "$STAGE" -name '*.node' >&2
68
+ exit 1
69
+ fi
70
+
71
+ # The manifest npm publishes: the built app has no dependencies left to install.
72
+ node -e '
73
+ const pkg = require(process.argv[1]);
74
+ const [name, version] = process.argv.slice(2);
75
+ const { description, keywords, author, license, homepage, bugs, repository, engines } = pkg;
76
+ console.log(JSON.stringify({
77
+ name, version, description, keywords, author, license, homepage, bugs, repository, engines,
78
+ bin: { [name]: `bin/${name}.mjs` },
79
+ files: ["app", "bin", "cli", "VERSION"],
80
+ }, null, 2));
81
+ ' "$ROOT/package.json" "$NAME" "$VERSION" > "$STAGE/package.json"
82
+
83
+ tar -czf "$OUT/$NAME.tar.gz" -C "$OUT" "$NAME"
84
+ cp install.sh "$OUT/install.sh"
85
+
86
+ echo "Packed $NAME $VERSION -> dist/$NAME.tar.gz ($(du -h "$OUT/$NAME.tar.gz" | cut -f1))"
package/app/server.js CHANGED
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
9
9
  const hostname = process.env.HOSTNAME || '0.0.0.0'
10
10
 
11
11
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
12
- const nextConfig = {"env":{"APP_VERSION":"0.1.8"},"webpack":null,"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"instrumentationClientInject":[],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/agent-session-inspector/agent-session-inspector","enablePrerenderSourceMaps":true,"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":true,"coldCacheBadge":false,"devValidationWorker":true,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"dynamicOnHover":false,"useOffline":false,"varyParams":true,"optimisticRouting":true,"instrumentationClientRouterTransitionEvents":false,"prefetchInlining":{"maxSize":2048,"maxBundleSize":10240},"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptOperationCache":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"devMemoryThresholdRestart":true,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"requestInsights":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"useTypeScriptCli":true,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":true,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"serverComponentsHmrCancellation":false,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":true,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","turbopackMemoryEvictionMode":"auto","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"useCacheTimeout":54,"instantInsights":{"validationLevel":"warning"},"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"/**":["./.git/**","./.claude/**","./src/**"]},"repoRoot":"/home/runner/work/agent-session-inspector/agent-session-inspector","turbopack":{"root":"/home/runner/work/agent-session-inspector/agent-session-inspector"},"distDirRoot":".next"}
12
+ const nextConfig = {"env":{"APP_VERSION":"0.1.10"},"webpack":null,"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"instrumentationClientInject":[],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/agent-session-inspector/agent-session-inspector","enablePrerenderSourceMaps":true,"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":true,"coldCacheBadge":false,"devValidationWorker":true,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"dynamicOnHover":false,"useOffline":false,"varyParams":true,"optimisticRouting":true,"instrumentationClientRouterTransitionEvents":false,"prefetchInlining":{"maxSize":2048,"maxBundleSize":10240},"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptOperationCache":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"devMemoryThresholdRestart":true,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"requestInsights":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"useTypeScriptCli":true,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":true,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"serverComponentsHmrCancellation":false,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":true,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","turbopackMemoryEvictionMode":"auto","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"useCacheTimeout":54,"instantInsights":{"validationLevel":"warning"},"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"/**":["./.git/**","./.claude/**","./src/**"]},"repoRoot":"/home/runner/work/agent-session-inspector/agent-session-inspector","turbopack":{"root":"/home/runner/work/agent-session-inspector/agent-session-inspector"},"distDirRoot":".next"}
13
13
 
14
14
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
15
15
 
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -33,7 +33,7 @@ Commands:
33
33
  Run a command with --help for its options.
34
34
 
35
35
  Options:
36
- -p, --port <port> Port to listen on (default: 3000, or the next free one)
36
+ -p, --port <port> Port to listen on (default: 4747, or the next free one)
37
37
  -H, --host <host> Interface to bind (default: 127.0.0.1)
38
38
  --no-open Don't open the browser
39
39
  -v, --version Print the version
@@ -165,7 +165,7 @@ if (!existsSync(SERVER)) {
165
165
 
166
166
  let port = opts.port;
167
167
  if (port === null) {
168
- port = await pickPort(Number(process.env.PORT) || 3000, opts.host);
168
+ port = await pickPort(Number(process.env.PORT) || 4747, opts.host);
169
169
  } else if (!(await isFree(port, opts.host))) {
170
170
  fail(`port ${port} is already in use`);
171
171
  }