@hirohsu/user-web-feedback 2.6.0

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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +953 -0
  3. package/dist/cli.cjs +95778 -0
  4. package/dist/index.cjs +92818 -0
  5. package/dist/static/app.js +385 -0
  6. package/dist/static/components/navbar.css +406 -0
  7. package/dist/static/components/navbar.html +49 -0
  8. package/dist/static/components/navbar.js +211 -0
  9. package/dist/static/dashboard.css +495 -0
  10. package/dist/static/dashboard.html +95 -0
  11. package/dist/static/dashboard.js +540 -0
  12. package/dist/static/favicon.svg +27 -0
  13. package/dist/static/index.html +541 -0
  14. package/dist/static/logs.html +376 -0
  15. package/dist/static/logs.js +442 -0
  16. package/dist/static/mcp-settings.html +797 -0
  17. package/dist/static/mcp-settings.js +884 -0
  18. package/dist/static/modules/app-core.js +124 -0
  19. package/dist/static/modules/conversation-panel.js +247 -0
  20. package/dist/static/modules/feedback-handler.js +1420 -0
  21. package/dist/static/modules/image-handler.js +155 -0
  22. package/dist/static/modules/log-viewer.js +296 -0
  23. package/dist/static/modules/mcp-manager.js +474 -0
  24. package/dist/static/modules/prompt-manager.js +364 -0
  25. package/dist/static/modules/settings-manager.js +299 -0
  26. package/dist/static/modules/socket-manager.js +170 -0
  27. package/dist/static/modules/state-manager.js +352 -0
  28. package/dist/static/modules/timer-controller.js +243 -0
  29. package/dist/static/modules/ui-helpers.js +246 -0
  30. package/dist/static/settings.html +355 -0
  31. package/dist/static/settings.js +425 -0
  32. package/dist/static/socket.io.min.js +7 -0
  33. package/dist/static/style.css +2157 -0
  34. package/dist/static/terminals.html +357 -0
  35. package/dist/static/terminals.js +321 -0
  36. package/package.json +91 -0
@@ -0,0 +1,797 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-TW">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>🔧 MCP Settings - User Feedback</title>
7
+ <link rel="icon" type="image/svg+xml" href="favicon.svg">
8
+ <script src="/socket.io.min.js"></script>
9
+ <!-- Navbar Component -->
10
+ <link rel="stylesheet" href="/components/navbar.css">
11
+ <link rel="stylesheet" href="style.css">
12
+ <link rel="stylesheet" href="dashboard.css">
13
+ <style>
14
+ .mcp-container {
15
+ max-width: 1200px;
16
+ margin: 0 auto;
17
+ padding: 20px;
18
+ }
19
+
20
+ .page-header {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ align-items: center;
24
+ margin-bottom: 24px;
25
+ padding-bottom: 16px;
26
+ border-bottom: 1px solid var(--border-color, #e1e5e9);
27
+ }
28
+
29
+ .page-title {
30
+ display: flex;
31
+ align-items: center;
32
+ gap: 12px;
33
+ font-size: 1.5rem;
34
+ font-weight: 600;
35
+ color: var(--text-primary, #1a1a2e);
36
+ }
37
+
38
+ .btn-group {
39
+ display: flex;
40
+ gap: 8px;
41
+ }
42
+
43
+ .btn {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ gap: 6px;
47
+ padding: 8px 16px;
48
+ border: none;
49
+ border-radius: 6px;
50
+ font-size: 14px;
51
+ font-weight: 500;
52
+ cursor: pointer;
53
+ transition: all 0.2s ease;
54
+ }
55
+
56
+ .btn-primary {
57
+ background: var(--primary-color, #4a90d9);
58
+ color: white;
59
+ }
60
+
61
+ .btn-primary:hover {
62
+ background: var(--primary-hover, #3a7bc8);
63
+ }
64
+
65
+ .btn-secondary {
66
+ background: var(--bg-secondary, #f5f7fa);
67
+ color: var(--text-primary, #1a1a2e);
68
+ border: 1px solid var(--border-color, #e1e5e9);
69
+ }
70
+
71
+ .btn-secondary:hover {
72
+ background: var(--bg-tertiary, #eef1f5);
73
+ }
74
+
75
+ .btn-success {
76
+ background: #22c55e;
77
+ color: white;
78
+ }
79
+
80
+ .btn-success:hover {
81
+ background: #16a34a;
82
+ }
83
+
84
+ .btn-danger {
85
+ background: #ef4444;
86
+ color: white;
87
+ }
88
+
89
+ .btn-danger:hover {
90
+ background: #dc2626;
91
+ }
92
+
93
+ .server-list {
94
+ display: flex;
95
+ flex-direction: column;
96
+ gap: 16px;
97
+ }
98
+
99
+ .server-card {
100
+ background: var(--bg-primary, #ffffff);
101
+ border: 1px solid var(--border-color, #e1e5e9);
102
+ border-radius: 12px;
103
+ overflow: hidden;
104
+ transition: box-shadow 0.2s ease;
105
+ }
106
+
107
+ .server-card:hover {
108
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
109
+ }
110
+
111
+ .server-card.connected {
112
+ border-color: #22c55e;
113
+ }
114
+
115
+ .server-card.error {
116
+ border-color: #ef4444;
117
+ }
118
+
119
+ .server-header {
120
+ display: flex;
121
+ justify-content: space-between;
122
+ align-items: center;
123
+ padding: 16px 20px;
124
+ background: var(--bg-secondary, #f5f7fa);
125
+ border-bottom: 1px solid var(--border-color, #e1e5e9);
126
+ }
127
+
128
+ .server-info {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 12px;
132
+ }
133
+
134
+ .server-name {
135
+ font-size: 16px;
136
+ font-weight: 600;
137
+ color: var(--text-primary, #1a1a2e);
138
+ }
139
+
140
+ .server-badge {
141
+ display: inline-flex;
142
+ align-items: center;
143
+ padding: 2px 8px;
144
+ border-radius: 10px;
145
+ font-size: 11px;
146
+ font-weight: 500;
147
+ }
148
+
149
+ .deferred-badge {
150
+ background: #fef3c7;
151
+ color: #92400e;
152
+ }
153
+
154
+ .server-card.deferred {
155
+ border-left: 3px solid #f59e0b;
156
+ }
157
+
158
+ .server-status {
159
+ display: inline-flex;
160
+ align-items: center;
161
+ gap: 6px;
162
+ padding: 4px 10px;
163
+ border-radius: 12px;
164
+ font-size: 12px;
165
+ font-weight: 500;
166
+ }
167
+
168
+ .server-status.connected {
169
+ background: #dcfce7;
170
+ color: #166534;
171
+ }
172
+
173
+ .server-status.disconnected {
174
+ background: #f3f4f6;
175
+ color: #6b7280;
176
+ }
177
+
178
+ .server-status.connecting {
179
+ background: #fef3c7;
180
+ color: #92400e;
181
+ }
182
+
183
+ .server-status.reconnecting {
184
+ background: #dbeafe;
185
+ color: #1e40af;
186
+ animation: pulse 2s infinite;
187
+ }
188
+
189
+ .server-status.error {
190
+ background: #fee2e2;
191
+ color: #991b1b;
192
+ }
193
+
194
+ @keyframes pulse {
195
+ 0%, 100% { opacity: 1; }
196
+ 50% { opacity: 0.6; }
197
+ }
198
+
199
+ .status-dot {
200
+ width: 8px;
201
+ height: 8px;
202
+ border-radius: 50%;
203
+ background: currentColor;
204
+ }
205
+
206
+ .btn-warning {
207
+ background: #f59e0b;
208
+ color: white;
209
+ }
210
+
211
+ .btn-warning:hover {
212
+ background: #d97706;
213
+ }
214
+
215
+ .error-section {
216
+ background: #fef2f2;
217
+ border-radius: 8px;
218
+ padding: 12px;
219
+ margin-top: 8px;
220
+ }
221
+
222
+ .server-actions {
223
+ display: flex;
224
+ gap: 8px;
225
+ flex-wrap: wrap;
226
+ }
227
+
228
+ .server-body {
229
+ padding: 16px 20px;
230
+ }
231
+
232
+ .server-details {
233
+ display: grid;
234
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
235
+ gap: 12px;
236
+ margin-bottom: 16px;
237
+ }
238
+
239
+ .detail-item {
240
+ display: flex;
241
+ flex-direction: column;
242
+ gap: 4px;
243
+ }
244
+
245
+ .detail-label {
246
+ font-size: 12px;
247
+ color: var(--text-secondary, #6b7280);
248
+ text-transform: uppercase;
249
+ letter-spacing: 0.5px;
250
+ }
251
+
252
+ .detail-value {
253
+ font-size: 14px;
254
+ color: var(--text-primary, #1a1a2e);
255
+ font-family: monospace;
256
+ word-break: break-all;
257
+ }
258
+
259
+ .tools-section {
260
+ margin-top: 20px;
261
+ padding-top: 16px;
262
+ border-top: 1px solid var(--border-color, #e1e5e9);
263
+ }
264
+
265
+ .tools-header {
266
+ display: flex;
267
+ justify-content: space-between;
268
+ align-items: center;
269
+ margin-bottom: 12px;
270
+ }
271
+
272
+ .tools-title {
273
+ font-size: 14px;
274
+ font-weight: 600;
275
+ color: var(--text-primary, #1a1a2e);
276
+ }
277
+
278
+ .tools-count {
279
+ font-size: 12px;
280
+ color: var(--text-secondary, #6b7280);
281
+ }
282
+
283
+ .tools-grid {
284
+ display: grid;
285
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
286
+ gap: 8px;
287
+ max-height: 400px;
288
+ overflow-y: auto;
289
+ }
290
+
291
+ .tool-item {
292
+ display: flex;
293
+ align-items: flex-start;
294
+ gap: 10px;
295
+ padding: 10px 12px;
296
+ background: var(--bg-secondary, #f5f7fa);
297
+ border-radius: 8px;
298
+ border: 1px solid transparent;
299
+ transition: all 0.2s ease;
300
+ }
301
+
302
+ .tool-item:hover {
303
+ border-color: var(--border-color, #e1e5e9);
304
+ }
305
+
306
+ .tool-item.disabled {
307
+ opacity: 0.6;
308
+ background: var(--bg-tertiary, #eef1f5);
309
+ }
310
+
311
+ .tool-checkbox {
312
+ margin-top: 2px;
313
+ width: 16px;
314
+ height: 16px;
315
+ cursor: pointer;
316
+ }
317
+
318
+ .tool-info {
319
+ flex: 1;
320
+ min-width: 0;
321
+ }
322
+
323
+ .tool-name {
324
+ font-size: 13px;
325
+ font-weight: 500;
326
+ color: var(--text-primary, #1a1a2e);
327
+ word-break: break-word;
328
+ }
329
+
330
+ .tool-description {
331
+ font-size: 12px;
332
+ color: var(--text-secondary, #6b7280);
333
+ margin-top: 2px;
334
+ display: -webkit-box;
335
+ -webkit-line-clamp: 2;
336
+ -webkit-box-orient: vertical;
337
+ overflow: hidden;
338
+ }
339
+
340
+ /* Serena 快速設定區塊 */
341
+ .serena-setup {
342
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
343
+ border-radius: 12px;
344
+ padding: 24px;
345
+ margin-bottom: 24px;
346
+ color: white;
347
+ }
348
+
349
+ .serena-setup h2 {
350
+ display: flex;
351
+ align-items: center;
352
+ gap: 10px;
353
+ margin: 0 0 12px 0;
354
+ font-size: 1.25rem;
355
+ }
356
+
357
+ .serena-setup p {
358
+ margin: 0 0 16px 0;
359
+ opacity: 0.9;
360
+ font-size: 14px;
361
+ }
362
+
363
+ .serena-form {
364
+ display: flex;
365
+ gap: 12px;
366
+ align-items: flex-end;
367
+ }
368
+
369
+ .serena-input-group {
370
+ flex: 1;
371
+ }
372
+
373
+ .serena-input-group label {
374
+ display: block;
375
+ font-size: 12px;
376
+ margin-bottom: 6px;
377
+ opacity: 0.9;
378
+ }
379
+
380
+ .serena-input-group input {
381
+ width: 100%;
382
+ padding: 10px 12px;
383
+ border: 1px solid rgba(255, 255, 255, 0.3);
384
+ border-radius: 6px;
385
+ background: rgba(255, 255, 255, 0.1);
386
+ color: white;
387
+ font-size: 14px;
388
+ }
389
+
390
+ .serena-input-group input::placeholder {
391
+ color: rgba(255, 255, 255, 0.6);
392
+ }
393
+
394
+ .serena-input-group input:focus {
395
+ outline: none;
396
+ border-color: rgba(255, 255, 255, 0.5);
397
+ background: rgba(255, 255, 255, 0.15);
398
+ }
399
+
400
+ .btn-serena {
401
+ background: white;
402
+ color: #667eea;
403
+ font-weight: 600;
404
+ padding: 10px 20px;
405
+ }
406
+
407
+ .btn-serena:hover {
408
+ background: #f0f0f0;
409
+ }
410
+
411
+ /* Modal */
412
+ .modal {
413
+ display: none;
414
+ position: fixed;
415
+ top: 0;
416
+ left: 0;
417
+ width: 100%;
418
+ height: 100%;
419
+ background: rgba(0, 0, 0, 0.5);
420
+ z-index: 1000;
421
+ align-items: center;
422
+ justify-content: center;
423
+ }
424
+
425
+ .modal.active {
426
+ display: flex;
427
+ }
428
+
429
+ .modal-content {
430
+ background: var(--bg-primary, #ffffff);
431
+ border-radius: 12px;
432
+ max-width: 500px;
433
+ width: 90%;
434
+ max-height: 80vh;
435
+ overflow-y: auto;
436
+ }
437
+
438
+ .modal-header {
439
+ display: flex;
440
+ justify-content: space-between;
441
+ align-items: center;
442
+ padding: 16px 20px;
443
+ border-bottom: 1px solid var(--border-color, #e1e5e9);
444
+ }
445
+
446
+ .modal-title {
447
+ font-size: 18px;
448
+ font-weight: 600;
449
+ }
450
+
451
+ .modal-close {
452
+ background: none;
453
+ border: none;
454
+ font-size: 24px;
455
+ cursor: pointer;
456
+ color: var(--text-secondary, #6b7280);
457
+ }
458
+
459
+ .modal-body {
460
+ padding: 20px;
461
+ }
462
+
463
+ .form-group {
464
+ margin-bottom: 16px;
465
+ }
466
+
467
+ .form-label {
468
+ display: block;
469
+ font-size: 14px;
470
+ font-weight: 500;
471
+ margin-bottom: 6px;
472
+ color: var(--text-primary, #1a1a2e);
473
+ }
474
+
475
+ .form-input,
476
+ .form-select,
477
+ .form-textarea {
478
+ width: 100%;
479
+ padding: 10px 12px;
480
+ border: 1px solid var(--border-color, #e1e5e9);
481
+ border-radius: 6px;
482
+ font-size: 14px;
483
+ background: var(--bg-primary, #ffffff);
484
+ color: var(--text-primary, #1a1a2e);
485
+ }
486
+
487
+ .form-input:focus,
488
+ .form-select:focus,
489
+ .form-textarea:focus {
490
+ outline: none;
491
+ border-color: var(--primary-color, #4a90d9);
492
+ }
493
+
494
+ .form-textarea {
495
+ min-height: 80px;
496
+ resize: vertical;
497
+ }
498
+
499
+ .form-divider {
500
+ border-top: 1px solid var(--border-color, #e1e5e9);
501
+ margin: 20px 0;
502
+ }
503
+
504
+ .form-checkbox-group {
505
+ display: flex;
506
+ align-items: flex-start;
507
+ gap: 10px;
508
+ }
509
+
510
+ .form-checkbox {
511
+ width: 18px;
512
+ height: 18px;
513
+ margin-top: 2px;
514
+ cursor: pointer;
515
+ accent-color: var(--primary-color, #4a90d9);
516
+ }
517
+
518
+ .form-checkbox-label {
519
+ display: flex;
520
+ flex-direction: column;
521
+ gap: 4px;
522
+ cursor: pointer;
523
+ margin-bottom: 0;
524
+ }
525
+
526
+ .form-hint {
527
+ font-size: 12px;
528
+ color: var(--text-secondary, #6b7280);
529
+ font-weight: normal;
530
+ }
531
+
532
+ .modal-footer {
533
+ display: flex;
534
+ justify-content: flex-end;
535
+ gap: 8px;
536
+ padding: 16px 20px;
537
+ border-top: 1px solid var(--border-color, #e1e5e9);
538
+ }
539
+
540
+ /* Loading */
541
+ .loading-overlay {
542
+ position: fixed;
543
+ top: 0;
544
+ left: 0;
545
+ width: 100%;
546
+ height: 100%;
547
+ background: rgba(255, 255, 255, 0.8);
548
+ display: none;
549
+ align-items: center;
550
+ justify-content: center;
551
+ z-index: 2000;
552
+ }
553
+
554
+ .loading-overlay.active {
555
+ display: flex;
556
+ }
557
+
558
+ .spinner {
559
+ width: 40px;
560
+ height: 40px;
561
+ border: 3px solid var(--border-color, #e1e5e9);
562
+ border-top-color: var(--primary-color, #4a90d9);
563
+ border-radius: 50%;
564
+ animation: spin 1s linear infinite;
565
+ }
566
+
567
+ @keyframes spin {
568
+ to { transform: rotate(360deg); }
569
+ }
570
+
571
+ /* Empty state */
572
+ .empty-state {
573
+ text-align: center;
574
+ padding: 60px 20px;
575
+ color: var(--text-secondary, #6b7280);
576
+ }
577
+
578
+ .empty-state .icon {
579
+ font-size: 48px;
580
+ margin-bottom: 16px;
581
+ }
582
+
583
+ .empty-state h3 {
584
+ margin: 0 0 8px 0;
585
+ color: var(--text-primary, #1a1a2e);
586
+ }
587
+
588
+ .empty-state p {
589
+ margin: 0;
590
+ }
591
+
592
+ /* Toast */
593
+ .toast-container {
594
+ position: fixed;
595
+ bottom: 20px;
596
+ right: 20px;
597
+ z-index: 3000;
598
+ }
599
+
600
+ .toast {
601
+ padding: 12px 20px;
602
+ border-radius: 8px;
603
+ margin-top: 8px;
604
+ font-size: 14px;
605
+ animation: slideIn 0.3s ease;
606
+ }
607
+
608
+ .toast.success {
609
+ background: #dcfce7;
610
+ color: #166534;
611
+ border: 1px solid #86efac;
612
+ }
613
+
614
+ .toast.error {
615
+ background: #fee2e2;
616
+ color: #991b1b;
617
+ border: 1px solid #fca5a5;
618
+ }
619
+
620
+ .toast.info {
621
+ background: #dbeafe;
622
+ color: #1e40af;
623
+ border: 1px solid #93c5fd;
624
+ }
625
+
626
+ @keyframes slideIn {
627
+ from {
628
+ transform: translateX(100%);
629
+ opacity: 0;
630
+ }
631
+ to {
632
+ transform: translateX(0);
633
+ opacity: 1;
634
+ }
635
+ }
636
+
637
+ /* Back link */
638
+ .back-link {
639
+ display: inline-flex;
640
+ align-items: center;
641
+ gap: 6px;
642
+ color: var(--text-secondary, #6b7280);
643
+ text-decoration: none;
644
+ font-size: 14px;
645
+ margin-bottom: 16px;
646
+ }
647
+
648
+ .back-link:hover {
649
+ color: var(--primary-color, #4a90d9);
650
+ }
651
+ </style>
652
+ </head>
653
+ <body class="dashboard-body">
654
+ <div class="mcp-container">
655
+ <a href="/dashboard" class="back-link">
656
+ <span>←</span> 返回 Dashboard
657
+ </a>
658
+
659
+ <div class="page-header">
660
+ <h1 class="page-title">
661
+ <span>🔧</span>
662
+ MCP Server 設定
663
+ </h1>
664
+ <div class="btn-group">
665
+ <button id="connectAllBtn" class="btn btn-success">
666
+ <span>🔌</span> 全部連接
667
+ </button>
668
+ <button id="disconnectAllBtn" class="btn btn-secondary">
669
+ <span>🔌</span> 全部斷開
670
+ </button>
671
+ <button id="addServerBtn" class="btn btn-primary">
672
+ <span>➕</span> 新增 Server
673
+ </button>
674
+ </div>
675
+ </div>
676
+
677
+ <!-- Serena 快速設定 -->
678
+ <div class="serena-setup">
679
+ <h2>
680
+ <span>🧠</span>
681
+ Serena MCP 快速設定
682
+ </h2>
683
+ <p>一鍵配置 Serena 智慧程式碼分析工具。Serena 提供強大的程式碼理解和符號分析功能。</p>
684
+ <div class="serena-form">
685
+ <div class="serena-input-group">
686
+ <label for="serenaProjectPath">專案路徑(可選,留空則自動偵測)</label>
687
+ <input type="text" id="serenaProjectPath" placeholder="例如:/path/to/your/project">
688
+ </div>
689
+ <button id="createSerenaBtn" class="btn btn-serena">
690
+ <span>🚀</span> 創建 Serena Server
691
+ </button>
692
+ </div>
693
+ </div>
694
+
695
+ <!-- Server 列表 -->
696
+ <div id="serverList" class="server-list">
697
+ <!-- 由 JavaScript 動態生成 -->
698
+ </div>
699
+
700
+ <!-- 空狀態 -->
701
+ <div id="emptyState" class="empty-state" style="display: none;">
702
+ <div class="icon">📭</div>
703
+ <h3>尚無 MCP Server</h3>
704
+ <p>點擊「新增 Server」或使用上方的 Serena 快速設定來開始</p>
705
+ </div>
706
+ </div>
707
+
708
+ <!-- 新增/編輯 Server Modal -->
709
+ <div id="serverModal" class="modal">
710
+ <div class="modal-content">
711
+ <div class="modal-header">
712
+ <h3 class="modal-title" id="modalTitle">新增 MCP Server</h3>
713
+ <button class="modal-close" id="closeModal">&times;</button>
714
+ </div>
715
+ <div class="modal-body">
716
+ <form id="serverForm">
717
+ <input type="hidden" id="serverId">
718
+
719
+ <div class="form-group">
720
+ <label class="form-label" for="serverName">名稱 *</label>
721
+ <input type="text" class="form-input" id="serverName" required>
722
+ </div>
723
+
724
+ <div class="form-group">
725
+ <label class="form-label" for="serverTransport">傳輸方式 *</label>
726
+ <select class="form-select" id="serverTransport" required>
727
+ <option value="stdio">stdio(標準輸入/輸出)</option>
728
+ <option value="sse">SSE(Server-Sent Events)</option>
729
+ <option value="streamable-http">Streamable HTTP</option>
730
+ </select>
731
+ </div>
732
+
733
+ <div id="stdioFields">
734
+ <div class="form-group">
735
+ <label class="form-label" for="serverCommand">命令 *</label>
736
+ <input type="text" class="form-input" id="serverCommand" placeholder="例如:uvx 或 node">
737
+ </div>
738
+
739
+ <div class="form-group">
740
+ <label class="form-label" for="serverArgs">參數(每行一個)</label>
741
+ <textarea class="form-textarea" id="serverArgs" placeholder="--from&#10;git+https://github.com/example/mcp&#10;start-server"></textarea>
742
+ </div>
743
+
744
+ <div class="form-group">
745
+ <label class="form-label" for="serverEnv">環境變數(JSON 格式)</label>
746
+ <textarea class="form-textarea" id="serverEnv" placeholder='{"KEY": "value"}'></textarea>
747
+ </div>
748
+ </div>
749
+
750
+ <div id="httpFields" style="display: none;">
751
+ <div class="form-group">
752
+ <label class="form-label" for="serverUrl">URL *</label>
753
+ <input type="url" class="form-input" id="serverUrl" placeholder="http://localhost:9121/mcp">
754
+ </div>
755
+ </div>
756
+
757
+ <div class="form-divider"></div>
758
+
759
+ <div class="form-group">
760
+ <div class="form-checkbox-group">
761
+ <input type="checkbox" class="form-checkbox" id="serverDeferredStartup">
762
+ <label class="form-label form-checkbox-label" for="serverDeferredStartup">
763
+ 延遲啟動
764
+ <span class="form-hint">啟用後,此 Server 將在 AI 首次回報專案資訊時才啟動</span>
765
+ </label>
766
+ </div>
767
+ </div>
768
+
769
+ <div id="deferredFields" style="display: none;">
770
+ <div class="form-group">
771
+ <label class="form-label" for="serverStartupArgsTemplate">啟動參數範本</label>
772
+ <textarea class="form-textarea" id="serverStartupArgsTemplate" placeholder="使用 {project_path} 和 {project_name} 作為變數&#10;例如:--project&#10;{project_path}"></textarea>
773
+ <span class="form-hint">當 AI 回報專案資訊時,會將 {project_path} 和 {project_name} 替換為實際值後加入啟動參數</span>
774
+ </div>
775
+ </div>
776
+ </form>
777
+ </div>
778
+ <div class="modal-footer">
779
+ <button type="button" class="btn btn-secondary" id="cancelBtn">取消</button>
780
+ <button type="button" class="btn btn-primary" id="saveBtn">儲存</button>
781
+ </div>
782
+ </div>
783
+ </div>
784
+
785
+ <!-- Loading Overlay -->
786
+ <div id="loadingOverlay" class="loading-overlay">
787
+ <div class="spinner"></div>
788
+ </div>
789
+
790
+ <!-- Toast Container -->
791
+ <div id="toastContainer" class="toast-container"></div>
792
+
793
+ <!-- Scripts -->
794
+ <script src="/components/navbar.js"></script>
795
+ <script src="mcp-settings.js"></script>
796
+ </body>
797
+ </html>