ai-agent-session-center 2.4.0 → 2.4.3

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 (30) hide show
  1. package/README.md +2 -0
  2. package/dist/client/assets/AnalyticsView-B7ALjnxe.js +1 -0
  3. package/dist/client/assets/Charts-IyRNWsxy.css +1 -0
  4. package/dist/client/assets/{Charts.module-Dx9gJPQR.js → Charts.module-BVWDL-nq.js} +2 -2
  5. package/dist/client/assets/{CyberdromeScene-CxjA5JVV.js → CyberdromeScene-fsiugRCk.js} +1 -1
  6. package/dist/client/assets/HistoryView-2SToJwhm.js +1 -0
  7. package/dist/client/assets/HistoryView-khsGJftp.css +1 -0
  8. package/dist/client/assets/{ProjectBrowserView-5bUQLVrl.js → ProjectBrowserView-CC-VpOqU.js} +1 -1
  9. package/dist/client/assets/QueueView-BolJW5o0.js +1 -0
  10. package/dist/client/assets/TimelineView-B_Lk9xQG.js +4 -0
  11. package/dist/client/assets/index-B7h3JN01.js +153 -0
  12. package/dist/client/assets/index-y70PbO5W.css +1 -0
  13. package/dist/client/assets/{useQuery-C-SRwqqC.js → useQuery-D3equUmE.js} +1 -1
  14. package/dist/client/assets/{with-selector-C0N9xw7F.js → with-selector-bHDjn-jq.js} +1 -1
  15. package/dist/client/index.html +2 -2
  16. package/hooks/install-hooks-api.cjs +169 -0
  17. package/hooks/install-hooks-core.cjs +89 -0
  18. package/hooks/package.json +1 -0
  19. package/package.json +4 -4
  20. package/server/apiRouter.ts +3 -3
  21. package/server/serverConfig.ts +5 -1
  22. package/server/sessionMatcher.ts +13 -3
  23. package/dist/client/assets/AnalyticsView-CbZwTSY4.js +0 -1
  24. package/dist/client/assets/Charts-BN9-_lNy.css +0 -1
  25. package/dist/client/assets/HistoryView-Cu23DcIM.css +0 -1
  26. package/dist/client/assets/HistoryView-tXMsxMhN.js +0 -1
  27. package/dist/client/assets/QueueView-DM_X1lfF.js +0 -1
  28. package/dist/client/assets/TimelineView-DuOSFGCv.js +0 -4
  29. package/dist/client/assets/index-ClPKOKvN.css +0 -1
  30. package/dist/client/assets/index-DS3KKkg_.js +0 -169
@@ -0,0 +1,169 @@
1
+ // CJS version of install-hooks-api.js for Electron main process use.
2
+ // The .js version (ESM) is used by the CLI; this .cjs version is used by Electron.
3
+ 'use strict';
4
+
5
+ const { readFileSync, mkdirSync, existsSync, statSync, writeFileSync } = require('fs');
6
+ const { join } = require('path');
7
+ const { homedir } = require('os');
8
+ const { execSync } = require('child_process');
9
+ const {
10
+ atomicWriteJSON, deployHookScript, configureClaudeHooks,
11
+ removeAllClaudeHooks, configureGeminiHooks,
12
+ } = require('./install-hooks-core.cjs');
13
+
14
+ const ALL_EVENTS = [
15
+ 'SessionStart', 'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'PostToolUseFailure',
16
+ 'PermissionRequest', 'Stop', 'Notification', 'SubagentStart', 'SubagentStop',
17
+ 'TeammateIdle', 'TaskCompleted', 'PreCompact', 'SessionEnd',
18
+ ];
19
+
20
+ const DENSITY_EVENTS = {
21
+ high: ALL_EVENTS,
22
+ medium: [
23
+ 'SessionStart', 'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'PostToolUseFailure',
24
+ 'PermissionRequest', 'Stop', 'Notification', 'SubagentStart', 'SubagentStop',
25
+ 'TaskCompleted', 'SessionEnd',
26
+ ],
27
+ low: ['SessionStart', 'UserPromptSubmit', 'PermissionRequest', 'Stop', 'SessionEnd'],
28
+ };
29
+
30
+ const GEMINI_DENSITY_EVENTS = {
31
+ high: ['SessionStart', 'BeforeAgent', 'BeforeTool', 'AfterTool', 'AfterAgent', 'SessionEnd', 'Notification'],
32
+ medium: ['SessionStart', 'BeforeAgent', 'AfterAgent', 'SessionEnd', 'Notification'],
33
+ low: ['SessionStart', 'AfterAgent', 'SessionEnd'],
34
+ };
35
+
36
+ const HOOK_SOURCE = 'ai-agent-session-center';
37
+ const HOOK_PATTERN = 'dashboard-hook.';
38
+
39
+ function formatBytes(bytes) {
40
+ return bytes < 1024 ? `${bytes} B` : `${(bytes / 1024).toFixed(1)} KB`;
41
+ }
42
+
43
+ async function installHooks({ density = 'medium', enabledClis = ['claude'], projectRoot, uninstall = false, onLog } = {}) {
44
+ const log = onLog ?? console.log;
45
+ const isWindows = process.platform === 'win32';
46
+
47
+ if (!DENSITY_EVENTS[density]) throw new Error(`Invalid density: "${density}"`);
48
+
49
+ const hooksDir = projectRoot ? join(projectRoot, 'hooks') : __dirname;
50
+ const EVENTS = DENSITY_EVENTS[density];
51
+ const GEMINI_EVENTS = GEMINI_DENSITY_EVENTS[density] || GEMINI_DENSITY_EVENTS.medium;
52
+ const HOOK_SCRIPT = isWindows ? 'dashboard-hook.ps1' : 'dashboard-hook.sh';
53
+ const HOOKS_DEST_DIR = join(homedir(), '.claude', 'hooks');
54
+ const HOOK_DEST = join(HOOKS_DEST_DIR, HOOK_SCRIPT);
55
+ const HOOK_COMMAND = isWindows
56
+ ? `powershell -NoProfile -ExecutionPolicy Bypass -File "${HOOK_DEST}"`
57
+ : '~/.claude/hooks/dashboard-hook.sh';
58
+ const SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');
59
+ const TOTAL_STEPS = uninstall ? 4 : 6;
60
+
61
+ log(`[1/${TOTAL_STEPS}] Detecting platform...`);
62
+ log(`Platform: ${process.platform} (${isWindows ? 'PowerShell' : 'Bash'} hook)`);
63
+ log(`Home directory: ${homedir()}`);
64
+ if (!uninstall) log(`Enabled CLIs: ${enabledClis.join(', ')} | Density: ${density} (${EVENTS.length} events)`);
65
+
66
+ log(`[2/${TOTAL_STEPS}] Checking dependencies...`);
67
+ if (!isWindows && !uninstall) {
68
+ try { const v = execSync('jq --version', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'], timeout: 3000 }).trim(); log(`jq: ${v}`); }
69
+ catch { log('jq: NOT FOUND -- hook will work but without enrichment'); }
70
+ try { execSync('which curl', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'], timeout: 3000 }); log('curl: found'); }
71
+ catch { log('curl: NOT FOUND -- HTTP fallback unavailable'); }
72
+ }
73
+
74
+ log(`[3/${TOTAL_STEPS}] Preparing directories...`);
75
+ if (!existsSync(HOOKS_DEST_DIR)) mkdirSync(HOOKS_DEST_DIR, { recursive: true });
76
+ const claudeDir = join(homedir(), '.claude');
77
+ if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true });
78
+
79
+ let settings;
80
+ try {
81
+ settings = JSON.parse(readFileSync(SETTINGS_PATH, 'utf8'));
82
+ log(`Settings loaded: ${SETTINGS_PATH}`);
83
+ } catch (err) {
84
+ if (err.code === 'ENOENT') { settings = {}; log(`Creating new settings: ${SETTINGS_PATH}`); }
85
+ else throw new Error(`Failed to read settings: ${err.message}`);
86
+ }
87
+ if (!settings.hooks) settings.hooks = {};
88
+
89
+ if (uninstall) {
90
+ log(`[4/${TOTAL_STEPS}] Removing hooks...`);
91
+ const removed = removeAllClaudeHooks(settings, ALL_EVENTS, HOOK_PATTERN);
92
+ atomicWriteJSON(SETTINGS_PATH, settings);
93
+ log(`Uninstall complete -- ${removed} hook(s) removed`);
94
+ return { success: true, summary: { removed } };
95
+ }
96
+
97
+ log(`[4/${TOTAL_STEPS}] Configuring hook events (density: ${density})...`);
98
+ const result = configureClaudeHooks(settings, EVENTS, ALL_EVENTS, HOOK_COMMAND, HOOK_PATTERN, HOOK_SOURCE);
99
+ atomicWriteJSON(SETTINGS_PATH, settings);
100
+ log(`Settings saved: +${result.added} ~${result.updated} -${result.removed} =${result.unchanged}`);
101
+
102
+ log(`[5/${TOTAL_STEPS}] Deploying hook scripts...`);
103
+ const src = join(hooksDir, HOOK_SCRIPT);
104
+ if (!existsSync(src)) throw new Error(`Hook script not found: ${src}`);
105
+ deployHookScript(src, HOOK_DEST, isWindows);
106
+ log(`Deployed ${HOOK_SCRIPT} -> ${HOOK_DEST} (${formatBytes(statSync(src).size)})`);
107
+
108
+ const altScript = isWindows ? 'dashboard-hook.sh' : 'dashboard-hook.ps1';
109
+ const altSrc = join(hooksDir, altScript);
110
+ if (existsSync(altSrc)) { deployHookScript(altSrc, join(HOOKS_DEST_DIR, altScript), isWindows); log(`Also copied ${altScript}`); }
111
+
112
+ if (enabledClis.includes('gemini')) {
113
+ const geminiSrc = join(hooksDir, 'dashboard-hook-gemini.sh');
114
+ const geminiDest = join(homedir(), '.gemini', 'hooks', 'dashboard-hook.sh');
115
+ if (existsSync(geminiSrc)) {
116
+ mkdirSync(join(homedir(), '.gemini', 'hooks'), { recursive: true });
117
+ deployHookScript(geminiSrc, geminiDest, false);
118
+ log(`Deployed Gemini hook -> ${geminiDest}`);
119
+ }
120
+ const geminiSettingsPath = join(homedir(), '.gemini', 'settings.json');
121
+ try {
122
+ let gs; try { gs = JSON.parse(readFileSync(geminiSettingsPath, 'utf8')); } catch { gs = {}; }
123
+ const gChanged = configureGeminiHooks(gs, GEMINI_EVENTS, HOOK_SOURCE);
124
+ if (gChanged) { mkdirSync(join(homedir(), '.gemini'), { recursive: true }); atomicWriteJSON(geminiSettingsPath, gs); log(`Registered ${gChanged} Gemini events`); }
125
+ else log('Gemini hooks already registered');
126
+ } catch (e) { log(`Gemini: ${e.message}`); }
127
+ }
128
+
129
+ if (enabledClis.includes('codex')) {
130
+ const codexSrc = join(hooksDir, 'dashboard-hook-codex.sh');
131
+ const codexDest = join(homedir(), '.codex', 'hooks', 'dashboard-hook.sh');
132
+ if (existsSync(codexSrc)) {
133
+ mkdirSync(join(homedir(), '.codex', 'hooks'), { recursive: true });
134
+ deployHookScript(codexSrc, codexDest, false);
135
+ log(`Deployed Codex hook -> ${codexDest}`);
136
+ }
137
+ const codexConfigPath = join(homedir(), '.codex', 'config.toml');
138
+ try {
139
+ let toml = ''; try { toml = readFileSync(codexConfigPath, 'utf8'); } catch {}
140
+ if (!toml.includes('dashboard-hook')) {
141
+ mkdirSync(join(homedir(), '.codex'), { recursive: true });
142
+ if (toml && !toml.endsWith('\n')) toml += '\n';
143
+ toml += `# [${HOOK_SOURCE}]\nnotify = ["~/.codex/hooks/dashboard-hook.sh"]\n`;
144
+ writeFileSync(codexConfigPath, toml);
145
+ log('Registered Codex notify hook');
146
+ } else log('Codex hook already registered');
147
+ } catch (e) { log(`Codex: ${e.message}`); }
148
+ }
149
+
150
+ log(`[6/${TOTAL_STEPS}] Verifying...`);
151
+ let verifyOk = true;
152
+ if (!isWindows) {
153
+ try { execSync(`test -x "${HOOK_DEST}"`, { stdio: 'ignore', timeout: 3000 }); log('Hook script is executable'); }
154
+ catch { log('Hook script is NOT executable'); verifyOk = false; }
155
+ }
156
+ try {
157
+ const check = JSON.parse(readFileSync(SETTINGS_PATH, 'utf8'));
158
+ const registered = Object.keys(check.hooks || {}).filter(e =>
159
+ check.hooks[e]?.some(g => g.hooks?.some(h => h.command?.includes(HOOK_PATTERN)))
160
+ );
161
+ log(`Registered: ${registered.length}/${EVENTS.length} events`);
162
+ if (registered.length !== EVENTS.length) verifyOk = false;
163
+ } catch (err) { log(`Settings invalid: ${err.message}`); verifyOk = false; }
164
+
165
+ log(verifyOk ? `Setup complete! (density: ${density}, ${EVENTS.length} events)` : 'Setup completed with warnings');
166
+ return { success: verifyOk, summary: { ...result, density, eventCount: EVENTS.length } };
167
+ }
168
+
169
+ module.exports = { installHooks };
@@ -0,0 +1,89 @@
1
+ // CJS version of install-hooks-core.js for Electron main process use.
2
+ // The .js version (ESM) is used by the CLI; this .cjs version is used by Electron.
3
+ 'use strict';
4
+
5
+ const { writeFileSync, copyFileSync, chmodSync, renameSync, unlinkSync } = require('fs');
6
+ const { randomBytes } = require('crypto');
7
+
8
+ function atomicWriteJSON(filePath, data) {
9
+ const tmpPath = filePath + '.tmp.' + randomBytes(4).toString('hex');
10
+ try {
11
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2) + '\n');
12
+ renameSync(tmpPath, filePath);
13
+ } catch (err) {
14
+ try { unlinkSync(tmpPath); } catch {}
15
+ throw err;
16
+ }
17
+ }
18
+
19
+ function buildHookEntry(hookCommand, hookSource) {
20
+ return {
21
+ _source: hookSource,
22
+ hooks: [{ type: 'command', command: hookCommand, async: true }],
23
+ };
24
+ }
25
+
26
+ function deployHookScript(srcPath, destPath, isWindows) {
27
+ copyFileSync(srcPath, destPath);
28
+ if (!isWindows) chmodSync(destPath, 0o755);
29
+ }
30
+
31
+ function configureClaudeHooks(settings, events, allEvents, hookCommand, hookPattern, hookSource) {
32
+ if (!settings.hooks) settings.hooks = {};
33
+ let added = 0, updated = 0, unchanged = 0, removed = 0;
34
+
35
+ for (const event of events) {
36
+ if (!settings.hooks[event]) settings.hooks[event] = [];
37
+ const existingIdx = settings.hooks[event].findIndex(g =>
38
+ g.hooks?.some(h => h.command?.includes(hookPattern))
39
+ );
40
+ if (existingIdx >= 0) {
41
+ const hookEntry = settings.hooks[event][existingIdx].hooks.find(h => h.command?.includes(hookPattern));
42
+ if (hookEntry && hookEntry.command !== hookCommand) { hookEntry.command = hookCommand; updated++; }
43
+ else unchanged++;
44
+ } else {
45
+ settings.hooks[event].push(buildHookEntry(hookCommand, hookSource));
46
+ added++;
47
+ }
48
+ }
49
+
50
+ const excluded = allEvents.filter(e => !events.includes(e));
51
+ for (const event of excluded) {
52
+ if (!settings.hooks[event]) continue;
53
+ const before = settings.hooks[event].length;
54
+ settings.hooks[event] = settings.hooks[event].filter(g => !g.hooks?.some(h => h.command?.includes(hookPattern)));
55
+ if (settings.hooks[event].length === 0) delete settings.hooks[event];
56
+ if (before !== (settings.hooks[event]?.length ?? 0)) removed++;
57
+ }
58
+ return { added, updated, removed, unchanged };
59
+ }
60
+
61
+ function removeAllClaudeHooks(settings, allEvents, hookPattern) {
62
+ if (!settings.hooks) return 0;
63
+ let removed = 0;
64
+ for (const event of allEvents) {
65
+ if (!settings.hooks[event]) continue;
66
+ const before = settings.hooks[event].length;
67
+ settings.hooks[event] = settings.hooks[event].filter(g => !g.hooks?.some(h => h.command?.includes(hookPattern)));
68
+ if (settings.hooks[event].length === 0) delete settings.hooks[event];
69
+ if (before !== (settings.hooks[event]?.length ?? 0)) removed++;
70
+ }
71
+ if (Object.keys(settings.hooks).length === 0) settings.hooks = {};
72
+ return removed;
73
+ }
74
+
75
+ function configureGeminiHooks(settings, events, hookSource) {
76
+ if (!settings.hooks) settings.hooks = {};
77
+ let added = 0;
78
+ for (const event of events) {
79
+ if (!settings.hooks[event]) settings.hooks[event] = [];
80
+ const has = settings.hooks[event].some(g => g.hooks?.some(h => h.command?.includes('dashboard-hook')));
81
+ if (!has) {
82
+ settings.hooks[event].push({ _source: hookSource, hooks: [{ type: 'command', command: `~/.gemini/hooks/dashboard-hook.sh ${event}` }] });
83
+ added++;
84
+ }
85
+ }
86
+ return added;
87
+ }
88
+
89
+ module.exports = { atomicWriteJSON, buildHookEntry, deployHookScript, configureClaudeHooks, removeAllClaudeHooks, configureGeminiHooks };
@@ -0,0 +1 @@
1
+ { "type": "module" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-agent-session-center",
3
- "version": "2.4.0",
3
+ "version": "2.4.3",
4
4
  "description": "A real-time dashboard for monitoring AI agent sessions (Claude Code, Gemini CLI, Codex) with 3D visualization",
5
5
  "type": "module",
6
6
  "main": "server/index.ts",
@@ -8,7 +8,7 @@
8
8
  "ai-agent-session-center": "bin/cli.js"
9
9
  },
10
10
  "scripts": {
11
- "dev": "concurrently \"vite\" \"tsx watch server/index.ts\"",
11
+ "dev": "concurrently \"vite --open\" \"tsx watch server/index.ts --no-open\"",
12
12
  "build": "vite build",
13
13
  "start": "tsx server/index.ts",
14
14
  "start:no-open": "tsx server/index.ts --no-open",
@@ -27,8 +27,8 @@
27
27
  "test:watch": "vitest",
28
28
  "test:e2e": "npx playwright test",
29
29
  "test:coverage": "vitest run --coverage",
30
- "electron:dev": "concurrently \"vite\" \"tsx watch server/index.ts\" \"wait-on tcp:3333 && electron .\"",
31
- "electron:build": "npm run build && tsc -p tsconfig.electron.json && electron-builder",
30
+ "electron:dev": "tsc -p tsconfig.electron.json && bash scripts/cjs-rename.sh && concurrently \"vite\" \"tsx watch server/index.ts\" \"wait-on tcp:3333 && electron dist/electron/main.cjs\"",
31
+ "electron:build": "npm run build && tsc -p tsconfig.electron.json && bash scripts/cjs-rename.sh && electron-builder",
32
32
  "electron:build:mac": "npm run electron:build -- --mac",
33
33
  "electron:build:win": "npm run electron:build -- --win",
34
34
  "electron:rebuild": "electron-rebuild -f -w better-sqlite3,node-pty",
@@ -926,7 +926,7 @@ const TEXT_NAMES = new Set([
926
926
  '.gitignore', '.dockerignore', '.editorconfig',
927
927
  ]);
928
928
 
929
- const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2 MB
929
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
930
930
  const MAX_STREAMABLE_SIZE = 100 * 1024 * 1024; // 100 MB (for PDF/image streaming)
931
931
 
932
932
  /** Extensions that can be streamed directly to the browser (not read into JSON). */
@@ -1059,7 +1059,7 @@ router.get('/files/read', (req: Request, res: Response) => {
1059
1059
  return;
1060
1060
  }
1061
1061
 
1062
- if (stat.size > MAX_FILE_SIZE) { res.status(413).json({ error: `File too large (${(stat.size / 1024 / 1024).toFixed(1)} MB, max 2 MB)` }); return; }
1062
+ if (stat.size > MAX_FILE_SIZE) { res.status(413).json({ error: `File too large (${(stat.size / 1024 / 1024).toFixed(1)} MB, max 10 MB)` }); return; }
1063
1063
 
1064
1064
  if (!isTextFile(name)) {
1065
1065
  res.json({ path: relPath, binary: true, size: stat.size, name });
@@ -1123,7 +1123,7 @@ router.get('/files/stream', (req: Request, res: Response) => {
1123
1123
  const fileWriteSchema = z.object({
1124
1124
  root: z.string().min(1),
1125
1125
  path: z.string().min(1).max(1024),
1126
- content: z.string().max(2 * 1024 * 1024), // 2 MB limit
1126
+ content: z.string().max(10 * 1024 * 1024), // 10 MB limit
1127
1127
  });
1128
1128
 
1129
1129
  router.post('/files/write', (req: Request, res: Response) => {
@@ -7,7 +7,11 @@ import { fileURLToPath } from 'url';
7
7
  import type { ServerConfig } from '../src/types/settings.js';
8
8
 
9
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
- const CONFIG_PATH = join(__dirname, '..', 'data', 'server-config.json');
10
+ // In packaged Electron, APP_USER_DATA is set to app.getPath('userData') — a writable directory.
11
+ // In dev/CLI mode, fall back to the local data/ directory.
12
+ const CONFIG_PATH = process.env.APP_USER_DATA
13
+ ? join(process.env.APP_USER_DATA, 'server-config.json')
14
+ : join(__dirname, '..', 'data', 'server-config.json');
11
15
 
12
16
  const DEFAULTS: ServerConfig = {
13
17
  port: 3333,
@@ -275,11 +275,19 @@ export function matchSession(
275
275
  && (Date.now() - (s.endedAt || 0)) < 30 * 60 * 1000) {
276
276
  candidates.push({ oldId, s, endedAt: s.endedAt || 0 });
277
277
  }
278
- // Match 2: Safety net zombie SSH sessions that slipped through cleanup
278
+ // Match 2: Idle sessions with ServerRestart event (process survived restart,
279
+ // PID match failed because PID wasn't cached or changed)
280
+ if (s.status === SESSION_STATUS.IDLE
281
+ && s.events?.some(e => e.type === 'ServerRestart')
282
+ && !s.terminalId) {
283
+ candidates.push({ oldId, s, endedAt: s.lastActivityAt || 0 });
284
+ }
285
+ // Match 3: Safety net — zombie SSH sessions that slipped through cleanup
279
286
  // (non-ended, source=ssh, no terminalId, stale for >60s)
280
287
  if (s.source === 'ssh'
281
288
  && s.status !== SESSION_STATUS.ENDED
282
289
  && !s.terminalId
290
+ && !s.events?.some(e => e.type === 'ServerRestart')
283
291
  && s.lastActivityAt && (Date.now() - s.lastActivityAt) > 60_000) {
284
292
  candidates.push({ oldId, s, endedAt: s.lastActivityAt || 0 });
285
293
  }
@@ -319,13 +327,15 @@ export function matchSession(
319
327
 
320
328
  // Priority 1.5: Match by cached PID — when Claude resumes with a new session_id
321
329
  // but the same process (e.g., `claude --resume` creates a new session internally),
322
- // link back to the same SSH terminal session instead of creating a duplicate card.
330
+ // link back to the same session instead of creating a duplicate card.
331
+ // Note: terminalId may be null after server restart (PTY died but Claude process
332
+ // survived). The PID match is a strong signal — re-key regardless of terminal state.
323
333
  if (!session && hookData.claude_pid && hook_event_name === EVENT_TYPES.SESSION_START) {
324
334
  const pid = Number(hookData.claude_pid);
325
335
  const existingSessionId = pidToSession.get(pid);
326
336
  if (existingSessionId && existingSessionId !== session_id) {
327
337
  const existingSession = sessions.get(existingSessionId);
328
- if (existingSession && existingSession.terminalId) {
338
+ if (existingSession) {
329
339
  session = reKeyResumedSession(sessions, existingSession, session_id, existingSessionId, pidToSession);
330
340
  consumePendingLink(existingSession.projectPath || '');
331
341
  log.info('session', `Re-keyed session ${existingSessionId?.slice(0, 8)} -> ${session_id?.slice(0, 8)} (via cached PID=${pid}, same process new session_id)`);
@@ -1 +0,0 @@
1
- import{j as t,r as m,a as C}from"./index-DS3KKkg_.js";import{u as d}from"./useQuery-C-SRwqqC.js";import{m as r,R as f,B as y,C as j,X as g,Y as v,T as b,n as _,o as S}from"./Charts.module-Dx9gJPQR.js";import"./with-selector-C0N9xw7F.js";async function u(e){const a=await C(e);if(!a.ok)throw new Error(`API error: ${a.status}`);return a.json()}function n(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":String(e)}function N(e,a){const s=a===0?0:Math.max(0,Math.min(1,e/a)),l=Math.round(18+-18*s),i=Math.round(18+237*s),o=Math.round(42+94*s);return`rgb(${l},${i},${o})`}const p=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];function K(){const{data:e}=d({queryKey:["analytics-summary"],queryFn:()=>u("/api/db/analytics/summary"),staleTime:3e4}),{data:a}=d({queryKey:["analytics-tools"],queryFn:()=>u("/api/db/analytics/tools"),staleTime:3e4}),{data:s}=d({queryKey:["analytics-projects"],queryFn:()=>u("/api/db/analytics/projects"),staleTime:3e4}),{data:l}=d({queryKey:["analytics-heatmap"],queryFn:()=>u("/api/db/analytics/heatmap"),staleTime:3e4});return t.jsxs("div",{className:r.analyticsView,"data-testid":"analytics-view",children:[t.jsx(T,{summary:e??null}),t.jsxs("div",{className:r.analyticsGrid,children:[t.jsxs("div",{className:r.analyticsCard,children:[t.jsx("h4",{children:"Tool Usage"}),t.jsx($,{data:a??[]})]}),t.jsxs("div",{className:r.analyticsCard,children:[t.jsx("h4",{children:"Active Projects"}),t.jsx(A,{data:s??[]})]}),t.jsxs("div",{className:r.analyticsCard,style:{gridColumn:"1 / -1"},children:[t.jsx("h4",{children:"Activity Heatmap"}),t.jsx(w,{data:l??[]})]})]})]})}function T({summary:e}){const a=[{label:"Total Sessions",value:n(e?.total_sessions??0),detail:"all time"},{label:"Total Prompts",value:n(e?.total_prompts??0),detail:"all time"},{label:"Total Tool Calls",value:n(e?.total_tool_calls??0),detail:"all time"},{label:"Active Sessions",value:n(e?.active_sessions??0),detail:"currently running"},{label:"Most Used Tool",value:e?.most_used_tool?.tool_name??"N/A",detail:e?.most_used_tool?n(e.most_used_tool.count)+" calls":""},{label:"Busiest Project",value:e?.busiest_project?.name??"N/A",detail:e?.busiest_project?n(e.busiest_project.count)+" sessions":""}];return t.jsx("div",{className:r.analyticsSummary,children:a.map(s=>t.jsxs("div",{className:r.summaryStat,children:[t.jsx("div",{className:r.statLabel,children:s.label}),t.jsx("div",{className:r.statValue,children:s.value}),t.jsx("div",{className:r.statDetail,children:s.detail})]},s.label))})}function $({data:e}){const a=e.slice(0,15);return a.length===0?t.jsx(h,{message:"No tool data"}):t.jsx(f,{width:"100%",height:Math.max(200,a.length*28),children:t.jsxs(y,{data:a,layout:"vertical",margin:{top:4,right:40,bottom:4,left:100},children:[t.jsx(j,{strokeDasharray:"3 3",stroke:"rgba(255,255,255,0.04)"}),t.jsx(g,{type:"number",tick:{fill:"#8888aa",fontSize:10}}),t.jsx(v,{type:"category",dataKey:"tool_name",tick:{fill:"#8888aa",fontSize:10},width:96}),t.jsx(b,{contentStyle:{background:"#12122a",border:"1px solid #00e5ff",borderRadius:4,fontSize:11,color:"#e0e0ff"},formatter:((s,l,i)=>[`${n(s)} (${i.payload.percentage}%)`,"Calls"])}),t.jsx(_,{dataKey:"count",radius:[0,4,4,0],children:a.map((s,l)=>t.jsx(S,{fill:"#00e5ff",fillOpacity:.85},l))})]})})}function A({data:e}){const a=m.useMemo(()=>[...e].sort((s,l)=>l.session_count-s.session_count).slice(0,15),[e]);return a.length===0?t.jsx(h,{message:"No project data"}):t.jsx(f,{width:"100%",height:Math.max(200,a.length*28),children:t.jsxs(y,{data:a,layout:"vertical",margin:{top:4,right:40,bottom:4,left:120},children:[t.jsx(j,{strokeDasharray:"3 3",stroke:"rgba(255,255,255,0.04)"}),t.jsx(g,{type:"number",tick:{fill:"#8888aa",fontSize:10}}),t.jsx(v,{type:"category",dataKey:"project_name",tick:{fill:"#8888aa",fontSize:10},width:116}),t.jsx(b,{contentStyle:{background:"#12122a",border:"1px solid #00e5ff",borderRadius:4,fontSize:11,color:"#e0e0ff"},formatter:(s=>[n(s)+" sessions","Sessions"])}),t.jsx(_,{dataKey:"session_count",radius:[0,4,4,0],children:a.map((s,l)=>t.jsx(S,{fill:"#00ff88",fillOpacity:.85},l))})]})})}function w({data:e}){const{grid:a,maxVal:s}=m.useMemo(()=>{const l=new Map;let i=0;for(const o of e){const c=`${o.day_of_week}-${o.hour}`;l.set(c,o.count),o.count>i&&(i=o.count)}return{grid:l,maxVal:i}},[e]);return e.length===0?t.jsx(h,{message:"No heatmap data"}):t.jsxs("div",{style:{display:"grid",gridTemplateColumns:"40px repeat(24, 14px)",gridTemplateRows:"14px repeat(7, 14px)",gap:"2px",alignItems:"center"},children:[t.jsx("div",{}),Array.from({length:24},(l,i)=>t.jsx("div",{style:{fontSize:"9px",color:"#8888aa",textAlign:"center"},children:i},`h-${i}`)),Array.from({length:7},(l,i)=>t.jsxs(m.Fragment,{children:[t.jsx("div",{style:{fontSize:"10px",color:"#8888aa",textAlign:"right",paddingRight:"4px"},children:p[i]}),Array.from({length:24},(o,c)=>{const x=a.get(`${i}-${c}`)??0;return t.jsx("div",{className:r.heatmapCell,title:`${p[i]} ${String(c).padStart(2,"0")}:00 - ${x} events`,style:{backgroundColor:N(x,s)}},`${i}-${c}`)})]},`row-${i}`))]})}function h({message:e}){return t.jsx("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",height:"100%",minHeight:"120px",color:"var(--text-dim, #555577)",fontSize:"0.85rem"},children:e})}export{K as default};
@@ -1 +0,0 @@
1
- ._historyView_10lx5_9{grid-area:main;padding:20px;overflow-y:auto}._historyControls_10lx5_11{display:flex;gap:12px;margin-bottom:20px;flex-wrap:wrap;align-items:center}._historyControls_10lx5_11 input,._historyControls_10lx5_11 select{background:var(--bg-card);border:1px solid var(--border-accent);color:var(--text-primary);font-family:var(--font-mono);font-size:11px;padding:8px 12px;border-radius:4px;outline:none}._historyControls_10lx5_11 input:focus,._historyControls_10lx5_11 select:focus{border-color:var(--accent-cyan)}._searchInput_10lx5_14{flex:1;min-width:200px}._historyRow_10lx5_16{display:grid;grid-template-columns:1.5fr 1fr auto auto auto auto auto auto 24px;gap:12px;padding:12px 16px;background:var(--bg-card);border:1px solid var(--border-faint);border-radius:8px;margin-bottom:8px;cursor:pointer;transition:all .2s;align-items:center;font-size:12px}._historyRow_10lx5_16:hover{background:var(--bg-card-hover);border-color:var(--border-accent)}._historyTitle_10lx5_19{font-weight:700;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._historyProject_10lx5_20{color:var(--text-secondary);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._historyDate_10lx5_21{color:var(--text-secondary);font-size:10px}._historyDuration_10lx5_22{color:var(--text-dim);font-size:10px}._historyStatus_10lx5_24{font-size:9px;font-weight:700;letter-spacing:1px;padding:2px 8px;border-radius:3px}._historyStatus_10lx5_24._idle_10lx5_25{color:var(--accent-green);border:1px solid rgba(0,255,136,.3);background:#00ff8814}._historyStatus_10lx5_24._working_10lx5_26{color:var(--accent-orange);border:1px solid rgba(255,145,0,.3);background:#ff910014}._historyStatus_10lx5_24._ended_10lx5_27{color:var(--accent-red);border:1px solid rgba(255,51,85,.3);background:#ff335514}._historyStatus_10lx5_24._prompting_10lx5_28{color:var(--accent-cyan);border:1px solid var(--border-accent-strong);background:var(--bg-accent)}._historyStatus_10lx5_24._archived_10lx5_29{color:var(--accent-purple);border:1px solid rgba(170,102,255,.3);background:#aa66ff14}._historyPrompts_10lx5_31,._historyTools_10lx5_31{color:var(--text-dim);font-size:10px}._historyBranch_10lx5_32{color:var(--accent-purple);font-size:10px}._historyDelete_10lx5_34{background:none;border:none;color:var(--text-dim);font-size:16px;cursor:pointer;padding:0;line-height:1;opacity:0;transition:opacity .2s,color .2s}._historyRow_10lx5_16:hover ._historyDelete_10lx5_34{opacity:1}._historyDelete_10lx5_34:hover{color:var(--accent-red)}._pagination_10lx5_38{display:flex;justify-content:center;gap:8px;margin-top:16px;padding:12px}._paginationBtn_10lx5_39{background:var(--bg-card);border:1px solid var(--border-accent);color:var(--text-secondary);padding:6px 12px;border-radius:4px;font-family:var(--font-mono);font-size:11px;cursor:pointer}._paginationBtn_10lx5_39:hover{border-color:var(--accent-cyan)}._paginationBtn_10lx5_39._active_10lx5_41{background:var(--bg-accent);color:var(--accent-cyan);border-color:var(--accent-cyan)}._timelineView_10lx5_45{grid-area:main;padding:20px;overflow-y:auto}._timelineControls_10lx5_46{display:flex;gap:12px;margin-bottom:20px;align-items:center}._timelineControls_10lx5_46 input,._timelineControls_10lx5_46 select{background:var(--bg-card);border:1px solid var(--border-accent);color:var(--text-primary);font-family:var(--font-mono);font-size:11px;padding:8px 12px;border-radius:4px;outline:none}._timelineControls_10lx5_46 input:focus,._timelineControls_10lx5_46 select:focus{border-color:var(--accent-cyan)}._timelineChart_10lx5_50{min-height:350px;background:var(--bg-card);border:1px solid var(--border-faint);border-radius:12px;padding:20px;position:relative}._analyticsView_10lx5_54{grid-area:main;padding:20px;overflow-y:auto}._analyticsSummary_10lx5_56{display:flex;gap:16px;margin-bottom:24px;flex-wrap:wrap}._summaryStat_10lx5_57{background:var(--bg-card);border:1px solid var(--border-faint);border-radius:8px;padding:16px 20px;flex:1;min-width:150px;text-align:center}._statLabel_10lx5_58{font-size:9px;letter-spacing:1.5px;color:var(--text-dim);text-transform:uppercase;margin-bottom:6px}._statValue_10lx5_59{font-size:24px;font-weight:700;color:var(--text-primary)}._statDetail_10lx5_60{font-size:10px;color:var(--text-secondary);margin-top:4px}._analyticsGrid_10lx5_62{display:grid;grid-template-columns:1fr 1fr;gap:20px}._analyticsCard_10lx5_63{background:var(--bg-card);border:1px solid var(--border-faint);border-radius:12px;padding:20px;min-height:300px}._analyticsCard_10lx5_63 h4{font-size:11px;letter-spacing:1.5px;color:var(--text-dim);text-transform:uppercase;margin-bottom:16px}._chartTooltip_10lx5_68{position:fixed;background:var(--bg-card);border:1px solid var(--accent-cyan);padding:8px 12px;border-radius:4px;font-size:10px;color:var(--text-primary);pointer-events:none;z-index:1000;box-shadow:0 0 20px var(--glow-accent)}._heatmapCell_10lx5_69{width:14px;height:14px;border-radius:2px;transition:opacity .2s}@media(max-width:960px){._analyticsGrid_10lx5_62{grid-template-columns:1fr}}@media(max-width:640px){._historyControls_10lx5_11{flex-direction:column}._historyRow_10lx5_16{grid-template-columns:1fr}._analyticsGrid_10lx5_62{grid-template-columns:1fr;gap:12px}._analyticsCard_10lx5_63{padding:14px;min-height:200px}._analyticsCard_10lx5_63 h4{font-size:10px;letter-spacing:1px;margin-bottom:10px}._analyticsSummary_10lx5_56{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px}._summaryStat_10lx5_57{min-width:0;padding:10px 12px}._statValue_10lx5_59{font-size:18px}._statLabel_10lx5_58{font-size:8px;letter-spacing:1px}._statDetail_10lx5_60{font-size:9px}._analyticsView_10lx5_54,._timelineView_10lx5_45,._historyView_10lx5_9{padding:12px 10px}._timelineChart_10lx5_50{padding:12px;min-height:250px}._timelineControls_10lx5_46{flex-wrap:wrap;gap:8px}._timelineControls_10lx5_46 input,._timelineControls_10lx5_46 select{min-height:44px;font-size:12px;flex:1 1 auto}._historyControls_10lx5_11 input,._historyControls_10lx5_11 select{min-height:44px;font-size:12px}._historyRow_10lx5_16{padding:10px 12px;gap:6px;font-size:11px}._heatmapCell_10lx5_69{width:12px;height:12px}}@media(max-width:480px){._analyticsSummary_10lx5_56{gap:6px}._summaryStat_10lx5_57{padding:8px 10px}._statValue_10lx5_59{font-size:16px}._analyticsCard_10lx5_63{padding:10px;min-height:180px}._analyticsView_10lx5_54,._timelineView_10lx5_45,._historyView_10lx5_9{padding:10px 8px}._timelineChart_10lx5_50{padding:10px;min-height:200px}}@media(max-width:375px){._analyticsSummary_10lx5_56{grid-template-columns:1fr;gap:4px}._summaryStat_10lx5_57{padding:6px 8px}._statValue_10lx5_59{font-size:14px}}
@@ -1 +0,0 @@
1
- ._container_ip9o0_5{display:flex;flex-direction:column;height:100%;padding:var(--layout-pad, 24px);gap:16px}._filters_ip9o0_15{display:flex;flex-wrap:wrap;gap:8px;align-items:center}._filterGroup_ip9o0_22{display:flex;align-items:center;gap:4px}._filterLabel_ip9o0_28{font-size:.7rem;color:var(--text-dim, #555577);text-transform:uppercase;letter-spacing:.04em}._filterSelect_ip9o0_35,._filterInput_ip9o0_36{padding:6px 10px;background:var(--bg-primary, #0a0a1a);border:1px solid var(--border-subtle, rgba(255, 255, 255, .06));border-radius:4px;color:var(--text-primary, #e0e0ff);font-size:.8rem;font-family:var(--font-mono, monospace);outline:none}._filterSelect_ip9o0_35:focus,._filterInput_ip9o0_36:focus{border-color:var(--accent-cyan, #00e5ff)}._sortToggle_ip9o0_52{padding:6px 10px;background:transparent;border:1px solid var(--border-subtle, rgba(255, 255, 255, .06));border-radius:4px;color:var(--text-secondary, #8888aa);font-size:.75rem;font-family:var(--font-mono, monospace);cursor:pointer}._sortToggle_ip9o0_52:hover{color:var(--accent-cyan, #00e5ff);border-color:var(--accent-cyan, #00e5ff)}._results_ip9o0_70{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:2px}._emptyState_ip9o0_78{display:flex;align-items:center;justify-content:center;padding:48px 16px;color:var(--text-dim, #555577);font-size:.9rem}._row_ip9o0_87{display:grid;grid-template-columns:1fr 120px 150px 80px 80px 70px 70px 32px;align-items:center;gap:8px;padding:10px 12px;background:var(--bg-card, #12122a);border:1px solid var(--border-subtle, rgba(255, 255, 255, .06));border-radius:6px;cursor:pointer;transition:border-color .15s,background .15s}._row_ip9o0_87:hover{border-color:var(--border-accent, rgba(0, 229, 255, .15));background:var(--bg-card-hover, #1a1a3a)}._rowTitle_ip9o0_105{font-size:.85rem;color:var(--text-primary, #e0e0ff);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._rowProject_ip9o0_113{font-size:.75rem;color:var(--accent-cyan, #00e5ff);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._rowDate_ip9o0_121,._rowDuration_ip9o0_127{font-size:.75rem;color:var(--text-secondary, #8888aa);white-space:nowrap}._rowStatus_ip9o0_133{font-size:.7rem;font-weight:600;text-transform:uppercase;padding:2px 6px;border-radius:3px;text-align:center}._rowStatus_ip9o0_133[data-status=idle]{color:var(--accent-green, #00ff88);background:#00ff881a}._rowStatus_ip9o0_133[data-status=working]{color:var(--accent-orange, #ff9100);background:#ff91001a}._rowStatus_ip9o0_133[data-status=ended]{color:var(--accent-red, #ff3355);background:#ff33551a}._rowStatus_ip9o0_133[data-status=waiting]{color:var(--accent-cyan, #00e5ff);background:#00e5ff1a}._rowStatus_ip9o0_133[data-status=approval]{color:#fc0;background:#ffcc001a}._rowMeta_ip9o0_163{font-size:.7rem;color:var(--text-dim, #555577);text-align:center}._deleteBtn_ip9o0_169{background:none;border:none;color:var(--text-dim, #555577);font-size:1rem;cursor:pointer;padding:2px 4px;border-radius:4px;line-height:1}._deleteBtn_ip9o0_169:hover{color:var(--accent-red, #ff3355);background:#ff33551a}._pagination_ip9o0_187{display:flex;align-items:center;justify-content:center;gap:4px;padding:8px 0}._pageBtn_ip9o0_195{padding:4px 10px;background:transparent;border:1px solid var(--border-subtle, rgba(255, 255, 255, .06));border-radius:4px;color:var(--text-secondary, #8888aa);font-size:.75rem;font-family:var(--font-mono, monospace);cursor:pointer}._pageBtn_ip9o0_195:hover:not(:disabled){border-color:var(--accent-cyan, #00e5ff);color:var(--accent-cyan, #00e5ff)}._pageBtn_ip9o0_195:disabled{opacity:.3;cursor:default}._pageBtnActive_ip9o0_216{background:var(--bg-accent, rgba(0, 229, 255, .1));border-color:var(--accent-cyan, #00e5ff);color:var(--accent-cyan, #00e5ff)}._pageEllipsis_ip9o0_222{color:var(--text-dim, #555577);padding:0 4px}._detailOverlay_ip9o0_229{position:fixed;inset:0;background:#000000b3;display:flex;align-items:center;justify-content:center;z-index:8000}._detailCard_ip9o0_239{background:var(--bg-card, #12122a);border:1px solid var(--border-accent, rgba(0, 229, 255, .15));border-radius:12px;padding:24px;max-width:900px;width:90%;max-height:80vh;display:flex;flex-direction:column;gap:16px;overflow:hidden}._detailTabs_ip9o0_253{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}._detailTabPanel_ip9o0_261{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}._detailHeader_ip9o0_269{display:flex;align-items:center;justify-content:space-between;gap:12px}._detailTitle_ip9o0_276{font-size:1.1rem;color:var(--accent-cyan, #00e5ff);margin:0}._detailMeta_ip9o0_282{display:flex;gap:16px;font-size:.75rem;color:var(--text-secondary, #8888aa)}._detailCloseBtn_ip9o0_289{background:none;border:none;color:var(--text-secondary, #8888aa);font-size:1.2rem;cursor:pointer;padding:4px 8px}._detailCloseBtn_ip9o0_289:hover{color:var(--text-primary, #e0e0ff)}._detailBody_ip9o0_302{flex:1;overflow-y:auto}._convoEntry_ip9o0_307{padding:8px 12px;border-left:3px solid transparent;margin-bottom:4px;border-radius:0 4px 4px 0;position:relative}._convoEntryHeader_ip9o0_315{display:flex;align-items:center;justify-content:space-between;gap:8px}._copyBtn_ip9o0_322{background:none;border:1px solid transparent;color:var(--text-dim, #555577);font-size:.8rem;cursor:pointer;padding:2px 6px;border-radius:4px;line-height:1;opacity:0;transition:opacity .15s,color .15s,border-color .15s}._convoEntry_ip9o0_307:hover ._copyBtn_ip9o0_322{opacity:1}._copyBtn_ip9o0_322:hover{color:var(--accent-cyan, #00e5ff);border-color:var(--accent-cyan, #00e5ff)}._convoPrompt_ip9o0_344{border-left-color:var(--accent-cyan, #00e5ff);background:#00e5ff08}._convoResponse_ip9o0_349{border-left-color:var(--accent-green, #00ff88);background:#00ff8808}._convoTime_ip9o0_354{font-size:.7rem;color:var(--text-dim, #555577);margin-bottom:2px}._convoText_ip9o0_360{font-size:.8rem;color:var(--text-primary, #e0e0ff);white-space:pre-wrap;word-break:break-word}._activityEntry_ip9o0_367{display:flex;gap:8px;padding:4px 0;font-size:.75rem;align-items:baseline}._activityTime_ip9o0_375{color:var(--text-dim, #555577);white-space:nowrap;flex-shrink:0}._activityBadge_ip9o0_381{padding:1px 6px;border-radius:3px;font-size:.7rem;font-weight:600;white-space:nowrap;flex-shrink:0}._activityBadgeTool_ip9o0_390{color:var(--accent-orange, #ff9100);background:#ff91001a}._activityBadgeEvent_ip9o0_395{color:var(--accent-purple, #aa66ff);background:#aa66ff1a}._activityDetail_ip9o0_400{color:var(--text-secondary, #8888aa);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:768px){._row_ip9o0_87{grid-template-columns:1fr 80px 32px}._rowProject_ip9o0_113,._rowDate_ip9o0_121,._rowDuration_ip9o0_127,._rowMeta_ip9o0_163:nth-child(6),._rowMeta_ip9o0_163:nth-child(7){display:none}._filters_ip9o0_15{flex-direction:column;align-items:stretch}}
@@ -1 +0,0 @@
1
- import{r as _,j as t,u as w,a as j}from"./index-DS3KKkg_.js";import{u as g}from"./useQuery-C-SRwqqC.js";function S({value:e,onChange:s,placeholder:l="Search...",debounceMs:c=300,className:r,inputClassName:u}){const[n,m]=_.useState(e??""),p=_.useRef(null);_.useEffect(()=>{e!==void 0&&m(e)},[e]);const d=_.useCallback(h=>{p.current&&clearTimeout(p.current),p.current=setTimeout(()=>s(h),c)},[s,c]);_.useEffect(()=>()=>{p.current&&clearTimeout(p.current)},[]);function v(h){const i=h.target.value;m(i),d(i)}function x(){m(""),p.current&&clearTimeout(p.current),s("")}return t.jsxs("div",{className:r,style:{position:"relative",display:"flex",alignItems:"center"},children:[t.jsx("input",{type:"text",value:n,onChange:v,placeholder:l,className:u,style:u?void 0:{width:"100%",padding:"8px 32px 8px 12px",background:"var(--bg-primary, #0a0a1a)",border:"1px solid var(--border-subtle, rgba(255,255,255,0.06))",borderRadius:"6px",color:"var(--text-primary, #e0e0ff)",fontSize:"0.85rem",fontFamily:"var(--font-mono, monospace)",outline:"none"}}),n&&t.jsx("button",{onClick:x,"aria-label":"Clear search",style:{position:"absolute",right:"8px",background:"none",border:"none",color:"var(--text-secondary, #8888aa)",cursor:"pointer",fontSize:"0.9rem",padding:"2px 4px",lineHeight:1},children:"x"})]})}function B({tabs:e,activeTab:s,onTabChange:l,containerClassName:c,panelClassName:r,tabListClassName:u,tabClassName:n,activeTabClassName:m}){return t.jsxs("div",{className:c,children:[t.jsx("div",{role:"tablist",className:u,style:u?void 0:{display:"flex",gap:"2px",borderBottom:"1px solid var(--border-subtle, rgba(255,255,255,0.06))",marginBottom:"12px"},children:e.map(p=>{const d=s===p.id,v=[n,d&&m].filter(Boolean).join(" ");return t.jsx("button",{role:"tab","aria-selected":d,onClick:()=>l(p.id),className:v||void 0,style:v?void 0:{padding:"8px 16px",background:d?"var(--bg-accent, rgba(0,229,255,0.1))":"transparent",border:"none",borderBottom:d?"2px solid var(--accent-cyan, #00e5ff)":"2px solid transparent",color:d?"var(--accent-cyan, #00e5ff)":"var(--text-secondary, #8888aa)",cursor:"pointer",fontSize:"0.85rem",fontFamily:"var(--font-mono, monospace)",transition:"color 0.15s, background 0.15s"},children:p.label},p.id)})}),t.jsx("div",{role:"tabpanel",className:r,children:e.find(p=>p.id===s)?.content})]})}const C="_container_ip9o0_5",E="_filters_ip9o0_15",D="_filterGroup_ip9o0_22",k="_filterLabel_ip9o0_28",F="_filterSelect_ip9o0_35",$="_filterInput_ip9o0_36",P="_sortToggle_ip9o0_52",q="_results_ip9o0_70",L="_emptyState_ip9o0_78",M="_row_ip9o0_87",I="_rowTitle_ip9o0_105",R="_rowProject_ip9o0_113",A="_rowDate_ip9o0_121",H="_rowDuration_ip9o0_127",G="_rowStatus_ip9o0_133",U="_rowMeta_ip9o0_163",O="_deleteBtn_ip9o0_169",z="_pagination_ip9o0_187",K="_pageBtn_ip9o0_195",Q="_pageBtnActive_ip9o0_216",W="_pageEllipsis_ip9o0_222",Z="_detailOverlay_ip9o0_229",J="_detailCard_ip9o0_239",V="_detailTabs_ip9o0_253",X="_detailTabPanel_ip9o0_261",Y="_detailHeader_ip9o0_269",tt="_detailTitle_ip9o0_276",et="_detailMeta_ip9o0_282",at="_detailCloseBtn_ip9o0_289",st="_detailBody_ip9o0_302",ot="_convoEntry_ip9o0_307",it="_convoEntryHeader_ip9o0_315",nt="_copyBtn_ip9o0_322",rt="_convoPrompt_ip9o0_344",lt="_convoResponse_ip9o0_349",ct="_convoTime_ip9o0_354",dt="_convoText_ip9o0_360",pt="_activityEntry_ip9o0_367",ut="_activityTime_ip9o0_375",mt="_activityBadge_ip9o0_381",_t="_activityBadgeTool_ip9o0_390",vt="_activityBadgeEvent_ip9o0_395",ht="_activityDetail_ip9o0_400",a={container:C,filters:E,filterGroup:D,filterLabel:k,filterSelect:F,filterInput:$,sortToggle:P,results:q,emptyState:L,row:M,rowTitle:I,rowProject:R,rowDate:A,rowDuration:H,rowStatus:G,rowMeta:U,deleteBtn:O,pagination:z,pageBtn:K,pageBtnActive:Q,pageEllipsis:W,detailOverlay:Z,detailCard:J,detailTabs:V,detailTabPanel:X,detailHeader:Y,detailTitle:tt,detailMeta:et,detailCloseBtn:at,detailBody:st,convoEntry:ot,convoEntryHeader:it,copyBtn:nt,convoPrompt:rt,convoResponse:lt,convoTime:ct,convoText:dt,activityEntry:pt,activityTime:ut,activityBadge:mt,activityBadgeTool:_t,activityBadgeEvent:vt,activityDetail:ht},N=50;function f(e){if(e<1e3)return"<1s";const s=Math.floor(e/1e3);if(s<60)return`${s}s`;const l=Math.floor(s/60);return l<60?`${l}m ${s%60}s`:`${Math.floor(l/60)}h ${l%60}m`}function xt(e){return e?new Date(e).toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}):"--"}function b(e){return new Date(e).toLocaleTimeString("en-US",{hour12:!1})}function yt(e){const s=new URLSearchParams;e.query&&s.set("query",e.query),e.project&&s.set("project",e.project),e.status==="archived"?s.set("archived","true"):e.status&&s.set("status",e.status),e.dateFrom&&s.set("dateFrom",String(new Date(e.dateFrom).getTime())),e.dateTo&&s.set("dateTo",String(new Date(e.dateTo+"T23:59:59").getTime()));const l={date:"started_at",duration:"last_activity_at",prompts:"started_at",tools:"started_at"};return s.set("sortBy",l[e.sortBy]||"started_at"),s.set("sortDir",e.sortDir),s.set("page",String(e.page)),s.set("pageSize",String(N)),s.toString()}function wt(){const e=w(),[s,l]=_.useState({query:"",project:"",status:"",dateFrom:"",dateTo:"",sortBy:"date",sortDir:"desc",page:1}),[c,r]=_.useState(null),{data:u}=g({queryKey:["db-projects"],queryFn:async()=>{const o=await j("/api/db/projects");if(!o.ok)throw new Error("Failed to load projects");return o.json()},staleTime:6e4}),{data:n,isLoading:m}=g({queryKey:["db-sessions",s],queryFn:async()=>{const o=await j(`/api/db/sessions?${yt(s)}`);if(!o.ok)throw new Error("Failed to load sessions");return o.json()}}),{data:p}=g({queryKey:["db-session-detail",c],queryFn:async()=>{if(!c)return null;const o=await j(`/api/db/sessions/${encodeURIComponent(c)}`);if(!o.ok)throw new Error("Failed to load session detail");return o.json()},enabled:!!c}),d=_.useCallback((o,y)=>{l(T=>({...T,[o]:y,page:o==="page"?y:1}))},[]),v=_.useCallback(async(o,y)=>{o.stopPropagation(),window.confirm("Delete this session from history? This cannot be undone.")&&(await j(`/api/db/sessions/${encodeURIComponent(y)}`,{method:"DELETE"}),e.invalidateQueries({queryKey:["db-sessions"]}))},[e]),x=n?.sessions??[],h=n?.total??0,i=Math.ceil(h/N);return t.jsxs("div",{className:a.container,"data-testid":"history-view",children:[t.jsxs("div",{className:a.filters,children:[t.jsx(S,{value:s.query,onChange:o=>d("query",o),placeholder:"Search prompts..."}),t.jsxs("div",{className:a.filterGroup,children:[t.jsx("span",{className:a.filterLabel,children:"Project"}),t.jsxs("select",{className:a.filterSelect,value:s.project,onChange:o=>d("project",o.target.value),children:[t.jsx("option",{value:"",children:"All"}),u?.map(o=>t.jsx("option",{value:o.project_path,children:o.project_name},o.project_path))]})]}),t.jsxs("div",{className:a.filterGroup,children:[t.jsx("span",{className:a.filterLabel,children:"Status"}),t.jsxs("select",{className:a.filterSelect,value:s.status,onChange:o=>d("status",o.target.value),children:[t.jsx("option",{value:"",children:"All"}),t.jsx("option",{value:"idle",children:"Idle"}),t.jsx("option",{value:"working",children:"Working"}),t.jsx("option",{value:"waiting",children:"Waiting"}),t.jsx("option",{value:"ended",children:"Ended"}),t.jsx("option",{value:"archived",children:"Archived"})]})]}),t.jsxs("div",{className:a.filterGroup,children:[t.jsx("span",{className:a.filterLabel,children:"From"}),t.jsx("input",{type:"date",className:a.filterInput,value:s.dateFrom,onChange:o=>d("dateFrom",o.target.value)})]}),t.jsxs("div",{className:a.filterGroup,children:[t.jsx("span",{className:a.filterLabel,children:"To"}),t.jsx("input",{type:"date",className:a.filterInput,value:s.dateTo,onChange:o=>d("dateTo",o.target.value)})]}),t.jsxs("div",{className:a.filterGroup,children:[t.jsx("span",{className:a.filterLabel,children:"Sort"}),t.jsxs("select",{className:a.filterSelect,value:s.sortBy,onChange:o=>d("sortBy",o.target.value),children:[t.jsx("option",{value:"date",children:"Date"}),t.jsx("option",{value:"duration",children:"Activity"}),t.jsx("option",{value:"prompts",children:"Prompts"}),t.jsx("option",{value:"tools",children:"Tools"})]}),t.jsx("button",{className:a.sortToggle,onClick:()=>d("sortDir",s.sortDir==="desc"?"asc":"desc"),children:s.sortDir.toUpperCase()})]})]}),t.jsxs("div",{className:a.results,children:[m&&t.jsx("div",{className:a.emptyState,children:"Loading..."}),!m&&x.length===0&&t.jsx("div",{className:a.emptyState,children:"No sessions found"}),x.map(o=>t.jsx(jt,{session:o,onClick:()=>r(o.id),onDelete:y=>v(y,o.id)},o.id))]}),i>1&&t.jsx(ft,{currentPage:s.page,totalPages:i,onPageChange:o=>d("page",o)}),c&&p&&t.jsx(bt,{detail:p,onClose:()=>r(null)})]})}function jt({session:e,onClick:s,onDelete:l}){const c=e.ended_at&&e.started_at?f(e.ended_at-e.started_at):e.started_at?f(Date.now()-e.started_at):"--";return t.jsxs("div",{className:a.row,onClick:s,children:[t.jsx("span",{className:a.rowTitle,children:e.title||e.project_name||e.id}),t.jsx("span",{className:a.rowProject,children:e.project_name}),t.jsx("span",{className:a.rowDate,children:xt(e.started_at)}),t.jsx("span",{className:a.rowDuration,children:c}),t.jsx("span",{className:a.rowStatus,"data-status":e.status,children:e.status.toUpperCase()}),t.jsxs("span",{className:a.rowMeta,children:[e.total_prompts," prompts"]}),t.jsxs("span",{className:a.rowMeta,children:[e.total_tool_calls," tools"]}),t.jsx("button",{className:a.deleteBtn,onClick:l,title:"Delete session","aria-label":"Delete session",children:"x"})]})}function ft({currentPage:e,totalPages:s,onPageChange:l}){const c=[];for(let n=1;n<=s;n++)(n===1||n===s||n>=e-2&&n<=e+2)&&c.push(n);const r=[];let u=0;for(const n of c)typeof n=="number"&&(u&&n-u>1&&r.push("ellipsis"),r.push(n),u=n);return t.jsxs("div",{className:a.pagination,children:[t.jsx("button",{className:a.pageBtn,disabled:e<=1,onClick:()=>l(e-1),children:"Prev"}),r.map((n,m)=>n==="ellipsis"?t.jsx("span",{className:a.pageEllipsis,children:"..."},`e-${m}`):t.jsx("button",{className:`${a.pageBtn} ${n===e?a.pageBtnActive:""}`,onClick:()=>l(n),children:n},n)),t.jsx("button",{className:a.pageBtn,disabled:e>=s,onClick:()=>l(e+1),children:"Next"})]})}function gt({text:e}){const[s,l]=_.useState(!1),c=r=>{r.stopPropagation(),navigator.clipboard.writeText(e).then(()=>{l(!0),setTimeout(()=>l(!1),1500)})};return t.jsx("button",{className:a.copyBtn,onClick:c,"aria-label":"Copy to clipboard",title:"Copy to clipboard",children:s?"✓":"⎘"})}function bt({detail:e,onClose:s}){const[l,c]=_.useState("conversation"),{session:r,prompts:u,responses:n,tool_calls:m,events:p}=e,d=[...u.map(i=>({type:"prompt",timestamp:i.timestamp,text:i.text})),...n.map(i=>({type:"response",timestamp:i.timestamp,text:i.text_excerpt}))].sort((i,o)=>i.timestamp-o.timestamp),v=[...m.map(i=>({kind:"tool",label:i.tool_name,detail:i.tool_input_summary,timestamp:i.timestamp})),...p.map(i=>({kind:"event",label:i.event_type,detail:i.detail,timestamp:i.timestamp}))].sort((i,o)=>o.timestamp-i.timestamp),x=r.ended_at&&r.started_at?f(r.ended_at-r.started_at):r.started_at?f(Date.now()-r.started_at):"--",h=[{id:"conversation",label:`Conversation (${d.length})`,content:t.jsxs("div",{className:a.detailBody,children:[d.length===0&&t.jsx("div",{className:a.emptyState,children:"No conversation recorded"}),d.map((i,o)=>t.jsxs("div",{className:`${a.convoEntry} ${i.type==="prompt"?a.convoPrompt:a.convoResponse}`,children:[t.jsxs("div",{className:a.convoEntryHeader,children:[t.jsx("div",{className:a.convoTime,children:b(i.timestamp)}),t.jsx(gt,{text:i.text})]}),t.jsx("div",{className:a.convoText,children:i.text})]},o))]})},{id:"activity",label:`Activity (${v.length})`,content:t.jsxs("div",{className:a.detailBody,children:[v.length===0&&t.jsx("div",{className:a.emptyState,children:"No activity recorded"}),v.map((i,o)=>t.jsxs("div",{className:a.activityEntry,children:[t.jsx("span",{className:a.activityTime,children:b(i.timestamp)}),t.jsx("span",{className:`${a.activityBadge} ${i.kind==="tool"?a.activityBadgeTool:a.activityBadgeEvent}`,children:i.label}),t.jsx("span",{className:a.activityDetail,children:i.detail})]},o))]})}];return t.jsx("div",{className:a.detailOverlay,onClick:s,children:t.jsxs("div",{className:a.detailCard,onClick:i=>i.stopPropagation(),children:[t.jsxs("div",{className:a.detailHeader,children:[t.jsxs("div",{children:[t.jsx("h2",{className:a.detailTitle,children:r.project_name||r.id}),t.jsxs("div",{className:a.detailMeta,children:[t.jsxs("span",{children:["Status: ",r.status.toUpperCase()]}),t.jsxs("span",{children:["Model: ",r.model||"--"]}),t.jsxs("span",{children:["Duration: ",x]}),t.jsxs("span",{children:[r.total_prompts," prompts / ",r.total_tool_calls," tools"]})]})]}),t.jsx("button",{className:a.detailCloseBtn,onClick:s,"aria-label":"Close",children:"x"})]}),t.jsx(B,{tabs:h,activeTab:l,onTabChange:c,containerClassName:a.detailTabs,panelClassName:a.detailTabPanel})]})})}export{wt as default};
@@ -1 +0,0 @@
1
- import{v as x,w as I,r as u,x as S,j as e,y as a}from"./index-DS3KKkg_.js";const D="_controls_uyjqd_6",$="_title_uyjqd_11",B="_stats_uyjqd_13",E="_statsSep_uyjqd_17",T="_content_uyjqd_19",M="_viewGroup_uyjqd_21",H="_groupHeader_uyjqd_22",P="_sessionName_uyjqd_23",R="_label_uyjqd_24",z="_sid_uyjqd_25",G="_itemCount_uyjqd_26",U="_table_uyjqd_28",K="_pos_uyjqd_34",L="_text_uyjqd_36",Q="_date_uyjqd_37",F="_deleteBtn_uyjqd_38",s={controls:D,title:$,stats:B,statsSep:E,content:T,viewGroup:M,groupHeader:H,sessionName:P,label:R,sid:z,itemCount:G,table:U,pos:K,text:L,date:Q,deleteBtn:F};let O=Date.now();function V(){return O++}function W(o){return new Date(o).toLocaleTimeString("en-US",{hour12:!1})}function J(){const o=x(t=>t.queues),v=x(t=>t.add),w=x(t=>t.remove),y=x(t=>t.moveToSession),h=I(t=>t.sessions),[r,k]=u.useState(""),[p,b]=u.useState(""),[d,g]=u.useState(null),m=Array.from(new Set([...o.keys(),...h.keys()])).filter(t=>{const n=o.get(t);return n&&n.length>0}),f=Array.from(o.values()).reduce((t,n)=>t+n.length,0),q=u.useCallback(()=>{const t=p.trim();if(!t||!r)return;const n=o.get(r)??[],i={id:V(),sessionId:r,text:t,position:n.length,createdAt:Date.now()};v(r,i),b(""),S("Prompt added to queue","info",2e3)},[p,r,o,v]),A=u.useCallback(t=>{d&&(y([d.itemId],d.fromSessionId,t),g(null),S("Prompt moved","info",2e3))},[d,y]),N=Array.from(h.entries());return e.jsxs("div",{"data-testid":"queue-view",style:{height:"100%",overflow:"auto"},children:[e.jsx("div",{className:s.controls,children:e.jsx("h2",{className:s.title,children:"PROMPT QUEUE"})}),e.jsxs("div",{className:s.stats,children:[e.jsxs("span",{children:[f," queued prompt",f!==1?"s":""]}),e.jsx("span",{className:s.statsSep,children:"|"}),e.jsxs("span",{children:[m.length," session",m.length!==1?"s":""]})]}),e.jsx("div",{style:{padding:"0 24px 16px"},children:e.jsxs("div",{className:a.queueCompose,children:[e.jsxs("select",{value:r,onChange:t=>k(t.target.value),style:{background:"rgba(255,255,255,0.04)",border:"1px solid var(--border-subtle, rgba(255,255,255,0.08))",borderRadius:"4px",color:"var(--text-primary)",fontFamily:"var(--font-mono)",fontSize:"11px",padding:"6px 8px",minWidth:"180px"},children:[e.jsx("option",{value:"",children:"Select session..."}),N.map(([t,n])=>e.jsxs("option",{value:t,children:[n.projectName||t.slice(0,8),n.title?` — ${n.title}`:""]},t))]}),e.jsx("textarea",{className:a.queueTextarea,placeholder:"Add a prompt to the queue...",rows:2,value:p,onChange:t=>b(t.target.value),onKeyDown:t=>{t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),q())}}),e.jsx("button",{className:`${a.toolbarBtn} ${a.queueAddBtn}`,onClick:q,disabled:!p.trim()||!r,children:"ADD"})]})}),e.jsx("div",{className:s.content,children:m.length===0?e.jsx("div",{style:{textAlign:"center",padding:"40px 0",color:"var(--text-dim)",fontSize:"13px"},children:"No prompts in queue. Add prompts from session detail panels or above."}):m.map(t=>{const n=o.get(t)??[],i=h.get(t);return e.jsxs("div",{className:s.viewGroup,children:[e.jsxs("div",{className:s.groupHeader,children:[e.jsx("span",{className:s.sessionName,children:i?.projectName||"Unknown"}),i?.label&&e.jsx("span",{className:s.label,children:i.label}),e.jsx("span",{className:s.sid,children:t.slice(0,8)}),e.jsxs("span",{className:s.itemCount,children:[n.length," item",n.length!==1?"s":""]})]}),e.jsxs("table",{className:s.table,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:s.pos,children:"#"}),e.jsx("th",{children:"Prompt"}),e.jsx("th",{children:"Added"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:n.map((l,C)=>e.jsxs("tr",{children:[e.jsx("td",{className:s.pos,children:C+1}),e.jsx("td",{className:s.text,children:l.text}),e.jsx("td",{className:s.date,children:W(l.createdAt)}),e.jsxs("td",{children:[e.jsxs("div",{style:{display:"flex",gap:"4px"},children:[e.jsx("button",{className:`${a.queueActionBtn} ${a.queueMove}`,onClick:()=>g(d?.itemId===l.id?null:{itemId:l.id,fromSessionId:t}),children:"MOVE"}),e.jsx("button",{className:`${a.queueActionBtn} ${a.queueDelete} ${s.deleteBtn}`,onClick:()=>w(t,l.id),children:"DEL"})]}),d?.itemId===l.id&&e.jsx("div",{style:{position:"absolute",zIndex:10,background:"var(--surface-card, #12122a)",border:"1px solid var(--border-subtle, rgba(255,255,255,0.08))",borderRadius:"4px",padding:"4px",maxHeight:"160px",overflowY:"auto",minWidth:"180px"},children:N.filter(([c])=>c!==t).map(([c,j])=>e.jsxs("button",{onClick:()=>A(c),style:{display:"block",width:"100%",padding:"4px 8px",background:"transparent",border:"none",color:"var(--text-primary)",fontFamily:"var(--font-mono)",fontSize:"10px",textAlign:"left",cursor:"pointer",borderRadius:"3px"},onMouseEnter:_=>{_.target.style.background="rgba(0,229,255,0.1)"},onMouseLeave:_=>{_.target.style.background="transparent"},children:[j.projectName||c.slice(0,8),j.title?` — ${j.title}`:""]},c))})]})]},l.id))})]})]},t)})})]})}export{J as default};
@@ -1,4 +0,0 @@
1
- import{r as l,b as A,j as c}from"./index-DS3KKkg_.js";import{u as O}from"./useQuery-C-SRwqqC.js";import{r as T,c as _,a as L,S as M,b as F,u as I,s as B,d as W,e as K,f as q,g as H,h as R,i as C,j as $,k as D,l as V,m as x,R as U,B as J,C as G,X,Y,T as Q,n as w}from"./Charts.module-Dx9gJPQR.js";import"./with-selector-C0N9xw7F.js";function j(){return j=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)({}).hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},j.apply(null,arguments)}function E(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable})),r.push.apply(r,n)}return r}function Z(e){for(var t=1;t<arguments.length;t++){var r=arguments[t]!=null?arguments[t]:{};t%2?E(Object(r),!0).forEach(function(n){ee(e,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):E(Object(r)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(r,n))})}return e}function ee(e,t,r){return(t=te(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function te(e){var t=re(e,"string");return typeof t=="symbol"?t:t+""}function re(e,t){if(typeof e!="object"||!e)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var n=r.call(e,t);if(typeof n!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}var p=32,ne={align:"center",iconSize:14,inactiveColor:"#ccc",layout:"horizontal",verticalAlign:"middle"};function ae(e){var{data:t,iconType:r,inactiveColor:n}=e,a=p/2,o=p/6,f=p/3,g=t.inactive?n:t.color,u=r??t.type;if(u==="none")return null;if(u==="plainline"){var d;return l.createElement("line",{strokeWidth:4,fill:"none",stroke:g,strokeDasharray:(d=t.payload)===null||d===void 0?void 0:d.strokeDasharray,x1:0,y1:a,x2:p,y2:a,className:"recharts-legend-icon"})}if(u==="line")return l.createElement("path",{strokeWidth:4,fill:"none",stroke:g,d:"M0,".concat(a,"h").concat(f,`
2
- A`).concat(o,",").concat(o,",0,1,1,").concat(2*f,",").concat(a,`
3
- H`).concat(p,"M").concat(2*f,",").concat(a,`
4
- A`).concat(o,",").concat(o,",0,1,1,").concat(f,",").concat(a),className:"recharts-legend-icon"});if(u==="rect")return l.createElement("path",{stroke:"none",fill:g,d:"M0,".concat(p/8,"h").concat(p,"v").concat(p*3/4,"h").concat(-p,"z"),className:"recharts-legend-icon"});if(l.isValidElement(t.legendIcon)){var s=Z({},t);return delete s.legendIcon,l.cloneElement(t.legendIcon,s)}return l.createElement(F,{fill:g,cx:a,cy:a,size:p,sizeType:"diameter",type:u})}function ie(e){var{payload:t,iconSize:r,layout:n,formatter:a,inactiveColor:o,iconType:f}=e,g={x:0,y:0,width:p,height:p},u={display:n==="horizontal"?"inline-block":"block",marginRight:10},d={display:"inline-block",verticalAlign:"middle",marginRight:4};return t.map((s,m)=>{var h=s.formatter||a,i=_({"recharts-legend-item":!0,["legend-item-".concat(m)]:!0,inactive:s.inactive});if(s.type==="none")return null;var v=s.inactive?o:s.color,b=h?h(s.value,s,m):s.value;return l.createElement("li",j({className:i,style:u,key:"legend-item-".concat(m)},L(e,s,m)),l.createElement(M,{width:r,height:r,viewBox:g,style:d,"aria-label":"".concat(b," legend icon")},l.createElement(ae,{data:s,iconType:f,inactiveColor:o})),l.createElement("span",{className:"recharts-legend-item-text",style:{color:v}},b))})}var oe=e=>{var t=T(e,ne),{payload:r,layout:n,align:a}=t;if(!r||!r.length)return null;var o={padding:0,margin:0,textAlign:n==="horizontal"?a:"left"};return l.createElement("ul",{className:"recharts-default-legend",style:o},l.createElement(ie,j({},t,{payload:r})))};function le(){return I(B)}var ce=["contextPayload"];function P(){return P=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)({}).hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},P.apply(null,arguments)}function k(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable})),r.push.apply(r,n)}return r}function y(e){for(var t=1;t<arguments.length;t++){var r=arguments[t]!=null?arguments[t]:{};t%2?k(Object(r),!0).forEach(function(n){se(e,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):k(Object(r)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(r,n))})}return e}function se(e,t,r){return(t=ue(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ue(e){var t=de(e,"string");return typeof t=="symbol"?t:t+""}function de(e,t){if(typeof e!="object"||!e)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var n=r.call(e,t);if(typeof n!="object")return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}function fe(e,t){if(e==null)return{};var r,n,a=ge(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)===-1&&{}.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}function ge(e,t){if(e==null)return{};var r={};for(var n in e)if({}.hasOwnProperty.call(e,n)){if(t.indexOf(n)!==-1)continue;r[n]=e[n]}return r}function he(e){return e.value}function pe(e){var{contextPayload:t}=e,r=fe(e,ce),n=V(t,e.payloadUniqBy,he),a=y(y({},r),{},{payload:n});return l.isValidElement(e.content)?l.cloneElement(e.content,a):typeof e.content=="function"?l.createElement(e.content,a):l.createElement(oe,a)}function me(e,t,r,n,a,o){var{layout:f,align:g,verticalAlign:u}=t,d,s;return(!e||(e.left===void 0||e.left===null)&&(e.right===void 0||e.right===null))&&(g==="center"&&f==="vertical"?d={left:((n||0)-o.width)/2}:d=g==="right"?{right:r&&r.right||0}:{left:r&&r.left||0}),(!e||(e.top===void 0||e.top===null)&&(e.bottom===void 0||e.bottom===null))&&(u==="middle"?s={top:((a||0)-o.height)/2}:s=u==="bottom"?{bottom:r&&r.bottom||0}:{top:r&&r.top||0}),y(y({},d),s)}function ve(e){var t=C();return l.useEffect(()=>{t($(e))},[t,e]),null}function ye(e){var t=C();return l.useEffect(()=>(t(D(e)),()=>{t(D({width:0,height:0}))}),[t,e]),null}function be(e,t,r,n){return e==="vertical"&&t!=null?{height:t}:e==="horizontal"?{width:r||n}:null}var je={align:"center",iconSize:14,inactiveColor:"#ccc",itemSorter:"value",layout:"horizontal",verticalAlign:"bottom"};function z(e){var t=T(e,je),r=le(),n=W(),a=K(),{width:o,height:f,wrapperStyle:g,portal:u}=t,[d,s]=q([r]),m=H(),h=R();if(m==null||h==null)return null;var i=m-(a?.left||0)-(a?.right||0),v=be(t.layout,f,o,i),b=u?g:y(y({position:"absolute",width:v?.width||o||"auto",height:v?.height||f||"auto"},me(g,t,a,m,h,d)),g),S=u??n;if(S==null||r==null)return null;var N=l.createElement("div",{className:"recharts-legend-wrapper",style:b,ref:s},l.createElement(ve,{layout:t.layout,align:t.align,verticalAlign:t.verticalAlign,itemSorter:t.itemSorter}),!u&&l.createElement(ye,{width:d.width,height:d.height}),l.createElement(pe,P({},t,v,{margin:a,chartWidth:m,chartHeight:h,contextPayload:r})));return A.createPortal(N,S)}z.displayName="Legend";function xe(){return new Date(Date.now()-2592e6).toISOString().split("T")[0]}function we(){return new Date().toISOString().split("T")[0]}function Pe(e,t){const r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];if(t==="week"){const a=e.match(/^(\d{4})-W(\d{1,2})$/);if(a){const o=parseInt(a[1],10),f=parseInt(a[2],10),g=new Date(o,0,1),u=(f-1)*7-g.getDay()+1,d=new Date(o,0,1+u);return r[d.getMonth()]+" "+d.getDate()}}if(t==="hour"){const a=e.match(/^(\d{4}-\d{2}-\d{2})\s+(\d{2}):(\d{2})$/);if(a){const o=new Date(a[1]+"T"+a[2]+":"+a[3]+":00");if(!isNaN(o.getTime()))return r[o.getMonth()]+" "+o.getDate()+" "+o.getHours().toString().padStart(2,"0")+":00"}}const n=new Date(e+(e.includes("T")?"":"T00:00:00"));return isNaN(n.getTime())?e:r[n.getMonth()]+" "+n.getDate()}function ke(){const[e,t]=l.useState("day"),[r,n]=l.useState(""),[a,o]=l.useState(xe),[f,g]=l.useState(we),{data:u}=O({queryKey:["timeline-projects"],queryFn:async()=>{const i=await fetch("/api/db/projects");return i.ok?i.json():[]}}),d=l.useMemo(()=>{const i=new URLSearchParams;return i.set("granularity",e),r&&i.set("project",r),a&&i.set("dateFrom",String(new Date(a).getTime())),f&&i.set("dateTo",String(new Date(f+"T23:59:59").getTime())),i.toString()},[e,r,a,f]),{data:s,isLoading:m}=O({queryKey:["timeline",d],queryFn:async()=>{const i=await fetch(`/api/db/analytics/timeline?${d}`);return i.ok?i.json():{buckets:[]}}}),h=l.useMemo(()=>s?.buckets?s.buckets.map(i=>({...i,label:Pe(i.period,e)})):[],[s,e]);return c.jsxs("div",{className:x.timelineView,"data-testid":"timeline-view",children:[c.jsxs("div",{className:x.timelineControls,children:[c.jsxs("select",{value:e,onChange:i=>t(i.target.value),children:[c.jsx("option",{value:"hour",children:"Hourly"}),c.jsx("option",{value:"day",children:"Daily"}),c.jsx("option",{value:"week",children:"Weekly"})]}),c.jsxs("select",{value:r,onChange:i=>n(i.target.value),children:[c.jsx("option",{value:"",children:"All Projects"}),u?.map(i=>c.jsx("option",{value:i.project_path,children:i.project_name},i.project_path))]}),c.jsx("input",{type:"date",value:a,onChange:i=>o(i.target.value)}),c.jsx("input",{type:"date",value:f,onChange:i=>g(i.target.value)})]}),c.jsx("div",{className:x.timelineChart,children:m?c.jsx("div",{style:{color:"var(--text-dim)",padding:"40px",textAlign:"center"},children:"Loading..."}):h.length===0?c.jsx("div",{style:{color:"var(--text-dim)",padding:"40px",textAlign:"center"},children:"No data for this period"}):c.jsx(U,{width:"100%",height:350,children:c.jsxs(J,{data:h,margin:{top:10,right:10,left:0,bottom:20},children:[c.jsx(G,{strokeDasharray:"3 3",stroke:"rgba(255,255,255,0.06)"}),c.jsx(X,{dataKey:"label",stroke:"#8892b0",fontSize:9,interval:h.length>15?Math.ceil(h.length/15):0,angle:h.length>10||e==="hour"?-40:0,textAnchor:h.length>10||e==="hour"?"end":"middle",height:e==="hour"?60:40}),c.jsx(Y,{stroke:"#8892b0",fontSize:10}),c.jsx(Q,{contentStyle:{background:"var(--bg-card, #12122a)",border:"1px solid var(--accent-cyan, #00e5ff)",borderRadius:"4px",fontSize:"11px",color:"var(--text-primary, #e0e0ff)"}}),c.jsx(z,{wrapperStyle:{fontSize:"10px",color:"#8892b0"}}),c.jsx(w,{dataKey:"session_count",name:"Sessions",fill:"#00e5ff",opacity:.85,radius:[2,2,0,0]}),c.jsx(w,{dataKey:"prompt_count",name:"Prompts",fill:"#00ff88",opacity:.85,radius:[2,2,0,0]}),c.jsx(w,{dataKey:"tool_call_count",name:"Tool Calls",fill:"#ff9800",opacity:.85,radius:[2,2,0,0]})]})})})]})}export{ke as default};