aicodeswitch 5.1.2 → 5.1.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.
@@ -0,0 +1,419 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.extractSessionContent = extractSessionContent;
13
+ exports.previewMigration = previewMigration;
14
+ exports.migrateSession = migrateSession;
15
+ function parseSSEChunks(sourceText) {
16
+ const chunks = sourceText.split('\n').map(item => item.trim()).join('\n')
17
+ .split('\n\n').filter(s => s.trim());
18
+ const events = [];
19
+ for (const chunk of chunks) {
20
+ let event = '';
21
+ let dataLines = [];
22
+ let dataInsert = 0;
23
+ const lines = chunk.split('\n');
24
+ lines.forEach((line) => {
25
+ if (/^[a-z]+:/.test(line)) {
26
+ const at = line.indexOf(':');
27
+ const type = line.slice(0, at).trim();
28
+ const content = line.slice(at + 1).trim();
29
+ if (type === 'event') {
30
+ event = content;
31
+ }
32
+ else if (type === 'data') {
33
+ dataLines.push(content);
34
+ dataInsert = 1;
35
+ }
36
+ else if (dataLines.length) {
37
+ dataInsert = -1;
38
+ }
39
+ }
40
+ else if (dataInsert === 1) {
41
+ dataLines.push(line);
42
+ }
43
+ });
44
+ if (dataLines.length) {
45
+ const raw = dataLines.join('\n');
46
+ let parsed = raw;
47
+ try {
48
+ parsed = JSON.parse(raw);
49
+ }
50
+ catch ( /* keep raw string */_a) { /* keep raw string */ }
51
+ events.push({ event, data: parsed, raw });
52
+ }
53
+ }
54
+ return events;
55
+ }
56
+ function assembleStreamText(events) {
57
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
58
+ let text = '', thinking = '';
59
+ let inTextBlock = false, inThinkingBlock = false;
60
+ let reasoningAccumulated = false;
61
+ for (const ev of events) {
62
+ const data = ev.data;
63
+ if (!data)
64
+ continue;
65
+ // Claude format
66
+ if (typeof data === 'object' && data.type) {
67
+ if (data.type === 'content_block_start') {
68
+ if (((_a = data.content_block) === null || _a === void 0 ? void 0 : _a.type) === 'text')
69
+ inTextBlock = true;
70
+ else if (((_b = data.content_block) === null || _b === void 0 ? void 0 : _b.type) === 'thinking')
71
+ inThinkingBlock = true;
72
+ }
73
+ if (data.type === 'content_block_delta') {
74
+ if (((_c = data.delta) === null || _c === void 0 ? void 0 : _c.type) === 'text_delta' && inTextBlock)
75
+ text += data.delta.text || '';
76
+ if (((_d = data.delta) === null || _d === void 0 ? void 0 : _d.type) === 'thinking_delta' && inThinkingBlock)
77
+ thinking += data.delta.thinking || '';
78
+ }
79
+ if (data.type === 'content_block_stop') {
80
+ inTextBlock = false;
81
+ inThinkingBlock = false;
82
+ }
83
+ }
84
+ // Responses API format
85
+ if (typeof data === 'object' && data.type) {
86
+ if (data.type === 'response.reasoning_text.delta') {
87
+ thinking += data.delta || '';
88
+ reasoningAccumulated = true;
89
+ }
90
+ if (data.type === 'response.content_part.done') {
91
+ if (((_e = data.part) === null || _e === void 0 ? void 0 : _e.type) === 'output_text' && ((_f = data.part) === null || _f === void 0 ? void 0 : _f.text)) {
92
+ text += data.part.text;
93
+ }
94
+ if (((_g = data.part) === null || _g === void 0 ? void 0 : _g.type) === 'reasoning_text' && ((_h = data.part) === null || _h === void 0 ? void 0 : _h.text) && !reasoningAccumulated) {
95
+ thinking += data.part.text;
96
+ }
97
+ }
98
+ }
99
+ // OpenAI Chat format
100
+ if (typeof data === 'object' && ((_k = (_j = data.choices) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.delta)) {
101
+ const delta = data.choices[0].delta;
102
+ if (delta.content)
103
+ text += delta.content;
104
+ if ((_l = delta.thinking) === null || _l === void 0 ? void 0 : _l.content)
105
+ thinking += delta.thinking.content;
106
+ }
107
+ // DeepSeek direct format
108
+ if (typeof data === 'object' && (data.reasoning_content || data.thinking)) {
109
+ thinking += data.reasoning_content || data.thinking;
110
+ }
111
+ }
112
+ return { text, thinking };
113
+ }
114
+ // ─── 工具调用摘要化 ───
115
+ const TOOL_SUMMARIES = {
116
+ Bash: (i) => `🔧 执行命令: \`${i.command || i.cmd || ''}\``,
117
+ Read: (i) => `📖 读取文件: ${i.file_path || ''}`,
118
+ Write: (i) => `📝 写入文件: ${i.file_path || ''}`,
119
+ Edit: (i) => `✏️ 编辑文件: ${i.file_path || i.target_file || ''}`,
120
+ Glob: (i) => `🔍 搜索文件: ${i.pattern || ''}`,
121
+ Grep: (i) => `🔍 搜索内容: ${i.pattern || ''}`,
122
+ TodoWrite: () => `📋 更新任务列表`,
123
+ Agent: () => `🤖 启动子代理`,
124
+ TaskOutput: () => `📤 获取任务输出`,
125
+ SendMessage: () => `💬 发送消息`,
126
+ shell: (i) => `🔧 执行命令: \`${i.command || ''}\``,
127
+ apply_diff: (_i) => `✏️ 应用代码变更`,
128
+ create_file: (_i) => `📝 创建文件`,
129
+ };
130
+ function summarizeToolCall(toolName, input) {
131
+ const summarizer = TOOL_SUMMARIES[toolName];
132
+ if (summarizer) {
133
+ try {
134
+ return summarizer(input);
135
+ }
136
+ catch (_a) {
137
+ return `🔧 调用工具: ${toolName}`;
138
+ }
139
+ }
140
+ return `🔧 调用工具: ${toolName}`;
141
+ }
142
+ function extractUserTextFromClaudeMessages(messages) {
143
+ const userMsgs = messages.filter(m => m.role === 'user');
144
+ if (!userMsgs.length)
145
+ return '';
146
+ const lastMsg = userMsgs[userMsgs.length - 1];
147
+ if (typeof lastMsg.content === 'string')
148
+ return lastMsg.content;
149
+ if (Array.isArray(lastMsg.content)) {
150
+ return lastMsg.content
151
+ .filter(b => b.type === 'text' && b.text)
152
+ .map(b => b.text)
153
+ .join('\n');
154
+ }
155
+ return '';
156
+ }
157
+ function extractToolCallsFromClaudeMessage(msg) {
158
+ if (!Array.isArray(msg.content))
159
+ return [];
160
+ return msg.content
161
+ .filter(b => b.type === 'tool_use')
162
+ .map(b => summarizeToolCall(b.name || 'unknown', b.input || {}));
163
+ }
164
+ function extractUserTextFromCodexInput(inputArr) {
165
+ const userItems = inputArr.filter(i => i.type === 'message' && i.role === 'user');
166
+ if (!userItems.length)
167
+ return '';
168
+ const lastItem = userItems[userItems.length - 1];
169
+ if (typeof lastItem.content === 'string')
170
+ return lastItem.content;
171
+ if (Array.isArray(lastItem.content)) {
172
+ return lastItem.content
173
+ .filter((b) => b.type === 'input_text' && b.text)
174
+ .map((b) => b.text)
175
+ .join('\n');
176
+ }
177
+ return '';
178
+ }
179
+ function extractToolCallsFromCodexInput(inputArr) {
180
+ return inputArr
181
+ .filter(i => i.type === 'function_call')
182
+ .map(i => summarizeToolCall(i.name || 'unknown', typeof i.arguments === 'string' ? JSON.parse(i.arguments || '{}') : (i.arguments || {})));
183
+ }
184
+ function extractAssistantResponseFromLog(log) {
185
+ var _a, _b, _c;
186
+ let text = '', thinking = '';
187
+ // 1. Try downstreamResponseBody (SSE)
188
+ const sourceText = log.downstreamResponseBody;
189
+ if (typeof sourceText === 'string' && (sourceText.includes('event:') || sourceText.includes('data:'))) {
190
+ const events = parseSSEChunks(sourceText);
191
+ const assembled = assembleStreamText(events);
192
+ text = assembled.text;
193
+ thinking = assembled.thinking;
194
+ }
195
+ // 2. Try responseBody (JSON)
196
+ if (!text && !thinking && log.responseBody) {
197
+ try {
198
+ const parsed = typeof log.responseBody === 'string' ? JSON.parse(log.responseBody) : log.responseBody;
199
+ if (parsed.content) {
200
+ if (Array.isArray(parsed.content)) {
201
+ const parts = [];
202
+ for (const block of parsed.content) {
203
+ if (block.type === 'text' && block.text)
204
+ parts.push(block.text);
205
+ else if (block.type === 'thinking' && block.thinking)
206
+ thinking += block.thinking;
207
+ }
208
+ text = parts.join('\n\n');
209
+ }
210
+ else if (typeof parsed.content === 'string') {
211
+ text = parsed.content;
212
+ }
213
+ }
214
+ if (!text && ((_c = (_b = (_a = parsed.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content)) {
215
+ text = parsed.choices[0].message.content;
216
+ }
217
+ if (!text && parsed.output) {
218
+ const parts = [];
219
+ for (const item of parsed.output) {
220
+ if (item.type === 'message') {
221
+ if (Array.isArray(item.content)) {
222
+ for (const c of item.content) {
223
+ if (c.type === 'output_text' && c.text)
224
+ parts.push(c.text);
225
+ }
226
+ }
227
+ }
228
+ }
229
+ text = parts.join('\n\n');
230
+ }
231
+ }
232
+ catch ( /* ignore parse errors */_d) { /* ignore parse errors */ }
233
+ }
234
+ // 3. Try streamChunks
235
+ if (!text && Array.isArray(log.streamChunks)) {
236
+ const chunksText = log.streamChunks.join('');
237
+ if (chunksText.includes('event:') || chunksText.includes('data:')) {
238
+ const events = parseSSEChunks(chunksText);
239
+ const assembled = assembleStreamText(events);
240
+ text = assembled.text;
241
+ thinking = assembled.thinking;
242
+ }
243
+ }
244
+ return { text: text.trim(), thinking: thinking.trim() };
245
+ }
246
+ function isClaudeCodeBody(body) {
247
+ return (body === null || body === void 0 ? void 0 : body.messages) && Array.isArray(body.messages);
248
+ }
249
+ function isCodexBody(body) {
250
+ return (body === null || body === void 0 ? void 0 : body.input) && Array.isArray(body.input);
251
+ }
252
+ // ─── Token 估算 ───
253
+ function estimateTokens(text) {
254
+ let cjk = 0, other = 0;
255
+ for (const ch of text) {
256
+ const code = ch.charCodeAt(0);
257
+ if ((code >= 0x4E00 && code <= 0x9FFF) ||
258
+ (code >= 0x3400 && code <= 0x4DBF) ||
259
+ (code >= 0x20000 && code <= 0x2A6DF) ||
260
+ (code >= 0xF900 && code <= 0xFAFF)) {
261
+ cjk++;
262
+ }
263
+ else {
264
+ other++;
265
+ }
266
+ }
267
+ return Math.ceil(cjk + other * 0.25);
268
+ }
269
+ // ─── 迁移 Prompt 生成 ───
270
+ function formatSessionTitle(title) {
271
+ if (!title)
272
+ return '(无标题)';
273
+ return title.replace(/<\/?session>/g, '').trim() || '(无标题)';
274
+ }
275
+ function generateMigrationPrompt(content, targetTool) {
276
+ const toolLabels = {
277
+ 'claude-code': 'Claude Code',
278
+ 'codex': 'Codex',
279
+ };
280
+ const sourceLabel = toolLabels[content.sourceTool];
281
+ const targetLabel = toolLabels[targetTool];
282
+ const lines = [];
283
+ lines.push(`# 会话迁移上下文`);
284
+ lines.push('');
285
+ lines.push(`> 以下内容从 ${sourceLabel} 会话「${formatSessionTitle(content.sessionTitle)}」迁移而来`);
286
+ lines.push(`> 目标工具:${targetLabel}`);
287
+ lines.push(`> 迁移时间:${new Date().toISOString()}`);
288
+ lines.push(`> 原始会话共 ${content.totalRounds} 轮对话,此处包含最近 ${content.extractedRounds} 轮`);
289
+ lines.push('');
290
+ lines.push('---');
291
+ lines.push('');
292
+ lines.push('## 对话历史');
293
+ lines.push('');
294
+ for (const round of content.rounds) {
295
+ lines.push(`### 👤 用户`);
296
+ lines.push(round.userMessage || '(无文本内容)');
297
+ lines.push('');
298
+ if (round.toolCallSummaries.length > 0) {
299
+ for (const summary of round.toolCallSummaries) {
300
+ lines.push(`> ${summary}`);
301
+ }
302
+ lines.push('');
303
+ }
304
+ lines.push(`### 🤖 助手`);
305
+ lines.push(round.assistantResponse || '(无文本内容)');
306
+ lines.push('');
307
+ if (round.thinking) {
308
+ lines.push('<details>');
309
+ lines.push('<summary>思考过程</summary>');
310
+ lines.push('');
311
+ lines.push(round.thinking);
312
+ lines.push('');
313
+ lines.push('</details>');
314
+ lines.push('');
315
+ }
316
+ lines.push('---');
317
+ lines.push('');
318
+ }
319
+ lines.push(`> ⚠️ 注意:以上对话历史和工具操作仅为上下文摘要,实际的文件修改和工具执行结果不会在目标工具中生效。`);
320
+ lines.push(`> 请基于以上上下文继续工作。`);
321
+ return lines.join('\n');
322
+ }
323
+ // ─── 主要导出 ───
324
+ function extractSessionContent(dbManager, sessionId, options) {
325
+ return __awaiter(this, void 0, void 0, function* () {
326
+ const logs = yield dbManager.getLogsBySessionId(sessionId, 10000);
327
+ const session = dbManager.getSession(sessionId);
328
+ if (!session) {
329
+ throw new Error(`Session not found: ${sessionId}`);
330
+ }
331
+ const sortedLogs = logs.sort((a, b) => a.timestamp - b.timestamp);
332
+ const rounds = [];
333
+ for (let i = 0; i < sortedLogs.length; i++) {
334
+ const log = sortedLogs[i];
335
+ const body = log.body
336
+ ? (typeof log.body === 'string' ? JSON.parse(log.body) : log.body)
337
+ : null;
338
+ if (!body)
339
+ continue;
340
+ // Extract user message
341
+ let userMessage = '';
342
+ let toolCallSummaries = [];
343
+ if (isClaudeCodeBody(body)) {
344
+ userMessage = extractUserTextFromClaudeMessages(body.messages);
345
+ // Extract tool calls from assistant messages
346
+ if (options.includeToolCalls !== false && body.messages) {
347
+ for (const msg of body.messages) {
348
+ if (msg.role === 'assistant') {
349
+ toolCallSummaries.push(...extractToolCallsFromClaudeMessage(msg));
350
+ }
351
+ }
352
+ }
353
+ }
354
+ else if (isCodexBody(body)) {
355
+ userMessage = extractUserTextFromCodexInput(body.input);
356
+ if (options.includeToolCalls !== false) {
357
+ toolCallSummaries = extractToolCallsFromCodexInput(body.input);
358
+ }
359
+ }
360
+ if (!userMessage && !toolCallSummaries.length)
361
+ continue;
362
+ // Extract assistant response
363
+ const { text, thinking } = extractAssistantResponseFromLog(log);
364
+ rounds.push({
365
+ index: rounds.length + 1,
366
+ userMessage,
367
+ assistantResponse: text,
368
+ toolCallSummaries,
369
+ thinking: options.includeThinking ? (thinking || undefined) : undefined,
370
+ timestamp: log.timestamp,
371
+ });
372
+ }
373
+ const maxRounds = options.maxRounds || 0;
374
+ const extractedRounds = maxRounds > 0 ? rounds.slice(-maxRounds) : rounds;
375
+ return {
376
+ sessionId,
377
+ sessionTitle: session.title || '',
378
+ sourceTool: session.targetType,
379
+ rounds: extractedRounds,
380
+ totalRounds: sortedLogs.length,
381
+ extractedRounds: extractedRounds.length,
382
+ };
383
+ });
384
+ }
385
+ function previewMigration(content, targetTool) {
386
+ const warnings = [];
387
+ const prompt = generateMigrationPrompt(content, targetTool);
388
+ const estimatedTokens = estimateTokens(prompt);
389
+ if (content.totalRounds > content.extractedRounds && content.extractedRounds > 0) {
390
+ warnings.push(`会话较长(${content.totalRounds} 轮),已截断到最近 ${content.extractedRounds} 轮对话`);
391
+ }
392
+ if (estimatedTokens > 100000) {
393
+ warnings.push(`迁移 Prompt 约 ${estimatedTokens.toLocaleString()} tokens,可能超过目标模型的上下文窗口`);
394
+ }
395
+ if (content.totalRounds === 0) {
396
+ warnings.push('该会话没有可提取的对话内容');
397
+ }
398
+ return {
399
+ content,
400
+ generatedPrompt: prompt,
401
+ estimatedTokens,
402
+ warnings,
403
+ };
404
+ }
405
+ function migrateSession(content, targetTool, editedPrompt) {
406
+ const prompt = editedPrompt || generateMigrationPrompt(content, targetTool);
407
+ const estimatedTokens = estimateTokens(prompt);
408
+ const warnings = [];
409
+ if (estimatedTokens > 100000) {
410
+ warnings.push(`迁移 Prompt 约 ${estimatedTokens.toLocaleString()} tokens,可能超过目标模型的上下文窗口`);
411
+ }
412
+ return {
413
+ success: true,
414
+ prompt,
415
+ format: 'markdown',
416
+ estimatedTokens,
417
+ warnings,
418
+ };
419
+ }
@@ -23,7 +23,7 @@ function isClientDisconnectError(error) {
23
23
  * 这个Transform会记录所有经过它的数据块,同时将数据原封不动地传递给下一个stream
24
24
  */
25
25
  class ChunkCollectorTransform extends stream_1.Transform {
26
- constructor() {
26
+ constructor(refreshCallback) {
27
27
  super({ writableObjectMode: true, readableObjectMode: true });
28
28
  Object.defineProperty(this, "chunks", {
29
29
  enumerable: true,
@@ -43,6 +43,25 @@ class ChunkCollectorTransform extends stream_1.Transform {
43
43
  writable: true,
44
44
  value: new string_decoder_1.StringDecoder('utf8')
45
45
  });
46
+ Object.defineProperty(this, "lastRefreshTime", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: 0
51
+ });
52
+ Object.defineProperty(this, "refreshCallback", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ Object.defineProperty(this, "REFRESH_INTERVAL", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: 5000
63
+ }); // 每5秒最多刷新一次
64
+ this.refreshCallback = refreshCallback;
46
65
  this.on('error', (err) => {
47
66
  if (isClientDisconnectError(err)) {
48
67
  console.warn('[ChunkCollectorTransform] Stream closed (client disconnected)');
@@ -69,6 +88,14 @@ class ChunkCollectorTransform extends stream_1.Transform {
69
88
  }
70
89
  // 将chunk传递给下一个stream
71
90
  this.push(chunk);
91
+ // 节流刷新规则使用状态(仅在有数据流过时触发)
92
+ if (this.refreshCallback) {
93
+ const now = Date.now();
94
+ if (now - this.lastRefreshTime >= this.REFRESH_INTERVAL) {
95
+ this.lastRefreshTime = now;
96
+ this.refreshCallback();
97
+ }
98
+ }
72
99
  callback();
73
100
  }
74
101
  catch (error) {
@@ -0,0 +1 @@
1
+ .nav-item-with-tooltip{position:relative;display:block}.nav-tooltip{position:absolute;left:calc(100% + 12px);top:50%;transform:translateY(-50%);background:var(--bg-card);color:var(--text-primary);padding:8px 12px;border-radius:8px;font-size:14px;font-weight:500;white-space:nowrap;z-index:999999;pointer-events:none;box-shadow:0 4px 12px #00000026;border:1px solid var(--border-primary);animation:tooltipFadeIn .2s ease-out}.nav-tooltip:before{content:"";position:absolute;right:100%;top:50%;transform:translateY(-50%);border:6px solid transparent;border-right-color:var(--border-primary)}.nav-tooltip:after{content:"";position:absolute;right:100%;top:50%;transform:translateY(-50%);border:5px solid transparent;border-right-color:var(--bg-card);margin-right:-1px}@keyframes tooltipFadeIn{0%{opacity:0;transform:translateY(-50%) translate(-8px)}to{opacity:1;transform:translateY(-50%) translate(0)}}.app{display:flex;width:100%;height:100%;overflow:hidden}.sidebar{width:260px;background:var(--bg-sidebar);color:var(--text-primary);display:flex;flex-direction:column;padding:0 0 80px;border-radius:12px;box-shadow:0 4px 12px #00000026;margin:8px;position:relative;z-index:999999;border:1px solid rgba(255,255,255,.15);transition:width .1s ease,margin .1s ease}.sidebar.collapsed{width:80px;margin-right:8px;overflow:visible}.sidebar.collapsed .logo h2,.sidebar.collapsed .nav-menu .nav-text,.sidebar.collapsed .github-link,.sidebar.collapsed .version-info{display:none;opacity:0}.sidebar.collapsed .logo{padding:20px 10px}.sidebar.collapsed .nav-menu a{padding:14px;justify-content:center}.sidebar.collapsed .theme-toggle{flex-direction:column;gap:8px;align-items:center}.logo{padding:16px 20px;border-bottom:2px solid rgba(255,255,255,.2);text-align:center;position:relative;overflow:hidden;transition:padding .3s ease;display:flex;flex-direction:row;align-items:center;justify-content:center;gap:12px}.logo h2{font-size:18px;font-weight:800;background:linear-gradient(135deg,#fff,#f8f8ff,#e6e6fa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;text-shadow:0 2px 4px rgba(0,0,0,.1);position:relative;z-index:1;letter-spacing:1px;text-transform:uppercase;transition:all .3s ease;margin:0}.logo-image{width:36px;height:36px;object-fit:contain;transition:all .3s ease;filter:drop-shadow(0 2px 8px rgba(0,0,0,.2));flex-shrink:0}.sidebar.collapsed .logo{justify-content:center;padding:12px 10px}.sidebar.collapsed .logo-image{width:32px;height:32px}.nav-menu{list-style:none;padding:16px 0;margin:0;overflow:visible}.nav-menu li{margin:8px 12px;overflow:visible}.nav-menu a{display:flex;align-items:center;gap:12px;padding:14px 20px;color:var(--text-sidebar);text-decoration:none;border-radius:12px;transition:all .3s ease-out;font-weight:500;position:relative;overflow:hidden}.nav-menu .nav-icon{font-size:20px;flex-shrink:0;transition:all .3s ease}.nav-menu .nav-text{transition:opacity .3s ease,width .3s ease;white-space:nowrap}.nav-menu a:before{content:"";position:absolute;top:0;left:-100%;width:100%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.15),transparent);transition:left .5s ease-out}.nav-menu a:hover:before{left:100%}.nav-menu a:hover{background-color:#ffffff1a}.nav-menu a.active{background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary))}.main-content{flex:1;padding:24px;overflow:auto;background:var(--bg-primary);position:relative;margin:16px 16px 16px 0;border-radius:20px;transition:margin .3s ease}.main-content>.routes-page,.main-content>.vendors-page,.main-content>.logs-page{min-width:1000px}.page-header{margin-bottom:24px;position:relative;z-index:1}.page-header-content{display:flex;justify-content:space-between;align-items:center;gap:20px}.page-header-text h1{font-family:Fredoka,sans-serif;font-size:28px;font-weight:700;color:var(--accent-primary);margin-bottom:8px;text-shadow:0 2px 4px var(--shadow-primary)}.page-header-text p{color:var(--text-muted);font-size:16px;font-weight:400}.card{background:var(--bg-card);border-radius:20px;padding:24px;box-shadow:0 2px 8px #00000014;margin-bottom:24px;border:1px solid var(--border-primary);position:relative;overflow:hidden;transition:all .3s ease-out}.card:before{content:"";position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--accent-primary),var(--accent-secondary));border-radius:20px 20px 0 0}.card:hover{box-shadow:0 4px 12px #0000001f}.btn{padding:10px 20px;border:none;border-radius:12px;cursor:pointer;font-size:14px;font-weight:600;transition:all .3s ease-out;position:relative;overflow:hidden;white-space:nowrap}.btn:before{content:"";position:absolute;top:50%;left:50%;width:0;height:0;background:#ffffff4d;border-radius:50%;transform:translate(-50%,-50%);transition:width .6s,height .6s}.btn:hover:before{width:300px;height:300px}.btn:active{transform:translateY(0)}.btn:disabled{opacity:.4;cursor:not-allowed}.btn-primary{background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary));color:#fff;position:relative;overflow:hidden}.btn-primary:before{content:"";position:absolute;top:0;left:-100%;width:100%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.3),transparent);transition:left .5s ease}.btn-primary:hover:before{left:100%}.btn-danger{background:var(--accent-danger);color:#fff}.btn-danger:hover{background:#ea580c}.btn-success{background:var(--accent-success);color:#fff}.btn-success:hover{background:#059669}.btn-secondary{background:var(--accent-secondary);color:#fff}.btn-secondary:hover{background:var(--accent-primary)}.btn-sm{padding:4px 8px}table{width:100%;border-collapse:collapse;margin-top:16px;border-radius:12px;overflow:hidden}table th,table td{padding:16px;text-align:left;border-bottom:1px solid var(--border-secondary);color:var(--text-primary)}table th{background:var(--bg-table-header);font-weight:700;color:var(--text-secondary);font-family:Fredoka,sans-serif;font-size:14px;white-space:nowrap}@media (max-width: 1200px){.rules-table .col-priority{display:none}.rules-table .action-buttons{flex-wrap:wrap;justify-content:flex-end}}.col-priority-box{display:flex;align-items:center;gap:4px}.priority-arrow-btn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;background-color:var(--bg-card);border:1px solid var(--border-primary);border-radius:4px;color:var(--text-primary);font-size:12px;line-height:1;cursor:pointer;transition:all .2s ease;vertical-align:middle}.priority-arrow-btn:hover{background-color:var(--primary-color);border-color:var(--primary-color);color:#fff}.priority-arrow-btn:active{transform:scale(.95)}.form-group{margin-bottom:20px}.form-group label{display:block;margin-bottom:8px;color:var(--text-primary);font-size:14px;font-weight:600;font-family:Nunito,sans-serif}.form-group input,.form-group select,.form-group textarea{width:100%;padding:12px 16px;border:2px solid var(--border-primary);border-radius:12px;font-size:14px;font-family:Nunito,sans-serif;background:var(--bg-secondary);color:var(--text-primary);transition:all .3s ease-out}.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--accent-primary);box-shadow:0 0 0 3px var(--shadow-secondary);background:var(--bg-secondary)}.form-group input:disabled,.form-group select:disabled,.form-group textarea:disabled{background:var(--bg-input-disabled);cursor:not-allowed;color:var(--text-input-disabled);opacity:.7}.form-group label small{font-size:.8em;color:var(--text-light)}@keyframes modalFadeIn{0%{opacity:0}to{opacity:1}}.modal{background:var(--bg-secondary);border-radius:24px;padding:32px 28px 32px 32px;min-width:500px;width:800px;max-width:90%;max-height:90vh;box-shadow:0 8px 24px #0003;border:1px solid var(--border-secondary);animation:modalSlideIn .4s ease-out;overflow:hidden;display:flex;flex-direction:column}.modal-container{overflow-y:auto;overflow-x:hidden;margin-right:-8px;padding-right:8px;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:var(--border-secondary) transparent}.modal-container::-webkit-scrollbar{width:8px}.modal-container::-webkit-scrollbar-track{background:transparent;border-radius:4px;margin:4px}.modal-container::-webkit-scrollbar-thumb{background:var(--border-secondary);border-radius:4px;border:2px solid transparent}.modal-container::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#0009;display:flex;justify-content:center;align-items:center;z-index:1000000;animation:modalFadeIn .3s ease-out}.modal-close-btn{position:absolute;top:20px;right:20px;width:48px;height:48px;border:none;background:var(--accent-light);color:var(--text-primary);font-size:32px;line-height:1;cursor:pointer;border-radius:50%;transition:all .2s ease;display:flex;align-items:center;justify-content:center;padding:0;border:1px solid rgba(255,255,255,.3);z-index:1001}.modal-close-btn:hover{background:var(--accent-danger);color:#fff;transform:scale(1.05)}.modal-close-btn:active{transform:scale(.95)}@keyframes modalSlideIn{0%{opacity:0;transform:translateY(-20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.modal-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;position:relative}.modal-header h2{font-size:20px;color:var(--text-primary);flex:1}.modal-footer{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}.modal--sticky-layout .modal-header{flex-shrink:0;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--border-color)}.modal--sticky-layout .modal-body-scrollable{flex:1;overflow-y:auto;overflow-x:hidden;min-height:0;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:var(--border-secondary) transparent;padding-right:8px;margin-right:-8px}.modal--sticky-layout .modal-body-scrollable::-webkit-scrollbar{width:8px}.modal--sticky-layout .modal-body-scrollable::-webkit-scrollbar-track{background:transparent}.modal--sticky-layout .modal-body-scrollable::-webkit-scrollbar-thumb{background-color:var(--border-secondary);border-radius:4px}.modal--sticky-layout .modal-footer{flex-shrink:0;margin-top:0;padding-top:16px;border-top:1px solid var(--border-color)}.session-refresh-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:1px solid var(--border-color);border-radius:8px;background:var(--bg-primary-solid);color:var(--text-secondary);cursor:pointer;transition:all .2s ease}.session-refresh-btn:hover:not(:disabled){background:var(--bg-hover);color:var(--text-primary)}.session-refresh-btn:disabled{opacity:.5;cursor:not-allowed}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.spin-icon{animation:spin 1s linear infinite}.session-view-toggle{display:inline-flex;gap:0;border:1px solid var(--border-color);border-radius:8px;overflow:hidden;margin-left:12px}.session-view-toggle button{padding:4px 14px;font-size:13px;border:none;background:var(--bg-primary);color:var(--text-secondary);cursor:pointer;transition:all .2s ease;white-space:nowrap}.session-view-toggle button:not(:last-child){border-right:1px solid var(--border-color)}.session-view-toggle button.active{background:var(--accent-light);color:var(--text-primary);font-weight:600}.session-view-toggle button:hover:not(.active){background:var(--bg-hover)}.chat-view-container{display:flex;flex-direction:column;gap:16px;padding:4px 0;position:relative}.chat-scroll-bottom{position:sticky;bottom:0;left:50%;display:flex;justify-content:center;padding:8px 0;pointer-events:none}.chat-scroll-bottom-btn{pointer-events:auto;width:36px;height:36px;border-radius:50%;border:1px solid var(--border-color);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s ease;box-shadow:0 2px 8px #00000026}.chat-scroll-bottom-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-message{display:flex;flex-direction:column}.chat-message--user{align-items:flex-end}.chat-message--assistant{align-items:flex-start}.chat-bubble{max-width:85%;padding:10px 14px;border-radius:12px;font-size:14px;line-height:1.6;word-break:break-word;white-space:pre-wrap}.chat-tool-header{font-size:12px;color:var(--text-tertiary);font-style:italic;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.55}.chat-collapse-top-bar{display:flex;align-items:center;justify-content:flex-end;gap:8px;position:sticky;top:0;z-index:1;margin-bottom:8px}.chat-message--user .chat-bubble{background:var(--accent-light);color:var(--text-primary);border-bottom-right-radius:4px}.chat-message--assistant .chat-bubble{background:var(--bg-primary-solid);color:var(--text-primary);border:1px solid var(--border-color);border-bottom-left-radius:4px}[data-theme=dark] .chat-message--user .chat-bubble{background:#003d22}[data-theme=dark] .chat-message--assistant .chat-bubble{background:#132d1c}[data-theme=dark] .chat-message--tool_result .chat-bubble,[data-theme=dark] .chat-message--tool_use .chat-bubble{background:#fff3}.chat-message--tool_result .chat-bubble,.chat-message--tool_use .chat-bubble{background:var(--bg-card);border:1px solid var(--border-color);opacity:.85}.chat-message--tool_result .chat-bubble{border-bottom-right-radius:4px}.chat-message--tool_use .chat-bubble{border-bottom-left-radius:4px}.chat-meta{font-size:12px;color:var(--text-tertiary);margin-top:4px;padding:0 4px}.chat-thinking{margin-bottom:8px;border:1px solid var(--border-thinking-box);border-radius:8px;padding:8px 10px;background-color:var(--bg-thinking-box)}.chat-thinking summary{cursor:pointer;font-weight:600;font-size:13px;color:var(--text-thinking-title);-webkit-user-select:none;user-select:none}.chat-thinking pre{margin-top:8px;white-space:pre-wrap;word-break:break-word;font-family:monospace;font-size:13px;color:var(--text-thinking-content);background-color:var(--bg-thinking-content);padding:8px;border-radius:4px;border:1px solid var(--border-thinking-content)}.chat-content-text{font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.chat-collapsible-wrapper{position:relative}.chat-collapse-btn-sticky{display:flex;justify-content:flex-end;flex-shrink:0;position:absolute;top:0;right:0}.chat-collapse-fade{position:relative;margin-top:-60px;height:60px;display:flex;align-items:center;justify-content:center;cursor:pointer}.chat-message--user .chat-collapse-fade{background:linear-gradient(to bottom,transparent,var(--accent-light))}.chat-message--assistant .chat-collapse-fade{background:linear-gradient(to bottom,transparent,var(--bg-primary-solid))}.chat-message--tool_result .chat-collapse-fade,.chat-message--tool_use .chat-collapse-fade{background:linear-gradient(to bottom,transparent,var(--bg-card))}[data-theme=dark] .chat-message--tool_result .chat-collapse-fade,[data-theme=dark] .chat-message--tool_use .chat-collapse-fade{background:linear-gradient(to bottom,transparent,rgba(255,255,255,.2))}.chat-collapse-fade-btn{font-size:12px;color:var(--text-secondary);background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:4px;padding:1px 10px;cursor:pointer;transition:all .2s ease;margin-top:40px}.chat-collapse-fade-btn:hover{background:var(--bg-secondary)}.chat-collapse-btn{display:inline-block;padding:2px 10px;font-size:12px;color:var(--text-secondary);background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:4px;cursor:pointer;transition:all .2s ease}.chat-collapse-btn:hover{background:var(--bg-secondary)}.chat-separator{text-align:center;color:var(--text-tertiary);font-size:12px;padding:4px 0;position:relative}.chat-separator:before,.chat-separator:after{content:"";position:absolute;top:50%;width:calc(50% - 40px);height:1px;background:var(--border-color)}.chat-separator:before{left:0}.chat-separator:after{right:0}.action-buttons{display:flex;gap:8px}.badge{display:inline-block;padding:6px 12px;border-radius:20px;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;white-space:nowrap}.badge-success{background:var(--accent-success);color:#fff}.badge-warning{background:var(--accent-warning);color:#fff}.badge-danger{background:var(--accent-danger);color:#fff}.badge-claude-code{background:#ce653c;color:#fff}.badge-codex{background:#1f2937;color:#fff}.empty-state{text-align:center;padding:60px 20px;color:var(--text-muted);font-family:Nunito,sans-serif}.empty-state p{margin-bottom:20px;font-size:16px;font-weight:500}.pagination{display:flex;justify-content:space-between;align-items:center;margin-top:20px;padding:16px;background:var(--bg-secondary);border-radius:12px;border:1px solid var(--border-primary);gap:20px;flex-wrap:wrap}.pagination-info{color:var(--text-muted);font-size:14px;font-weight:500}.pagination-controls{display:flex;align-items:center;gap:10px}.pagination-btn{padding:6px 14px;border:1px solid var(--border-primary);background:var(--bg-card);color:var(--text-primary);border-radius:8px;cursor:pointer;font-size:14px;font-weight:500;transition:all .2s ease}.pagination-btn:hover:not(:disabled){background:var(--accent-primary);color:#fff;border-color:var(--accent-primary)}.pagination-btn:disabled{opacity:.4;cursor:not-allowed;background:var(--bg-secondary)}.pagination-size{display:flex;align-items:center;gap:8px;color:var(--text-primary);font-size:14px;font-weight:500}.pagination-select{padding:6px 10px;border:1px solid var(--border-primary);background:var(--bg-card);color:var(--text-primary);border-radius:8px;cursor:pointer;font-size:14px;outline:none;transition:all .2s ease}.pagination-select:hover{border-color:var(--accent-primary)}.pagination-select:focus{border-color:var(--accent-primary);box-shadow:0 0 0 2px #3498db1a}.toolbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.theme-toggle{position:absolute;bottom:20px;left:20px;right:20px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.sidebar-toggle-btn{background:none;border:none;color:var(--text-sidebar);cursor:pointer;padding:8px;border-radius:8px;transition:all .3s ease-out;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700}.sidebar-toggle-btn:hover{background:#ffffff26;opacity:1}.github-link{background:none;border:none;color:var(--text-sidebar);cursor:pointer;padding:8px;border-radius:8px;transition:all .3s ease-out;display:flex;align-items:center;justify-content:center;opacity:.8;margin-left:auto}.github-link:hover{background:#ffffff26;opacity:1}.theme-toggle button{background:none;border:none;color:var(--text-sidebar);cursor:pointer;padding:8px;border-radius:8px;transition:all .3s ease-out;display:flex;align-items:center;justify-content:center}.version-info{font-size:12px;color:var(--text-sidebar);opacity:.7;font-family:Monaco,Menlo,monospace;font-weight:500;-webkit-user-select:none;user-select:none;transition:opacity .3s ease}.theme-toggle button:hover{background:#ffffff26}.theme-toggle button.active{background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary));color:#fff;animation:pulse 2s ease-in-out infinite}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.05)}}.version-info-wrapper{position:relative;display:flex;align-items:center}.version-info{font-size:12px;color:var(--text-sidebar);opacity:.7;font-family:Monaco,Menlo,monospace;font-weight:500;-webkit-user-select:none;user-select:none;transition:opacity .3s ease;position:relative}.version-info:hover{opacity:1}.version-badge{position:absolute;top:-2px;right:-6px;width:8px;height:8px;background:linear-gradient(135deg,#ef4444,#dc2626);border-radius:50%;border:2px solid var(--bg-sidebar);animation:pulse-badge 2s ease-in-out infinite;box-shadow:0 0 8px #ef444499}@keyframes pulse-badge{0%,to{transform:scale(1);opacity:1}50%{transform:scale(1.2);opacity:.8}}.version-update-popup{position:absolute;bottom:calc(100% + 12px);left:50%;transform:translate(-50%);background:#10b98126;border:1px solid rgba(16,185,129,.4);border-radius:12px;padding:12px;min-width:220px;box-shadow:0 4px 12px #0003;opacity:0;visibility:hidden;transition:all .3s ease-out;pointer-events:none;z-index:10000;text-decoration:none;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.version-info-wrapper:hover .version-update-popup,.version-update-popup:hover{opacity:1;visibility:visible;pointer-events:auto;transform:translate(-50%) translateY(12px)}.version-update-popup:after{content:"";position:absolute;top:100%;left:50%;transform:translate(-50%);border:6px solid transparent;border-top-color:#10b98166}.update-popup-content{display:flex;align-items:flex-start;gap:10px}.update-icon{font-size:18px;animation:bounce 1s ease-in-out infinite;flex-shrink:0}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.update-text{flex:1}.update-title{font-size:13px;font-weight:600;color:var(--text-sidebar);margin-bottom:4px}.update-versions{font-size:11px;color:#fffc;font-family:Monaco,Menlo,monospace;margin-bottom:6px}.update-message{font-size:10px;color:var(--text-sidebar);line-height:1.4}.update-message code{background:#ffffff26;padding:2px 4px;border-radius:4px;font-family:Monaco,Menlo,monospace;margin-top:2px;display:inline-block;color:#ffffffe6}@media (prefers-reduced-motion: reduce){.nav-menu a,.card,.btn,.form-group input,.form-group select,.form-group textarea,.modal-overlay,.modal,table tr{transition:none;animation:none}.nav-menu a:hover,.card:hover,.btn:hover,table tr:hover{transform:none}.btn:before{display:none}}.markdown-content{line-height:1.7;color:var(--text-primary);max-width:100%;overflow-x:auto}.markdown-content h1{font-size:2em;font-weight:700;margin-top:0;margin-bottom:.8em;color:var(--text-primary);border-bottom:2px solid var(--border-color);padding-bottom:.3em}.markdown-content h2{font-size:1.6em;font-weight:600;margin-top:1.5em;margin-bottom:.6em;color:var(--text-primary);border-bottom:1px solid var(--border-color);padding-bottom:.25em}.markdown-content h3{font-size:1.3em;font-weight:600;margin-top:1.2em;margin-bottom:.5em;color:var(--text-primary)}.markdown-content h4{font-size:1.1em;font-weight:600;margin-top:1em;margin-bottom:.4em;color:var(--text-primary)}.markdown-content p{margin-bottom:1em;line-height:1.8}.markdown-content ul,.markdown-content ol{margin-bottom:1em;padding-left:2em}.markdown-content li{margin-bottom:.5em;line-height:1.7}.markdown-content code{background:var(--bg-secondary);padding:.2em .4em;border-radius:4px;font-size:.9em;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,monospace;color:var(--accent-secondary);border:1px solid var(--border-color)}.markdown-content pre{background:var(--bg-secondary);padding:1em;border-radius:8px;overflow-x:auto;margin-bottom:1em;border:1px solid var(--border-color)}.markdown-content pre code{background:none;padding:0;border:none;color:var(--text-primary);font-size:.95em}.markdown-content blockquote{border-left:4px solid var(--accent-primary);padding-left:1em;margin-left:0;margin-bottom:1em;color:var(--text-secondary);font-style:italic}.markdown-content a{color:var(--accent-primary);text-decoration:none;border-bottom:1px solid var(--accent-secondary);transition:all .2s ease}.markdown-content a:hover{color:var(--accent-secondary)}.markdown-content table{width:100%;border-collapse:collapse;margin-bottom:1em}.markdown-content table th,.markdown-content table td{padding:.75em;text-align:left;border:1px solid var(--border-color)}.markdown-content table th{background:var(--bg-secondary);font-weight:600}.markdown-content hr{border:none;border-top:2px solid var(--border-color);margin:2em 0}.markdown-content strong{font-weight:600;color:var(--text-primary)}.markdown-content em{font-style:italic}.markdown-content img{max-width:100%;height:auto;border-radius:8px;margin:1em 0}.config-status-indicator{display:inline-block}.status-badge{display:inline-block;padding:4px 10px;border-radius:12px;font-size:11px;font-weight:600}.status-active{background:linear-gradient(135deg,#4caf50,#45a049);color:#fff}.status-backup{background:linear-gradient(135deg,#ff9800,#f57c00);color:#fff}.status-inactive{background:linear-gradient(135deg,#9e9e9e,#757575);color:#fff}.skills-header-row{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap}.skills-header-actions{margin-top:8px}.skills-discover-btn{padding:18px 36px;font-size:16px;font-weight:700;border-radius:14px;box-shadow:0 4px 12px #00000026;position:relative}.skills-discover-btn:after{content:"";position:absolute;top:-6px;right:-6px;bottom:-6px;left:-6px;border-radius:18px;border:2px solid rgba(16,185,129,.35);opacity:.6}.skills-section-header{display:flex;flex-direction:column;gap:6px;margin-bottom:20px}.skills-section-header h2{margin:0;font-size:22px;color:var(--text-primary)}.skills-section-header span{color:var(--text-muted);font-size:14px}.skills-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:16px}.skill-card{display:flex;flex-direction:column;gap:16px;min-height:180px}.skill-title{font-size:18px;font-weight:700;color:var(--text-primary);margin-bottom:8px}.skill-description{color:var(--text-muted);font-size:14px;line-height:1.6;flex:1}.skill-tags{display:flex;flex-wrap:wrap;gap:8px}.skills-discover{display:flex;flex-direction:column;gap:20px}.skills-search-card{display:flex;flex-direction:column;gap:16px}.skills-search-header h3{margin:0 0 6px;font-size:18px;color:var(--text-primary)}.skills-search-header p{margin:0;color:var(--text-muted);font-size:14px}.skills-search-input{width:100%;padding:12px 14px;border-radius:12px;border:1px solid var(--border-primary);background:var(--bg-secondary);color:var(--text-primary);resize:vertical;min-height:120px;font-size:14px;line-height:1.6}.skills-search-actions{display:flex;justify-content:flex-end}.skills-results{display:flex;flex-direction:column;gap:16px}.skills-result-actions{display:flex;justify-content:flex-end;gap:8px}.badge-secondary{background:#0f513226;color:var(--text-primary)}.switch{position:relative;width:44px;height:24px;border-radius:12px;border:none;cursor:pointer;background-color:#4b5563;transition:background-color .2s}.switch.active{background-color:var(--primary-color)}.switch:disabled{cursor:not-allowed;opacity:.6}.switch:focus{outline:none;box-shadow:0 0 0 2px var(--primary-color)}.switch::-moz-focus-inner{border:0}.rules-table .vendor-sevices-col>div{white-space:nowrap}.api-binding-card{padding:20px 24px!important}.api-binding-header{display:flex;align-items:center;gap:10px;margin-bottom:6px}.api-binding-header-icon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:10px;background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary));color:#fff;font-size:16px;flex-shrink:0}.api-binding-header h3{margin:0!important;font-size:18px!important;font-weight:700;letter-spacing:.2px}.api-binding-desc{margin:0 0 18px!important;font-size:13px!important;color:var(--text-muted)!important;line-height:1.6}.api-binding-baseurl-row{display:flex;align-items:center;margin:20px;border:1px solid var(--border-primary);border-radius:6px;overflow:hidden;background:var(--bg-secondary)}.api-binding-baseurl-prefix{flex-shrink:0;padding:6px 12px;font-size:12px;font-weight:600;color:var(--text-muted);background:var(--border-primary);letter-spacing:.3px}.api-binding-baseurl-value{flex:1;padding:6px 12px;font-family:monospace;font-size:13px;color:var(--text-secondary);-webkit-user-select:all;user-select:all}.api-binding-list{display:flex;flex-direction:column;gap:10px;margin:20px}.api-binding-row{display:flex;align-items:center;gap:12px;padding:10px 14px;border-radius:12px;background:var(--bg-secondary);border:1px solid var(--border-primary);transition:all .25s ease}.api-binding-row:hover{border-color:var(--accent-secondary);box-shadow:0 2px 8px var(--shadow-secondary)}.api-binding-path{flex:0 0 300px;padding:6px 12px;border-radius:8px;font-family:Monaco,Menlo,Consolas,monospace;font-size:13px;font-weight:600;letter-spacing:.3px;background:var(--bg-code);color:var(--accent-secondary);border:1px solid var(--border-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-user-select:all;user-select:all;transition:all .2s ease}.api-binding-path:hover{border-color:var(--accent-secondary)}.api-binding-path--disabled{background:var(--bg-route-item);color:var(--text-route-muted);opacity:.7}.api-binding-arrow{flex-shrink:0;color:var(--border-primary);font-size:16px;transition:color .2s ease}.api-binding-row:hover .api-binding-arrow{color:var(--accent-secondary)}.api-binding-control{flex:1;min-width:0;position:relative}.api-binding-control select,.api-binding-control input{width:100%;padding:8px 12px;border:1.5px solid var(--border-primary);border-radius:10px;font-size:13px;font-family:Nunito,sans-serif;background:var(--bg-card);color:var(--text-primary);transition:all .25s ease;-moz-appearance:none;appearance:none;-webkit-appearance:none;cursor:pointer}.api-binding-control input{cursor:text}.api-binding-control select{padding-right:32px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23065F46' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;background-size:14px}[data-theme=dark] .api-binding-control select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236EE7B7' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")}.api-binding-control select:focus,.api-binding-control input:focus{outline:none;border-color:var(--accent-primary);box-shadow:0 0 0 3px var(--shadow-secondary)}.api-binding-control select:hover,.api-binding-control input:hover{border-color:var(--accent-secondary)}.api-binding-status{flex-shrink:0;width:8px;height:8px;border-radius:50%;background:var(--border-primary);transition:all .3s ease}.api-binding-status--bound{background:var(--accent-success);box-shadow:0 0 6px var(--shadow-secondary)}.api-binding-footer{margin-top:18px;display:flex;align-items:center;justify-content:flex-end;gap:12px}.api-binding-save-btn{padding:14px 36px!important;font-size:16px!important;border-radius:14px!important;font-weight:700;letter-spacing:.3px;display:inline-flex;align-items:center;gap:8px}@media (max-width: 900px){.api-binding-row{flex-wrap:wrap}.api-binding-path{flex:1 1 100%}.api-binding-arrow{display:none}.api-binding-control{flex:1 1 100%}}.tool-binding-block{margin-bottom:20px;padding:16px 18px;border-radius:12px;background:var(--bg-secondary);border:1px solid var(--border-primary);transition:all .25s ease}.tool-binding-block:hover{border-color:var(--accent-secondary);box-shadow:0 2px 8px var(--shadow-secondary)}.tool-binding-label{display:flex;align-items:center;gap:8px;font-weight:600;font-size:14px;margin-bottom:12px;color:var(--text-primary)}.tool-binding-label-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:6px;background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary));color:#fff;font-size:13px;flex-shrink:0}.tool-binding-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.tool-binding-row select{flex:1;min-width:200px;padding:9px 32px 9px 12px;border:1.5px solid var(--border-primary);border-radius:10px;font-size:13px;font-family:Nunito,sans-serif;background-color:var(--bg-card);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23065F46' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;background-size:14px;color:var(--text-primary);-moz-appearance:none;appearance:none;-webkit-appearance:none;cursor:pointer;transition:all .25s ease}[data-theme=dark] .tool-binding-row select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236EE7B7' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")}.tool-binding-row select:hover{border-color:var(--accent-secondary)}.tool-binding-row select:focus{outline:none;border-color:var(--accent-primary);box-shadow:0 0 0 3px var(--shadow-secondary)}.tool-binding-row select:disabled{opacity:.5;cursor:not-allowed}.tool-binding-deactivate-btn{padding:8px 18px!important;font-size:13px!important;border-radius:10px!important;font-weight:600;white-space:nowrap}.tool-binding-desc{font-size:12px;color:var(--text-muted);margin-top:10px;line-height:1.6}.migration-source-info{background:var(--bg-secondary, #f5f6fa);border-radius:8px;padding:14px 18px;border:1px solid var(--border-primary)}.migration-source-title{font-size:16px;font-weight:600;color:var(--text-primary);margin-bottom:8px}.migration-source-meta{display:flex;gap:12px;align-items:center;font-size:13px;color:var(--text-tertiary);flex-wrap:wrap}.migration-source-meta .badge{padding:2px 10px;border-radius:12px;font-size:12px;font-weight:500}.migration-source-badge{padding:3px 12px!important;border-radius:20px!important;font-size:11px!important;font-weight:600!important;text-transform:uppercase;letter-spacing:.5px}.migration-badge-claude{background:#e67e22!important;color:#fff!important}.migration-badge-codex{background:#2d3436!important;color:#fff!important}.migration-tool-cards{display:flex;align-items:stretch;justify-content:flex-start;gap:12px}.migration-tool-card{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;gap:8px;padding:18px 20px 14px;border:2px solid var(--border-primary);border-radius:12px;background:var(--bg-primary);cursor:pointer;transition:all .15s ease;font-family:inherit;color:var(--text-primary)}.migration-tool-card:hover{border-color:var(--accent-color, #6c5ce7);background:var(--bg-secondary, #f5f6fa);transform:translateY(-1px);box-shadow:0 2px 8px #0000000a}.migration-tool-card.active{border-color:var(--accent-color, #6c5ce7);background:linear-gradient(135deg,#6c5ce70a,#00b8940a);box-shadow:0 0 0 3px #6c5ce71a}.migration-tool-card.is-source{cursor:default;border-style:dashed;border-color:var(--border-primary);background:var(--bg-secondary, #f5f6fa)}.migration-tool-card.is-source:hover{transform:none;box-shadow:none;border-color:var(--border-primary);background:var(--bg-secondary, #f5f6fa)}.migration-tool-card-icon{width:52px;height:52px;border-radius:14px;display:flex;align-items:center;justify-content:center;background:var(--bg-secondary, #f5f6fa);color:var(--accent-color, #6c5ce7);transition:all .15s ease}.migration-tool-card.active .migration-tool-card-icon{background:#6c5ce71a}.migration-tool-card.is-source .migration-tool-card-icon{opacity:.7}.migration-tool-card-name{font-size:16px;font-weight:600;white-space:nowrap}.migration-tool-card-desc{font-size:12px;color:var(--text-tertiary);text-align:center}.migration-tool-card-badge{position:absolute;top:-8px;right:-8px;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;color:#fff;background:#8e44ad;box-shadow:0 2px 4px #8e44ad4d}.migration-arrow{flex-shrink:0;display:flex;align-items:center;color:var(--accent-color, #6c5ce7);opacity:.5}.migration-empty-hint{margin-top:16px;padding:20px 24px;border:1px dashed var(--border-primary);border-radius:10px;background:var(--bg-secondary, #f5f6fa);display:flex;align-items:center;gap:16px;color:var(--text-tertiary)}.migration-empty-hint svg{flex-shrink:0;opacity:.4}.migration-options label{color:var(--text-secondary)}.migration-options input[type=checkbox]{accent-color:var(--accent-color, #6c5ce7)}.migration-prompt-textarea{width:100%;min-height:400px;padding:12px;border:1px solid var(--border-primary);border-radius:8px;font-size:13px;font-family:SF Mono,Menlo,Monaco,Consolas,monospace;background-color:var(--input-bg);color:var(--text-primary);resize:vertical;line-height:1.5}.migration-prompt-textarea:focus{outline:none;border-color:var(--accent-color, #6c5ce7);box-shadow:0 0 0 2px #6c5ce71a}.migration-preview-footer{font-size:13px;color:var(--text-tertiary)}.migration-launch-result{animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}[data-theme=dark] .migration-source-info{background:var(--bg-secondary, #1e1e2e)}[data-theme=dark] .migration-tool-card{border-color:var(--border-primary, #3a3a5c);background:var(--bg-primary, #1a1a2e)}[data-theme=dark] .migration-tool-card:hover{border-color:var(--accent-color, #a29bfe);background:var(--bg-secondary, #1e1e2e)}[data-theme=dark] .migration-tool-card.active{border-color:var(--accent-color, #a29bfe);background:linear-gradient(135deg,#a29bfe0f,#00cec90f)}[data-theme=dark] .migration-tool-card.is-source,[data-theme=dark] .migration-tool-card.is-source:hover{border-color:var(--border-primary, #3a3a5c);background:var(--bg-secondary, #1e1e2e)}[data-theme=dark] .migration-tool-card-icon{background:var(--bg-secondary, #1e1e2e);color:var(--accent-color, #a29bfe)}[data-theme=dark] .migration-tool-card.active .migration-tool-card-icon{background:#a29bfe1a}[data-theme=dark] .migration-arrow{color:var(--accent-color, #a29bfe)}[data-theme=dark] .migration-prompt-textarea{background:var(--input-bg, #1e1e2e);color:var(--text-primary, #e0e0e0);border-color:var(--border-primary, #3a3a5c)}[data-theme=dark] .migration-options label,[data-theme=dark] .migration-source-meta{color:var(--text-secondary, #a0a0b8)}.route-icon-popover{position:absolute;bottom:calc(100% + 6px);right:0;background:var(--bg-tooltip, #333);color:#fff;font-size:11px;padding:4px 8px;border-radius:4px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .15s ease;z-index:100;box-shadow:0 2px 8px #00000026}.route-icon-popover:after{content:"";position:absolute;top:100%;right:4px;border:4px solid transparent;border-top-color:var(--bg-tooltip, #333)}div:hover>.route-icon-popover{opacity:1}*{margin:0;padding:0;box-sizing:border-box}:root{--primary-color: #14532D;--error-color: #DC2626;--bg-primary: linear-gradient(135deg, #F7FEE7 0%, #F0FDF4 100%);--bg-primary-solid: #F3FCEF;--bg-secondary: rgba(255, 255, 255, .95);--bg-sidebar: linear-gradient(135deg, #0F5132 0%, #065F46 100%);--bg-card: rgba(255, 255, 255, .98);--bg-code: #f4fff7;--bg-table-header: linear-gradient(135deg, #A7F3D0 0%, #6EE7B7 100%);--text-primary: #14532D;--text-secondary: #064E3B;--text-muted: #065F46;--text-sidebar: #FFFFFF;--text-on-dark: #FFFFFF;--border-primary: rgba(15, 81, 50, .2);--border-secondary: rgba(6, 95, 70, .2);--accent-primary: #0F5132;--accent-secondary: #047857;--accent-light: #a1e9c7;--accent-success: #047857;--accent-warning: #D97706;--accent-danger: #DC2626;--shadow-primary: rgba(15, 81, 50, .3);--shadow-secondary: rgba(15, 81, 50, .15);--bg-route-item: rgba(248, 249, 250, .9);--bg-route-item-hover: rgba(230, 244, 234, .95);--bg-route-item-selected: rgba(161, 233, 199, .25);--text-route-muted: #6c757d;--text-info: #2faeee;--text-light: #018038;--bg-info-box: #f8f9fa;--border-info-box: #e0e0e0;--text-info-box: #666;--bg-info-blue: #e3f2fd;--border-info-blue: #2196f3;--bg-info-green: #f1f8e9;--border-info-green: #8bc34a;--bg-info-orange: #fff3e0;--border-info-orange: #ff9800;--bg-info-yellow: #fff8e1;--border-info-yellow: #ffc107;--bg-assembled-text: #f8f9fa;--bg-thinking-box: #fff9e6;--border-thinking-box: #e0e0e0;--text-thinking-title: #f39c12;--bg-thinking-content: #fff;--border-thinking-content: #f0e6d3;--text-thinking-content: #555;--text-reply-title: #333;--bg-reply-content: #fff;--border-reply-content: #ddd;--text-reply-content: #333;--bg-input-disabled: #e5e7eb;--text-input-disabled: #9ca3af}[data-theme=dark]{--bg-primary: linear-gradient(135deg, #0A1A0F 0%, #0F2415 100%);--bg-primary-solid: #0C1F12;--bg-secondary: rgba(15, 36, 21, .9);--bg-sidebar: linear-gradient(135deg, #0F5132 0%, #065F46 100%);--bg-card: rgba(25, 51, 31, .95);--bg-code: #0f172a;--bg-table-header: linear-gradient(135deg, #0F5132 0%, #047857 100%);--text-primary: #ECFEF5;--text-secondary: #A7F3D0;--text-muted: #6EE7B7;--text-sidebar: #FFFFFF;--text-on-dark: #ECFEF5;--border-primary: rgba(15, 81, 50, .5);--border-secondary: rgba(6, 95, 70, .5);--accent-primary: #0F5132;--accent-secondary: #047857;--accent-light: #002d18;--accent-success: #10B981;--accent-warning: #F59E0B;--accent-danger: #EF4444;--shadow-primary: rgba(15, 81, 50, .4);--shadow-secondary: rgba(6, 95, 70, .3);--bg-route-item: rgba(20, 46, 28, .7);--bg-route-item-hover: rgba(30, 60, 38, .85);--bg-route-item-selected: rgba(16, 185, 129, .15);--text-route-muted: #A7F3D0;--text-light: #999999;--bg-info-box: rgba(20, 46, 28, .6);--border-info-box: rgba(161, 233, 199, .2);--text-info-box: #A7F3D0;--bg-info-blue: rgba(13, 71, 161, .25);--border-info-blue: #1976d2;--bg-info-green: rgba(27, 94, 32, .25);--border-info-green: #689f38;--bg-info-orange: rgba(230, 81, 0, .2);--border-info-orange: #f57c00;--bg-info-yellow: rgba(255, 193, 7, .15);--border-info-yellow: #ffb300;--bg-assembled-text: rgba(15, 23, 42, .5);--bg-thinking-box: rgba(230, 81, 0, .15);--border-thinking-box: rgba(245, 158, 11, .3);--text-thinking-title: #fbbf24;--bg-thinking-content: rgba(15, 23, 42, .4);--border-thinking-content: rgba(245, 158, 11, .2);--text-thinking-content: #d1d5db;--text-reply-title: #e5e7eb;--bg-reply-content: rgba(15, 23, 42, .4);--border-reply-content: rgba(161, 233, 199, .2);--text-reply-content: #e5e7eb;--bg-input-disabled: #2d3748;--text-input-disabled: #718096}body{font-family:Nunito,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:var(--bg-primary);color:var(--text-primary);transition:all .3s ease;min-height:100vh}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}#root{width:100vw;height:100vh;overflow:visible}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:var(--bg-secondary);border-radius:6px}::-webkit-scrollbar-thumb{background:var(--accent-secondary);border-radius:6px;border:2px solid var(--bg-secondary)}::-webkit-scrollbar-thumb:hover{background:var(--accent-primary)}::-webkit-scrollbar-corner{background:var(--bg-secondary)}*{scrollbar-width:thin;scrollbar-color:var(--accent-primary) var(--bg-secondary)}::-webkit-scrollbar-button{display:none}html{scroll-behavior:smooth}.datetime-picker-input{cursor:pointer}.datetime-picker-input::-webkit-calendar-picker-indicator{cursor:pointer;opacity:1;filter:brightness(0);padding:2px 4px}.datetime-picker-input::-webkit-calendar-picker-indicator:hover{filter:brightness(.3)}.datetime-picker-input::-moz-calendar-picker-indicator{cursor:pointer;opacity:1;filter:brightness(0);padding:2px 4px}.datetime-picker-input::-moz-calendar-picker-indicator:hover{filter:brightness(.3)}[data-theme=dark] .datetime-picker-input::-webkit-calendar-picker-indicator{filter:brightness(0) invert(1)}[data-theme=dark] .datetime-picker-input::-webkit-calendar-picker-indicator:hover{filter:brightness(.2) invert(1)}[data-theme=dark] .datetime-picker-input::-moz-calendar-picker-indicator{filter:brightness(0) invert(1)}[data-theme=dark] .datetime-picker-input::-moz-calendar-picker-indicator:hover{filter:brightness(.2) invert(1)}