agentgui 1.0.855 → 1.0.857
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/CHANGELOG.md +6 -0
- package/CLAUDE.md +33 -164
- package/lib/jsonl-parser.js +29 -0
- package/lib/jsonl-watcher.js +13 -0
- package/lib/process-message.js +47 -0
- package/lib/server-startup.js +9 -0
- package/lib/stream-event-handler.js +96 -0
- package/package.json +1 -1
- package/static/css/main.css +159 -0
- package/static/js/client.js +68 -0
- package/static/js/conversations.js +9 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
<<<<<<< HEAD
|
|
2
|
+
export function createEventHandler({ queries, activeExecutions, broadcastSync, rateLimitState, batcherRef, sessionId, conversationId, messageId, content, agentId, model, subAgent, ownedSessionIds, allBlocksRef, currentSequenceRef, scheduleRetry, eagerTTS, debugLog, parseRateLimitResetTime }) {
|
|
3
|
+
=======
|
|
1
4
|
/**
|
|
2
5
|
* Minimal Claude stdout event handler.
|
|
3
6
|
*
|
|
@@ -11,10 +14,35 @@
|
|
|
11
14
|
* No batcher, no broadcastSync for individual blocks.
|
|
12
15
|
*/
|
|
13
16
|
export function createEventHandler({ queries, activeExecutions, broadcastSync, rateLimitState, batcherRef, sessionId, conversationId, messageId, content, agentId, model, subAgent, getJsonlWatcher, scheduleRetry, eagerTTS, debugLog, parseRateLimitResetTime }) {
|
|
17
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
14
18
|
return function onEvent(parsed) {
|
|
15
19
|
batcherRef.eventCount++;
|
|
16
20
|
const entry = activeExecutions.get(conversationId);
|
|
17
21
|
if (entry) entry.lastActivity = Date.now();
|
|
22
|
+
<<<<<<< HEAD
|
|
23
|
+
if (parsed.session_id) {
|
|
24
|
+
ownedSessionIds.add(parsed.session_id);
|
|
25
|
+
if (!batcherRef.resumeSessionId || batcherRef.resumeSessionId !== parsed.session_id) {
|
|
26
|
+
batcherRef.resumeSessionId = parsed.session_id;
|
|
27
|
+
queries.setClaudeSessionId(conversationId, parsed.session_id, sessionId);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
debugLog(`[stream] Event ${batcherRef.eventCount}: type=${parsed.type}`);
|
|
31
|
+
|
|
32
|
+
if (parsed.type === 'system') {
|
|
33
|
+
if (parsed.subtype === 'task_notification') return;
|
|
34
|
+
if (!parsed.model && !parsed.cwd && !parsed.tools) return;
|
|
35
|
+
const block = { type: 'system', subtype: parsed.subtype, model: parsed.model, cwd: parsed.cwd, tools: parsed.tools, session_id: parsed.session_id };
|
|
36
|
+
currentSequenceRef.val++;
|
|
37
|
+
batcherRef.batcher.add(sessionId, conversationId, currentSequenceRef.val, 'system', block);
|
|
38
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block, blockRole: 'system', blockIndex: allBlocksRef.val.length, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
39
|
+
} else if (parsed.type === 'assistant' && parsed.message?.content) {
|
|
40
|
+
for (const block of parsed.message.content) {
|
|
41
|
+
allBlocksRef.val.push(block);
|
|
42
|
+
currentSequenceRef.val++;
|
|
43
|
+
batcherRef.batcher.add(sessionId, conversationId, currentSequenceRef.val, block.type || 'assistant', block);
|
|
44
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block, blockRole: 'assistant', blockIndex: allBlocksRef.val.length - 1, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
45
|
+
=======
|
|
18
46
|
|
|
19
47
|
// Register session with file watcher as soon as we see the session_id.
|
|
20
48
|
// This pre-maps claudeSessionId → (convId, dbSessionId) in JsonlParser before
|
|
@@ -32,15 +60,23 @@ export function createEventHandler({ queries, activeExecutions, broadcastSync, r
|
|
|
32
60
|
// Rate-limit detection in assistant text blocks
|
|
33
61
|
if (parsed.type === 'assistant' && parsed.message?.content) {
|
|
34
62
|
for (const block of parsed.message.content) {
|
|
63
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
35
64
|
if (block.type === 'text' && block.text) {
|
|
36
65
|
const rateLimitMatch = block.text.match(/you'?ve hit your limit|rate limit exceeded/i);
|
|
37
66
|
if (rateLimitMatch) {
|
|
38
67
|
debugLog(`[rate-limit] Detected rate limit message in stream for conv ${conversationId}`);
|
|
39
68
|
const retryAfterSec = parseRateLimitResetTime(block.text);
|
|
40
69
|
const entry2 = activeExecutions.get(conversationId);
|
|
70
|
+
<<<<<<< HEAD
|
|
71
|
+
if (entry2 && entry2.pid) { try { process.kill(entry2.pid); } catch (e) {} }
|
|
72
|
+
const existingCount = rateLimitState.get(conversationId)?.retryCount || 0;
|
|
73
|
+
if (existingCount >= 3) {
|
|
74
|
+
batcherRef.batcher.drain();
|
|
75
|
+
=======
|
|
41
76
|
if (entry2 && entry2.pid) { try { process.kill(entry2.pid); } catch (_) {} }
|
|
42
77
|
const existingCount = rateLimitState.get(conversationId)?.retryCount || 0;
|
|
43
78
|
if (existingCount >= 3) {
|
|
79
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
44
80
|
activeExecutions.delete(conversationId);
|
|
45
81
|
queries.setIsStreaming(conversationId, false);
|
|
46
82
|
const errMsg = queries.createMessage(conversationId, 'assistant', `Error: Rate limit exceeded after ${existingCount + 1} attempts. Please try again later.`);
|
|
@@ -50,6 +86,10 @@ export function createEventHandler({ queries, activeExecutions, broadcastSync, r
|
|
|
50
86
|
}
|
|
51
87
|
rateLimitState.set(conversationId, { retryAt: Date.now() + (retryAfterSec * 1000), cooldownMs: retryAfterSec * 1000, retryCount: existingCount + 1, isStreamDetected: true });
|
|
52
88
|
broadcastSync({ type: 'rate_limit_hit', sessionId, conversationId, retryAfterMs: retryAfterSec * 1000, retryAt: Date.now() + (retryAfterSec * 1000), retryCount: 1, timestamp: Date.now() });
|
|
89
|
+
<<<<<<< HEAD
|
|
90
|
+
batcherRef.batcher.drain();
|
|
91
|
+
=======
|
|
92
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
53
93
|
activeExecutions.delete(conversationId);
|
|
54
94
|
queries.setIsStreaming(conversationId, false);
|
|
55
95
|
setTimeout(() => {
|
|
@@ -62,6 +102,61 @@ export function createEventHandler({ queries, activeExecutions, broadcastSync, r
|
|
|
62
102
|
eagerTTS(block.text, conversationId, sessionId);
|
|
63
103
|
}
|
|
64
104
|
}
|
|
105
|
+
<<<<<<< HEAD
|
|
106
|
+
} else if (parsed.type === 'user' && parsed.message?.content) {
|
|
107
|
+
for (const block of parsed.message.content) {
|
|
108
|
+
if (block.type === 'tool_result') {
|
|
109
|
+
const toolResultBlock = { type: 'tool_result', tool_use_id: block.tool_use_id, content: typeof block.content === 'string' ? block.content : JSON.stringify(block.content), is_error: block.is_error || false };
|
|
110
|
+
currentSequenceRef.val++;
|
|
111
|
+
batcherRef.batcher.add(sessionId, conversationId, currentSequenceRef.val, 'tool_result', toolResultBlock);
|
|
112
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block: toolResultBlock, blockRole: 'tool_result', blockIndex: allBlocksRef.val.length, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} else if (parsed.type === 'result') {
|
|
116
|
+
const resultBlock = { type: 'result', subtype: parsed.subtype, duration_ms: parsed.duration_ms, total_cost_usd: parsed.total_cost_usd, num_turns: parsed.num_turns, is_error: parsed.is_error || false, result: parsed.result };
|
|
117
|
+
currentSequenceRef.val++;
|
|
118
|
+
batcherRef.batcher.add(sessionId, conversationId, currentSequenceRef.val, 'result', resultBlock);
|
|
119
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block: resultBlock, blockRole: 'result', blockIndex: allBlocksRef.val.length, isResult: true, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
120
|
+
if (parsed.result) {
|
|
121
|
+
const resultText = typeof parsed.result === 'string' ? parsed.result : JSON.stringify(parsed.result);
|
|
122
|
+
const rlMatch = resultText.match(/you'?ve hit your limit|rate limit exceeded/i);
|
|
123
|
+
if (rlMatch) {
|
|
124
|
+
debugLog(`[rate-limit] Detected rate limit in result for conv ${conversationId}`);
|
|
125
|
+
const retryAfterSec = parseRateLimitResetTime(resultText);
|
|
126
|
+
const entry3 = activeExecutions.get(conversationId);
|
|
127
|
+
if (entry3 && entry3.pid) { try { process.kill(entry3.pid); } catch (e) {} }
|
|
128
|
+
const existingCount2 = rateLimitState.get(conversationId)?.retryCount || 0;
|
|
129
|
+
if (existingCount2 >= 3) {
|
|
130
|
+
batcherRef.batcher.drain();
|
|
131
|
+
activeExecutions.delete(conversationId);
|
|
132
|
+
queries.setIsStreaming(conversationId, false);
|
|
133
|
+
const errMsg2 = queries.createMessage(conversationId, 'assistant', `Error: Rate limit exceeded after ${existingCount2 + 1} attempts. Please try again later.`);
|
|
134
|
+
broadcastSync({ type: 'message_created', conversationId, message: errMsg2, timestamp: Date.now() });
|
|
135
|
+
broadcastSync({ type: 'streaming_complete', sessionId, conversationId, interrupted: true, timestamp: Date.now() });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
rateLimitState.set(conversationId, { retryAt: Date.now() + (retryAfterSec * 1000), cooldownMs: retryAfterSec * 1000, retryCount: existingCount2 + 1, isStreamDetected: true });
|
|
139
|
+
broadcastSync({ type: 'rate_limit_hit', sessionId, conversationId, retryAfterMs: retryAfterSec * 1000, retryAt: Date.now() + (retryAfterSec * 1000), retryCount: existingCount2 + 1, timestamp: Date.now() });
|
|
140
|
+
batcherRef.batcher.drain();
|
|
141
|
+
activeExecutions.delete(conversationId);
|
|
142
|
+
queries.setIsStreaming(conversationId, false);
|
|
143
|
+
setTimeout(() => {
|
|
144
|
+
rateLimitState.delete(conversationId);
|
|
145
|
+
broadcastSync({ type: 'rate_limit_clear', conversationId, timestamp: Date.now() });
|
|
146
|
+
scheduleRetry(conversationId, messageId, content, agentId, model, subAgent);
|
|
147
|
+
}, retryAfterSec * 1000);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (resultText) eagerTTS(resultText, conversationId, sessionId);
|
|
151
|
+
}
|
|
152
|
+
if (parsed.result && allBlocksRef.val.length === 0) allBlocksRef.val.push({ type: 'text', text: String(parsed.result) });
|
|
153
|
+
} else if (parsed.type === 'tool_status') {
|
|
154
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block: { type: 'tool_status', tool_use_id: parsed.tool_use_id, status: parsed.status }, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
155
|
+
} else if (parsed.type === 'usage') {
|
|
156
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block: { type: 'usage', usage: parsed.usage }, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
157
|
+
} else if (parsed.type === 'plan') {
|
|
158
|
+
broadcastSync({ type: 'streaming_progress', sessionId, conversationId, block: { type: 'plan', entries: parsed.entries }, seq: currentSequenceRef.val, timestamp: Date.now() });
|
|
159
|
+
=======
|
|
65
160
|
}
|
|
66
161
|
|
|
67
162
|
// Rate-limit detection in result blocks
|
|
@@ -94,6 +189,7 @@ export function createEventHandler({ queries, activeExecutions, broadcastSync, r
|
|
|
94
189
|
return;
|
|
95
190
|
}
|
|
96
191
|
if (resultText) eagerTTS(resultText, conversationId, sessionId);
|
|
192
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
97
193
|
}
|
|
98
194
|
};
|
|
99
195
|
}
|
package/package.json
CHANGED
package/static/css/main.css
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
<<<<<<< HEAD
|
|
2
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
--color-primary: #3b82f6;
|
|
6
|
+
--color-primary-dark: #1e40af;
|
|
7
|
+
--color-bg-primary: #ffffff;
|
|
8
|
+
--color-bg-secondary: #f9fafb;
|
|
9
|
+
--color-bg-code: #f1f5f9;
|
|
10
|
+
--color-code-text: #1e293b;
|
|
11
|
+
--color-code-border: #cbd5e1;
|
|
12
|
+
--color-thinking-bg: #f5f3ff;
|
|
13
|
+
--color-text-primary: #111827;
|
|
14
|
+
--color-text-secondary: #6b7280;
|
|
15
|
+
--color-border: #e5e7eb;
|
|
16
|
+
=======
|
|
1
17
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
|
2
18
|
|
|
3
19
|
*, *::before, *::after { box-sizing: border-box; }
|
|
@@ -16,10 +32,30 @@
|
|
|
16
32
|
--color-text-muted: #9ca3af;
|
|
17
33
|
--color-border: #e5e7eb;
|
|
18
34
|
--color-border-strong: #d1d5db;
|
|
35
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
19
36
|
--color-success: #10b981;
|
|
20
37
|
--color-error: #ef4444;
|
|
21
38
|
--color-warning: #f59e0b;
|
|
22
39
|
--color-info: #0891b2;
|
|
40
|
+
<<<<<<< HEAD
|
|
41
|
+
--sidebar-width: 300px;
|
|
42
|
+
--header-height: 52px;
|
|
43
|
+
--msg-max-width: 800px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
html.dark {
|
|
47
|
+
--color-bg-primary: #1a1a1a;
|
|
48
|
+
--color-bg-secondary: #242424;
|
|
49
|
+
--color-text-primary: #e5e5e5;
|
|
50
|
+
--color-text-secondary: #a3a3a3;
|
|
51
|
+
--color-border: #333333;
|
|
52
|
+
--color-primary: #737373;
|
|
53
|
+
--color-primary-dark: #525252;
|
|
54
|
+
--color-bg-code: #1e293b;
|
|
55
|
+
--color-code-text: #e2e8f0;
|
|
56
|
+
--color-code-border: #334155;
|
|
57
|
+
--color-thinking-bg: #1e1a2e;
|
|
58
|
+
=======
|
|
23
59
|
--sidebar-width: 260px;
|
|
24
60
|
--header-height: 48px;
|
|
25
61
|
--msg-max-width: 800px;
|
|
@@ -51,17 +87,24 @@
|
|
|
51
87
|
--shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
|
|
52
88
|
--shadow-md: 0 4px 12px rgba(0,0,0,0.4);
|
|
53
89
|
--shadow-lg: 0 8px 24px rgba(0,0,0,0.5);
|
|
90
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
54
91
|
}
|
|
55
92
|
|
|
56
93
|
html, body {
|
|
57
94
|
margin: 0;
|
|
58
95
|
padding: 0;
|
|
59
96
|
height: 100%;
|
|
97
|
+
<<<<<<< HEAD
|
|
98
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
99
|
+
background-color: var(--color-bg-primary);
|
|
100
|
+
color: var(--color-text-primary);
|
|
101
|
+
=======
|
|
60
102
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
61
103
|
background-color: var(--color-bg-primary);
|
|
62
104
|
color: var(--color-text-primary);
|
|
63
105
|
-webkit-font-smoothing: antialiased;
|
|
64
106
|
-moz-osx-font-smoothing: grayscale;
|
|
107
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
65
108
|
}
|
|
66
109
|
|
|
67
110
|
/* ===== ROOT LAYOUT: sidebar + main, full viewport ===== */
|
|
@@ -82,7 +125,10 @@
|
|
|
82
125
|
display: flex;
|
|
83
126
|
flex-direction: column;
|
|
84
127
|
background-color: var(--color-bg-secondary);
|
|
128
|
+
<<<<<<< HEAD
|
|
129
|
+
=======
|
|
85
130
|
border-right: 1px solid var(--color-border);
|
|
131
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
86
132
|
overflow: hidden;
|
|
87
133
|
transition: none !important;
|
|
88
134
|
animation: none !important;
|
|
@@ -97,26 +143,51 @@
|
|
|
97
143
|
}
|
|
98
144
|
|
|
99
145
|
.sidebar-header {
|
|
146
|
+
<<<<<<< HEAD
|
|
147
|
+
padding: 0.75rem 1rem;
|
|
148
|
+
=======
|
|
100
149
|
padding: 0.875rem 1rem 0.75rem;
|
|
150
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
101
151
|
display: flex;
|
|
102
152
|
justify-content: space-between;
|
|
103
153
|
align-items: center;
|
|
104
154
|
flex-shrink: 0;
|
|
105
155
|
min-height: var(--header-height);
|
|
156
|
+
<<<<<<< HEAD
|
|
157
|
+
=======
|
|
106
158
|
border-bottom: 1px solid var(--color-border);
|
|
159
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
107
160
|
}
|
|
108
161
|
|
|
109
162
|
.sidebar-header h2 {
|
|
110
163
|
margin: 0;
|
|
164
|
+
<<<<<<< HEAD
|
|
165
|
+
font-size: 0.875rem;
|
|
166
|
+
font-weight: 600;
|
|
167
|
+
text-transform: uppercase;
|
|
168
|
+
letter-spacing: 0.05em;
|
|
169
|
+
color: var(--color-text-secondary);
|
|
170
|
+
=======
|
|
111
171
|
font-size: 1rem;
|
|
112
172
|
font-weight: 700;
|
|
113
173
|
letter-spacing: -0.01em;
|
|
114
174
|
color: var(--color-text-primary);
|
|
175
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
115
176
|
white-space: nowrap;
|
|
116
177
|
overflow: hidden;
|
|
117
178
|
}
|
|
118
179
|
|
|
119
180
|
.sidebar-new-btn {
|
|
181
|
+
<<<<<<< HEAD
|
|
182
|
+
padding: 0.375rem 0.625rem;
|
|
183
|
+
font-size: 0.75rem;
|
|
184
|
+
background-color: var(--color-primary);
|
|
185
|
+
color: white;
|
|
186
|
+
border: none;
|
|
187
|
+
border-radius: 0.375rem;
|
|
188
|
+
cursor: pointer;
|
|
189
|
+
transition: background-color 0.2s;
|
|
190
|
+
=======
|
|
120
191
|
padding: 0.375rem 0.75rem;
|
|
121
192
|
font-size: 0.8rem;
|
|
122
193
|
font-weight: 600;
|
|
@@ -126,6 +197,7 @@
|
|
|
126
197
|
border-radius: var(--radius-md);
|
|
127
198
|
cursor: pointer;
|
|
128
199
|
transition: background-color var(--transition-fast);
|
|
200
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
129
201
|
white-space: nowrap;
|
|
130
202
|
flex-shrink: 0;
|
|
131
203
|
}
|
|
@@ -154,6 +226,8 @@
|
|
|
154
226
|
|
|
155
227
|
.sidebar-clone-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }
|
|
156
228
|
|
|
229
|
+
<<<<<<< HEAD
|
|
230
|
+
=======
|
|
157
231
|
/* Sidebar overflow menu */
|
|
158
232
|
.sidebar-overflow-btn {
|
|
159
233
|
width: 28px;
|
|
@@ -205,6 +279,7 @@
|
|
|
205
279
|
.sidebar-overflow-menu-item.danger { color: var(--color-error); }
|
|
206
280
|
.sidebar-overflow-menu-wrapper { position: relative; }
|
|
207
281
|
|
|
282
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
208
283
|
.clone-input-bar {
|
|
209
284
|
display: flex;
|
|
210
285
|
align-items: center;
|
|
@@ -285,6 +360,24 @@
|
|
|
285
360
|
}
|
|
286
361
|
|
|
287
362
|
.conversation-item {
|
|
363
|
+
<<<<<<< HEAD
|
|
364
|
+
padding: 0.75rem 0.75rem;
|
|
365
|
+
margin: 0.125rem 0.5rem;
|
|
366
|
+
border-radius: 0.375rem;
|
|
367
|
+
cursor: pointer;
|
|
368
|
+
transition: background-color 0.15s;
|
|
369
|
+
border-left: 3px solid transparent;
|
|
370
|
+
user-select: none;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.conversation-item:hover { background-color: var(--color-bg-primary); }
|
|
374
|
+
|
|
375
|
+
.conversation-item.active {
|
|
376
|
+
background-color: var(--color-primary);
|
|
377
|
+
color: white;
|
|
378
|
+
border-left-color: var(--color-primary-dark);
|
|
379
|
+
}
|
|
380
|
+
=======
|
|
288
381
|
padding: 0.625rem 0.75rem;
|
|
289
382
|
margin: 0.125rem 0.5rem;
|
|
290
383
|
border-radius: var(--radius-md);
|
|
@@ -301,6 +394,7 @@
|
|
|
301
394
|
color: var(--color-primary);
|
|
302
395
|
}
|
|
303
396
|
.conversation-item.active .conversation-item-meta { color: var(--color-primary); opacity: 0.7; }
|
|
397
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
304
398
|
|
|
305
399
|
.conversation-item-title {
|
|
306
400
|
font-weight: 500;
|
|
@@ -320,7 +414,11 @@
|
|
|
320
414
|
text-overflow: ellipsis;
|
|
321
415
|
}
|
|
322
416
|
|
|
417
|
+
<<<<<<< HEAD
|
|
418
|
+
.conversation-item.active .conversation-item-meta { color: rgba(255,255,255,0.7); }
|
|
419
|
+
=======
|
|
323
420
|
/* conversation-item.active meta color handled in active block */
|
|
421
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
324
422
|
|
|
325
423
|
.conversation-streaming-badge {
|
|
326
424
|
display: inline-flex;
|
|
@@ -331,14 +429,22 @@
|
|
|
331
429
|
|
|
332
430
|
.streaming-dot {
|
|
333
431
|
display: inline-block;
|
|
432
|
+
<<<<<<< HEAD
|
|
433
|
+
width: 0.5rem;
|
|
434
|
+
height: 0.5rem;
|
|
435
|
+
=======
|
|
334
436
|
width: 0.4rem;
|
|
335
437
|
height: 0.4rem;
|
|
438
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
336
439
|
border-radius: 50%;
|
|
337
440
|
background-color: var(--color-success);
|
|
338
441
|
animation: pulse 1.5s ease-in-out infinite;
|
|
339
442
|
}
|
|
340
443
|
|
|
341
444
|
.conversation-item.active .streaming-dot {
|
|
445
|
+
<<<<<<< HEAD
|
|
446
|
+
background-color: #fff;
|
|
447
|
+
=======
|
|
342
448
|
background-color: var(--color-success);
|
|
343
449
|
}
|
|
344
450
|
|
|
@@ -362,6 +468,7 @@
|
|
|
362
468
|
@keyframes typing-bounce {
|
|
363
469
|
0%, 80%, 100% { transform: scale(0.7); opacity: 0.5; }
|
|
364
470
|
40% { transform: scale(1); opacity: 1; }
|
|
471
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
365
472
|
}
|
|
366
473
|
|
|
367
474
|
.conversation-item {
|
|
@@ -377,6 +484,8 @@
|
|
|
377
484
|
overflow: hidden;
|
|
378
485
|
}
|
|
379
486
|
|
|
487
|
+
<<<<<<< HEAD
|
|
488
|
+
=======
|
|
380
489
|
/* Date group headers in sidebar */
|
|
381
490
|
.conv-date-group-header {
|
|
382
491
|
padding: 0.5rem 1.25rem 0.25rem;
|
|
@@ -402,6 +511,7 @@
|
|
|
402
511
|
margin-right: 0.375rem;
|
|
403
512
|
}
|
|
404
513
|
|
|
514
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
405
515
|
.conversation-item.pinned { cursor: grab; }
|
|
406
516
|
.conversation-item.pinned:active { cursor: grabbing; }
|
|
407
517
|
.conversation-item-checkbox {
|
|
@@ -459,16 +569,25 @@
|
|
|
459
569
|
.conversation-item.active .conversation-item-delete,
|
|
460
570
|
.conversation-item.active .conversation-item-archive,
|
|
461
571
|
.conversation-item.active .conversation-item-export {
|
|
572
|
+
<<<<<<< HEAD
|
|
573
|
+
color: rgba(255,255,255,0.8);
|
|
574
|
+
=======
|
|
462
575
|
color: var(--color-primary);
|
|
463
576
|
opacity: 0.7;
|
|
577
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
464
578
|
}
|
|
465
579
|
|
|
466
580
|
.conversation-item.active .conversation-item-delete:hover,
|
|
467
581
|
.conversation-item.active .conversation-item-archive:hover,
|
|
468
582
|
.conversation-item.active .conversation-item-export:hover {
|
|
583
|
+
<<<<<<< HEAD
|
|
584
|
+
background-color: rgba(255,255,255,0.2);
|
|
585
|
+
color: white;
|
|
586
|
+
=======
|
|
469
587
|
background-color: rgba(var(--color-primary-rgb),0.15);
|
|
470
588
|
color: var(--color-primary);
|
|
471
589
|
opacity: 1;
|
|
590
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
472
591
|
}
|
|
473
592
|
|
|
474
593
|
.sidebar-empty {
|
|
@@ -494,11 +613,18 @@
|
|
|
494
613
|
align-items: center;
|
|
495
614
|
gap: 0.75rem;
|
|
496
615
|
padding: 0 1rem;
|
|
616
|
+
<<<<<<< HEAD
|
|
617
|
+
height: var(--header-height);
|
|
618
|
+
min-height: var(--header-height);
|
|
619
|
+
flex-shrink: 0;
|
|
620
|
+
background-color: var(--color-bg-secondary);
|
|
621
|
+
=======
|
|
497
622
|
height: 48px;
|
|
498
623
|
min-height: 48px;
|
|
499
624
|
flex-shrink: 0;
|
|
500
625
|
background: var(--color-bg-primary);
|
|
501
626
|
border-bottom: 1px solid var(--color-border);
|
|
627
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
502
628
|
}
|
|
503
629
|
|
|
504
630
|
.sidebar-toggle-btn {
|
|
@@ -528,9 +654,14 @@
|
|
|
528
654
|
}
|
|
529
655
|
|
|
530
656
|
.header-title {
|
|
657
|
+
<<<<<<< HEAD
|
|
658
|
+
font-size: 1.125rem;
|
|
659
|
+
font-weight: 600;
|
|
660
|
+
=======
|
|
531
661
|
font-size: 0.9375rem;
|
|
532
662
|
font-weight: 600;
|
|
533
663
|
letter-spacing: -0.01em;
|
|
664
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
534
665
|
margin: 0;
|
|
535
666
|
flex: 1;
|
|
536
667
|
min-width: 0;
|
|
@@ -693,6 +824,8 @@
|
|
|
693
824
|
flex-direction: column;
|
|
694
825
|
}
|
|
695
826
|
|
|
827
|
+
<<<<<<< HEAD
|
|
828
|
+
=======
|
|
696
829
|
/* ===== MESSAGE BUBBLES ===== */
|
|
697
830
|
.message-user-bubble {
|
|
698
831
|
display: flex;
|
|
@@ -771,6 +904,7 @@
|
|
|
771
904
|
.message-action-btn svg { width: 13px; height: 13px; }
|
|
772
905
|
.message-wrapper { position: relative; }
|
|
773
906
|
|
|
907
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
774
908
|
#output {
|
|
775
909
|
display: flex;
|
|
776
910
|
flex-direction: column;
|
|
@@ -1017,6 +1151,15 @@
|
|
|
1017
1151
|
white-space: nowrap;
|
|
1018
1152
|
}
|
|
1019
1153
|
|
|
1154
|
+
<<<<<<< HEAD
|
|
1155
|
+
/* --- Input area: fixed at bottom --- */
|
|
1156
|
+
.input-section {
|
|
1157
|
+
flex-shrink: 0;
|
|
1158
|
+
background-color: var(--color-bg-primary);
|
|
1159
|
+
padding: 0.75rem 1rem;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
=======
|
|
1020
1163
|
/* ===== INPUT AREA REDESIGN ===== */
|
|
1021
1164
|
.input-section {
|
|
1022
1165
|
flex-shrink: 0;
|
|
@@ -1139,6 +1282,7 @@
|
|
|
1139
1282
|
.input-send-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
|
|
1140
1283
|
.input-send-btn svg { width: 16px; height: 16px; }
|
|
1141
1284
|
|
|
1285
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
1142
1286
|
.input-wrapper {
|
|
1143
1287
|
max-width: var(--msg-max-width);
|
|
1144
1288
|
margin: 0 auto;
|
|
@@ -1401,9 +1545,15 @@
|
|
|
1401
1545
|
.permanently-expanded > summary::marker { display: none; content: ''; }
|
|
1402
1546
|
|
|
1403
1547
|
/* ===== Folder Browser Modal ===== */
|
|
1548
|
+
<<<<<<< HEAD
|
|
1549
|
+
.folder-modal-overlay { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:2000; align-items:center; justify-content:center; }
|
|
1550
|
+
.folder-modal-overlay.visible { display:flex; }
|
|
1551
|
+
.folder-modal { background:var(--color-bg-primary); border-radius:0.5rem; width:500px; max-width:90vw; max-height:80vh; display:flex; flex-direction:column; box-shadow:0 20px 60px rgba(0,0,0,0.3); }
|
|
1552
|
+
=======
|
|
1404
1553
|
.folder-modal-overlay { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px); z-index:2000; align-items:center; justify-content:center; transition:opacity 0.15s ease; animation:fadeIn 0.15s ease; }
|
|
1405
1554
|
.folder-modal-overlay.visible { display:flex; }
|
|
1406
1555
|
.folder-modal { background:var(--color-bg-primary); border-radius:var(--radius-xl); width:500px; max-width:90vw; max-height:80vh; display:flex; flex-direction:column; box-shadow:var(--shadow-lg); animation:scaleIn 0.15s ease; }
|
|
1556
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
1407
1557
|
.folder-modal-header { padding:1rem; display:flex; justify-content:space-between; align-items:center; flex-shrink:0; }
|
|
1408
1558
|
.folder-modal-header h3 { margin:0; font-size:1rem; font-weight:600; }
|
|
1409
1559
|
.folder-modal-close { background:none; border:none; font-size:1.25rem; cursor:pointer; color:var(--color-text-secondary); padding:0.25rem; line-height:1; }
|
|
@@ -1423,6 +1573,8 @@
|
|
|
1423
1573
|
.folder-modal-footer { padding:0.75rem 1rem; display:flex; justify-content:flex-end; gap:0.5rem; flex-shrink:0; }
|
|
1424
1574
|
.folder-modal-footer .btn { padding:0.5rem 1rem; font-size:0.8rem; }
|
|
1425
1575
|
|
|
1576
|
+
<<<<<<< HEAD
|
|
1577
|
+
=======
|
|
1426
1578
|
@keyframes fadeIn {
|
|
1427
1579
|
from { opacity: 0; }
|
|
1428
1580
|
to { opacity: 1; }
|
|
@@ -1432,6 +1584,7 @@
|
|
|
1432
1584
|
to { opacity: 1; transform: scale(1); }
|
|
1433
1585
|
}
|
|
1434
1586
|
|
|
1587
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
1435
1588
|
.btn { padding:0.5rem 1rem; border:none; border-radius:0.375rem; font-weight:500; cursor:pointer; transition:all 0.15s; font-size:0.875rem; }
|
|
1436
1589
|
.btn-primary { background-color:var(--color-primary); color:white; }
|
|
1437
1590
|
.btn-primary:hover:not(:disabled) { background-color:var(--color-primary-dark); }
|
|
@@ -1554,6 +1707,8 @@
|
|
|
1554
1707
|
scrollbar-color: #475569 transparent;
|
|
1555
1708
|
}
|
|
1556
1709
|
|
|
1710
|
+
<<<<<<< HEAD
|
|
1711
|
+
=======
|
|
1557
1712
|
/* Modern thin scrollbars */
|
|
1558
1713
|
.sidebar-list, #output-scroll, .message-scroll-area {
|
|
1559
1714
|
scrollbar-width: thin;
|
|
@@ -1563,6 +1718,7 @@
|
|
|
1563
1718
|
scrollbar-color: var(--color-border-strong) transparent;
|
|
1564
1719
|
}
|
|
1565
1720
|
|
|
1721
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
1566
1722
|
.voice-mic-btn {
|
|
1567
1723
|
position: absolute;
|
|
1568
1724
|
top: 4px;
|
|
@@ -1818,6 +1974,8 @@
|
|
|
1818
1974
|
.icon-sm svg { width: 1rem !important; height: 1rem !important; }
|
|
1819
1975
|
.icon-lg svg { width: 1.5rem !important; height: 1.5rem !important; }
|
|
1820
1976
|
|
|
1977
|
+
<<<<<<< HEAD
|
|
1978
|
+
=======
|
|
1821
1979
|
/* ===== STREAMING STATUS BAR ===== */
|
|
1822
1980
|
.streaming-status-bar {
|
|
1823
1981
|
max-width: var(--msg-max-width);
|
|
@@ -1942,6 +2100,7 @@
|
|
|
1942
2100
|
line-height: 1.4;
|
|
1943
2101
|
}
|
|
1944
2102
|
|
|
2103
|
+
>>>>>>> 6bfde951cbeb65ec72b73da9c23b9c8c0ba0bbc1
|
|
1945
2104
|
/* ===== STREAMING BLOCK STYLES ===== */
|
|
1946
2105
|
.block-text {
|
|
1947
2106
|
margin-bottom: 0;
|