nc1709 1.15.4__py3-none-any.whl → 1.18.8__py3-none-any.whl

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.
@@ -2,8 +2,11 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>NC1709 Dashboard</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+ <meta name="theme-color" content="#0d1117">
7
+ <meta name="apple-mobile-web-app-capable" content="yes">
8
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
9
+ <title>NC1709 - AI Coding Assistant</title>
7
10
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
8
11
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
9
12
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.1/marked.min.js"></script>
@@ -20,13 +23,22 @@
20
23
  --success: #3fb950;
21
24
  --warning: #d29922;
22
25
  --error: #f85149;
23
- --sidebar-width: 260px;
26
+ --sidebar-width: 280px;
27
+ --header-height: 56px;
28
+ --safe-area-inset-top: env(safe-area-inset-top, 0px);
29
+ --safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
24
30
  }
25
31
 
26
32
  * {
27
33
  margin: 0;
28
34
  padding: 0;
29
35
  box-sizing: border-box;
36
+ -webkit-tap-highlight-color: transparent;
37
+ }
38
+
39
+ html, body {
40
+ height: 100%;
41
+ overflow: hidden;
30
42
  }
31
43
 
32
44
  body {
@@ -34,12 +46,32 @@
34
46
  background: var(--bg-primary);
35
47
  color: var(--text-primary);
36
48
  line-height: 1.5;
49
+ padding-top: var(--safe-area-inset-top);
50
+ padding-bottom: var(--safe-area-inset-bottom);
37
51
  }
38
52
 
39
53
  /* Layout */
40
54
  .app {
41
55
  display: flex;
42
- height: 100vh;
56
+ height: 100%;
57
+ position: relative;
58
+ }
59
+
60
+ /* Overlay for mobile sidebar */
61
+ .sidebar-overlay {
62
+ display: none;
63
+ position: fixed;
64
+ inset: 0;
65
+ background: rgba(0, 0, 0, 0.5);
66
+ z-index: 40;
67
+ opacity: 0;
68
+ transition: opacity 0.3s ease;
69
+ pointer-events: none;
70
+ }
71
+
72
+ .sidebar-overlay.active {
73
+ opacity: 1;
74
+ pointer-events: auto;
43
75
  }
44
76
 
45
77
  /* Sidebar */
@@ -50,42 +82,80 @@
50
82
  display: flex;
51
83
  flex-direction: column;
52
84
  flex-shrink: 0;
85
+ z-index: 50;
86
+ transition: transform 0.3s ease;
53
87
  }
54
88
 
55
89
  .sidebar-header {
56
90
  padding: 16px;
57
91
  border-bottom: 1px solid var(--border-color);
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: space-between;
95
+ min-height: var(--header-height);
58
96
  }
59
97
 
60
98
  .sidebar-header h1 {
61
99
  font-size: 20px;
62
100
  font-weight: 600;
63
101
  color: var(--accent);
102
+ display: flex;
103
+ align-items: center;
104
+ gap: 8px;
105
+ }
106
+
107
+ .sidebar-header h1::before {
108
+ content: '';
109
+ width: 8px;
110
+ height: 8px;
111
+ background: var(--success);
112
+ border-radius: 50%;
64
113
  }
65
114
 
66
115
  .sidebar-header .version {
67
- font-size: 12px;
116
+ font-size: 11px;
117
+ color: var(--text-secondary);
118
+ display: block;
119
+ margin-top: 2px;
120
+ }
121
+
122
+ .close-sidebar {
123
+ display: none;
124
+ width: 40px;
125
+ height: 40px;
126
+ background: transparent;
127
+ border: none;
68
128
  color: var(--text-secondary);
129
+ cursor: pointer;
130
+ border-radius: 8px;
131
+ font-size: 24px;
132
+ }
133
+
134
+ .close-sidebar:hover {
135
+ background: var(--bg-tertiary);
136
+ color: var(--text-primary);
69
137
  }
70
138
 
71
139
  .nav {
72
140
  flex: 1;
73
141
  padding: 8px;
74
142
  overflow-y: auto;
143
+ -webkit-overflow-scrolling: touch;
75
144
  }
76
145
 
77
146
  .nav-item {
78
147
  display: flex;
79
148
  align-items: center;
80
- padding: 10px 12px;
81
- border-radius: 6px;
149
+ padding: 12px 14px;
150
+ border-radius: 8px;
82
151
  cursor: pointer;
83
152
  color: var(--text-secondary);
84
153
  transition: all 0.15s ease;
85
- margin-bottom: 2px;
154
+ margin-bottom: 4px;
155
+ font-size: 15px;
86
156
  }
87
157
 
88
- .nav-item:hover {
158
+ .nav-item:hover, .nav-item:active {
89
159
  background: var(--bg-tertiary);
90
160
  color: var(--text-primary);
91
161
  }
@@ -96,18 +166,19 @@
96
166
  }
97
167
 
98
168
  .nav-item svg {
99
- width: 16px;
100
- height: 16px;
101
- margin-right: 10px;
169
+ width: 18px;
170
+ height: 18px;
171
+ margin-right: 12px;
172
+ flex-shrink: 0;
102
173
  }
103
174
 
104
175
  .nav-section {
105
- padding: 8px 12px 4px;
176
+ padding: 12px 14px 6px;
106
177
  font-size: 11px;
107
178
  font-weight: 600;
108
179
  text-transform: uppercase;
109
180
  color: var(--text-secondary);
110
- margin-top: 16px;
181
+ margin-top: 12px;
111
182
  }
112
183
 
113
184
  /* Main Content */
@@ -116,25 +187,68 @@
116
187
  display: flex;
117
188
  flex-direction: column;
118
189
  overflow: hidden;
190
+ min-width: 0;
119
191
  }
120
192
 
121
193
  .header {
122
- padding: 16px 24px;
194
+ padding: 12px 16px;
123
195
  border-bottom: 1px solid var(--border-color);
124
196
  display: flex;
125
197
  align-items: center;
126
198
  justify-content: space-between;
199
+ min-height: var(--header-height);
200
+ gap: 12px;
201
+ background: var(--bg-secondary);
202
+ }
203
+
204
+ .header-left {
205
+ display: flex;
206
+ align-items: center;
207
+ gap: 12px;
208
+ min-width: 0;
209
+ }
210
+
211
+ .menu-btn {
212
+ display: none;
213
+ width: 40px;
214
+ height: 40px;
215
+ background: transparent;
216
+ border: none;
217
+ color: var(--text-primary);
218
+ cursor: pointer;
219
+ border-radius: 8px;
220
+ flex-shrink: 0;
221
+ }
222
+
223
+ .menu-btn:hover {
224
+ background: var(--bg-tertiary);
225
+ }
226
+
227
+ .menu-btn svg {
228
+ width: 24px;
229
+ height: 24px;
127
230
  }
128
231
 
129
232
  .header h2 {
130
- font-size: 18px;
233
+ font-size: 17px;
131
234
  font-weight: 600;
235
+ white-space: nowrap;
236
+ overflow: hidden;
237
+ text-overflow: ellipsis;
238
+ }
239
+
240
+ .header-actions {
241
+ display: flex;
242
+ gap: 8px;
243
+ flex-shrink: 0;
132
244
  }
133
245
 
134
246
  .content {
135
247
  flex: 1;
136
248
  overflow-y: auto;
137
- padding: 24px;
249
+ overflow-x: hidden;
250
+ padding: 16px;
251
+ -webkit-overflow-scrolling: touch;
138
252
  }
139
253
 
140
254
  /* Chat Panel */
@@ -147,12 +261,13 @@
147
261
  .chat-messages {
148
262
  flex: 1;
149
263
  overflow-y: auto;
150
- padding: 16px;
264
+ padding: 12px;
265
+ -webkit-overflow-scrolling: touch;
151
266
  }
152
267
 
153
268
  .message {
154
269
  margin-bottom: 16px;
155
- max-width: 85%;
270
+ max-width: 90%;
156
271
  }
157
272
 
158
273
  .message.user {
@@ -161,25 +276,32 @@
161
276
 
162
277
  .message-content {
163
278
  padding: 12px 16px;
164
- border-radius: 12px;
279
+ border-radius: 16px;
165
280
  background: var(--bg-tertiary);
281
+ word-break: break-word;
166
282
  }
167
283
 
168
284
  .message.user .message-content {
169
285
  background: var(--accent);
170
286
  color: white;
287
+ border-radius: 16px 16px 4px 16px;
288
+ }
289
+
290
+ .message:not(.user) .message-content {
291
+ border-radius: 16px 16px 16px 4px;
171
292
  }
172
293
 
173
294
  .message-content pre {
174
295
  margin: 8px 0;
175
296
  padding: 12px;
176
297
  background: var(--bg-primary);
177
- border-radius: 6px;
298
+ border-radius: 8px;
178
299
  overflow-x: auto;
300
+ -webkit-overflow-scrolling: touch;
179
301
  }
180
302
 
181
303
  .message-content code {
182
- font-family: 'SF Mono', 'Fira Code', monospace;
304
+ font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
183
305
  font-size: 13px;
184
306
  }
185
307
 
@@ -192,13 +314,16 @@
192
314
  }
193
315
 
194
316
  .chat-input-container {
195
- padding: 16px;
317
+ padding: 12px;
196
318
  border-top: 1px solid var(--border-color);
319
+ background: var(--bg-secondary);
320
+ padding-bottom: calc(12px + var(--safe-area-inset-bottom));
197
321
  }
198
322
 
199
323
  .chat-input-wrapper {
200
324
  display: flex;
201
- gap: 12px;
325
+ gap: 10px;
326
+ align-items: flex-end;
202
327
  }
203
328
 
204
329
  .chat-input {
@@ -206,10 +331,13 @@
206
331
  padding: 12px 16px;
207
332
  background: var(--bg-tertiary);
208
333
  border: 1px solid var(--border-color);
209
- border-radius: 8px;
334
+ border-radius: 24px;
210
335
  color: var(--text-primary);
211
- font-size: 14px;
336
+ font-size: 16px;
212
337
  resize: none;
338
+ min-height: 48px;
339
+ max-height: 120px;
340
+ line-height: 1.4;
213
341
  }
214
342
 
215
343
  .chat-input:focus {
@@ -218,37 +346,55 @@
218
346
  }
219
347
 
220
348
  .send-btn {
221
- padding: 12px 24px;
349
+ width: 48px;
350
+ height: 48px;
222
351
  background: var(--accent);
223
352
  color: white;
224
353
  border: none;
225
- border-radius: 8px;
354
+ border-radius: 50%;
226
355
  cursor: pointer;
227
356
  font-weight: 500;
228
- transition: background 0.15s ease;
357
+ transition: all 0.15s ease;
358
+ display: flex;
359
+ align-items: center;
360
+ justify-content: center;
361
+ flex-shrink: 0;
229
362
  }
230
363
 
231
364
  .send-btn:hover {
232
365
  background: var(--accent-hover);
366
+ transform: scale(1.05);
367
+ }
368
+
369
+ .send-btn:active {
370
+ transform: scale(0.95);
233
371
  }
234
372
 
235
373
  .send-btn:disabled {
236
374
  opacity: 0.5;
237
375
  cursor: not-allowed;
376
+ transform: none;
377
+ }
378
+
379
+ .send-btn svg {
380
+ width: 20px;
381
+ height: 20px;
238
382
  }
239
383
 
240
384
  /* Cards */
241
385
  .card {
242
386
  background: var(--bg-secondary);
243
387
  border: 1px solid var(--border-color);
244
- border-radius: 8px;
388
+ border-radius: 12px;
245
389
  margin-bottom: 16px;
390
+ overflow: hidden;
246
391
  }
247
392
 
248
393
  .card-header {
249
- padding: 16px;
394
+ padding: 14px 16px;
250
395
  border-bottom: 1px solid var(--border-color);
251
396
  font-weight: 600;
397
+ font-size: 15px;
252
398
  }
253
399
 
254
400
  .card-body {
@@ -258,34 +404,41 @@
258
404
  /* Stats Grid */
259
405
  .stats-grid {
260
406
  display: grid;
261
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
262
- gap: 16px;
263
- margin-bottom: 24px;
407
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
408
+ gap: 12px;
409
+ margin-bottom: 20px;
264
410
  }
265
411
 
266
412
  .stat-card {
267
413
  background: var(--bg-secondary);
268
414
  border: 1px solid var(--border-color);
269
- border-radius: 8px;
270
- padding: 20px;
415
+ border-radius: 12px;
416
+ padding: 16px;
417
+ text-align: center;
271
418
  }
272
419
 
273
420
  .stat-value {
274
- font-size: 32px;
421
+ font-size: 28px;
275
422
  font-weight: 700;
276
423
  color: var(--accent);
277
424
  }
278
425
 
279
426
  .stat-label {
280
- font-size: 14px;
427
+ font-size: 13px;
281
428
  color: var(--text-secondary);
282
429
  margin-top: 4px;
283
430
  }
284
431
 
285
- /* Tables */
432
+ /* Tables - Mobile friendly */
433
+ .table-container {
434
+ overflow-x: auto;
435
+ -webkit-overflow-scrolling: touch;
436
+ }
437
+
286
438
  .table {
287
439
  width: 100%;
288
440
  border-collapse: collapse;
441
+ min-width: 400px;
289
442
  }
290
443
 
291
444
  .table th,
@@ -304,17 +457,19 @@
304
457
 
305
458
  /* Buttons */
306
459
  .btn {
307
- padding: 8px 16px;
308
- border-radius: 6px;
460
+ padding: 10px 16px;
461
+ border-radius: 8px;
309
462
  border: 1px solid var(--border-color);
310
463
  background: var(--bg-tertiary);
311
464
  color: var(--text-primary);
312
465
  cursor: pointer;
313
466
  font-size: 14px;
314
467
  transition: all 0.15s ease;
468
+ white-space: nowrap;
469
+ touch-action: manipulation;
315
470
  }
316
471
 
317
- .btn:hover {
472
+ .btn:hover, .btn:active {
318
473
  background: var(--bg-secondary);
319
474
  border-color: var(--accent);
320
475
  }
@@ -325,14 +480,19 @@
325
480
  color: white;
326
481
  }
327
482
 
328
- .btn-primary:hover {
483
+ .btn-primary:hover, .btn-primary:active {
329
484
  background: var(--accent-hover);
330
485
  }
331
486
 
487
+ .btn-sm {
488
+ padding: 8px 12px;
489
+ font-size: 13px;
490
+ }
491
+
332
492
  /* Status badges */
333
493
  .badge {
334
494
  display: inline-block;
335
- padding: 2px 8px;
495
+ padding: 4px 10px;
336
496
  border-radius: 12px;
337
497
  font-size: 12px;
338
498
  font-weight: 500;
@@ -355,17 +515,17 @@
355
515
 
356
516
  /* Search */
357
517
  .search-container {
358
- margin-bottom: 24px;
518
+ margin-bottom: 20px;
359
519
  }
360
520
 
361
521
  .search-input {
362
522
  width: 100%;
363
- padding: 12px 16px;
523
+ padding: 14px 16px;
364
524
  background: var(--bg-tertiary);
365
525
  border: 1px solid var(--border-color);
366
- border-radius: 8px;
526
+ border-radius: 12px;
367
527
  color: var(--text-primary);
368
- font-size: 14px;
528
+ font-size: 16px;
369
529
  }
370
530
 
371
531
  .search-input:focus {
@@ -380,7 +540,7 @@
380
540
  .search-result {
381
541
  background: var(--bg-secondary);
382
542
  border: 1px solid var(--border-color);
383
- border-radius: 8px;
543
+ border-radius: 12px;
384
544
  margin-bottom: 12px;
385
545
  overflow: hidden;
386
546
  }
@@ -391,11 +551,15 @@
391
551
  font-size: 14px;
392
552
  display: flex;
393
553
  justify-content: space-between;
554
+ align-items: center;
555
+ flex-wrap: wrap;
556
+ gap: 8px;
394
557
  }
395
558
 
396
559
  .search-result-code {
397
560
  padding: 12px 16px;
398
561
  overflow-x: auto;
562
+ -webkit-overflow-scrolling: touch;
399
563
  }
400
564
 
401
565
  .search-result-code pre {
@@ -412,8 +576,8 @@
412
576
  }
413
577
 
414
578
  .spinner {
415
- width: 20px;
416
- height: 20px;
579
+ width: 24px;
580
+ height: 24px;
417
581
  border: 2px solid var(--border-color);
418
582
  border-top-color: var(--accent);
419
583
  border-radius: 50%;
@@ -428,30 +592,33 @@
428
592
  /* Hidden panels */
429
593
  .panel {
430
594
  display: none;
595
+ height: 100%;
431
596
  }
432
597
 
433
598
  .panel.active {
434
- display: block;
599
+ display: flex;
600
+ flex-direction: column;
435
601
  }
436
602
 
437
603
  /* Sessions list */
438
604
  .session-item {
439
- padding: 12px 16px;
605
+ padding: 14px 16px;
440
606
  border-bottom: 1px solid var(--border-color);
441
607
  cursor: pointer;
442
608
  transition: background 0.15s ease;
443
609
  }
444
610
 
445
- .session-item:hover {
611
+ .session-item:hover, .session-item:active {
446
612
  background: var(--bg-tertiary);
447
613
  }
448
614
 
449
615
  .session-item-name {
450
616
  font-weight: 500;
617
+ font-size: 15px;
451
618
  }
452
619
 
453
620
  .session-item-meta {
454
- font-size: 12px;
621
+ font-size: 13px;
455
622
  color: var(--text-secondary);
456
623
  margin-top: 4px;
457
624
  }
@@ -468,7 +635,8 @@
468
635
 
469
636
  .tool-name {
470
637
  font-weight: 600;
471
- margin-bottom: 4px;
638
+ margin-bottom: 6px;
639
+ font-size: 15px;
472
640
  }
473
641
 
474
642
  .tool-description {
@@ -482,72 +650,408 @@
482
650
  color: var(--text-secondary);
483
651
  }
484
652
 
653
+ .tool-actions {
654
+ margin-top: 12px;
655
+ display: flex;
656
+ flex-wrap: wrap;
657
+ gap: 8px;
658
+ }
659
+
485
660
  /* Toast notifications */
486
661
  .toast-container {
487
662
  position: fixed;
488
- bottom: 20px;
489
- right: 20px;
663
+ bottom: calc(20px + var(--safe-area-inset-bottom));
664
+ left: 50%;
665
+ transform: translateX(-50%);
490
666
  z-index: 1000;
667
+ width: calc(100% - 32px);
668
+ max-width: 400px;
491
669
  }
492
670
 
493
671
  .toast {
494
672
  background: var(--bg-secondary);
495
673
  border: 1px solid var(--border-color);
496
- border-radius: 8px;
497
- padding: 12px 20px;
674
+ border-radius: 12px;
675
+ padding: 14px 20px;
498
676
  margin-top: 8px;
499
- animation: slideIn 0.3s ease;
677
+ animation: slideUp 0.3s ease;
678
+ text-align: center;
679
+ font-size: 14px;
500
680
  }
501
681
 
502
- @keyframes slideIn {
682
+ @keyframes slideUp {
503
683
  from {
504
- transform: translateX(100%);
684
+ transform: translateY(100%);
505
685
  opacity: 0;
506
686
  }
507
687
  to {
508
- transform: translateX(0);
688
+ transform: translateY(0);
509
689
  opacity: 1;
510
690
  }
511
691
  }
692
+
693
+ /* Mobile Responsive */
694
+ @media (max-width: 768px) {
695
+ .sidebar {
696
+ position: fixed;
697
+ left: 0;
698
+ top: 0;
699
+ bottom: 0;
700
+ transform: translateX(-100%);
701
+ box-shadow: 4px 0 20px rgba(0, 0, 0, 0.3);
702
+ }
703
+
704
+ .sidebar.open {
705
+ transform: translateX(0);
706
+ }
707
+
708
+ .sidebar-overlay {
709
+ display: block;
710
+ }
711
+
712
+ .close-sidebar {
713
+ display: flex;
714
+ align-items: center;
715
+ justify-content: center;
716
+ }
717
+
718
+ .menu-btn {
719
+ display: flex;
720
+ align-items: center;
721
+ justify-content: center;
722
+ }
723
+
724
+ .message {
725
+ max-width: 95%;
726
+ }
727
+
728
+ .stats-grid {
729
+ grid-template-columns: repeat(2, 1fr);
730
+ }
731
+
732
+ .header-actions .btn-text {
733
+ display: none;
734
+ }
735
+
736
+ .header h2 {
737
+ font-size: 16px;
738
+ }
739
+ }
740
+
741
+ @media (max-width: 480px) {
742
+ .stats-grid {
743
+ grid-template-columns: 1fr 1fr;
744
+ gap: 8px;
745
+ }
746
+
747
+ .stat-card {
748
+ padding: 12px;
749
+ }
750
+
751
+ .stat-value {
752
+ font-size: 24px;
753
+ }
754
+
755
+ .content {
756
+ padding: 12px;
757
+ }
758
+
759
+ .chat-messages {
760
+ padding: 8px;
761
+ }
762
+ }
763
+
764
+ /* Landscape phone */
765
+ @media (max-height: 500px) and (orientation: landscape) {
766
+ .header {
767
+ min-height: 48px;
768
+ padding: 8px 12px;
769
+ }
770
+
771
+ .chat-input-container {
772
+ padding: 8px;
773
+ }
774
+
775
+ .chat-input {
776
+ min-height: 40px;
777
+ padding: 10px 14px;
778
+ }
779
+
780
+ .send-btn {
781
+ width: 40px;
782
+ height: 40px;
783
+ }
784
+ }
785
+
786
+ /* Empty state */
787
+ .empty-state {
788
+ text-align: center;
789
+ padding: 40px 20px;
790
+ color: var(--text-secondary);
791
+ }
792
+
793
+ .empty-state-icon {
794
+ font-size: 48px;
795
+ margin-bottom: 16px;
796
+ }
797
+
798
+ .empty-state-title {
799
+ font-size: 18px;
800
+ font-weight: 600;
801
+ color: var(--text-primary);
802
+ margin-bottom: 8px;
803
+ }
804
+
805
+ .empty-state-description {
806
+ font-size: 14px;
807
+ max-width: 300px;
808
+ margin: 0 auto;
809
+ }
810
+
811
+ /* Welcome Screen */
812
+ .welcome-screen {
813
+ padding: 20px;
814
+ max-width: 800px;
815
+ margin: 0 auto;
816
+ }
817
+
818
+ .welcome-hero {
819
+ text-align: center;
820
+ padding: 40px 20px 30px;
821
+ }
822
+
823
+ .welcome-logo {
824
+ font-size: 48px;
825
+ font-weight: 800;
826
+ color: var(--accent);
827
+ letter-spacing: -2px;
828
+ margin-bottom: 12px;
829
+ }
830
+
831
+ .welcome-title {
832
+ font-size: 24px;
833
+ font-weight: 600;
834
+ color: var(--text-primary);
835
+ margin-bottom: 8px;
836
+ }
837
+
838
+ .welcome-subtitle {
839
+ font-size: 16px;
840
+ color: var(--text-secondary);
841
+ max-width: 400px;
842
+ margin: 0 auto;
843
+ }
844
+
845
+ .welcome-features {
846
+ display: grid;
847
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
848
+ gap: 16px;
849
+ margin: 30px 0;
850
+ }
851
+
852
+ .feature-card {
853
+ background: var(--bg-secondary);
854
+ border: 1px solid var(--border-color);
855
+ border-radius: 12px;
856
+ padding: 20px;
857
+ text-align: center;
858
+ }
859
+
860
+ .feature-icon {
861
+ font-size: 32px;
862
+ margin-bottom: 12px;
863
+ }
864
+
865
+ .feature-card h3 {
866
+ font-size: 16px;
867
+ font-weight: 600;
868
+ margin-bottom: 8px;
869
+ color: var(--text-primary);
870
+ }
871
+
872
+ .feature-card p {
873
+ font-size: 13px;
874
+ color: var(--text-secondary);
875
+ line-height: 1.4;
876
+ }
877
+
878
+ .welcome-install {
879
+ background: var(--bg-secondary);
880
+ border: 1px solid var(--border-color);
881
+ border-radius: 12px;
882
+ padding: 24px;
883
+ margin: 24px 0;
884
+ }
885
+
886
+ .welcome-install h3 {
887
+ font-size: 18px;
888
+ font-weight: 600;
889
+ margin-bottom: 20px;
890
+ text-align: center;
891
+ color: var(--text-primary);
892
+ }
893
+
894
+ .install-steps {
895
+ display: flex;
896
+ flex-direction: column;
897
+ gap: 16px;
898
+ }
899
+
900
+ .install-step {
901
+ display: flex;
902
+ align-items: center;
903
+ gap: 16px;
904
+ }
905
+
906
+ .step-number {
907
+ width: 32px;
908
+ height: 32px;
909
+ background: var(--accent);
910
+ color: white;
911
+ border-radius: 50%;
912
+ display: flex;
913
+ align-items: center;
914
+ justify-content: center;
915
+ font-weight: 600;
916
+ font-size: 14px;
917
+ flex-shrink: 0;
918
+ }
919
+
920
+ .step-content {
921
+ display: flex;
922
+ flex-direction: column;
923
+ gap: 4px;
924
+ }
925
+
926
+ .step-content code {
927
+ font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
928
+ background: var(--bg-primary);
929
+ padding: 8px 16px;
930
+ border-radius: 8px;
931
+ font-size: 14px;
932
+ color: var(--accent);
933
+ }
934
+
935
+ .step-label {
936
+ font-size: 12px;
937
+ color: var(--text-secondary);
938
+ }
939
+
940
+ .welcome-actions {
941
+ display: flex;
942
+ justify-content: center;
943
+ gap: 12px;
944
+ margin: 24px 0;
945
+ flex-wrap: wrap;
946
+ }
947
+
948
+ .btn-lg {
949
+ padding: 14px 28px;
950
+ font-size: 16px;
951
+ font-weight: 500;
952
+ }
953
+
954
+ .welcome-note {
955
+ text-align: center;
956
+ padding: 16px;
957
+ background: rgba(88, 166, 255, 0.1);
958
+ border-radius: 8px;
959
+ margin-top: 20px;
960
+ }
961
+
962
+ .welcome-note p {
963
+ font-size: 13px;
964
+ color: var(--text-secondary);
965
+ margin: 0;
966
+ }
967
+
968
+ @media (max-width: 600px) {
969
+ .welcome-hero {
970
+ padding: 20px 10px;
971
+ }
972
+
973
+ .welcome-logo {
974
+ font-size: 36px;
975
+ }
976
+
977
+ .welcome-title {
978
+ font-size: 20px;
979
+ }
980
+
981
+ .welcome-features {
982
+ grid-template-columns: 1fr;
983
+ }
984
+
985
+ .feature-card {
986
+ padding: 16px;
987
+ }
988
+
989
+ .welcome-install {
990
+ padding: 16px;
991
+ }
992
+
993
+ .install-step {
994
+ flex-direction: column;
995
+ text-align: center;
996
+ }
997
+
998
+ .step-content {
999
+ align-items: center;
1000
+ }
1001
+
1002
+ .welcome-actions {
1003
+ flex-direction: column;
1004
+ }
1005
+
1006
+ .welcome-actions .btn {
1007
+ width: 100%;
1008
+ }
1009
+ }
512
1010
  </style>
513
1011
  </head>
514
1012
  <body>
515
1013
  <div class="app">
1014
+ <!-- Sidebar Overlay (mobile) -->
1015
+ <div class="sidebar-overlay" onclick="closeSidebar()"></div>
1016
+
516
1017
  <!-- Sidebar -->
517
- <aside class="sidebar">
1018
+ <aside class="sidebar" id="sidebar">
518
1019
  <div class="sidebar-header">
519
- <h1>NC1709</h1>
520
- <span class="version">v1.0.0 - Local AI Assistant</span>
1020
+ <div>
1021
+ <h1>NC1709</h1>
1022
+ <span class="version" id="version-display">v1.18.6</span>
1023
+ </div>
1024
+ <button class="close-sidebar" onclick="closeSidebar()">&times;</button>
521
1025
  </div>
522
1026
  <nav class="nav">
523
1027
  <div class="nav-item active" data-panel="chat">
524
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.5a.5.5 0 00-1 0v4a.5.5 0 00.5.5h2.5a.5.5 0 000-1H8.5v-3.5z"/></svg>
1028
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
525
1029
  Chat
526
1030
  </div>
527
1031
 
528
1032
  <div class="nav-section">Memory</div>
529
1033
  <div class="nav-item" data-panel="sessions">
530
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M0 1.75A.75.75 0 01.75 1h4.253a.75.75 0 01.592.288l1.67 2.168H14.25a.75.75 0 01.75.75v8.044a.75.75 0 01-.75.75H.75a.75.75 0 01-.75-.75V1.75z"/></svg>
1034
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3h18v18H3z"></path><path d="M3 9h18M9 21V9"></path></svg>
531
1035
  Sessions
532
1036
  </div>
533
1037
  <div class="nav-item" data-panel="search">
534
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M11.5 7a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zm-.82 4.74a6 6 0 111.06-1.06l2.28 2.28a.75.75 0 11-1.06 1.06l-2.28-2.28z"/></svg>
1038
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><path d="M21 21l-4.35-4.35"></path></svg>
535
1039
  Search Code
536
1040
  </div>
537
1041
 
538
1042
  <div class="nav-section">Tools</div>
539
1043
  <div class="nav-item" data-panel="plugins">
540
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M2 3.75A.75.75 0 012.75 3h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4A.75.75 0 012.75 7h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 7.75zm0 4a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z"/></svg>
1044
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><path d="M3 9h18M9 21V9"></path></svg>
541
1045
  Plugins
542
1046
  </div>
543
1047
  <div class="nav-item" data-panel="mcp">
544
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.78 5.22a.75.75 0 010 1.06l-4.5 4.5a.75.75 0 01-1.06 0l-2-2a.75.75 0 011.06-1.06L6.75 9.19l3.97-3.97a.75.75 0 011.06 0z"/></svg>
1048
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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"></path></svg>
545
1049
  MCP Tools
546
1050
  </div>
547
1051
 
548
1052
  <div class="nav-section">System</div>
549
1053
  <div class="nav-item" data-panel="config">
550
- <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8.2 8.2 0 01.701.031C10.042.11 10.989.39 11.5 1.5c.4.865.464 1.92.32 2.984l.15.022c.732.1 1.332.48 1.78 1.084.447.604.67 1.39.564 2.16-.106.77-.513 1.47-1.128 2-.61.53-1.406.845-2.266.96l-.003.053a3.49 3.49 0 01-.064.498c-.164.775-.576 1.454-1.238 1.914-.66.46-1.52.629-2.315.48-.79-.15-1.513-.61-1.972-1.27a3.24 3.24 0 01-.52-1.667l-.026-.003c-.76-.11-1.456-.5-1.97-1.084a3.26 3.26 0 01-.768-2.16c.045-.77.37-1.472.928-2.005.557-.533 1.296-.852 2.101-.968l.068-.011c-.034-.355-.024-.71.03-1.064.09-.59.303-1.15.633-1.64.33-.49.77-.88 1.28-1.15A3.18 3.18 0 018 0z"/></svg>
1054
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
551
1055
  Settings
552
1056
  </div>
553
1057
  </nav>
@@ -558,15 +1062,88 @@
558
1062
  <!-- Chat Panel -->
559
1063
  <div id="panel-chat" class="panel active">
560
1064
  <div class="header">
561
- <h2>Chat</h2>
562
- <button class="btn" onclick="clearChat()">Clear Chat</button>
1065
+ <div class="header-left">
1066
+ <button class="menu-btn" onclick="openSidebar()">
1067
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
1068
+ </button>
1069
+ <h2>Chat</h2>
1070
+ </div>
1071
+ <div class="header-actions">
1072
+ <button class="btn btn-sm" onclick="clearChat()">
1073
+ <span class="btn-text">Clear</span>
1074
+ </button>
1075
+ </div>
563
1076
  </div>
564
1077
  <div class="content chat-container">
565
1078
  <div class="chat-messages" id="chat-messages">
566
- <div class="message">
1079
+ <!-- Welcome screen for direct visitors -->
1080
+ <div class="welcome-screen" id="welcome-screen">
1081
+ <div class="welcome-hero">
1082
+ <div class="welcome-logo">NC1709</div>
1083
+ <h2 class="welcome-title">Your AI Coding Partner</h2>
1084
+ <p class="welcome-subtitle">Powerful local-first AI assistant that brings your code to life</p>
1085
+ </div>
1086
+
1087
+ <div class="welcome-features">
1088
+ <div class="feature-card">
1089
+ <div class="feature-icon">&#x1F4BB;</div>
1090
+ <h3>Local-First</h3>
1091
+ <p>Run AI locally with Ollama or connect to any LLM provider</p>
1092
+ </div>
1093
+ <div class="feature-card">
1094
+ <div class="feature-icon">&#x1F6E0;</div>
1095
+ <h3>17+ Tools</h3>
1096
+ <p>File ops, search, bash, git, docker, web browsing & more</p>
1097
+ </div>
1098
+ <div class="feature-card">
1099
+ <div class="feature-icon">&#x1F50D;</div>
1100
+ <h3>Code Intelligence</h3>
1101
+ <p>Semantic search and memory across your codebase</p>
1102
+ </div>
1103
+ </div>
1104
+
1105
+ <div class="welcome-install">
1106
+ <h3>Get Started</h3>
1107
+ <div class="install-steps">
1108
+ <div class="install-step">
1109
+ <span class="step-number">1</span>
1110
+ <div class="step-content">
1111
+ <code>pip install nc1709</code>
1112
+ <span class="step-label">Install from PyPI</span>
1113
+ </div>
1114
+ </div>
1115
+ <div class="install-step">
1116
+ <span class="step-number">2</span>
1117
+ <div class="step-content">
1118
+ <code>nc1709</code>
1119
+ <span class="step-label">Run in any project</span>
1120
+ </div>
1121
+ </div>
1122
+ <div class="install-step">
1123
+ <span class="step-number">3</span>
1124
+ <div class="step-content">
1125
+ <code>nc1709 --remote</code>
1126
+ <span class="step-label">Or connect to this server</span>
1127
+ </div>
1128
+ </div>
1129
+ </div>
1130
+ </div>
1131
+
1132
+ <div class="welcome-actions">
1133
+ <button class="btn btn-primary btn-lg" onclick="dismissWelcome()">Try Web Chat</button>
1134
+ <a href="https://github.com/nc1709/nc1709" target="_blank" class="btn btn-lg">View on GitHub</a>
1135
+ </div>
1136
+
1137
+ <div class="welcome-note">
1138
+ <p>The CLI provides the full experience with local tool execution. This web interface offers basic chat capabilities.</p>
1139
+ </div>
1140
+ </div>
1141
+
1142
+ <!-- Chat messages (hidden initially for direct visitors) -->
1143
+ <div class="message" id="chat-welcome" style="display: none;">
567
1144
  <div class="message-content">
568
- <p>Welcome to NC1709! I'm your local AI developer assistant.</p>
569
- <p>Ask me to help with code, search your project, manage git, docker, and more.</p>
1145
+ <p><strong>Welcome to NC1709!</strong></p>
1146
+ <p>I'm your AI coding assistant. Ask me to help with code, search your project, manage git, docker, and more.</p>
570
1147
  </div>
571
1148
  </div>
572
1149
  </div>
@@ -578,8 +1155,11 @@
578
1155
  placeholder="Ask me anything..."
579
1156
  rows="1"
580
1157
  onkeydown="handleChatKeydown(event)"
1158
+ oninput="autoResizeInput(this)"
581
1159
  ></textarea>
582
- <button class="send-btn" id="send-btn" onclick="sendMessage()">Send</button>
1160
+ <button class="send-btn" id="send-btn" onclick="sendMessage()">
1161
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>
1162
+ </button>
583
1163
  </div>
584
1164
  </div>
585
1165
  </div>
@@ -588,12 +1168,19 @@
588
1168
  <!-- Sessions Panel -->
589
1169
  <div id="panel-sessions" class="panel">
590
1170
  <div class="header">
591
- <h2>Sessions</h2>
592
- <button class="btn btn-primary" onclick="createSession()">New Session</button>
1171
+ <div class="header-left">
1172
+ <button class="menu-btn" onclick="openSidebar()">
1173
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
1174
+ </button>
1175
+ <h2>Sessions</h2>
1176
+ </div>
1177
+ <div class="header-actions">
1178
+ <button class="btn btn-primary btn-sm" onclick="createSession()">+ New</button>
1179
+ </div>
593
1180
  </div>
594
1181
  <div class="content">
595
1182
  <div id="sessions-list" class="card">
596
- <div class="loading"><div class="spinner"></div> Loading sessions...</div>
1183
+ <div class="loading"><div class="spinner"></div> Loading...</div>
597
1184
  </div>
598
1185
  </div>
599
1186
  </div>
@@ -601,36 +1188,44 @@
601
1188
  <!-- Search Panel -->
602
1189
  <div id="panel-search" class="panel">
603
1190
  <div class="header">
604
- <h2>Semantic Code Search</h2>
605
- <button class="btn" onclick="indexProject()">Re-index Project</button>
1191
+ <div class="header-left">
1192
+ <button class="menu-btn" onclick="openSidebar()">
1193
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
1194
+ </button>
1195
+ <h2>Search Code</h2>
1196
+ </div>
1197
+ <div class="header-actions">
1198
+ <button class="btn btn-sm" onclick="indexProject()">Index</button>
1199
+ </div>
606
1200
  </div>
607
1201
  <div class="content">
608
- <div id="index-status" class="stats-grid">
609
- <!-- Index stats loaded here -->
610
- </div>
1202
+ <div id="index-status" class="stats-grid"></div>
611
1203
  <div class="search-container">
612
1204
  <input
613
1205
  type="text"
614
1206
  class="search-input"
615
1207
  id="search-input"
616
- placeholder="Search your code semantically... (e.g., 'authentication logic')"
1208
+ placeholder="Search semantically... (e.g., 'auth logic')"
617
1209
  onkeydown="if(event.key==='Enter')searchCode()"
618
1210
  >
619
1211
  </div>
620
- <div id="search-results" class="search-results">
621
- <!-- Results loaded here -->
622
- </div>
1212
+ <div id="search-results" class="search-results"></div>
623
1213
  </div>
624
1214
  </div>
625
1215
 
626
1216
  <!-- Plugins Panel -->
627
1217
  <div id="panel-plugins" class="panel">
628
1218
  <div class="header">
629
- <h2>Plugins</h2>
1219
+ <div class="header-left">
1220
+ <button class="menu-btn" onclick="openSidebar()">
1221
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
1222
+ </button>
1223
+ <h2>Plugins</h2>
1224
+ </div>
630
1225
  </div>
631
1226
  <div class="content">
632
1227
  <div id="plugins-list">
633
- <div class="loading"><div class="spinner"></div> Loading plugins...</div>
1228
+ <div class="loading"><div class="spinner"></div> Loading...</div>
634
1229
  </div>
635
1230
  </div>
636
1231
  </div>
@@ -638,16 +1233,19 @@
638
1233
  <!-- MCP Panel -->
639
1234
  <div id="panel-mcp" class="panel">
640
1235
  <div class="header">
641
- <h2>MCP Tools</h2>
1236
+ <div class="header-left">
1237
+ <button class="menu-btn" onclick="openSidebar()">
1238
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
1239
+ </button>
1240
+ <h2>MCP Tools</h2>
1241
+ </div>
642
1242
  </div>
643
1243
  <div class="content">
644
- <div id="mcp-status" class="stats-grid">
645
- <!-- MCP stats loaded here -->
646
- </div>
1244
+ <div id="mcp-status" class="stats-grid"></div>
647
1245
  <div id="mcp-tools" class="card">
648
1246
  <div class="card-header">Available Tools</div>
649
1247
  <div class="card-body" id="mcp-tools-list">
650
- <div class="loading"><div class="spinner"></div> Loading tools...</div>
1248
+ <div class="loading"><div class="spinner"></div> Loading...</div>
651
1249
  </div>
652
1250
  </div>
653
1251
  </div>
@@ -656,16 +1254,19 @@
656
1254
  <!-- Config Panel -->
657
1255
  <div id="panel-config" class="panel">
658
1256
  <div class="header">
659
- <h2>Settings</h2>
1257
+ <div class="header-left">
1258
+ <button class="menu-btn" onclick="openSidebar()">
1259
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
1260
+ </button>
1261
+ <h2>Settings</h2>
1262
+ </div>
660
1263
  </div>
661
1264
  <div class="content">
662
- <div class="stats-grid" id="system-status">
663
- <!-- Status loaded here -->
664
- </div>
1265
+ <div class="stats-grid" id="system-status"></div>
665
1266
  <div class="card">
666
1267
  <div class="card-header">Configuration</div>
667
1268
  <div class="card-body">
668
- <pre id="config-display" style="background: var(--bg-primary); padding: 16px; border-radius: 6px; overflow-x: auto;"></pre>
1269
+ <pre id="config-display" style="background: var(--bg-primary); padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 13px;"></pre>
669
1270
  </div>
670
1271
  </div>
671
1272
  </div>
@@ -687,6 +1288,19 @@
687
1288
  breaks: true
688
1289
  });
689
1290
 
1291
+ // Sidebar controls
1292
+ function openSidebar() {
1293
+ document.getElementById('sidebar').classList.add('open');
1294
+ document.querySelector('.sidebar-overlay').classList.add('active');
1295
+ document.body.style.overflow = 'hidden';
1296
+ }
1297
+
1298
+ function closeSidebar() {
1299
+ document.getElementById('sidebar').classList.remove('open');
1300
+ document.querySelector('.sidebar-overlay').classList.remove('active');
1301
+ document.body.style.overflow = '';
1302
+ }
1303
+
690
1304
  // Navigation
691
1305
  document.querySelectorAll('.nav-item').forEach(item => {
692
1306
  item.addEventListener('click', () => {
@@ -700,6 +1314,11 @@
700
1314
  document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
701
1315
  document.getElementById(`panel-${panel}`).classList.add('active');
702
1316
 
1317
+ // Close sidebar on mobile
1318
+ if (window.innerWidth <= 768) {
1319
+ closeSidebar();
1320
+ }
1321
+
703
1322
  // Load data for panel
704
1323
  loadPanelData(panel);
705
1324
  }
@@ -740,6 +1359,12 @@
740
1359
  setTimeout(() => toast.remove(), 3000);
741
1360
  }
742
1361
 
1362
+ // Auto-resize input
1363
+ function autoResizeInput(textarea) {
1364
+ textarea.style.height = 'auto';
1365
+ textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
1366
+ }
1367
+
743
1368
  // Chat functions
744
1369
  function addMessage(role, content) {
745
1370
  const messages = document.getElementById('chat-messages');
@@ -773,6 +1398,7 @@
773
1398
  // Add user message
774
1399
  addMessage('user', message);
775
1400
  input.value = '';
1401
+ input.style.height = 'auto';
776
1402
  btn.disabled = true;
777
1403
 
778
1404
  try {
@@ -806,6 +1432,11 @@
806
1432
 
807
1433
  function clearChat() {
808
1434
  const messages = document.getElementById('chat-messages');
1435
+ // Hide welcome screen if visible and show simple chat message
1436
+ const welcomeScreen = document.getElementById('welcome-screen');
1437
+ if (welcomeScreen) {
1438
+ welcomeScreen.style.display = 'none';
1439
+ }
809
1440
  messages.innerHTML = `
810
1441
  <div class="message">
811
1442
  <div class="message-content">
@@ -813,6 +1444,7 @@
813
1444
  </div>
814
1445
  </div>
815
1446
  `;
1447
+ localStorage.setItem('nc1709_welcomed', 'true');
816
1448
  }
817
1449
 
818
1450
  // Sessions
@@ -824,7 +1456,13 @@
824
1456
  const data = await response.json();
825
1457
 
826
1458
  if (data.sessions.length === 0) {
827
- container.innerHTML = '<div class="card-body">No sessions yet. Start chatting to create one!</div>';
1459
+ container.innerHTML = `
1460
+ <div class="empty-state">
1461
+ <div class="empty-state-icon">📝</div>
1462
+ <div class="empty-state-title">No sessions yet</div>
1463
+ <div class="empty-state-description">Start chatting to create your first session!</div>
1464
+ </div>
1465
+ `;
828
1466
  return;
829
1467
  }
830
1468
 
@@ -884,19 +1522,15 @@
884
1522
  container.innerHTML = `
885
1523
  <div class="stat-card">
886
1524
  <div class="stat-value">${data.total_files || 0}</div>
887
- <div class="stat-label">Files Indexed</div>
1525
+ <div class="stat-label">Files</div>
888
1526
  </div>
889
1527
  <div class="stat-card">
890
1528
  <div class="stat-value">${data.total_chunks || 0}</div>
891
- <div class="stat-label">Code Chunks</div>
892
- </div>
893
- <div class="stat-card">
894
- <div class="stat-value">${Object.keys(data.languages || {}).length}</div>
895
- <div class="stat-label">Languages</div>
1529
+ <div class="stat-label">Chunks</div>
896
1530
  </div>
897
1531
  `;
898
1532
  } catch (e) {
899
- container.innerHTML = `<div class="stat-card">Error loading index status</div>`;
1533
+ container.innerHTML = `<div class="stat-card">Error loading status</div>`;
900
1534
  }
901
1535
  }
902
1536
 
@@ -919,15 +1553,21 @@
919
1553
  const data = await response.json();
920
1554
 
921
1555
  if (data.results.length === 0) {
922
- results.innerHTML = '<p>No results found.</p>';
1556
+ results.innerHTML = `
1557
+ <div class="empty-state">
1558
+ <div class="empty-state-icon">🔍</div>
1559
+ <div class="empty-state-title">No results</div>
1560
+ <div class="empty-state-description">Try a different search query</div>
1561
+ </div>
1562
+ `;
923
1563
  return;
924
1564
  }
925
1565
 
926
1566
  results.innerHTML = data.results.map(r => `
927
1567
  <div class="search-result">
928
1568
  <div class="search-result-header">
929
- <span>${r.location}</span>
930
- <span class="badge badge-success">${(r.similarity * 100).toFixed(1)}% match</span>
1569
+ <span style="word-break: break-all;">${r.location}</span>
1570
+ <span class="badge badge-success">${(r.similarity * 100).toFixed(0)}%</span>
931
1571
  </div>
932
1572
  <div class="search-result-code">
933
1573
  <pre><code class="language-${r.language || 'plaintext'}">${escapeHtml(r.content)}</code></pre>
@@ -935,7 +1575,6 @@
935
1575
  </div>
936
1576
  `).join('');
937
1577
 
938
- // Highlight code
939
1578
  results.querySelectorAll('pre code').forEach(block => {
940
1579
  hljs.highlightElement(block);
941
1580
  });
@@ -951,7 +1590,7 @@
951
1590
  const response = await fetch('/api/index', { method: 'POST' });
952
1591
  const data = await response.json();
953
1592
 
954
- showToast(`Indexed ${data.files_indexed} files, ${data.chunks_created} chunks`);
1593
+ showToast(`Indexed ${data.files_indexed} files`);
955
1594
  loadIndexStatus();
956
1595
  } catch (e) {
957
1596
  showToast(`Error: ${e.message}`, 'error');
@@ -967,23 +1606,28 @@
967
1606
  const data = await response.json();
968
1607
 
969
1608
  if (data.plugins.length === 0) {
970
- container.innerHTML = '<p>No plugins available.</p>';
1609
+ container.innerHTML = `
1610
+ <div class="empty-state">
1611
+ <div class="empty-state-icon">🔌</div>
1612
+ <div class="empty-state-title">No plugins</div>
1613
+ <div class="empty-state-description">No plugins available</div>
1614
+ </div>
1615
+ `;
971
1616
  return;
972
1617
  }
973
1618
 
974
1619
  container.innerHTML = data.plugins.map(p => `
975
- <div class="card" style="margin-bottom: 16px;">
976
- <div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
977
- <span>${p.name} <span style="color: var(--text-secondary);">v${p.version}</span></span>
1620
+ <div class="card" style="margin-bottom: 12px;">
1621
+ <div class="card-header" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px;">
1622
+ <span>${p.name} <span style="color: var(--text-secondary); font-size: 12px;">v${p.version}</span></span>
978
1623
  <span class="badge ${p.status === 'active' ? 'badge-success' : 'badge-warning'}">${p.status}</span>
979
1624
  </div>
980
1625
  <div class="card-body">
981
- <p style="color: var(--text-secondary); margin-bottom: 12px;">
1626
+ <p style="color: var(--text-secondary); margin-bottom: 12px; font-size: 14px;">
982
1627
  ${p.builtin ? 'Built-in plugin' : 'Custom plugin'}
983
1628
  </p>
984
- <div>
985
- <strong>Actions:</strong>
986
- ${p.actions.map(a => `<button class="btn" style="margin: 4px;" onclick="executePlugin('${p.name}', '${a}')">${a}</button>`).join('')}
1629
+ <div class="tool-actions">
1630
+ ${p.actions.map(a => `<button class="btn btn-sm" onclick="executePlugin('${p.name}', '${a}')">${a}</button>`).join('')}
987
1631
  </div>
988
1632
  </div>
989
1633
  </div>
@@ -1005,7 +1649,6 @@
1005
1649
 
1006
1650
  if (data.success) {
1007
1651
  showToast(data.message);
1008
- // Show result in chat
1009
1652
  document.querySelector('[data-panel="chat"]').click();
1010
1653
  addMessage('assistant', `**${plugin}:${action}**\n\n${data.message}\n\n${typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)}`);
1011
1654
  } else {
@@ -1036,15 +1679,11 @@
1036
1679
  </div>
1037
1680
  <div class="stat-card">
1038
1681
  <div class="stat-value">${data.client.connected_servers}</div>
1039
- <div class="stat-label">Connected Servers</div>
1040
- </div>
1041
- <div class="stat-card">
1042
- <div class="stat-value">${data.server.running ? 'Yes' : 'No'}</div>
1043
- <div class="stat-label">Server Running</div>
1682
+ <div class="stat-label">Servers</div>
1044
1683
  </div>
1045
1684
  `;
1046
1685
  } catch (e) {
1047
- container.innerHTML = `<div class="stat-card">Error loading MCP status</div>`;
1686
+ container.innerHTML = `<div class="stat-card">Error loading status</div>`;
1048
1687
  }
1049
1688
  }
1050
1689
 
@@ -1058,7 +1697,13 @@
1058
1697
  const tools = [...data.local, ...data.remote];
1059
1698
 
1060
1699
  if (tools.length === 0) {
1061
- container.innerHTML = '<p>No tools available.</p>';
1700
+ container.innerHTML = `
1701
+ <div class="empty-state">
1702
+ <div class="empty-state-icon">🛠️</div>
1703
+ <div class="empty-state-title">No tools</div>
1704
+ <div class="empty-state-description">No MCP tools available</div>
1705
+ </div>
1706
+ `;
1062
1707
  return;
1063
1708
  }
1064
1709
 
@@ -1066,7 +1711,7 @@
1066
1711
  <div class="tool-item">
1067
1712
  <div class="tool-name">${t.name}</div>
1068
1713
  <div class="tool-description">${t.description}</div>
1069
- ${t.parameters ? `<div class="tool-params">Parameters: ${t.parameters.map(p => p.name).join(', ')}</div>` : ''}
1714
+ ${t.parameters ? `<div class="tool-params">Params: ${t.parameters.map(p => p.name).join(', ')}</div>` : ''}
1070
1715
  </div>
1071
1716
  `).join('');
1072
1717
  } catch (e) {
@@ -1094,19 +1739,18 @@
1094
1739
  const response = await fetch('/api/status');
1095
1740
  const data = await response.json();
1096
1741
 
1742
+ // Update version display
1743
+ document.getElementById('version-display').textContent = `v${data.version || '1.18.6'}`;
1744
+
1097
1745
  container.innerHTML = `
1098
1746
  <div class="stat-card">
1099
- <div class="stat-value" style="font-size: 20px;">${data.status === 'ok' ? '✅' : '❌'}</div>
1100
- <div class="stat-label">System Status</div>
1747
+ <div class="stat-value" style="font-size: 24px;">${data.status === 'ok' ? '✅' : '❌'}</div>
1748
+ <div class="stat-label">Status</div>
1101
1749
  </div>
1102
1750
  <div class="stat-card">
1103
- <div class="stat-value" style="font-size: 16px;">${data.version}</div>
1751
+ <div class="stat-value" style="font-size: 16px;">${data.version || 'N/A'}</div>
1104
1752
  <div class="stat-label">Version</div>
1105
1753
  </div>
1106
- <div class="stat-card">
1107
- <div class="stat-value" style="font-size: 14px; word-break: break-all;">${data.project.slice(-30)}</div>
1108
- <div class="stat-label">Project</div>
1109
- </div>
1110
1754
  `;
1111
1755
  } catch (e) {
1112
1756
  container.innerHTML = `<div class="stat-card">Error loading status</div>`;
@@ -1120,8 +1764,43 @@
1120
1764
  return div.innerHTML;
1121
1765
  }
1122
1766
 
1767
+ // Handle window resize
1768
+ window.addEventListener('resize', () => {
1769
+ if (window.innerWidth > 768) {
1770
+ closeSidebar();
1771
+ }
1772
+ });
1773
+
1774
+ // Dismiss welcome screen and show chat
1775
+ function dismissWelcome() {
1776
+ const welcomeScreen = document.getElementById('welcome-screen');
1777
+ const chatWelcome = document.getElementById('chat-welcome');
1778
+
1779
+ if (welcomeScreen) {
1780
+ welcomeScreen.style.display = 'none';
1781
+ }
1782
+ if (chatWelcome) {
1783
+ chatWelcome.style.display = 'block';
1784
+ }
1785
+
1786
+ // Store preference
1787
+ localStorage.setItem('nc1709_welcomed', 'true');
1788
+
1789
+ // Focus on chat input
1790
+ document.getElementById('chat-input').focus();
1791
+ }
1792
+
1793
+ // Check if user has already seen welcome
1794
+ function checkWelcomeState() {
1795
+ const welcomed = localStorage.getItem('nc1709_welcomed');
1796
+ if (welcomed === 'true') {
1797
+ dismissWelcome();
1798
+ }
1799
+ }
1800
+
1123
1801
  // Initial load
1124
1802
  loadStatus();
1803
+ checkWelcomeState();
1125
1804
  </script>
1126
1805
  </body>
1127
1806
  </html>