aicodeswitch 2.0.11 → 2.1.1
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 +2 -0
- package/CLAUDE.md +28 -1
- package/TECH.md +292 -170
- package/dist/server/proxy-server.js +88 -13
- package/dist/server/transformers/claude-openai.js +554 -48
- package/dist/server/transformers/streaming.js +169 -2
- package/dist/ui/assets/index-B5wnowv6.css +1 -0
- package/dist/ui/assets/{index-BC_wSFXP.js → index-DXvVJfvE.js} +53 -53
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/schemes/claude.schema.md +945 -0
- package/schemes/openai.schema.md +2162 -0
- package/dist/ui/assets/index-DQ2LJr-O.css +0 -1
|
@@ -287,6 +287,13 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
|
|
|
287
287
|
callback();
|
|
288
288
|
return;
|
|
289
289
|
}
|
|
290
|
+
// 检查是否是 OpenAI Responses API 的事件
|
|
291
|
+
// Responses API 事件类型如:response.reasoning_text.delta, response.output_text.delta 等
|
|
292
|
+
if (event.event && event.event.startsWith('response.')) {
|
|
293
|
+
this.handleResponsesAPIEvent(event);
|
|
294
|
+
callback();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
290
297
|
const chunk = event.data;
|
|
291
298
|
if (!chunk) {
|
|
292
299
|
callback();
|
|
@@ -384,6 +391,7 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
|
|
|
384
391
|
},
|
|
385
392
|
});
|
|
386
393
|
}
|
|
394
|
+
// 处理 OpenAI Chat Completions API 的 thinking content
|
|
387
395
|
if (typeof ((_a = delta.thinking) === null || _a === void 0 ? void 0 : _a.content) === 'string') {
|
|
388
396
|
this.ensureMessageStart();
|
|
389
397
|
if (this.thinkingBlockIndex === null) {
|
|
@@ -448,6 +456,107 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
|
|
|
448
456
|
}
|
|
449
457
|
}
|
|
450
458
|
}
|
|
459
|
+
// 处理 OpenAI Responses API 的流式事件
|
|
460
|
+
handleResponsesAPIEvent(event) {
|
|
461
|
+
const type = event.event;
|
|
462
|
+
const data = event.data;
|
|
463
|
+
// 处理 reasoning 文本增量(完整推理过程)
|
|
464
|
+
if (type === 'response.reasoning_text.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
465
|
+
this.ensureMessageStart();
|
|
466
|
+
if (this.thinkingBlockIndex === null) {
|
|
467
|
+
this.thinkingBlockIndex = this.assignContentBlockIndex();
|
|
468
|
+
this.pushEvent('content_block_start', {
|
|
469
|
+
type: 'content_block_start',
|
|
470
|
+
index: this.thinkingBlockIndex,
|
|
471
|
+
content_block: { type: 'thinking', thinking: '' },
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
this.pushEvent('content_block_delta', {
|
|
475
|
+
type: 'content_block_delta',
|
|
476
|
+
index: this.thinkingBlockIndex,
|
|
477
|
+
delta: {
|
|
478
|
+
type: 'thinking_delta',
|
|
479
|
+
thinking: data.delta,
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
// 处理 reasoning summary 文本增量(推理摘要)
|
|
484
|
+
if (type === 'response.reasoning_summary_text.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
485
|
+
this.ensureMessageStart();
|
|
486
|
+
if (this.thinkingBlockIndex === null) {
|
|
487
|
+
this.thinkingBlockIndex = this.assignContentBlockIndex();
|
|
488
|
+
this.pushEvent('content_block_start', {
|
|
489
|
+
type: 'content_block_start',
|
|
490
|
+
index: this.thinkingBlockIndex,
|
|
491
|
+
content_block: { type: 'thinking', thinking: '' },
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
this.pushEvent('content_block_delta', {
|
|
495
|
+
type: 'content_block_delta',
|
|
496
|
+
index: this.thinkingBlockIndex,
|
|
497
|
+
delta: {
|
|
498
|
+
type: 'thinking_delta',
|
|
499
|
+
thinking: data.delta,
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
// 处理普通文本增量
|
|
504
|
+
if (type === 'response.output_text.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
505
|
+
this.ensureMessageStart();
|
|
506
|
+
if (this.textBlockIndex === null) {
|
|
507
|
+
this.textBlockIndex = this.assignContentBlockIndex();
|
|
508
|
+
this.pushEvent('content_block_start', {
|
|
509
|
+
type: 'content_block_start',
|
|
510
|
+
index: this.textBlockIndex,
|
|
511
|
+
content_block: { type: 'text' },
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
this.pushEvent('content_block_delta', {
|
|
515
|
+
type: 'content_block_delta',
|
|
516
|
+
index: this.textBlockIndex,
|
|
517
|
+
delta: {
|
|
518
|
+
type: 'text_delta',
|
|
519
|
+
text: data.delta,
|
|
520
|
+
},
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
// 处理拒绝内容增量(内容过滤等)
|
|
524
|
+
if (type === 'response.refusal.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
525
|
+
// 拒绝内容可以作为文本发送
|
|
526
|
+
this.ensureMessageStart();
|
|
527
|
+
if (this.textBlockIndex === null) {
|
|
528
|
+
this.textBlockIndex = this.assignContentBlockIndex();
|
|
529
|
+
this.pushEvent('content_block_start', {
|
|
530
|
+
type: 'content_block_start',
|
|
531
|
+
index: this.textBlockIndex,
|
|
532
|
+
content_block: { type: 'text' },
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
this.pushEvent('content_block_delta', {
|
|
536
|
+
type: 'content_block_delta',
|
|
537
|
+
index: this.textBlockIndex,
|
|
538
|
+
delta: {
|
|
539
|
+
type: 'text_delta',
|
|
540
|
+
text: data.delta,
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
// 处理函数调用参数增量
|
|
545
|
+
if (type === 'response.function_call_arguments.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
546
|
+
// OpenAI Responses API 的函数调用
|
|
547
|
+
// 这需要与现有的 tool_calls 处理逻辑配合
|
|
548
|
+
// 暂时先跳过,因为 Responses API 使用不同的函数调用格式
|
|
549
|
+
}
|
|
550
|
+
// 处理响应完成事件
|
|
551
|
+
if (type === 'response.completed' || type === 'response.failed' || type === 'response.incomplete') {
|
|
552
|
+
// 确保所有内容块都已关闭
|
|
553
|
+
this.finalize();
|
|
554
|
+
}
|
|
555
|
+
// 处理响应创建和进行中事件
|
|
556
|
+
if (type === 'response.created' || type === 'response.in_progress') {
|
|
557
|
+
this.ensureMessageStart();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
451
560
|
finalize() {
|
|
452
561
|
if (this.finalized)
|
|
453
562
|
return;
|
|
@@ -536,6 +645,12 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
536
645
|
writable: true,
|
|
537
646
|
value: null
|
|
538
647
|
});
|
|
648
|
+
Object.defineProperty(this, "stopReason", {
|
|
649
|
+
enumerable: true,
|
|
650
|
+
configurable: true,
|
|
651
|
+
writable: true,
|
|
652
|
+
value: 'stop'
|
|
653
|
+
}); // OpenAI 的 finish_reason
|
|
539
654
|
Object.defineProperty(this, "errorEmitted", {
|
|
540
655
|
enumerable: true,
|
|
541
656
|
configurable: true,
|
|
@@ -573,6 +688,9 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
573
688
|
if (data.content_block.type === 'text') {
|
|
574
689
|
// 文本块开始
|
|
575
690
|
}
|
|
691
|
+
else if (data.content_block.type === 'thinking') {
|
|
692
|
+
// thinking 块开始(无需特殊处理)
|
|
693
|
+
}
|
|
576
694
|
else if (data.content_block.type === 'tool_use') {
|
|
577
695
|
this.pendingToolCallId = data.content_block.id;
|
|
578
696
|
this.pendingToolName = data.content_block.name;
|
|
@@ -588,6 +706,14 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
588
706
|
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { content: text } }] } });
|
|
589
707
|
}
|
|
590
708
|
}
|
|
709
|
+
else if (data.delta.type === 'thinking_delta') {
|
|
710
|
+
// 处理 thinking 增量,转换为 OpenAI 格式
|
|
711
|
+
const thinking = data.delta.thinking || '';
|
|
712
|
+
if (thinking) {
|
|
713
|
+
// OpenAI 兼容格式:使用 delta.thinking.content
|
|
714
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { thinking: { content: thinking } } }] } });
|
|
715
|
+
}
|
|
716
|
+
}
|
|
591
717
|
else if (data.delta.type === 'input_json_delta') {
|
|
592
718
|
this.pendingToolArgs += data.delta.partial_json || '';
|
|
593
719
|
}
|
|
@@ -616,11 +742,30 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
616
742
|
}
|
|
617
743
|
if (type === 'message_stop' || (data === null || data === void 0 ? void 0 : data.type) === 'message_stop') {
|
|
618
744
|
this.finished = true;
|
|
619
|
-
|
|
745
|
+
// 使用映射后的 stop reason
|
|
746
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: this.stopReason }] } });
|
|
620
747
|
this.push({ event: 'done', data: { type: 'done' } });
|
|
621
748
|
callback();
|
|
622
749
|
return;
|
|
623
750
|
}
|
|
751
|
+
// 处理 message_delta 事件(包含 stop_reason 和 usage)
|
|
752
|
+
if (type === 'message_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
753
|
+
// 映射 Claude 的 stop_reason 到 OpenAI 的 finish_reason
|
|
754
|
+
if (data.delta.stop_reason) {
|
|
755
|
+
this.stopReason = this.mapStopReason(data.delta.stop_reason);
|
|
756
|
+
}
|
|
757
|
+
// 处理 usage 信息
|
|
758
|
+
if (data.usage) {
|
|
759
|
+
this.usage = {
|
|
760
|
+
prompt_tokens: data.usage.input_tokens || 0,
|
|
761
|
+
completion_tokens: data.usage.output_tokens || 0,
|
|
762
|
+
total_tokens: (data.usage.input_tokens || 0) + (data.usage.output_tokens || 0),
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
// 不发送 delta 事件,只在最终 message_stop 时发送 finish_reason
|
|
766
|
+
callback();
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
624
769
|
if (data === null || data === void 0 ? void 0 : data.usage) {
|
|
625
770
|
this.usage = {
|
|
626
771
|
prompt_tokens: data.usage.input_tokens || 0,
|
|
@@ -639,7 +784,7 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
639
784
|
try {
|
|
640
785
|
if (!this.finished) {
|
|
641
786
|
this.finished = true;
|
|
642
|
-
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason:
|
|
787
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: this.stopReason }] } });
|
|
643
788
|
this.push({ event: 'done', data: { type: 'done' } });
|
|
644
789
|
}
|
|
645
790
|
callback();
|
|
@@ -649,5 +794,27 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
649
794
|
callback();
|
|
650
795
|
}
|
|
651
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* 将 Claude 的 stop_reason 映射到 OpenAI 的 finish_reason
|
|
799
|
+
* Claude: "end_turn" | "max_tokens" | "tool_use" | "stop_sequence" | "max_thinking_length"
|
|
800
|
+
* OpenAI: "stop" | "length" | "tool_calls" | "content_filter"
|
|
801
|
+
*/
|
|
802
|
+
mapStopReason(stopReason) {
|
|
803
|
+
switch (stopReason) {
|
|
804
|
+
case 'end_turn':
|
|
805
|
+
return 'stop';
|
|
806
|
+
case 'max_tokens':
|
|
807
|
+
case 'max_thinking_length':
|
|
808
|
+
return 'length';
|
|
809
|
+
case 'tool_use':
|
|
810
|
+
return 'tool_calls';
|
|
811
|
+
case 'stop_sequence':
|
|
812
|
+
return 'stop';
|
|
813
|
+
case 'content_filter':
|
|
814
|
+
return 'content_filter';
|
|
815
|
+
default:
|
|
816
|
+
return 'stop';
|
|
817
|
+
}
|
|
818
|
+
}
|
|
652
819
|
}
|
|
653
820
|
exports.ClaudeToOpenAIChatEventTransform = ClaudeToOpenAIChatEventTransform;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.app{display:flex;width:100%;height:100%}.sidebar{width:260px;background:var(--bg-sidebar);color:var(--text-primary);display:flex;flex-direction:column;padding:0 0 80px;border-radius:20px;box-shadow:0 4px 12px #00000026;margin:16px;position:relative;z-index:1;border:1px solid rgba(255,255,255,.15)}.logo{padding:28px 20px;border-bottom:2px solid rgba(255,255,255,.2);text-align:center;position:relative;overflow:hidden}.logo:before{content:"✨";position:absolute;top:12px;left:12px;font-size:16px;opacity:.7;transition:all .3s ease}.logo:after{content:"🌟";position:absolute;top:12px;right:12px;font-size:16px;opacity:.7;transition:all .3s ease}.logo h2{font-size:22px;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}.nav-menu{list-style:none;padding:16px 0;margin:0}.nav-menu li{margin:8px 12px}.nav-menu a{display:block;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 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;transform:translate(4px)}.nav-menu a.active{background:linear-gradient(135deg,var(--accent-primary),var(--accent-secondary))}.main-content{flex:1;padding:24px;overflow-y:auto;background:var(--bg-primary);position:relative;z-index:1;margin:16px 16px 16px 0;border-radius:20px}.main-content:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background-image:radial-gradient(circle at 20% 80%,rgba(255,206,92,.1) 0%,transparent 50%),radial-gradient(circle at 80% 20%,rgba(134,204,202,.1) 0%,transparent 50%),radial-gradient(circle at 40% 40%,rgba(255,113,206,.05) 0%,transparent 50%);pointer-events:none}.page-header{margin-bottom:24px;position:relative;z-index:1}.page-header 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 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{transform:translateY(-2px);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:hover{transform:translateY(-1px)}.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-primary:hover{transform:translateY(-2px)}.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}.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:1000;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}.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}.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}.version-info:hover{opacity:1}.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)}}.update-notification{position:absolute;bottom:48px;left:20px;right:20px;background:#10b98126;border:1px solid rgba(16,185,129,.4);border-radius:12px;padding:8px;animation:slideUp .3s ease-out;box-shadow:0 2px 8px #0000001a;margin-bottom:12px}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.update-notification-content{display:flex;align-items:center;gap:10px}.update-icon{font-size:18px;animation:bounce 1s ease-in-out infinite}@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:2px}.update-versions{font-size:11px;color:#ffffffb3;font-family:Monaco,Menlo,monospace}.update-message{font-size:10px;color:var(--text-sidebar);margin-bottom:2px}.update-message code{background:#ffffff1a;padding:2px 4px;border-radius:4px;font-family:Monaco,Menlo,monospace;margin-top:2px;display:inline-block}.update-link{display:block;text-align:center;padding:6px 12px;background:linear-gradient(135deg,var(--accent-success),#059669);color:#fff;text-decoration:none;border-radius:8px;font-size:12px;font-weight:600;transition:all .3s ease-out}.update-link:hover{transform:translateY(-1px)}@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}*{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-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-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:hidden}::-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)}
|