@greatlhd/ailo-desktop 1.0.0 → 1.0.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.
@@ -360,19 +360,6 @@ code {
360
360
  .sub-panel { display:none; }
361
361
  .sub-panel.active { display:block; }
362
362
 
363
- /* ─── Blueprint viewer ───────────────────────────────────────── */
364
- .blueprint-tabs { flex-wrap:wrap; }
365
- .blueprint-content {
366
- background: var(--bg-base);
367
- border: 1px solid var(--border);
368
- border-radius: var(--radius-md);
369
- padding: 16px 18px;
370
- font-size: 13px; line-height:1.65;
371
- white-space: pre-wrap; overflow: auto;
372
- max-height: 60vh; color: var(--text-secondary);
373
- font-family:'SF Mono','Fira Code',monospace;
374
- }
375
-
376
363
  /* ─── Skills ─────────────────────────────────────────────────── */
377
364
  .skill-item {
378
365
  display: flex; justify-content:space-between; align-items:center;
@@ -537,3 +524,255 @@ code {
537
524
  .main-content { padding:16px; }
538
525
  .info-grid { grid-template-columns:1fr; }
539
526
  }
527
+
528
+ /* ─── Tools Grid ─────────────────────────────────────────────── */
529
+ .tools-section {
530
+ margin-bottom: 20px;
531
+ }
532
+ .tools-section-title {
533
+ font-size: 13px;
534
+ font-weight: 600;
535
+ color: var(--text-muted);
536
+ text-transform: uppercase;
537
+ letter-spacing: 0.05em;
538
+ margin-bottom: 10px;
539
+ display: flex;
540
+ align-items: center;
541
+ gap: 8px;
542
+ }
543
+ .tools-section-title .count {
544
+ background: var(--bg-muted);
545
+ padding: 2px 8px;
546
+ border-radius: 10px;
547
+ font-size: 12px;
548
+ }
549
+ .tools-grid {
550
+ display: grid;
551
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
552
+ gap: 10px;
553
+ }
554
+ .tool-item {
555
+ background: var(--bg-surface);
556
+ border: 1px solid var(--border);
557
+ border-radius: var(--radius-md);
558
+ padding: 12px 14px;
559
+ }
560
+ .tool-name {
561
+ font-size: 14px;
562
+ font-weight: 500;
563
+ margin-bottom: 4px;
564
+ }
565
+ .tool-name code {
566
+ background: var(--bg-muted);
567
+ padding: 2px 6px;
568
+ border-radius: 4px;
569
+ font-size: 13px;
570
+ color: var(--accent-light);
571
+ }
572
+ .tool-desc {
573
+ font-size: 13px;
574
+ color: var(--text-muted);
575
+ line-height: 1.5;
576
+ }
577
+ .tools-empty {
578
+ font-size: 13px;
579
+ color: var(--text-muted);
580
+ font-style: italic;
581
+ }
582
+
583
+ /* ─── Skills Grid ─────────────────────────────────────────────── */
584
+ .skills-grid {
585
+ display: grid;
586
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
587
+ gap: 10px;
588
+ }
589
+ .skill-item {
590
+ background: var(--bg-surface);
591
+ border: 1px solid var(--border);
592
+ border-radius: var(--radius-md);
593
+ padding: 14px 16px;
594
+ }
595
+ .skill-name {
596
+ font-size: 14px;
597
+ font-weight: 600;
598
+ color: var(--accent-light);
599
+ margin-bottom: 4px;
600
+ }
601
+ .skill-desc {
602
+ font-size: 13px;
603
+ color: var(--text-muted);
604
+ }
605
+
606
+ /* ─── MCP Servers ──────────────────────────────────────────────── */
607
+ .mcp-servers {
608
+ display: flex;
609
+ flex-direction: column;
610
+ gap: 10px;
611
+ }
612
+ .mcp-server-item {
613
+ background: var(--bg-surface);
614
+ border: 1px solid var(--border);
615
+ border-radius: var(--radius-md);
616
+ padding: 14px 16px;
617
+ }
618
+ .mcp-server-item.running {
619
+ border-color: rgba(80, 214, 141, 0.3);
620
+ }
621
+ .mcp-server-header {
622
+ display: flex;
623
+ align-items: center;
624
+ justify-content: space-between;
625
+ margin-bottom: 8px;
626
+ }
627
+ .mcp-server-name {
628
+ font-size: 15px;
629
+ font-weight: 600;
630
+ }
631
+ .mcp-server-status {
632
+ display: flex;
633
+ align-items: center;
634
+ gap: 6px;
635
+ font-size: 13px;
636
+ color: var(--text-muted);
637
+ }
638
+ .mcp-server-status .status-dot {
639
+ width: 8px;
640
+ height: 8px;
641
+ border-radius: 50%;
642
+ }
643
+ .mcp-server-status .status-dot.running {
644
+ background: var(--success);
645
+ box-shadow: 0 0 6px var(--success);
646
+ }
647
+ .mcp-server-status .status-dot.stopped {
648
+ background: var(--text-muted);
649
+ }
650
+ .mcp-server-conn {
651
+ font-size: 12px;
652
+ color: var(--text-muted);
653
+ margin-bottom: 10px;
654
+ word-break: break-all;
655
+ }
656
+ .mcp-server-conn code {
657
+ background: var(--bg-muted);
658
+ padding: 2px 6px;
659
+ border-radius: 4px;
660
+ }
661
+ .mcp-server-footer {
662
+ display: flex;
663
+ align-items: center;
664
+ justify-content: space-between;
665
+ }
666
+ .mcp-server-tools {
667
+ font-size: 12px;
668
+ color: var(--text-muted);
669
+ }
670
+ .mcp-server-actions {
671
+ display: flex;
672
+ gap: 6px;
673
+ }
674
+
675
+ /* ─── Status Header ────────────────────────────────────────────── */
676
+ .status-header {
677
+ display: flex;
678
+ align-items: center;
679
+ gap: 16px;
680
+ margin-bottom: 20px;
681
+ }
682
+ .status-icon {
683
+ width: 56px;
684
+ height: 56px;
685
+ border-radius: var(--radius-lg);
686
+ display: flex;
687
+ align-items: center;
688
+ justify-content: center;
689
+ flex-shrink: 0;
690
+ }
691
+ .status-icon svg {
692
+ width: 28px;
693
+ height: 28px;
694
+ }
695
+ .status-icon.connected {
696
+ background: var(--success-soft);
697
+ color: var(--success);
698
+ }
699
+ .status-icon.disconnected {
700
+ background: var(--bg-muted);
701
+ color: var(--text-muted);
702
+ }
703
+ .status-info {
704
+ flex: 1;
705
+ min-width: 0;
706
+ }
707
+ .status-title {
708
+ font-size: 20px;
709
+ font-weight: 700;
710
+ }
711
+ .status-subtitle {
712
+ font-size: 14px;
713
+ color: var(--text-muted);
714
+ margin-top: 2px;
715
+ }
716
+
717
+ /* ─── Status Stats ─────────────────────────────────────────────── */
718
+ .status-stats {
719
+ display: grid;
720
+ grid-template-columns: repeat(4, 1fr);
721
+ gap: 12px;
722
+ margin-bottom: 20px;
723
+ }
724
+ @media (max-width: 900px) {
725
+ .status-stats {
726
+ grid-template-columns: repeat(2, 1fr);
727
+ }
728
+ }
729
+ .stat-item {
730
+ background: var(--bg-surface);
731
+ border: 1px solid var(--border);
732
+ border-radius: var(--radius-md);
733
+ padding: 14px 16px;
734
+ }
735
+ .stat-label {
736
+ font-size: 12px;
737
+ color: var(--text-muted);
738
+ text-transform: uppercase;
739
+ letter-spacing: 0.05em;
740
+ margin-bottom: 4px;
741
+ }
742
+ .stat-value {
743
+ font-size: 18px;
744
+ font-weight: 700;
745
+ color: var(--text-primary);
746
+ }
747
+
748
+ /* ─── Connection Status in Sidebar ────────────────────────────── */
749
+ .connection-status {
750
+ display: flex;
751
+ align-items: center;
752
+ gap: 6px;
753
+ margin-top: 3px;
754
+ font-size: 12px;
755
+ color: var(--text-muted);
756
+ }
757
+ .connection-status .status-dot {
758
+ width: 6px;
759
+ height: 6px;
760
+ }
761
+
762
+ /* ─── Tab Count Badge ──────────────────────────────────────────── */
763
+ .tab-count {
764
+ background: var(--bg-muted);
765
+ padding: 1px 6px;
766
+ border-radius: 8px;
767
+ font-size: 11px;
768
+ margin-left: 4px;
769
+ }
770
+
771
+ /* ─── Env Grid ────────────────────────────────────────────────── */
772
+ .env-grid {
773
+ display: flex;
774
+ flex-direction: column;
775
+ }
776
+ .env-action {
777
+ flex-shrink: 0;
778
+ }
@@ -18,7 +18,7 @@
18
18
  </div>
19
19
  <div class="brand-info">
20
20
  <div class="brand-name">Ailo Desktop</div>
21
- <div class="brand-status">
21
+ <div class="connection-status" id="connectionStatus">
22
22
  <span class="status-dot off" id="globalDot"></span>
23
23
  <span id="globalStatus">未连接</span>
24
24
  </div>
@@ -26,7 +26,6 @@
26
26
  </div>
27
27
 
28
28
  <nav class="sidebar-nav">
29
- <div class="nav-section-label">主界面</div>
30
29
  <div class="nav-item active" data-panel="chat" onclick="nav('chat')">
31
30
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
32
31
  <span>网页聊天</span>
@@ -35,25 +34,21 @@
35
34
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
36
35
  <span>状态</span>
37
36
  </div>
38
-
39
- <div class="nav-section-label">能力</div>
40
37
  <div class="nav-item" data-panel="tools" onclick="nav('tools')">
41
38
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
42
39
  <span>工具</span>
40
+ <span class="nav-badge" id="toolsCount" style="display:none">0</span>
43
41
  </div>
44
42
  <div class="nav-item" data-panel="mcp" onclick="nav('mcp')">
45
43
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
46
44
  <span>MCP</span>
45
+ <span class="nav-badge" id="mcpCount" style="display:none">0</span>
47
46
  </div>
48
-
49
- <div class="nav-section-label">通道配置</div>
50
47
  <div class="nav-item" data-panel="feishu" onclick="nav('feishu')">
51
48
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
52
49
  <span>飞书</span>
53
50
  <span class="nav-badge off" id="feishuNavBadge" style="display:none"></span>
54
51
  </div>
55
-
56
- <div class="nav-section-label">系统</div>
57
52
  <div class="nav-item" data-panel="env" onclick="nav('env')">
58
53
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
59
54
  <span>运行环境</span>
@@ -72,46 +67,53 @@
72
67
 
73
68
  <!-- 状态 -->
74
69
  <div class="panel" id="panel-status">
75
- <div class="card" id="statusCard">
76
- <div class="connection-hero">
77
- <div class="connection-icon" id="connectionIcon">
78
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
70
+ <div class="card">
71
+ <div class="status-header">
72
+ <div class="status-icon" id="statusIcon">
73
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
79
74
  <path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/>
80
75
  <path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/>
81
76
  </svg>
82
77
  </div>
83
- <div>
84
- <div class="connection-label" id="connectionLabel">未连接</div>
85
- <div class="connection-sublabel" id="connectionSublabel">尚未连接至 Ailo 服务</div>
78
+ <div class="status-info">
79
+ <div class="status-title" id="statusTitle">未连接</div>
80
+ <div class="status-subtitle" id="statusSubtitle">尚未连接至 Ailo 服务</div>
86
81
  </div>
87
- <div style="margin-left:auto" id="connectionBadgeWrap"></div>
88
82
  </div>
89
- <div class="info-grid" id="statusInfoGrid" style="display:none">
90
- <div class="info-item">
91
- <div class="info-item-label">端点 ID</div>
92
- <div class="info-item-value" id="statusEndpointId">-</div>
83
+ <div class="status-stats" id="statusStats">
84
+ <div class="stat-item">
85
+ <div class="stat-label">端点 ID</div>
86
+ <div class="stat-value" id="statEndpointId">-</div>
87
+ </div>
88
+ <div class="stat-item">
89
+ <div class="stat-label">已上报工具</div>
90
+ <div class="stat-value" id="statToolCount">-</div>
93
91
  </div>
94
- <div class="info-item">
95
- <div class="info-item-label">连接状态</div>
96
- <div class="info-item-value" id="statusConnected">-</div>
92
+ <div class="stat-item">
93
+ <div class="stat-label">MCP 服务</div>
94
+ <div class="stat-value" id="statMcpCount">-</div>
95
+ </div>
96
+ <div class="stat-item">
97
+ <div class="stat-label">运行时间</div>
98
+ <div class="stat-value" id="statUptime">-</div>
97
99
  </div>
98
100
  </div>
99
101
  </div>
100
102
 
101
- <!-- 连接配置(仅 showConnectionForm=true 时显示) -->
103
+ <!-- 连接配置 -->
102
104
  <div class="card" id="connectionFormCard" style="display:none">
103
105
  <div class="card-header">
104
- <div>
105
- <div class="card-title">
106
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
107
- Ailo 连接配置
108
- </div>
109
- <div class="card-desc">保存后将使用新配置自动重连,无需重启进程</div>
106
+ <div class="card-title">
107
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
108
+ Ailo 连接配置
110
109
  </div>
111
110
  </div>
112
- <div class="form-group"><label>AILO_WS_URL</label><input id="connWsUrl" placeholder="ws://127.0.0.1:19800/ws"></div>
113
- <div class="form-group"><label>AILO_API_KEY</label><input id="connApiKey" type="text" placeholder="ailo_ep_xxx" autocomplete="off"></div>
114
- <div class="form-group"><label>AILO_ENDPOINT_ID</label><input id="connEndpointId" placeholder="desktop-01"></div>
111
+ <div class="card-desc">保存后将使用新配置自动重连,无需重启进程</div>
112
+ <div class="form-row">
113
+ <div class="form-group"><label>AILO_WS_URL</label><input id="connWsUrl" placeholder="ws://127.0.0.1:19800/ws"></div>
114
+ <div class="form-group"><label>AILO_API_KEY</label><input id="connApiKey" type="text" placeholder="ailo_ep_xxx" autocomplete="off"></div>
115
+ <div class="form-group"><label>端点 ID</label><input id="connEndpointId" placeholder="desktop-01"></div>
116
+ </div>
115
117
  <div class="btn-group">
116
118
  <button class="btn btn-primary" id="saveConnBtn" onclick="saveConnection()">
117
119
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
@@ -124,40 +126,31 @@
124
126
  <!-- 工具 -->
125
127
  <div class="panel" id="panel-tools">
126
128
  <div class="sub-tabs">
127
- <button class="sub-tab active" data-sub="reported" onclick="toolsSub('reported')">已上报工具</button>
128
- <button class="sub-tab" data-sub="blueprints" onclick="toolsSub('blueprints')">蓝图</button>
129
+ <button class="sub-tab active" data-sub="tools" onclick="toolsSub('tools')">工具<span class="tab-count" id="toolsTabCount">0</span></button>
130
+ <button class="sub-tab" data-sub="skills" onclick="toolsSub('skills')">技能<span class="tab-count" id="skillsTabCount">0</span></button>
129
131
  </div>
130
- <div class="sub-panel active" id="sub-reported">
132
+ <div class="sub-panel active" id="sub-tools">
131
133
  <div class="card">
132
134
  <div class="card-header">
133
- <div class="card-title">
134
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
135
- 已上报工具
136
- </div>
137
- <button class="btn btn-secondary btn-sm" onclick="loadReportedTools()">
135
+ <div class="card-title">已上报工具</div>
136
+ <button class="btn btn-secondary btn-sm" onclick="refreshTools()">
138
137
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-3.51"/></svg>
139
138
  刷新
140
139
  </button>
141
140
  </div>
142
- <div class="card-desc" style="margin-bottom:12px">桌面端向 Ailo 注册的能力(蓝图 + MCP),可直接在对话中调用</div>
143
141
  <div id="reportedToolsList"><div class="loading-text">加载中...</div></div>
144
142
  </div>
145
143
  </div>
146
- <div class="sub-panel" id="sub-blueprints">
144
+ <div class="sub-panel" id="sub-skills">
147
145
  <div class="card">
148
146
  <div class="card-header">
149
- <div class="card-title">
150
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
151
- 蓝图
152
- </div>
153
- <button class="btn btn-secondary btn-sm" onclick="loadAllBlueprints()">
147
+ <div class="card-title">已上报技能</div>
148
+ <button class="btn btn-secondary btn-sm" onclick="loadReportedSkills()">
154
149
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-3.51"/></svg>
155
150
  刷新
156
151
  </button>
157
152
  </div>
158
- <div class="card-desc" style="margin-bottom:14px">当前激活蓝图列表(仅已配置的通道才会出现)</div>
159
- <div class="sub-tabs blueprint-tabs" id="blueprintTabRow"></div>
160
- <div id="blueprintPanels"><div class="loading-text">加载中...</div></div>
153
+ <div id="reportedSkillsList"><div class="loading-text">加载中...</div></div>
161
154
  </div>
162
155
  </div>
163
156
  </div>
@@ -166,11 +159,8 @@
166
159
  <div class="panel" id="panel-mcp">
167
160
  <div class="card">
168
161
  <div class="card-header">
169
- <div class="card-title">
170
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
171
- MCP 服务
172
- </div>
173
- <div class="btn-group" style="margin:0">
162
+ <div class="card-title">MCP 服务</div>
163
+ <div class="btn-group">
174
164
  <button class="btn btn-primary btn-sm" onclick="showMCPCreateModal()">
175
165
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
176
166
  新增
@@ -181,7 +171,7 @@
181
171
  </button>
182
172
  </div>
183
173
  </div>
184
- <div class="card-desc" style="margin-bottom:12px">配置保存在 <code>~/.agents/mcp_config.json</code>,新增后需点击「启动」才会上报工具</div>
174
+ <div class="card-desc">新增或启动 MCP 服务后,工具会自动上报到 Ailo</div>
185
175
  <div id="mcpList"><div class="loading-text">加载中...</div></div>
186
176
  </div>
187
177
  </div>
@@ -189,16 +179,15 @@
189
179
  <!-- 飞书 -->
190
180
  <div class="panel" id="panel-feishu">
191
181
  <div class="card">
192
- <div class="channel-header">
193
- <div class="channel-icon" style="background:rgba(6,182,212,.15)">🐦</div>
194
- <div>
195
- <div class="channel-title">飞书通道</div>
196
- <div class="channel-subtitle">通过飞书 WebSocket 接收消息并代为回复</div>
197
- </div>
198
- <div style="margin-left:auto" id="feishuStatusBadge"></div>
182
+ <div class="card-header">
183
+ <div class="card-title">飞书配置</div>
184
+ <div id="feishuStatusBadge"></div>
185
+ </div>
186
+ <div class="card-desc">配置飞书机器人以接收和回复消息</div>
187
+ <div class="form-row">
188
+ <div class="form-group"><label>App ID</label><input id="feishuAppId" placeholder="cli_xxx"></div>
189
+ <div class="form-group"><label>App Secret</label><input id="feishuAppSecret" type="text" autocomplete="off" placeholder="应用密钥"></div>
199
190
  </div>
200
- <div class="form-group"><label>App ID</label><input id="feishuAppId" placeholder="cli_xxx"></div>
201
- <div class="form-group"><label>App Secret</label><input id="feishuAppSecret" type="text" autocomplete="off" placeholder="应用密钥"></div>
202
191
  <div class="btn-group">
203
192
  <button class="btn btn-primary" id="saveFeishuBtn" onclick="saveFeishuConfig()">
204
193
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
@@ -212,16 +201,12 @@
212
201
  <div class="panel" id="panel-env">
213
202
  <div class="card">
214
203
  <div class="card-header">
215
- <div class="card-title">
216
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
217
- 运行环境检测
218
- </div>
204
+ <div class="card-title">运行环境</div>
219
205
  <button class="btn btn-secondary btn-sm" onclick="loadEnvCheck()">
220
206
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-3.51"/></svg>
221
207
  刷新
222
208
  </button>
223
209
  </div>
224
- <div class="card-desc" style="margin-bottom:16px">以下为桌面端与 Skills 所需的运行环境。未安装时请按提示操作;仅「Playwright Chromium」支持一键安装。</div>
225
210
  <div id="envCheckList"><div class="loading-text">加载中...</div></div>
226
211
  <div id="envInstallRow" style="margin-top:14px;display:none">
227
212
  <button class="btn btn-primary btn-sm" id="envInstallBtn" onclick="doEnvInstall()">
@@ -244,20 +229,22 @@
244
229
  <div class="modal-overlay" id="mcpCreateModal">
245
230
  <div class="modal modal-lg">
246
231
  <div class="modal-title">新增 MCP 服务</div>
247
- <div class="modal-sub">选择传输类型:stdio(本地命令)或 SSE(远程服务器 URL)</div>
248
- <div class="form-group"><label>名称</label><input id="mcpName" placeholder="filesystem"></div>
249
- <div class="form-group">
250
- <label>传输类型</label>
251
- <select id="mcpTransport" onchange="onMCPTransportChange()">
252
- <option value="stdio">stdio(本地命令)</option>
253
- <option value="sse">SSE(远程服务器)</option>
254
- </select>
232
+ <div class="modal-sub">stdio(本地命令)或 SSE(远程服务器 URL)</div>
233
+ <div class="form-row">
234
+ <div class="form-group"><label>名称</label><input id="mcpName" placeholder="filesystem"></div>
235
+ <div class="form-group">
236
+ <label>传输类型</label>
237
+ <select id="mcpTransport" onchange="onMCPTransportChange()">
238
+ <option value="stdio">stdio</option>
239
+ <option value="sse">SSE</option>
240
+ </select>
241
+ </div>
255
242
  </div>
256
243
  <div id="mcpStdioFields">
257
244
  <div class="form-group">
258
- <label>命令与参数(数组,每行一项)</label>
259
- <div id="mcpCommandArgsList" style="display:flex;flex-direction:column;gap:6px;margin-bottom:8px"></div>
260
- <button type="button" class="btn btn-secondary btn-sm" onclick="addMCPArgvRow()">+ 添加一项</button>
245
+ <label>命令与参数</label>
246
+ <div id="mcpCommandArgsList"></div>
247
+ <button type="button" class="btn btn-secondary btn-sm" onclick="addMCPArgvRow()">+ 添加参数</button>
261
248
  </div>
262
249
  </div>
263
250
  <div id="mcpSSEFields" style="display:none">
@@ -265,7 +252,7 @@
265
252
  </div>
266
253
  <div class="form-group">
267
254
  <label>环境变量</label>
268
- <div id="mcpEnvList" style="display:flex;flex-direction:column;gap:6px;margin-bottom:8px"></div>
255
+ <div id="mcpEnvList"></div>
269
256
  <button type="button" class="btn btn-secondary btn-sm" onclick="addMCPEnvRow()">+ 添加环境变量</button>
270
257
  </div>
271
258
  <div class="modal-footer">
@@ -279,7 +266,7 @@
279
266
  <div class="modal-overlay" id="envHintModal">
280
267
  <div class="modal">
281
268
  <div class="modal-title" id="envHintModalTitle">安装说明</div>
282
- <div id="envHintModalContent" style="font-size:14px;color:var(--text-secondary);line-height:1.65;white-space:pre-line;max-height:55vh;overflow:auto"></div>
269
+ <div id="envHintModalContent"></div>
283
270
  <div class="modal-footer">
284
271
  <button class="btn btn-secondary btn-sm" onclick="hideModal('envHintModal')">关闭</button>
285
272
  </div>