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.
- package/README.md +2 -0
- package/dist/client/assets/AnalyticsView-B7ALjnxe.js +1 -0
- package/dist/client/assets/Charts-IyRNWsxy.css +1 -0
- package/dist/client/assets/{Charts.module-Dx9gJPQR.js → Charts.module-BVWDL-nq.js} +2 -2
- package/dist/client/assets/{CyberdromeScene-CxjA5JVV.js → CyberdromeScene-fsiugRCk.js} +1 -1
- package/dist/client/assets/HistoryView-2SToJwhm.js +1 -0
- package/dist/client/assets/HistoryView-khsGJftp.css +1 -0
- package/dist/client/assets/{ProjectBrowserView-5bUQLVrl.js → ProjectBrowserView-CC-VpOqU.js} +1 -1
- package/dist/client/assets/QueueView-BolJW5o0.js +1 -0
- package/dist/client/assets/TimelineView-B_Lk9xQG.js +4 -0
- package/dist/client/assets/index-B7h3JN01.js +153 -0
- package/dist/client/assets/index-y70PbO5W.css +1 -0
- package/dist/client/assets/{useQuery-C-SRwqqC.js → useQuery-D3equUmE.js} +1 -1
- package/dist/client/assets/{with-selector-C0N9xw7F.js → with-selector-bHDjn-jq.js} +1 -1
- package/dist/client/index.html +2 -2
- package/hooks/install-hooks-api.cjs +169 -0
- package/hooks/install-hooks-core.cjs +89 -0
- package/hooks/package.json +1 -0
- package/package.json +4 -4
- package/server/apiRouter.ts +3 -3
- package/server/serverConfig.ts +5 -1
- package/server/sessionMatcher.ts +13 -3
- package/dist/client/assets/AnalyticsView-CbZwTSY4.js +0 -1
- package/dist/client/assets/Charts-BN9-_lNy.css +0 -1
- package/dist/client/assets/HistoryView-Cu23DcIM.css +0 -1
- package/dist/client/assets/HistoryView-tXMsxMhN.js +0 -1
- package/dist/client/assets/QueueView-DM_X1lfF.js +0 -1
- package/dist/client/assets/TimelineView-DuOSFGCv.js +0 -4
- package/dist/client/assets/index-ClPKOKvN.css +0 -1
- 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.
|
|
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",
|
package/server/apiRouter.ts
CHANGED
|
@@ -926,7 +926,7 @@ const TEXT_NAMES = new Set([
|
|
|
926
926
|
'.gitignore', '.dockerignore', '.editorconfig',
|
|
927
927
|
]);
|
|
928
928
|
|
|
929
|
-
const MAX_FILE_SIZE =
|
|
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
|
|
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(
|
|
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) => {
|
package/server/serverConfig.ts
CHANGED
|
@@ -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
|
-
|
|
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,
|
package/server/sessionMatcher.ts
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
|
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};
|