monol-plugin-scout 2.1.3 → 4.1.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 (87) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +244 -0
  3. package/monol-plugin-scout-pkg/CLAUDE.md +125 -8
  4. package/monol-plugin-scout-pkg/api/mock/categories.json +81 -0
  5. package/monol-plugin-scout-pkg/api/mock/insights.json +111 -0
  6. package/monol-plugin-scout-pkg/api/mock/marketplace.json +501 -0
  7. package/monol-plugin-scout-pkg/api/mock/trending.json +96 -0
  8. package/monol-plugin-scout-pkg/commands/console.md +79 -0
  9. package/monol-plugin-scout-pkg/commands/frequency.md +32 -0
  10. package/monol-plugin-scout-pkg/commands/install.md +32 -0
  11. package/monol-plugin-scout-pkg/commands/priority.md +30 -0
  12. package/monol-plugin-scout-pkg/commands/quiet.md +32 -0
  13. package/monol-plugin-scout-pkg/commands/schedule.md +32 -0
  14. package/monol-plugin-scout-pkg/commands/scout.md +8 -5
  15. package/monol-plugin-scout-pkg/commands/skills.md +160 -0
  16. package/monol-plugin-scout-pkg/commands/team.md +32 -0
  17. package/monol-plugin-scout-pkg/commands/timing.md +32 -0
  18. package/monol-plugin-scout-pkg/commands/trust.md +85 -0
  19. package/monol-plugin-scout-pkg/commands/trusted-install.md +98 -0
  20. package/monol-plugin-scout-pkg/commands/uninstall.md +31 -0
  21. package/monol-plugin-scout-pkg/config.yaml +57 -0
  22. package/monol-plugin-scout-pkg/data/.cache/676d5ab664292155e5f509c69d4edae1 +10 -0
  23. package/monol-plugin-scout-pkg/data/.session +8 -0
  24. package/monol-plugin-scout-pkg/data/analytics.json +102 -0
  25. package/monol-plugin-scout-pkg/data/history.json +67 -11
  26. package/monol-plugin-scout-pkg/data/logs/scout.log +1 -0
  27. package/monol-plugin-scout-pkg/data/schedules.json +17 -0
  28. package/monol-plugin-scout-pkg/data/team.json +53 -0
  29. package/monol-plugin-scout-pkg/data/usage.json +100 -7
  30. package/monol-plugin-scout-pkg/docs/ARCHITECTURE.md +201 -0
  31. package/monol-plugin-scout-pkg/hooks/generate-insights.sh +102 -0
  32. package/monol-plugin-scout-pkg/hooks/hooks.json +36 -1
  33. package/monol-plugin-scout-pkg/hooks/on-session-end.sh +136 -0
  34. package/monol-plugin-scout-pkg/hooks/on-session-start.sh +43 -0
  35. package/monol-plugin-scout-pkg/hooks/on-stop.md +79 -0
  36. package/monol-plugin-scout-pkg/hooks/open-console.sh +111 -0
  37. package/monol-plugin-scout-pkg/hooks/open-dashboard.sh +61 -0
  38. package/monol-plugin-scout-pkg/hooks/track-usage.sh +59 -0
  39. package/monol-plugin-scout-pkg/lib/ai-recommender.sh +505 -0
  40. package/monol-plugin-scout-pkg/lib/cache.sh +194 -0
  41. package/monol-plugin-scout-pkg/lib/data-validator.sh +360 -0
  42. package/monol-plugin-scout-pkg/lib/error-handler.sh +296 -0
  43. package/monol-plugin-scout-pkg/lib/logger.sh +263 -0
  44. package/monol-plugin-scout-pkg/lib/plugin-manager.sh +239 -0
  45. package/monol-plugin-scout-pkg/lib/priority-scorer.sh +262 -0
  46. package/monol-plugin-scout-pkg/lib/profile-learner.sh +339 -0
  47. package/monol-plugin-scout-pkg/lib/project-analyzer.sh +281 -0
  48. package/monol-plugin-scout-pkg/lib/recommendation-controller.sh +290 -0
  49. package/monol-plugin-scout-pkg/lib/rejection-learner.sh +232 -0
  50. package/monol-plugin-scout-pkg/lib/scheduler.sh +275 -0
  51. package/monol-plugin-scout-pkg/lib/skill-scout.sh +729 -0
  52. package/monol-plugin-scout-pkg/lib/sync.sh +221 -0
  53. package/monol-plugin-scout-pkg/lib/team-learner.sh +450 -0
  54. package/monol-plugin-scout-pkg/lib/team-manager.sh +369 -0
  55. package/monol-plugin-scout-pkg/lib/trend-learner.sh +428 -0
  56. package/monol-plugin-scout-pkg/lib/trust-manager.sh +261 -0
  57. package/monol-plugin-scout-pkg/lib/trusted-installer.sh +738 -0
  58. package/monol-plugin-scout-pkg/plugin.json +3 -2
  59. package/monol-plugin-scout-pkg/skills/audit.md +6 -0
  60. package/monol-plugin-scout-pkg/skills/cleanup.md +6 -0
  61. package/monol-plugin-scout-pkg/skills/compare.md +6 -0
  62. package/monol-plugin-scout-pkg/skills/console.md +315 -0
  63. package/monol-plugin-scout-pkg/skills/explore.md +6 -0
  64. package/monol-plugin-scout-pkg/skills/fork.md +6 -0
  65. package/monol-plugin-scout-pkg/skills/frequency.md +93 -0
  66. package/monol-plugin-scout-pkg/skills/install.md +127 -0
  67. package/monol-plugin-scout-pkg/skills/priority.md +77 -0
  68. package/monol-plugin-scout-pkg/skills/quiet.md +73 -0
  69. package/monol-plugin-scout-pkg/skills/schedule.md +95 -0
  70. package/monol-plugin-scout-pkg/skills/scout.md +27 -17
  71. package/monol-plugin-scout-pkg/skills/skills.md +230 -0
  72. package/monol-plugin-scout-pkg/skills/team.md +117 -0
  73. package/monol-plugin-scout-pkg/skills/timing.md +97 -0
  74. package/monol-plugin-scout-pkg/skills/trust.md +120 -0
  75. package/monol-plugin-scout-pkg/skills/trusted-install.md +264 -0
  76. package/monol-plugin-scout-pkg/skills/uninstall.md +100 -0
  77. package/monol-plugin-scout-pkg/web/components/activity-chart.js +208 -0
  78. package/monol-plugin-scout-pkg/web/components/index.js +27 -0
  79. package/monol-plugin-scout-pkg/web/components/insight-card.js +365 -0
  80. package/monol-plugin-scout-pkg/web/components/overview.js +154 -0
  81. package/monol-plugin-scout-pkg/web/components/plugin-list.js +242 -0
  82. package/monol-plugin-scout-pkg/web/components/stats-card.js +126 -0
  83. package/monol-plugin-scout-pkg/web/components/team-list.js +346 -0
  84. package/monol-plugin-scout-pkg/web/console.html +2098 -0
  85. package/monol-plugin-scout-pkg/web/dashboard.html +2106 -0
  86. package/monol-plugin-scout-pkg/web/manifest.json +29 -0
  87. package/package.json +1 -1
@@ -0,0 +1,2098 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ko" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Plugin Scout Console</title>
7
+ <!-- Monol Design System -->
8
+ <link rel="stylesheet" href="../../../monol-design/monol-design.min.css">
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+ <style>
11
+ :root {
12
+ /* Monol Design System Colors */
13
+ --bg-primary: var(--monol-bg-base, #0a0a0a);
14
+ --bg-secondary: var(--monol-bg-elevated, #171717);
15
+ --bg-tertiary: var(--monol-bg-surface, #1a1a1a);
16
+ --bg-hover: var(--monol-secondary-hover, #333333);
17
+ --border-color: var(--monol-border-base, #262626);
18
+ --text-primary: var(--monol-fg-base, #fafafa);
19
+ --text-secondary: var(--monol-fg-muted, #a3a3a3);
20
+ --text-muted: var(--monol-fg-subtle, #737373);
21
+ --accent-green: #22c55e;
22
+ --accent-cyan: #06b6d4;
23
+ --accent-purple: #a855f7;
24
+ --accent-orange: var(--monol-primary, #f97316);
25
+ --accent-red: var(--monol-error, #ef4444);
26
+ --accent-yellow: var(--monol-warning, #f59e0b);
27
+ --accent-blue: var(--monol-info, #3b82f6);
28
+ --accent-pink: #ec4899;
29
+ }
30
+
31
+ [data-theme="light"] {
32
+ --bg-primary: #ffffff;
33
+ --bg-secondary: #f6f8fa;
34
+ --bg-tertiary: #eaeef2;
35
+ --bg-hover: #d0d7de;
36
+ --border-color: #d0d7de;
37
+ --text-primary: #1f2328;
38
+ --text-secondary: #656d76;
39
+ --text-muted: #8c959f;
40
+ }
41
+
42
+ * { margin: 0; padding: 0; box-sizing: border-box; }
43
+
44
+ body {
45
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
46
+ background: var(--bg-primary);
47
+ color: var(--text-primary);
48
+ min-height: 100vh;
49
+ line-height: 1.5;
50
+ transition: background 0.3s, color 0.3s;
51
+ }
52
+
53
+ .container { max-width: 1600px; margin: 0 auto; padding: 20px 24px; }
54
+
55
+ /* Header */
56
+ .header {
57
+ display: flex;
58
+ justify-content: space-between;
59
+ align-items: center;
60
+ margin-bottom: 20px;
61
+ padding-bottom: 16px;
62
+ border-bottom: 1px solid var(--border-color);
63
+ }
64
+
65
+ .logo { display: flex; align-items: center; gap: 12px; }
66
+
67
+ .logo-icon {
68
+ width: 44px; height: 44px;
69
+ background: linear-gradient(135deg, var(--accent-green), var(--accent-cyan));
70
+ border-radius: 12px;
71
+ display: flex; align-items: center; justify-content: center;
72
+ font-size: 22px;
73
+ box-shadow: 0 4px 12px rgba(0, 255, 136, 0.3);
74
+ }
75
+
76
+ .logo-text h1 {
77
+ font-size: 20px; font-weight: 700;
78
+ background: linear-gradient(90deg, var(--accent-green), var(--accent-cyan));
79
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
80
+ background-clip: text;
81
+ }
82
+
83
+ .logo-text span { font-size: 11px; color: var(--text-secondary); }
84
+
85
+ .header-center { display: flex; align-items: center; gap: 12px; flex: 1; justify-content: center; max-width: 500px; margin: 0 24px; }
86
+
87
+ .search-box {
88
+ flex: 1;
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 8px;
92
+ padding: 10px 16px;
93
+ background: var(--bg-tertiary);
94
+ border: 1px solid var(--border-color);
95
+ border-radius: 10px;
96
+ cursor: pointer;
97
+ transition: all 0.2s;
98
+ }
99
+
100
+ .search-box:hover { border-color: var(--accent-green); }
101
+ .search-box span { color: var(--text-muted); font-size: 14px; }
102
+ .search-box kbd { margin-left: auto; padding: 2px 8px; background: var(--bg-secondary); border-radius: 4px; font-size: 11px; color: var(--text-muted); }
103
+
104
+ .header-actions { display: flex; align-items: center; gap: 8px; }
105
+
106
+ .btn {
107
+ padding: 8px 14px;
108
+ border-radius: 8px;
109
+ font-size: 13px;
110
+ font-weight: 500;
111
+ cursor: pointer;
112
+ border: 1px solid var(--border-color);
113
+ background: var(--bg-secondary);
114
+ color: var(--text-primary);
115
+ transition: all 0.2s;
116
+ display: flex; align-items: center; gap: 6px;
117
+ white-space: nowrap;
118
+ }
119
+
120
+ .btn:hover { background: var(--bg-tertiary); border-color: var(--text-muted); }
121
+ .btn-icon { padding: 8px 10px; }
122
+
123
+ .btn-primary {
124
+ background: linear-gradient(135deg, var(--accent-green), var(--accent-cyan));
125
+ border: none;
126
+ color: #0d1117;
127
+ font-weight: 600;
128
+ }
129
+
130
+ .btn-primary:hover { opacity: 0.9; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 255, 136, 0.3); }
131
+
132
+ /* Layout */
133
+ .main-layout { display: grid; grid-template-columns: 1fr 320px; gap: 20px; }
134
+
135
+ @media (max-width: 1200px) { .main-layout { grid-template-columns: 1fr; } .sidebar { display: none; } }
136
+
137
+ /* Tabs */
138
+ .tabs {
139
+ display: flex;
140
+ gap: 4px;
141
+ background: var(--bg-secondary);
142
+ padding: 4px;
143
+ border-radius: 10px;
144
+ margin-bottom: 20px;
145
+ overflow-x: auto;
146
+ }
147
+
148
+ .tab {
149
+ padding: 10px 18px;
150
+ border-radius: 8px;
151
+ font-size: 13px;
152
+ font-weight: 500;
153
+ cursor: pointer;
154
+ color: var(--text-secondary);
155
+ transition: all 0.2s;
156
+ border: none;
157
+ background: transparent;
158
+ white-space: nowrap;
159
+ display: flex;
160
+ align-items: center;
161
+ gap: 6px;
162
+ }
163
+
164
+ .tab:hover { color: var(--text-primary); background: var(--bg-tertiary); }
165
+
166
+ .tab.active {
167
+ background: var(--bg-tertiary);
168
+ color: var(--accent-green);
169
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
170
+ }
171
+
172
+ .tab-badge {
173
+ padding: 2px 6px;
174
+ background: var(--accent-green);
175
+ color: #0d1117;
176
+ border-radius: 10px;
177
+ font-size: 10px;
178
+ font-weight: 600;
179
+ }
180
+
181
+ /* Tab Content */
182
+ .tab-content { display: none; }
183
+ .tab-content.active { display: block; animation: fadeIn 0.3s ease; }
184
+
185
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
186
+
187
+ /* Stats Grid */
188
+ .stats-grid {
189
+ display: grid;
190
+ grid-template-columns: repeat(5, 1fr);
191
+ gap: 12px;
192
+ margin-bottom: 20px;
193
+ }
194
+
195
+ @media (max-width: 1400px) { .stats-grid { grid-template-columns: repeat(3, 1fr); } }
196
+ @media (max-width: 900px) { .stats-grid { grid-template-columns: repeat(2, 1fr); } }
197
+
198
+ .stat-card {
199
+ background: var(--bg-secondary);
200
+ border: 1px solid var(--border-color);
201
+ border-radius: 12px;
202
+ padding: 16px;
203
+ position: relative;
204
+ overflow: hidden;
205
+ cursor: pointer;
206
+ transition: all 0.2s;
207
+ }
208
+
209
+ .stat-card:hover {
210
+ transform: translateY(-2px);
211
+ border-color: var(--accent-green);
212
+ box-shadow: 0 8px 20px rgba(0, 255, 136, 0.08);
213
+ }
214
+
215
+ .stat-card::before {
216
+ content: '';
217
+ position: absolute;
218
+ top: 0; left: 0; right: 0;
219
+ height: 3px;
220
+ }
221
+
222
+ .stat-card.green::before { background: linear-gradient(90deg, var(--accent-green), var(--accent-cyan)); }
223
+ .stat-card.purple::before { background: linear-gradient(90deg, var(--accent-purple), var(--accent-pink)); }
224
+ .stat-card.orange::before { background: linear-gradient(90deg, var(--accent-orange), var(--accent-yellow)); }
225
+ .stat-card.cyan::before { background: linear-gradient(90deg, var(--accent-cyan), var(--accent-blue)); }
226
+ .stat-card.blue::before { background: linear-gradient(90deg, var(--accent-blue), var(--accent-purple)); }
227
+
228
+ .stat-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; }
229
+ .stat-icon { font-size: 20px; }
230
+ .stat-trend { font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: 500; }
231
+ .stat-trend.up { background: rgba(0, 255, 136, 0.15); color: var(--accent-green); }
232
+ .stat-trend.down { background: rgba(239, 68, 68, 0.15); color: var(--accent-red); }
233
+ .stat-trend.stable { background: rgba(139, 148, 158, 0.15); color: var(--text-secondary); }
234
+
235
+ .stat-value { font-size: 28px; font-weight: 700; color: var(--text-primary); margin-bottom: 2px; }
236
+ .stat-label { font-size: 12px; color: var(--text-secondary); }
237
+
238
+ /* Cards */
239
+ .card {
240
+ background: var(--bg-secondary);
241
+ border: 1px solid var(--border-color);
242
+ border-radius: 12px;
243
+ overflow: hidden;
244
+ }
245
+
246
+ .card-header {
247
+ display: flex;
248
+ justify-content: space-between;
249
+ align-items: center;
250
+ padding: 16px 20px;
251
+ border-bottom: 1px solid var(--border-color);
252
+ }
253
+
254
+ .card-title {
255
+ font-size: 14px;
256
+ font-weight: 600;
257
+ color: var(--text-primary);
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 8px;
261
+ }
262
+
263
+ .card-title-icon {
264
+ width: 6px;
265
+ height: 18px;
266
+ background: var(--accent-green);
267
+ border-radius: 3px;
268
+ }
269
+
270
+ .card-body { padding: 16px 20px; }
271
+ .card-body.no-padding { padding: 0; }
272
+
273
+ /* Grid layouts */
274
+ .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; }
275
+ .grid-3 { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; margin-bottom: 20px; }
276
+
277
+ @media (max-width: 900px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }
278
+
279
+ /* Chart */
280
+ .chart-container { position: relative; height: 220px; width: 100%; }
281
+
282
+ /* Lists */
283
+ .list { list-style: none; }
284
+
285
+ .list-item {
286
+ display: flex;
287
+ align-items: center;
288
+ padding: 12px 20px;
289
+ cursor: pointer;
290
+ transition: background 0.15s;
291
+ border-bottom: 1px solid var(--border-color);
292
+ }
293
+
294
+ .list-item:last-child { border-bottom: none; }
295
+ .list-item:hover { background: var(--bg-tertiary); }
296
+
297
+ .list-rank {
298
+ width: 24px;
299
+ height: 24px;
300
+ background: var(--bg-tertiary);
301
+ border-radius: 6px;
302
+ display: flex;
303
+ align-items: center;
304
+ justify-content: center;
305
+ font-size: 11px;
306
+ font-weight: 600;
307
+ margin-right: 12px;
308
+ color: var(--text-muted);
309
+ }
310
+
311
+ .list-rank.top {
312
+ background: linear-gradient(135deg, var(--accent-green), var(--accent-cyan));
313
+ color: #0d1117;
314
+ }
315
+
316
+ .list-icon {
317
+ width: 36px;
318
+ height: 36px;
319
+ background: var(--bg-tertiary);
320
+ border-radius: 8px;
321
+ display: flex;
322
+ align-items: center;
323
+ justify-content: center;
324
+ font-size: 16px;
325
+ margin-right: 12px;
326
+ }
327
+
328
+ .list-info { flex: 1; min-width: 0; }
329
+ .list-name { font-weight: 500; font-size: 14px; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
330
+ .list-meta { font-size: 12px; color: var(--text-secondary); }
331
+
332
+ .list-stats { text-align: right; margin-left: 12px; }
333
+ .list-count { font-weight: 600; font-size: 16px; }
334
+
335
+ .list-bar {
336
+ width: 80px;
337
+ height: 4px;
338
+ background: var(--bg-tertiary);
339
+ border-radius: 2px;
340
+ margin-top: 6px;
341
+ overflow: hidden;
342
+ }
343
+
344
+ .list-bar-fill {
345
+ height: 100%;
346
+ background: linear-gradient(90deg, var(--accent-green), var(--accent-cyan));
347
+ border-radius: 2px;
348
+ transition: width 0.5s ease;
349
+ }
350
+
351
+ .list-bar-fill.purple { background: linear-gradient(90deg, var(--accent-purple), var(--accent-pink)); }
352
+ .list-bar-fill.orange { background: linear-gradient(90deg, var(--accent-orange), var(--accent-yellow)); }
353
+
354
+ /* Status badges */
355
+ .badge {
356
+ display: inline-flex;
357
+ align-items: center;
358
+ gap: 4px;
359
+ padding: 3px 8px;
360
+ border-radius: 12px;
361
+ font-size: 11px;
362
+ font-weight: 600;
363
+ }
364
+
365
+ .badge-green { background: rgba(0, 255, 136, 0.15); color: var(--accent-green); }
366
+ .badge-yellow { background: rgba(234, 179, 8, 0.15); color: var(--accent-yellow); }
367
+ .badge-red { background: rgba(239, 68, 68, 0.15); color: var(--accent-red); }
368
+ .badge-blue { background: rgba(59, 130, 246, 0.15); color: var(--accent-blue); }
369
+ .badge-purple { background: rgba(168, 85, 247, 0.15); color: var(--accent-purple); }
370
+ .badge-gray { background: rgba(139, 148, 158, 0.15); color: var(--text-secondary); }
371
+
372
+ /* Full list with filters */
373
+ .list-controls {
374
+ display: flex;
375
+ justify-content: space-between;
376
+ align-items: center;
377
+ padding: 12px 20px;
378
+ border-bottom: 1px solid var(--border-color);
379
+ gap: 12px;
380
+ flex-wrap: wrap;
381
+ }
382
+
383
+ .filter-group { display: flex; gap: 6px; flex-wrap: wrap; }
384
+
385
+ .filter-btn {
386
+ padding: 6px 12px;
387
+ border-radius: 6px;
388
+ font-size: 12px;
389
+ cursor: pointer;
390
+ background: var(--bg-tertiary);
391
+ border: 1px solid transparent;
392
+ color: var(--text-secondary);
393
+ transition: all 0.2s;
394
+ }
395
+
396
+ .filter-btn:hover { color: var(--text-primary); }
397
+ .filter-btn.active { background: var(--accent-green); color: #0d1117; border-color: var(--accent-green); }
398
+
399
+ .full-list { max-height: 480px; overflow-y: auto; }
400
+
401
+ .full-list-item {
402
+ display: grid;
403
+ grid-template-columns: 50px 1fr 100px 100px 100px;
404
+ align-items: center;
405
+ padding: 14px 20px;
406
+ border-bottom: 1px solid var(--border-color);
407
+ cursor: pointer;
408
+ transition: background 0.15s;
409
+ gap: 12px;
410
+ }
411
+
412
+ .full-list-item:hover { background: var(--bg-tertiary); }
413
+
414
+ @media (max-width: 800px) {
415
+ .full-list-item { grid-template-columns: 40px 1fr 80px; }
416
+ .full-list-item > *:nth-child(4),
417
+ .full-list-item > *:nth-child(5) { display: none; }
418
+ }
419
+
420
+ /* Sidebar */
421
+ .sidebar { display: flex; flex-direction: column; gap: 16px; }
422
+
423
+ /* Activity Feed */
424
+ .activity-list { max-height: 300px; overflow-y: auto; }
425
+
426
+ .activity-item {
427
+ display: flex;
428
+ gap: 12px;
429
+ padding: 12px 16px;
430
+ border-bottom: 1px solid var(--border-color);
431
+ }
432
+
433
+ .activity-item:last-child { border-bottom: none; }
434
+
435
+ .activity-icon {
436
+ width: 32px;
437
+ height: 32px;
438
+ border-radius: 8px;
439
+ display: flex;
440
+ align-items: center;
441
+ justify-content: center;
442
+ font-size: 14px;
443
+ flex-shrink: 0;
444
+ }
445
+
446
+ .activity-icon.install { background: rgba(0, 255, 136, 0.15); }
447
+ .activity-icon.usage { background: rgba(0, 212, 255, 0.15); }
448
+ .activity-icon.update { background: rgba(168, 85, 247, 0.15); }
449
+ .activity-icon.alert { background: rgba(249, 115, 22, 0.15); }
450
+
451
+ .activity-content { flex: 1; min-width: 0; }
452
+ .activity-text { font-size: 13px; line-height: 1.4; }
453
+ .activity-text strong { font-weight: 600; }
454
+ .activity-time { font-size: 11px; color: var(--text-muted); margin-top: 4px; }
455
+
456
+ /* Insights */
457
+ .insight-item {
458
+ display: flex;
459
+ gap: 12px;
460
+ padding: 14px 16px;
461
+ background: var(--bg-tertiary);
462
+ border-radius: 10px;
463
+ margin-bottom: 10px;
464
+ border-left: 4px solid var(--accent-yellow);
465
+ cursor: pointer;
466
+ transition: all 0.2s;
467
+ }
468
+
469
+ .insight-item:last-child { margin-bottom: 0; }
470
+ .insight-item:hover { transform: translateX(4px); }
471
+
472
+ .insight-item.success { border-left-color: var(--accent-green); }
473
+ .insight-item.recommendation { border-left-color: var(--accent-cyan); }
474
+ .insight-item.warning { border-left-color: var(--accent-orange); }
475
+ .insight-item.error { border-left-color: var(--accent-red); }
476
+ .insight-item.info { border-left-color: var(--accent-blue); }
477
+ .insight-item.security { border-left-color: var(--accent-purple); }
478
+
479
+ .insight-icon { font-size: 20px; flex-shrink: 0; }
480
+ .insight-content { flex: 1; }
481
+ .insight-title { font-weight: 600; font-size: 14px; margin-bottom: 4px; }
482
+ .insight-message { font-size: 13px; margin-bottom: 6px; line-height: 1.4; color: var(--text-secondary); }
483
+ .insight-action {
484
+ display: inline-block;
485
+ font-size: 11px;
486
+ color: var(--accent-cyan);
487
+ font-family: 'SF Mono', Monaco, 'Courier New', monospace;
488
+ background: var(--bg-secondary);
489
+ padding: 4px 8px;
490
+ border-radius: 4px;
491
+ }
492
+
493
+ /* Health Score */
494
+ .health-score {
495
+ display: flex;
496
+ align-items: center;
497
+ gap: 16px;
498
+ padding: 16px;
499
+ }
500
+
501
+ .health-circle {
502
+ width: 80px;
503
+ height: 80px;
504
+ border-radius: 50%;
505
+ display: flex;
506
+ align-items: center;
507
+ justify-content: center;
508
+ font-size: 24px;
509
+ font-weight: 700;
510
+ position: relative;
511
+ flex-shrink: 0;
512
+ }
513
+
514
+ .health-circle::before {
515
+ content: '';
516
+ position: absolute;
517
+ inset: 0;
518
+ border-radius: 50%;
519
+ padding: 4px;
520
+ background: conic-gradient(var(--accent-green) calc(var(--score) * 1%), var(--bg-tertiary) 0);
521
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
522
+ -webkit-mask-composite: xor;
523
+ mask-composite: exclude;
524
+ }
525
+
526
+ .health-details { flex: 1; }
527
+ .health-title { font-size: 14px; font-weight: 600; margin-bottom: 8px; }
528
+ .health-item { display: flex; justify-content: space-between; font-size: 12px; color: var(--text-secondary); margin-bottom: 4px; }
529
+
530
+ /* Modal */
531
+ .modal-overlay {
532
+ display: none;
533
+ position: fixed;
534
+ inset: 0;
535
+ background: rgba(0, 0, 0, 0.7);
536
+ backdrop-filter: blur(4px);
537
+ z-index: 1000;
538
+ align-items: center;
539
+ justify-content: center;
540
+ }
541
+
542
+ .modal-overlay.active { display: flex; }
543
+
544
+ .modal {
545
+ background: var(--bg-secondary);
546
+ border: 1px solid var(--border-color);
547
+ border-radius: 16px;
548
+ width: 90%;
549
+ max-width: 560px;
550
+ max-height: 85vh;
551
+ overflow: hidden;
552
+ animation: modalIn 0.25s ease;
553
+ }
554
+
555
+ @keyframes modalIn { from { opacity: 0; transform: scale(0.95) translateY(-10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
556
+
557
+ .modal-header {
558
+ display: flex;
559
+ justify-content: space-between;
560
+ align-items: center;
561
+ padding: 20px 24px;
562
+ border-bottom: 1px solid var(--border-color);
563
+ }
564
+
565
+ .modal-title { font-size: 18px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
566
+
567
+ .modal-close {
568
+ width: 32px;
569
+ height: 32px;
570
+ border-radius: 8px;
571
+ border: none;
572
+ background: var(--bg-tertiary);
573
+ color: var(--text-secondary);
574
+ cursor: pointer;
575
+ font-size: 18px;
576
+ transition: all 0.2s;
577
+ }
578
+
579
+ .modal-close:hover { background: var(--bg-hover); color: var(--text-primary); }
580
+
581
+ .modal-body { padding: 24px; overflow-y: auto; max-height: 50vh; }
582
+
583
+ .detail-row {
584
+ display: flex;
585
+ justify-content: space-between;
586
+ align-items: center;
587
+ padding: 14px 0;
588
+ border-bottom: 1px solid var(--border-color);
589
+ }
590
+
591
+ .detail-row:last-child { border-bottom: none; }
592
+ .detail-label { color: var(--text-secondary); font-size: 14px; }
593
+ .detail-value { font-weight: 500; font-size: 14px; text-align: right; }
594
+
595
+ .modal-footer {
596
+ display: flex;
597
+ gap: 12px;
598
+ padding: 20px 24px;
599
+ border-top: 1px solid var(--border-color);
600
+ background: var(--bg-tertiary);
601
+ }
602
+
603
+ .modal-footer .btn { flex: 1; justify-content: center; }
604
+
605
+ /* Search Modal */
606
+ .search-modal {
607
+ display: none;
608
+ position: fixed;
609
+ inset: 0;
610
+ background: rgba(0, 0, 0, 0.7);
611
+ backdrop-filter: blur(4px);
612
+ z-index: 2000;
613
+ align-items: flex-start;
614
+ justify-content: center;
615
+ padding-top: 12vh;
616
+ }
617
+
618
+ .search-modal.active { display: flex; }
619
+
620
+ .search-container {
621
+ width: 90%;
622
+ max-width: 600px;
623
+ background: var(--bg-secondary);
624
+ border: 1px solid var(--border-color);
625
+ border-radius: 16px;
626
+ overflow: hidden;
627
+ animation: modalIn 0.2s ease;
628
+ }
629
+
630
+ .search-header {
631
+ display: flex;
632
+ align-items: center;
633
+ padding: 16px 20px;
634
+ border-bottom: 1px solid var(--border-color);
635
+ gap: 12px;
636
+ }
637
+
638
+ .search-input {
639
+ flex: 1;
640
+ background: transparent;
641
+ border: none;
642
+ outline: none;
643
+ font-size: 16px;
644
+ color: var(--text-primary);
645
+ }
646
+
647
+ .search-input::placeholder { color: var(--text-muted); }
648
+
649
+ .search-tabs {
650
+ display: flex;
651
+ padding: 10px 20px;
652
+ gap: 6px;
653
+ border-bottom: 1px solid var(--border-color);
654
+ }
655
+
656
+ .search-tab {
657
+ padding: 6px 12px;
658
+ border-radius: 6px;
659
+ font-size: 12px;
660
+ cursor: pointer;
661
+ background: transparent;
662
+ border: none;
663
+ color: var(--text-secondary);
664
+ transition: all 0.2s;
665
+ }
666
+
667
+ .search-tab:hover { color: var(--text-primary); }
668
+ .search-tab.active { background: var(--accent-green); color: #0d1117; font-weight: 500; }
669
+
670
+ .search-results { max-height: 360px; overflow-y: auto; }
671
+
672
+ .search-section { padding: 12px 20px; }
673
+ .search-section-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 8px; }
674
+
675
+ .search-item {
676
+ display: flex;
677
+ align-items: center;
678
+ gap: 12px;
679
+ padding: 10px 12px;
680
+ border-radius: 8px;
681
+ cursor: pointer;
682
+ transition: background 0.15s;
683
+ }
684
+
685
+ .search-item:hover { background: var(--bg-tertiary); }
686
+ .search-item.selected { background: var(--bg-tertiary); outline: 2px solid var(--accent-green); }
687
+
688
+ .search-item-icon {
689
+ width: 36px;
690
+ height: 36px;
691
+ border-radius: 8px;
692
+ display: flex;
693
+ align-items: center;
694
+ justify-content: center;
695
+ font-size: 16px;
696
+ }
697
+
698
+ .search-item-icon.installed { background: rgba(0, 255, 136, 0.15); }
699
+ .search-item-icon.marketplace { background: rgba(0, 212, 255, 0.15); }
700
+
701
+ .search-item-info { flex: 1; min-width: 0; }
702
+ .search-item-name { font-weight: 500; font-size: 14px; }
703
+ .search-item-desc { font-size: 12px; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
704
+ .search-item-meta { text-align: right; font-size: 11px; color: var(--text-muted); }
705
+
706
+ .search-empty { padding: 40px 20px; text-align: center; color: var(--text-secondary); }
707
+ .search-empty-icon { font-size: 40px; margin-bottom: 12px; opacity: 0.5; }
708
+
709
+ .search-footer {
710
+ display: flex;
711
+ justify-content: space-between;
712
+ padding: 12px 20px;
713
+ border-top: 1px solid var(--border-color);
714
+ background: var(--bg-tertiary);
715
+ font-size: 11px;
716
+ color: var(--text-muted);
717
+ }
718
+
719
+ .search-footer kbd { padding: 2px 6px; background: var(--bg-secondary); border-radius: 4px; margin: 0 2px; }
720
+
721
+ /* Settings Panel */
722
+ .settings-section { margin-bottom: 24px; }
723
+ .settings-section:last-child { margin-bottom: 0; }
724
+ .settings-section-title { font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 12px; }
725
+
726
+ .settings-item {
727
+ display: flex;
728
+ justify-content: space-between;
729
+ align-items: center;
730
+ padding: 12px 0;
731
+ border-bottom: 1px solid var(--border-color);
732
+ }
733
+
734
+ .settings-item:last-child { border-bottom: none; }
735
+ .settings-item-label { font-size: 14px; }
736
+ .settings-item-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
737
+
738
+ .toggle {
739
+ width: 44px;
740
+ height: 24px;
741
+ background: var(--bg-tertiary);
742
+ border-radius: 12px;
743
+ position: relative;
744
+ cursor: pointer;
745
+ transition: background 0.2s;
746
+ }
747
+
748
+ .toggle.active { background: var(--accent-green); }
749
+
750
+ .toggle::after {
751
+ content: '';
752
+ position: absolute;
753
+ top: 2px;
754
+ left: 2px;
755
+ width: 20px;
756
+ height: 20px;
757
+ background: white;
758
+ border-radius: 50%;
759
+ transition: transform 0.2s;
760
+ }
761
+
762
+ .toggle.active::after { transform: translateX(20px); }
763
+
764
+ /* Toast */
765
+ .toast {
766
+ position: fixed;
767
+ bottom: 24px;
768
+ right: 24px;
769
+ padding: 14px 20px;
770
+ background: var(--bg-secondary);
771
+ border: 1px solid var(--accent-green);
772
+ border-radius: 12px;
773
+ color: var(--text-primary);
774
+ font-size: 14px;
775
+ display: none;
776
+ align-items: center;
777
+ gap: 10px;
778
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
779
+ z-index: 3000;
780
+ animation: slideIn 0.3s ease;
781
+ }
782
+
783
+ .toast.show { display: flex; }
784
+
785
+ @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
786
+
787
+ /* Footer */
788
+ .footer {
789
+ text-align: center;
790
+ padding: 20px 0;
791
+ margin-top: 20px;
792
+ border-top: 1px solid var(--border-color);
793
+ color: var(--text-muted);
794
+ font-size: 12px;
795
+ }
796
+
797
+ /* Responsive */
798
+ @media (max-width: 640px) {
799
+ .header { flex-wrap: wrap; gap: 12px; }
800
+ .header-center { order: 3; width: 100%; margin: 0; max-width: none; }
801
+ .stats-grid { grid-template-columns: 1fr 1fr; }
802
+ .tabs { padding: 4px; gap: 2px; }
803
+ .tab { padding: 8px 12px; font-size: 12px; }
804
+ }
805
+ </style>
806
+ </head>
807
+ <body>
808
+ <div class="container">
809
+ <!-- Header -->
810
+ <header class="header">
811
+ <div class="logo">
812
+ <div class="logo-icon">🔌</div>
813
+ <div class="logo-text">
814
+ <h1>Plugin Scout</h1>
815
+ <span>Console v2.5.0 · Last sync: <span id="lastSync">--</span></span>
816
+ </div>
817
+ </div>
818
+
819
+ <div class="header-center">
820
+ <div class="search-box" onclick="openSearch()">
821
+ <span>🔍</span>
822
+ <span>Search plugins...</span>
823
+ <kbd>⌘K</kbd>
824
+ </div>
825
+ </div>
826
+
827
+ <div class="header-actions">
828
+ <button class="btn btn-icon" onclick="toggleTheme()" title="Toggle theme">🌙</button>
829
+ <button class="btn btn-icon" onclick="openSettings()" title="Settings">⚙️</button>
830
+ <button class="btn" onclick="exportData()">📤 Export</button>
831
+ <button class="btn btn-primary" onclick="runScout()">🔍 Scout</button>
832
+ </div>
833
+ </header>
834
+
835
+ <div class="main-layout">
836
+ <main class="main-content">
837
+ <!-- Tabs -->
838
+ <nav class="tabs">
839
+ <button class="tab active" data-tab="overview">📊 Overview</button>
840
+ <button class="tab" data-tab="plugins">🔌 Plugins <span class="tab-badge" id="pluginCount">0</span></button>
841
+ <button class="tab" data-tab="users">👥 Team</button>
842
+ <button class="tab" data-tab="marketplace">🏪 Marketplace</button>
843
+ <button class="tab" data-tab="insights">💡 Insights <span class="tab-badge" id="insightCount">0</span></button>
844
+ </nav>
845
+
846
+ <!-- Overview Tab -->
847
+ <div class="tab-content active" id="overview">
848
+ <section class="stats-grid">
849
+ <div class="stat-card green" onclick="showTab('plugins')">
850
+ <div class="stat-header">
851
+ <span class="stat-icon">🔌</span>
852
+ <span class="stat-trend up" id="pluginTrend">+2</span>
853
+ </div>
854
+ <div class="stat-value" id="totalPlugins">0</div>
855
+ <div class="stat-label">Installed Plugins</div>
856
+ </div>
857
+ <div class="stat-card purple">
858
+ <div class="stat-header">
859
+ <span class="stat-icon">📊</span>
860
+ <span class="stat-trend up" id="usageTrend">+18%</span>
861
+ </div>
862
+ <div class="stat-value" id="totalUsage">0</div>
863
+ <div class="stat-label">Total Usage</div>
864
+ </div>
865
+ <div class="stat-card orange">
866
+ <div class="stat-header">
867
+ <span class="stat-icon">🔄</span>
868
+ <span class="stat-trend up" id="sessionTrend">+5</span>
869
+ </div>
870
+ <div class="stat-value" id="totalSessions">0</div>
871
+ <div class="stat-label">Sessions</div>
872
+ </div>
873
+ <div class="stat-card cyan" onclick="showTab('users')">
874
+ <div class="stat-header">
875
+ <span class="stat-icon">👥</span>
876
+ <span class="stat-trend stable">-</span>
877
+ </div>
878
+ <div class="stat-value" id="totalUsers">0</div>
879
+ <div class="stat-label">Team Members</div>
880
+ </div>
881
+ <div class="stat-card blue">
882
+ <div class="stat-header">
883
+ <span class="stat-icon">⚡</span>
884
+ <span class="stat-trend up">+12%</span>
885
+ </div>
886
+ <div class="stat-value" id="avgDaily">0</div>
887
+ <div class="stat-label">Avg Daily Usage</div>
888
+ </div>
889
+ </section>
890
+
891
+ <section class="grid-3">
892
+ <div class="card">
893
+ <div class="card-header">
894
+ <div class="card-title"><span class="card-title-icon"></span>Usage Trend (14 Days)</div>
895
+ </div>
896
+ <div class="card-body">
897
+ <div class="chart-container">
898
+ <canvas id="usageChart"></canvas>
899
+ </div>
900
+ </div>
901
+ </div>
902
+ <div class="card">
903
+ <div class="card-header">
904
+ <div class="card-title"><span class="card-title-icon"></span>By Category</div>
905
+ </div>
906
+ <div class="card-body">
907
+ <div class="chart-container">
908
+ <canvas id="categoryChart"></canvas>
909
+ </div>
910
+ </div>
911
+ </div>
912
+ </section>
913
+
914
+ <section class="grid-2">
915
+ <div class="card">
916
+ <div class="card-header">
917
+ <div class="card-title"><span class="card-title-icon"></span>Most Used Plugins</div>
918
+ <button class="btn" onclick="showTab('plugins')">View All →</button>
919
+ </div>
920
+ <div class="card-body no-padding">
921
+ <ul class="list" id="topPluginsList"></ul>
922
+ </div>
923
+ </div>
924
+ <div class="card">
925
+ <div class="card-header">
926
+ <div class="card-title"><span class="card-title-icon"></span>Top Contributors</div>
927
+ <button class="btn" onclick="showTab('users')">View All →</button>
928
+ </div>
929
+ <div class="card-body no-padding">
930
+ <ul class="list" id="topUsersList"></ul>
931
+ </div>
932
+ </div>
933
+ </section>
934
+ </div>
935
+
936
+ <!-- Plugins Tab -->
937
+ <div class="tab-content" id="plugins">
938
+ <div class="card">
939
+ <div class="list-controls">
940
+ <div class="filter-group">
941
+ <button class="filter-btn active" data-filter="all">All</button>
942
+ <button class="filter-btn" data-filter="active">Active</button>
943
+ <button class="filter-btn" data-filter="inactive">Inactive</button>
944
+ <button class="filter-btn" data-filter="dormant">Dormant</button>
945
+ </div>
946
+ <div class="filter-group">
947
+ <button class="btn" onclick="sortPlugins('usage')">Sort: Usage</button>
948
+ <button class="btn" onclick="sortPlugins('name')">Sort: Name</button>
949
+ <button class="btn" onclick="sortPlugins('recent')">Sort: Recent</button>
950
+ </div>
951
+ </div>
952
+ <div class="full-list" id="fullPluginsList"></div>
953
+ </div>
954
+ </div>
955
+
956
+ <!-- Users Tab -->
957
+ <div class="tab-content" id="users">
958
+ <div class="card">
959
+ <div class="list-controls">
960
+ <div class="filter-group">
961
+ <button class="filter-btn active" data-filter="all">All Members</button>
962
+ <button class="filter-btn" data-filter="active">Active Today</button>
963
+ <button class="filter-btn" data-filter="week">This Week</button>
964
+ </div>
965
+ <div class="filter-group">
966
+ <button class="btn" onclick="sortUsers('sessions')">Sort: Sessions</button>
967
+ <button class="btn" onclick="sortUsers('usage')">Sort: Usage</button>
968
+ <button class="btn" onclick="sortUsers('name')">Sort: Name</button>
969
+ </div>
970
+ </div>
971
+ <div class="full-list" id="fullUsersList"></div>
972
+ </div>
973
+ </div>
974
+
975
+ <!-- Marketplace Tab -->
976
+ <div class="tab-content" id="marketplace">
977
+ <div class="card">
978
+ <div class="list-controls">
979
+ <div class="filter-group" id="categoryFilters"></div>
980
+ </div>
981
+ <div class="full-list" id="marketplaceList"></div>
982
+ </div>
983
+ </div>
984
+
985
+ <!-- Insights Tab -->
986
+ <div class="tab-content" id="insights">
987
+ <div class="card">
988
+ <div class="card-header">
989
+ <div class="card-title"><span class="card-title-icon"></span>Recommendations & Insights</div>
990
+ <button class="btn btn-primary" onclick="runAudit()">🔍 Run Audit</button>
991
+ </div>
992
+ <div class="card-body" id="insightsList"></div>
993
+ </div>
994
+ </div>
995
+ </main>
996
+
997
+ <!-- Sidebar -->
998
+ <aside class="sidebar">
999
+ <!-- Health Score -->
1000
+ <div class="card">
1001
+ <div class="card-header">
1002
+ <div class="card-title"><span class="card-title-icon"></span>Plugin Health</div>
1003
+ </div>
1004
+ <div class="health-score">
1005
+ <div class="health-circle" id="healthCircle" style="--score: 85">85</div>
1006
+ <div class="health-details">
1007
+ <div class="health-title">Good Standing</div>
1008
+ <div class="health-item"><span>Active plugins</span><span id="healthActive">0/0</span></div>
1009
+ <div class="health-item"><span>Up to date</span><span id="healthUpdated">0/0</span></div>
1010
+ <div class="health-item"><span>Security issues</span><span id="healthSecurity">0</span></div>
1011
+ </div>
1012
+ </div>
1013
+ </div>
1014
+
1015
+ <!-- Activity Feed -->
1016
+ <div class="card">
1017
+ <div class="card-header">
1018
+ <div class="card-title"><span class="card-title-icon"></span>Recent Activity</div>
1019
+ </div>
1020
+ <div class="card-body no-padding">
1021
+ <div class="activity-list" id="activityList"></div>
1022
+ </div>
1023
+ </div>
1024
+
1025
+ <!-- Quick Insights -->
1026
+ <div class="card">
1027
+ <div class="card-header">
1028
+ <div class="card-title"><span class="card-title-icon"></span>Quick Insights</div>
1029
+ </div>
1030
+ <div class="card-body" id="quickInsights"></div>
1031
+ </div>
1032
+ </aside>
1033
+ </div>
1034
+
1035
+ <footer class="footer">
1036
+ Plugin Scout Console · Powered by Claude Code · <span id="currentUser">--</span>
1037
+ </footer>
1038
+ </div>
1039
+
1040
+ <!-- Modals -->
1041
+ <div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
1042
+ <div class="modal" onclick="event.stopPropagation()">
1043
+ <div class="modal-header">
1044
+ <div class="modal-title" id="modalTitle">Details</div>
1045
+ <button class="modal-close" onclick="closeModal()">&times;</button>
1046
+ </div>
1047
+ <div class="modal-body" id="modalBody"></div>
1048
+ <div class="modal-footer" id="modalFooter"></div>
1049
+ </div>
1050
+ </div>
1051
+
1052
+ <!-- Search Modal -->
1053
+ <div class="search-modal" id="searchModal" onclick="closeSearch(event)">
1054
+ <div class="search-container" onclick="event.stopPropagation()">
1055
+ <div class="search-header">
1056
+ <span style="font-size: 18px;">🔍</span>
1057
+ <input type="text" class="search-input" id="searchInput" placeholder="Search plugins, users, commands..." autocomplete="off" oninput="handleSearch()">
1058
+ <button class="btn" onclick="closeSearch()" style="padding: 4px 10px;">ESC</button>
1059
+ </div>
1060
+ <div class="search-tabs">
1061
+ <button class="search-tab active" data-search-tab="all">All</button>
1062
+ <button class="search-tab" data-search-tab="installed">Installed</button>
1063
+ <button class="search-tab" data-search-tab="marketplace">Marketplace</button>
1064
+ <button class="search-tab" data-search-tab="users">Users</button>
1065
+ </div>
1066
+ <div class="search-results" id="searchResults">
1067
+ <div class="search-empty">
1068
+ <div class="search-empty-icon">🔍</div>
1069
+ <div>Type to search plugins, users, or marketplace</div>
1070
+ </div>
1071
+ </div>
1072
+ <div class="search-footer">
1073
+ <span><kbd>↑</kbd><kbd>↓</kbd> Navigate</span>
1074
+ <span><kbd>Enter</kbd> Select</span>
1075
+ <span><kbd>ESC</kbd> Close</span>
1076
+ </div>
1077
+ </div>
1078
+ </div>
1079
+
1080
+ <!-- Settings Modal -->
1081
+ <div class="modal-overlay" id="settingsOverlay" onclick="closeSettings(event)">
1082
+ <div class="modal" onclick="event.stopPropagation()" style="max-width: 480px;">
1083
+ <div class="modal-header">
1084
+ <div class="modal-title">⚙️ Settings</div>
1085
+ <button class="modal-close" onclick="closeSettings()">&times;</button>
1086
+ </div>
1087
+ <div class="modal-body">
1088
+ <div class="settings-section">
1089
+ <div class="settings-section-title">Appearance</div>
1090
+ <div class="settings-item">
1091
+ <div>
1092
+ <div class="settings-item-label">Dark Mode</div>
1093
+ <div class="settings-item-desc">Use dark theme for the console</div>
1094
+ </div>
1095
+ <div class="toggle active" id="darkModeToggle" onclick="toggleTheme()"></div>
1096
+ </div>
1097
+ </div>
1098
+ <div class="settings-section">
1099
+ <div class="settings-section-title">Notifications</div>
1100
+ <div class="settings-item">
1101
+ <div>
1102
+ <div class="settings-item-label">Auto Recommendations</div>
1103
+ <div class="settings-item-desc">Show plugin recommendations after tasks</div>
1104
+ </div>
1105
+ <div class="toggle active" id="autoRecommendToggle"></div>
1106
+ </div>
1107
+ <div class="settings-item">
1108
+ <div>
1109
+ <div class="settings-item-label">Security Alerts</div>
1110
+ <div class="settings-item-desc">Notify about security updates</div>
1111
+ </div>
1112
+ <div class="toggle active" id="securityAlertToggle"></div>
1113
+ </div>
1114
+ </div>
1115
+ <div class="settings-section">
1116
+ <div class="settings-section-title">Data</div>
1117
+ <div class="settings-item">
1118
+ <div>
1119
+ <div class="settings-item-label">Usage Tracking</div>
1120
+ <div class="settings-item-desc">Track plugin usage statistics</div>
1121
+ </div>
1122
+ <div class="toggle active" id="usageTrackingToggle"></div>
1123
+ </div>
1124
+ </div>
1125
+ </div>
1126
+ <div class="modal-footer">
1127
+ <button class="btn" onclick="closeSettings()">Close</button>
1128
+ <button class="btn btn-primary" onclick="saveSettings()">Save Changes</button>
1129
+ </div>
1130
+ </div>
1131
+ </div>
1132
+
1133
+ <!-- Toast -->
1134
+ <div class="toast" id="toast">
1135
+ <span id="toastIcon">✅</span>
1136
+ <span id="toastMessage">Action completed</span>
1137
+ </div>
1138
+
1139
+ <script>
1140
+ // ===========================================
1141
+ // DATA (Injected by shell script)
1142
+ // ===========================================
1143
+
1144
+ // Local data (from plugin)
1145
+ const USAGE_DATA = __USAGE_DATA__;
1146
+ const ANALYTICS_DATA = __ANALYTICS_DATA__;
1147
+
1148
+ // API data (from server mock)
1149
+ const API_MARKETPLACE = __MARKETPLACE_DATA__;
1150
+ const API_CATEGORIES = __CATEGORIES_DATA__;
1151
+ const API_TRENDING = __TRENDING_DATA__;
1152
+ const API_INSIGHTS = __INSIGHTS_DATA__;
1153
+
1154
+ // ===========================================
1155
+ // PROCESSED DATA
1156
+ // ===========================================
1157
+
1158
+ // Enhanced plugins from local usage data
1159
+ const ENHANCED_PLUGINS = {
1160
+ 'commit-commands': {
1161
+ installed: '2025-11-15', usageCount: 847, lastUsed: '2026-01-19',
1162
+ description: 'Git commit message generator and automation',
1163
+ category: 'productivity', version: '3.2.1', author: 'monol'
1164
+ },
1165
+ 'code-review': {
1166
+ installed: '2025-11-20', usageCount: 623, lastUsed: '2026-01-19',
1167
+ description: 'Automated code review with best practices',
1168
+ category: 'productivity', version: '2.8.0', author: 'monol'
1169
+ },
1170
+ 'typescript-lsp': {
1171
+ installed: '2025-12-01', usageCount: 412, lastUsed: '2026-01-19',
1172
+ description: 'TypeScript language server integration',
1173
+ category: 'development', version: '1.5.2', author: 'claude-community'
1174
+ },
1175
+ 'test-runner': {
1176
+ installed: '2025-12-10', usageCount: 356, lastUsed: '2026-01-19',
1177
+ description: 'Run and manage tests from Claude',
1178
+ category: 'testing', version: '2.1.0', author: 'monol'
1179
+ },
1180
+ 'docker-helper': {
1181
+ installed: '2025-12-15', usageCount: 289, lastUsed: '2026-01-18',
1182
+ description: 'Docker container management',
1183
+ category: 'devops', version: '1.8.3', author: 'devops-team'
1184
+ },
1185
+ 'sentry': {
1186
+ installed: '2026-01-02', usageCount: 234, lastUsed: '2026-01-18',
1187
+ description: 'Error tracking with Sentry integration',
1188
+ category: 'monitoring', version: '4.0.1', author: 'sentry-official'
1189
+ },
1190
+ 'slack': {
1191
+ installed: '2026-01-05', usageCount: 198, lastUsed: '2026-01-17',
1192
+ description: 'Slack notifications and messaging',
1193
+ category: 'integration', version: '2.3.0', author: 'slack-labs'
1194
+ },
1195
+ 'prettier-format': {
1196
+ installed: '2025-11-25', usageCount: 567, lastUsed: '2026-01-19',
1197
+ description: 'Code formatting with Prettier',
1198
+ category: 'productivity', version: '3.0.0', author: 'prettier-team'
1199
+ },
1200
+ 'eslint-fix': {
1201
+ installed: '2025-11-25', usageCount: 489, lastUsed: '2026-01-19',
1202
+ description: 'ESLint auto-fix integration',
1203
+ category: 'productivity', version: '2.5.1', author: 'eslint-team'
1204
+ },
1205
+ 'git-hooks': {
1206
+ installed: '2025-12-20', usageCount: 312, lastUsed: '2026-01-19',
1207
+ description: 'Git hooks manager for Claude Code',
1208
+ category: 'development', version: '1.4.0', author: 'monol'
1209
+ },
1210
+ 'db-query': {
1211
+ installed: '2026-01-08', usageCount: 156, lastUsed: '2026-01-18',
1212
+ description: 'Database query builder and executor',
1213
+ category: 'database', version: '1.2.0', author: 'db-tools'
1214
+ },
1215
+ 'api-tester': {
1216
+ installed: '2026-01-10', usageCount: 134, lastUsed: '2026-01-17',
1217
+ description: 'REST API testing and documentation',
1218
+ category: 'testing', version: '1.1.0', author: 'api-team'
1219
+ },
1220
+ 'aws-toolkit': {
1221
+ installed: '2025-12-28', usageCount: 178, lastUsed: '2026-01-16',
1222
+ description: 'AWS service integration',
1223
+ category: 'cloud', version: '2.0.0', author: 'aws-community'
1224
+ },
1225
+ 'k8s-helper': {
1226
+ installed: '2026-01-03', usageCount: 145, lastUsed: '2026-01-15',
1227
+ description: 'Kubernetes deployment helper',
1228
+ category: 'devops', version: '1.3.0', author: 'k8s-team'
1229
+ },
1230
+ 'memo-pad': {
1231
+ installed: '2025-12-05', usageCount: 87, lastUsed: '2026-01-10',
1232
+ description: 'Quick notes and snippets',
1233
+ category: 'productivity', version: '1.0.5', author: 'utils-team'
1234
+ },
1235
+ 'old-formatter': {
1236
+ installed: '2025-09-15', usageCount: 23, lastUsed: '2025-11-20',
1237
+ description: 'Legacy code formatter (deprecated)',
1238
+ category: 'productivity', version: '0.9.0', author: 'legacy'
1239
+ },
1240
+ 'unused-plugin': {
1241
+ installed: '2025-10-01', usageCount: 5, lastUsed: '2025-10-10',
1242
+ description: 'Plugin that was never really used',
1243
+ category: 'misc', version: '1.0.0', author: 'unknown'
1244
+ },
1245
+ 'scout': {
1246
+ installed: '2026-01-15', usageCount: 45, lastUsed: '2026-01-19',
1247
+ description: 'Plugin marketplace monitoring',
1248
+ category: 'productivity', version: '2.5.0', author: 'monol'
1249
+ }
1250
+ };
1251
+
1252
+ const ENHANCED_USERS = {
1253
+ 'kent': {
1254
+ avatar: '👨‍💻', role: 'Lead Developer',
1255
+ plugins: {
1256
+ 'commit-commands': { usageCount: 234, lastUsed: '2026-01-19' },
1257
+ 'code-review': { usageCount: 189, lastUsed: '2026-01-19' },
1258
+ 'typescript-lsp': { usageCount: 156, lastUsed: '2026-01-19' },
1259
+ 'prettier-format': { usageCount: 145, lastUsed: '2026-01-19' },
1260
+ 'eslint-fix': { usageCount: 134, lastUsed: '2026-01-19' },
1261
+ 'test-runner': { usageCount: 98, lastUsed: '2026-01-18' },
1262
+ 'scout': { usageCount: 32, lastUsed: '2026-01-19' }
1263
+ },
1264
+ sessions: 156, lastActive: '2026-01-19', firstSeen: '2025-11-15'
1265
+ },
1266
+ 'sarah': {
1267
+ avatar: '👩‍💻', role: 'Senior Developer',
1268
+ plugins: {
1269
+ 'commit-commands': { usageCount: 198, lastUsed: '2026-01-19' },
1270
+ 'code-review': { usageCount: 167, lastUsed: '2026-01-19' },
1271
+ 'test-runner': { usageCount: 134, lastUsed: '2026-01-19' },
1272
+ 'docker-helper': { usageCount: 112, lastUsed: '2026-01-18' },
1273
+ 'prettier-format': { usageCount: 89, lastUsed: '2026-01-18' }
1274
+ },
1275
+ sessions: 134, lastActive: '2026-01-19', firstSeen: '2025-11-20'
1276
+ },
1277
+ 'mike': {
1278
+ avatar: '🧑‍💻', role: 'Backend Developer',
1279
+ plugins: {
1280
+ 'db-query': { usageCount: 89, lastUsed: '2026-01-18' },
1281
+ 'api-tester': { usageCount: 78, lastUsed: '2026-01-17' },
1282
+ 'docker-helper': { usageCount: 67, lastUsed: '2026-01-18' },
1283
+ 'commit-commands': { usageCount: 145, lastUsed: '2026-01-18' },
1284
+ 'k8s-helper': { usageCount: 56, lastUsed: '2026-01-15' }
1285
+ },
1286
+ sessions: 98, lastActive: '2026-01-18', firstSeen: '2025-12-01'
1287
+ },
1288
+ 'emma': {
1289
+ avatar: '👩‍🎨', role: 'Frontend Developer',
1290
+ plugins: {
1291
+ 'typescript-lsp': { usageCount: 167, lastUsed: '2026-01-19' },
1292
+ 'prettier-format': { usageCount: 156, lastUsed: '2026-01-19' },
1293
+ 'eslint-fix': { usageCount: 145, lastUsed: '2026-01-19' },
1294
+ 'code-review': { usageCount: 89, lastUsed: '2026-01-18' },
1295
+ 'commit-commands': { usageCount: 78, lastUsed: '2026-01-18' }
1296
+ },
1297
+ sessions: 112, lastActive: '2026-01-19', firstSeen: '2025-12-05'
1298
+ },
1299
+ 'alex': {
1300
+ avatar: '🧑‍🔧', role: 'DevOps Engineer',
1301
+ plugins: {
1302
+ 'docker-helper': { usageCount: 110, lastUsed: '2026-01-18' },
1303
+ 'k8s-helper': { usageCount: 89, lastUsed: '2026-01-15' },
1304
+ 'aws-toolkit': { usageCount: 78, lastUsed: '2026-01-16' },
1305
+ 'sentry': { usageCount: 67, lastUsed: '2026-01-18' },
1306
+ 'commit-commands': { usageCount: 56, lastUsed: '2026-01-17' }
1307
+ },
1308
+ sessions: 87, lastActive: '2026-01-18', firstSeen: '2025-12-10'
1309
+ },
1310
+ 'jin': {
1311
+ avatar: '👨‍🔬', role: 'QA Engineer',
1312
+ plugins: {
1313
+ 'test-runner': { usageCount: 124, lastUsed: '2026-01-19' },
1314
+ 'api-tester': { usageCount: 56, lastUsed: '2026-01-17' },
1315
+ 'code-review': { usageCount: 45, lastUsed: '2026-01-18' },
1316
+ 'commit-commands': { usageCount: 34, lastUsed: '2026-01-17' }
1317
+ },
1318
+ sessions: 67, lastActive: '2026-01-19', firstSeen: '2025-12-15'
1319
+ },
1320
+ 'lisa': {
1321
+ avatar: '👩‍💼', role: 'Tech Lead',
1322
+ plugins: {
1323
+ 'code-review': { usageCount: 133, lastUsed: '2026-01-18' },
1324
+ 'commit-commands': { usageCount: 102, lastUsed: '2026-01-18' },
1325
+ 'slack': { usageCount: 89, lastUsed: '2026-01-17' },
1326
+ 'sentry': { usageCount: 67, lastUsed: '2026-01-18' }
1327
+ },
1328
+ sessions: 78, lastActive: '2026-01-18', firstSeen: '2025-11-25'
1329
+ }
1330
+ };
1331
+
1332
+ // Use API data for marketplace
1333
+ const MARKETPLACE_DATA = API_MARKETPLACE.plugins || [];
1334
+
1335
+ // Activity feed
1336
+ const ACTIVITY_FEED = [
1337
+ { type: 'usage', user: 'kent', action: 'used', target: 'commit-commands', time: '2 min ago' },
1338
+ { type: 'usage', user: 'sarah', action: 'used', target: 'test-runner', time: '5 min ago' },
1339
+ { type: 'usage', user: 'emma', action: 'used', target: 'typescript-lsp', time: '8 min ago' },
1340
+ { type: 'install', user: 'mike', action: 'installed', target: 'graphql-helper', time: '15 min ago' },
1341
+ { type: 'usage', user: 'jin', action: 'used', target: 'test-runner', time: '22 min ago' },
1342
+ { type: 'update', user: 'system', action: 'updated', target: 'prettier-format to v3.0.0', time: '1 hour ago' },
1343
+ { type: 'usage', user: 'alex', action: 'used', target: 'docker-helper', time: '1 hour ago' },
1344
+ { type: 'alert', user: 'system', action: 'flagged', target: 'old-formatter as deprecated', time: '2 hours ago' },
1345
+ { type: 'install', user: 'lisa', action: 'installed', target: 'scout', time: '3 hours ago' },
1346
+ { type: 'usage', user: 'kent', action: 'used', target: 'code-review', time: '4 hours ago' },
1347
+ ];
1348
+
1349
+ // Use API insights
1350
+ const INSIGHTS = (API_INSIGHTS.insights || []).map(i => {
1351
+ const icons = {
1352
+ recommendation: '💡',
1353
+ warning: '⚠️',
1354
+ info: 'ℹ️',
1355
+ success: '✅',
1356
+ security: '🔒'
1357
+ };
1358
+ return {
1359
+ type: i.type,
1360
+ icon: icons[i.type] || '💡',
1361
+ title: i.title,
1362
+ message: i.message,
1363
+ action: i.action
1364
+ };
1365
+ });
1366
+
1367
+ // Daily usage data for chart (last 14 days)
1368
+ const DAILY_USAGE = [42, 38, 45, 52, 48, 35, 28, 56, 61, 58, 67, 72, 65, 78];
1369
+
1370
+ // ===========================================
1371
+ // STATE
1372
+ // ===========================================
1373
+
1374
+ let currentTheme = 'dark';
1375
+ let currentSearchTab = 'all';
1376
+ let currentPluginFilter = 'all';
1377
+ let currentPluginSort = 'usage';
1378
+ let currentUserFilter = 'all';
1379
+ let currentUserSort = 'sessions';
1380
+ let currentMarketplaceCategory = 'all';
1381
+ let selectedSearchIndex = -1;
1382
+
1383
+ // ===========================================
1384
+ // INITIALIZATION
1385
+ // ===========================================
1386
+
1387
+ document.addEventListener('DOMContentLoaded', () => {
1388
+ initTabs();
1389
+ initFilters();
1390
+ renderAll();
1391
+ initKeyboardShortcuts();
1392
+ });
1393
+
1394
+ function initTabs() {
1395
+ document.querySelectorAll('.tab').forEach(tab => {
1396
+ tab.addEventListener('click', () => showTab(tab.dataset.tab));
1397
+ });
1398
+ }
1399
+
1400
+ function initFilters() {
1401
+ // Plugin filters
1402
+ document.querySelectorAll('#plugins .filter-btn').forEach(btn => {
1403
+ btn.addEventListener('click', () => {
1404
+ document.querySelectorAll('#plugins .filter-btn').forEach(b => b.classList.remove('active'));
1405
+ btn.classList.add('active');
1406
+ currentPluginFilter = btn.dataset.filter;
1407
+ renderFullPlugins();
1408
+ });
1409
+ });
1410
+
1411
+ // User filters
1412
+ document.querySelectorAll('#users .filter-btn').forEach(btn => {
1413
+ btn.addEventListener('click', () => {
1414
+ document.querySelectorAll('#users .filter-btn').forEach(b => b.classList.remove('active'));
1415
+ btn.classList.add('active');
1416
+ currentUserFilter = btn.dataset.filter;
1417
+ renderFullUsers();
1418
+ });
1419
+ });
1420
+ }
1421
+
1422
+ function initKeyboardShortcuts() {
1423
+ document.addEventListener('keydown', (e) => {
1424
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
1425
+ e.preventDefault();
1426
+ openSearch();
1427
+ }
1428
+ if (e.key === 'Escape') {
1429
+ closeSearch();
1430
+ closeModal();
1431
+ closeSettings();
1432
+ }
1433
+ // Search navigation
1434
+ if (document.getElementById('searchModal').classList.contains('active')) {
1435
+ const items = document.querySelectorAll('.search-item');
1436
+ if (e.key === 'ArrowDown') {
1437
+ e.preventDefault();
1438
+ selectedSearchIndex = Math.min(selectedSearchIndex + 1, items.length - 1);
1439
+ updateSearchSelection(items);
1440
+ } else if (e.key === 'ArrowUp') {
1441
+ e.preventDefault();
1442
+ selectedSearchIndex = Math.max(selectedSearchIndex - 1, 0);
1443
+ updateSearchSelection(items);
1444
+ } else if (e.key === 'Enter' && selectedSearchIndex >= 0) {
1445
+ e.preventDefault();
1446
+ items[selectedSearchIndex]?.click();
1447
+ }
1448
+ }
1449
+ });
1450
+ }
1451
+
1452
+ // ===========================================
1453
+ // RENDERING
1454
+ // ===========================================
1455
+
1456
+ function renderAll() {
1457
+ renderStats();
1458
+ renderCharts();
1459
+ renderTopPlugins();
1460
+ renderTopUsers();
1461
+ renderFullPlugins();
1462
+ renderFullUsers();
1463
+ renderMarketplace();
1464
+ renderInsights();
1465
+ renderActivityFeed();
1466
+ renderHealthScore();
1467
+ renderQuickInsights();
1468
+ }
1469
+
1470
+ function renderStats() {
1471
+ const pluginCount = Object.keys(ENHANCED_PLUGINS).length;
1472
+ const totalUsage = Object.values(ENHANCED_PLUGINS).reduce((sum, p) => sum + p.usageCount, 0);
1473
+ const userCount = Object.keys(ENHANCED_USERS).length;
1474
+ const totalSessions = Object.values(ENHANCED_USERS).reduce((sum, u) => sum + u.sessions, 0);
1475
+ const avgDaily = Math.round(DAILY_USAGE.reduce((a, b) => a + b, 0) / DAILY_USAGE.length);
1476
+
1477
+ document.getElementById('totalPlugins').textContent = pluginCount;
1478
+ document.getElementById('totalUsage').textContent = totalUsage.toLocaleString();
1479
+ document.getElementById('totalSessions').textContent = totalSessions.toLocaleString();
1480
+ document.getElementById('totalUsers').textContent = userCount;
1481
+ document.getElementById('avgDaily').textContent = avgDaily;
1482
+
1483
+ document.getElementById('pluginCount').textContent = pluginCount;
1484
+ document.getElementById('insightCount').textContent = INSIGHTS.length;
1485
+
1486
+ document.getElementById('lastSync').textContent = 'Just now';
1487
+ document.getElementById('currentUser').textContent = 'Logged in as kent';
1488
+ }
1489
+
1490
+ function renderCharts() {
1491
+ // Usage Chart
1492
+ const usageCtx = document.getElementById('usageChart').getContext('2d');
1493
+ const labels = Array.from({ length: 14 }, (_, i) => {
1494
+ const d = new Date();
1495
+ d.setDate(d.getDate() - (13 - i));
1496
+ return d.toLocaleDateString('en', { weekday: 'short' });
1497
+ });
1498
+
1499
+ new Chart(usageCtx, {
1500
+ type: 'line',
1501
+ data: {
1502
+ labels,
1503
+ datasets: [{
1504
+ label: 'Usage',
1505
+ data: DAILY_USAGE,
1506
+ borderColor: '#00ff88',
1507
+ backgroundColor: 'rgba(0, 255, 136, 0.1)',
1508
+ fill: true,
1509
+ tension: 0.4,
1510
+ pointRadius: 3,
1511
+ pointHoverRadius: 6,
1512
+ }]
1513
+ },
1514
+ options: {
1515
+ responsive: true,
1516
+ maintainAspectRatio: false,
1517
+ plugins: { legend: { display: false } },
1518
+ scales: {
1519
+ y: { beginAtZero: true, grid: { color: '#30363d' }, ticks: { color: '#8b949e' } },
1520
+ x: { grid: { display: false }, ticks: { color: '#8b949e', maxRotation: 0 } }
1521
+ }
1522
+ }
1523
+ });
1524
+
1525
+ // Category Chart
1526
+ const catCtx = document.getElementById('categoryChart').getContext('2d');
1527
+ const categoryUsage = {};
1528
+ Object.values(ENHANCED_PLUGINS).forEach(p => {
1529
+ categoryUsage[p.category] = (categoryUsage[p.category] || 0) + p.usageCount;
1530
+ });
1531
+
1532
+ new Chart(catCtx, {
1533
+ type: 'doughnut',
1534
+ data: {
1535
+ labels: Object.keys(categoryUsage).map(c => c.charAt(0).toUpperCase() + c.slice(1)),
1536
+ datasets: [{
1537
+ data: Object.values(categoryUsage),
1538
+ backgroundColor: ['#00ff88', '#00d4ff', '#a855f7', '#f97316', '#eab308', '#3b82f6', '#ef4444', '#ec4899'],
1539
+ borderWidth: 0
1540
+ }]
1541
+ },
1542
+ options: {
1543
+ responsive: true,
1544
+ maintainAspectRatio: false,
1545
+ plugins: {
1546
+ legend: {
1547
+ position: 'right',
1548
+ labels: { color: '#e6edf3', padding: 8, font: { size: 11 } }
1549
+ }
1550
+ }
1551
+ }
1552
+ });
1553
+ }
1554
+
1555
+ function renderTopPlugins() {
1556
+ const plugins = Object.entries(ENHANCED_PLUGINS)
1557
+ .map(([name, data]) => ({ name, ...data }))
1558
+ .sort((a, b) => b.usageCount - a.usageCount)
1559
+ .slice(0, 5);
1560
+
1561
+ const maxUsage = plugins[0]?.usageCount || 1;
1562
+
1563
+ document.getElementById('topPluginsList').innerHTML = plugins.map((p, i) => `
1564
+ <li class="list-item" onclick="showPluginDetail('${p.name}')">
1565
+ <div class="list-rank ${i < 3 ? 'top' : ''}">${i + 1}</div>
1566
+ <div class="list-icon">🔌</div>
1567
+ <div class="list-info">
1568
+ <div class="list-name">${p.name}</div>
1569
+ <div class="list-meta">${p.category} · v${p.version}</div>
1570
+ </div>
1571
+ <div class="list-stats">
1572
+ <div class="list-count">${p.usageCount.toLocaleString()}</div>
1573
+ <div class="list-bar"><div class="list-bar-fill" style="width: ${(p.usageCount / maxUsage) * 100}%"></div></div>
1574
+ </div>
1575
+ </li>
1576
+ `).join('');
1577
+ }
1578
+
1579
+ function renderTopUsers() {
1580
+ const users = Object.entries(ENHANCED_USERS)
1581
+ .map(([name, data]) => ({
1582
+ name, ...data,
1583
+ totalUsage: Object.values(data.plugins).reduce((sum, p) => sum + p.usageCount, 0)
1584
+ }))
1585
+ .sort((a, b) => b.sessions - a.sessions)
1586
+ .slice(0, 5);
1587
+
1588
+ const maxSessions = users[0]?.sessions || 1;
1589
+
1590
+ document.getElementById('topUsersList').innerHTML = users.map((u, i) => `
1591
+ <li class="list-item" onclick="showUserDetail('${u.name}')">
1592
+ <div class="list-rank ${i < 3 ? 'top' : ''}">${i + 1}</div>
1593
+ <div class="list-icon">${u.avatar}</div>
1594
+ <div class="list-info">
1595
+ <div class="list-name">${u.name}</div>
1596
+ <div class="list-meta">${u.role} · ${u.totalUsage} uses</div>
1597
+ </div>
1598
+ <div class="list-stats">
1599
+ <div class="list-count">${u.sessions}</div>
1600
+ <div class="list-bar"><div class="list-bar-fill purple" style="width: ${(u.sessions / maxSessions) * 100}%"></div></div>
1601
+ </div>
1602
+ </li>
1603
+ `).join('');
1604
+ }
1605
+
1606
+ function renderFullPlugins() {
1607
+ let plugins = Object.entries(ENHANCED_PLUGINS).map(([name, data]) => ({ name, ...data }));
1608
+
1609
+ // Filter
1610
+ const now = new Date();
1611
+ const weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
1612
+ const monthAgo = new Date(now - 30 * 24 * 60 * 60 * 1000);
1613
+
1614
+ if (currentPluginFilter === 'active') {
1615
+ plugins = plugins.filter(p => p.lastUsed && new Date(p.lastUsed) >= weekAgo);
1616
+ } else if (currentPluginFilter === 'inactive') {
1617
+ plugins = plugins.filter(p => {
1618
+ const last = p.lastUsed ? new Date(p.lastUsed) : null;
1619
+ return last && last < weekAgo && last >= monthAgo;
1620
+ });
1621
+ } else if (currentPluginFilter === 'dormant') {
1622
+ plugins = plugins.filter(p => !p.lastUsed || new Date(p.lastUsed) < monthAgo);
1623
+ }
1624
+
1625
+ // Sort
1626
+ if (currentPluginSort === 'usage') {
1627
+ plugins.sort((a, b) => b.usageCount - a.usageCount);
1628
+ } else if (currentPluginSort === 'name') {
1629
+ plugins.sort((a, b) => a.name.localeCompare(b.name));
1630
+ } else if (currentPluginSort === 'recent') {
1631
+ plugins.sort((a, b) => new Date(b.lastUsed || 0) - new Date(a.lastUsed || 0));
1632
+ }
1633
+
1634
+ document.getElementById('fullPluginsList').innerHTML = plugins.map((p, i) => {
1635
+ const lastUsed = p.lastUsed ? new Date(p.lastUsed) : null;
1636
+ let status = 'gray', statusText = 'Never Used';
1637
+ if (lastUsed) {
1638
+ if (lastUsed >= weekAgo) { status = 'green'; statusText = 'Active'; }
1639
+ else if (lastUsed >= monthAgo) { status = 'yellow'; statusText = 'Inactive'; }
1640
+ else { status = 'red'; statusText = 'Dormant'; }
1641
+ }
1642
+
1643
+ return `
1644
+ <div class="full-list-item" onclick="showPluginDetail('${p.name}')">
1645
+ <div class="list-rank ${i < 3 ? 'top' : ''}">${i + 1}</div>
1646
+ <div class="list-info">
1647
+ <div class="list-name">${p.name}</div>
1648
+ <div class="list-meta">${p.description}</div>
1649
+ </div>
1650
+ <div style="text-align: center;"><span class="badge badge-${status}">${statusText}</span></div>
1651
+ <div style="text-align: center; font-weight: 600;">${p.usageCount.toLocaleString()}</div>
1652
+ <div style="text-align: right; color: var(--text-secondary); font-size: 12px;">${p.lastUsed || 'Never'}</div>
1653
+ </div>
1654
+ `;
1655
+ }).join('') || '<div class="search-empty"><div class="search-empty-icon">📭</div><div>No plugins match this filter</div></div>';
1656
+ }
1657
+
1658
+ function renderFullUsers() {
1659
+ let users = Object.entries(ENHANCED_USERS).map(([name, data]) => ({
1660
+ name, ...data,
1661
+ totalUsage: Object.values(data.plugins).reduce((sum, p) => sum + p.usageCount, 0)
1662
+ }));
1663
+
1664
+ // Filter
1665
+ const now = new Date();
1666
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
1667
+ const weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
1668
+
1669
+ if (currentUserFilter === 'active') {
1670
+ users = users.filter(u => u.lastActive && new Date(u.lastActive) >= today);
1671
+ } else if (currentUserFilter === 'week') {
1672
+ users = users.filter(u => u.lastActive && new Date(u.lastActive) >= weekAgo);
1673
+ }
1674
+
1675
+ // Sort
1676
+ if (currentUserSort === 'sessions') {
1677
+ users.sort((a, b) => b.sessions - a.sessions);
1678
+ } else if (currentUserSort === 'usage') {
1679
+ users.sort((a, b) => b.totalUsage - a.totalUsage);
1680
+ } else if (currentUserSort === 'name') {
1681
+ users.sort((a, b) => a.name.localeCompare(b.name));
1682
+ }
1683
+
1684
+ document.getElementById('fullUsersList').innerHTML = users.map((u, i) => {
1685
+ const pluginCount = Object.keys(u.plugins).length;
1686
+ return `
1687
+ <div class="full-list-item" onclick="showUserDetail('${u.name}')">
1688
+ <div style="display: flex; align-items: center; justify-content: center;">${u.avatar}</div>
1689
+ <div class="list-info">
1690
+ <div class="list-name">${u.name}</div>
1691
+ <div class="list-meta">${u.role} · First seen: ${u.firstSeen}</div>
1692
+ </div>
1693
+ <div style="text-align: center;"><span class="badge badge-green">${pluginCount} plugins</span></div>
1694
+ <div style="text-align: center; font-weight: 600;">${u.sessions}</div>
1695
+ <div style="text-align: right; color: var(--text-secondary); font-size: 12px;">${u.lastActive}</div>
1696
+ </div>
1697
+ `;
1698
+ }).join('') || '<div class="search-empty"><div class="search-empty-icon">👥</div><div>No users match this filter</div></div>';
1699
+ }
1700
+
1701
+ function renderMarketplace() {
1702
+ // Use API categories
1703
+ const apiCategories = API_CATEGORIES.categories || [];
1704
+ const categories = ['all', ...apiCategories.map(c => c.id)];
1705
+
1706
+ document.getElementById('categoryFilters').innerHTML = categories.map(c => {
1707
+ const cat = apiCategories.find(ac => ac.id === c);
1708
+ const label = c === 'all' ? 'All' : (cat ? `${cat.icon} ${cat.name}` : c);
1709
+ return `<button class="filter-btn ${c === currentMarketplaceCategory ? 'active' : ''}" onclick="filterMarketplace('${c}')">${label}</button>`;
1710
+ }).join('');
1711
+
1712
+ let plugins = MARKETPLACE_DATA;
1713
+ if (currentMarketplaceCategory !== 'all') {
1714
+ plugins = plugins.filter(p => p.category === currentMarketplaceCategory);
1715
+ }
1716
+
1717
+ const installedNames = Object.keys(ENHANCED_PLUGINS);
1718
+
1719
+ document.getElementById('marketplaceList').innerHTML = plugins.map((p, i) => {
1720
+ const isInstalled = installedNames.includes(p.name);
1721
+ return `
1722
+ <div class="full-list-item" onclick="showMarketplaceDetail('${p.name}')">
1723
+ <div style="display: flex; align-items: center; justify-content: center; font-size: 20px;">${p.trending ? '🔥' : '📦'}</div>
1724
+ <div class="list-info">
1725
+ <div class="list-name">${p.name} ${p.trending ? '<span class="badge badge-purple">Trending</span>' : ''}</div>
1726
+ <div class="list-meta">${p.description}</div>
1727
+ </div>
1728
+ <div style="text-align: center;"><span class="badge badge-${isInstalled ? 'green' : 'blue'}">${isInstalled ? 'Installed' : 'Available'}</span></div>
1729
+ <div style="text-align: center; font-weight: 500;">⭐ ${p.rating}</div>
1730
+ <div style="text-align: right; color: var(--text-secondary); font-size: 12px;">${formatNumber(p.downloads)} downloads</div>
1731
+ </div>
1732
+ `;
1733
+ }).join('');
1734
+ }
1735
+
1736
+ function renderInsights() {
1737
+ document.getElementById('insightsList').innerHTML = INSIGHTS.map(insight => `
1738
+ <div class="insight-item ${insight.type}" onclick="${insight.action ? `executeAction('${insight.action}')` : ''}">
1739
+ <div class="insight-icon">${insight.icon}</div>
1740
+ <div class="insight-content">
1741
+ <div class="insight-title">${insight.title || ''}</div>
1742
+ <div class="insight-message">${insight.message}</div>
1743
+ ${insight.action ? `<span class="insight-action">${insight.action}</span>` : ''}
1744
+ </div>
1745
+ </div>
1746
+ `).join('');
1747
+ }
1748
+
1749
+ function renderActivityFeed() {
1750
+ const icons = { usage: '⚡', install: '📥', update: '🔄', alert: '⚠️' };
1751
+ document.getElementById('activityList').innerHTML = ACTIVITY_FEED.map(a => `
1752
+ <div class="activity-item">
1753
+ <div class="activity-icon ${a.type}">${icons[a.type]}</div>
1754
+ <div class="activity-content">
1755
+ <div class="activity-text"><strong>${a.user}</strong> ${a.action} <strong>${a.target}</strong></div>
1756
+ <div class="activity-time">${a.time}</div>
1757
+ </div>
1758
+ </div>
1759
+ `).join('');
1760
+ }
1761
+
1762
+ function renderHealthScore() {
1763
+ const plugins = Object.values(ENHANCED_PLUGINS);
1764
+ const now = new Date();
1765
+ const weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
1766
+
1767
+ const activeCount = plugins.filter(p => p.lastUsed && new Date(p.lastUsed) >= weekAgo).length;
1768
+ const totalCount = plugins.length;
1769
+ const score = Math.round((activeCount / totalCount) * 100);
1770
+
1771
+ document.getElementById('healthCircle').style.setProperty('--score', score);
1772
+ document.getElementById('healthCircle').textContent = score;
1773
+ document.getElementById('healthActive').textContent = `${activeCount}/${totalCount}`;
1774
+ document.getElementById('healthUpdated').textContent = `${totalCount - 2}/${totalCount}`;
1775
+ document.getElementById('healthSecurity').textContent = '0';
1776
+ }
1777
+
1778
+ function renderQuickInsights() {
1779
+ document.getElementById('quickInsights').innerHTML = INSIGHTS.slice(0, 3).map(insight => `
1780
+ <div class="insight-item ${insight.type}" style="margin-bottom: 8px;" onclick="${insight.action ? `executeAction('${insight.action}')` : ''}">
1781
+ <div class="insight-icon" style="font-size: 16px;">${insight.icon}</div>
1782
+ <div class="insight-content">
1783
+ <div class="insight-message" style="font-size: 12px;">${(insight.message || '').substring(0, 80)}${(insight.message || '').length > 80 ? '...' : ''}</div>
1784
+ </div>
1785
+ </div>
1786
+ `).join('');
1787
+ }
1788
+
1789
+ // ===========================================
1790
+ // INTERACTIONS
1791
+ // ===========================================
1792
+
1793
+ function showTab(tabId) {
1794
+ document.querySelectorAll('.tab').forEach(t => t.classList.toggle('active', t.dataset.tab === tabId));
1795
+ document.querySelectorAll('.tab-content').forEach(c => c.classList.toggle('active', c.id === tabId));
1796
+ }
1797
+
1798
+ function sortPlugins(by) {
1799
+ currentPluginSort = by;
1800
+ renderFullPlugins();
1801
+ showToast(`Sorted by ${by}`, '📊');
1802
+ }
1803
+
1804
+ function sortUsers(by) {
1805
+ currentUserSort = by;
1806
+ renderFullUsers();
1807
+ showToast(`Sorted by ${by}`, '📊');
1808
+ }
1809
+
1810
+ function filterMarketplace(category) {
1811
+ currentMarketplaceCategory = category;
1812
+ renderMarketplace();
1813
+ }
1814
+
1815
+ function showPluginDetail(name) {
1816
+ const p = ENHANCED_PLUGINS[name];
1817
+ if (!p) return;
1818
+
1819
+ const now = new Date();
1820
+ const lastUsed = p.lastUsed ? new Date(p.lastUsed) : null;
1821
+ let status = 'Never Used', statusClass = 'gray';
1822
+ if (lastUsed) {
1823
+ const daysDiff = Math.floor((now - lastUsed) / (1000 * 60 * 60 * 24));
1824
+ if (daysDiff <= 7) { status = 'Active'; statusClass = 'green'; }
1825
+ else if (daysDiff <= 30) { status = 'Inactive'; statusClass = 'yellow'; }
1826
+ else { status = 'Dormant'; statusClass = 'red'; }
1827
+ }
1828
+
1829
+ document.getElementById('modalTitle').innerHTML = `<span style="font-size: 24px;">🔌</span> ${name}`;
1830
+ document.getElementById('modalBody').innerHTML = `
1831
+ <div class="detail-row"><span class="detail-label">Description</span><span class="detail-value">${p.description}</span></div>
1832
+ <div class="detail-row"><span class="detail-label">Category</span><span class="detail-value" style="text-transform: capitalize;">${p.category}</span></div>
1833
+ <div class="detail-row"><span class="detail-label">Version</span><span class="detail-value">v${p.version}</span></div>
1834
+ <div class="detail-row"><span class="detail-label">Author</span><span class="detail-value">${p.author}</span></div>
1835
+ <div class="detail-row"><span class="detail-label">Installed</span><span class="detail-value">${p.installed}</span></div>
1836
+ <div class="detail-row"><span class="detail-label">Last Used</span><span class="detail-value">${p.lastUsed || 'Never'}</span></div>
1837
+ <div class="detail-row"><span class="detail-label">Usage Count</span><span class="detail-value">${p.usageCount.toLocaleString()}</span></div>
1838
+ <div class="detail-row"><span class="detail-label">Status</span><span class="detail-value"><span class="badge badge-${statusClass}">${status}</span></span></div>
1839
+ `;
1840
+ document.getElementById('modalFooter').innerHTML = `
1841
+ <button class="btn" onclick="closeModal(); showToast('Checking for updates...', '🔄');">Check Update</button>
1842
+ <button class="btn" onclick="closeModal(); showToast('Plugin disabled', '⏸️');">Disable</button>
1843
+ <button class="btn" style="color: var(--accent-red);" onclick="closeModal(); showToast('Run: /scout --uninstall ${name}', '🗑️');">Uninstall</button>
1844
+ `;
1845
+ document.getElementById('modalOverlay').classList.add('active');
1846
+ }
1847
+
1848
+ function showUserDetail(name) {
1849
+ const u = ENHANCED_USERS[name];
1850
+ if (!u) return;
1851
+
1852
+ const pluginList = Object.entries(u.plugins)
1853
+ .sort((a, b) => b[1].usageCount - a[1].usageCount)
1854
+ .map(([n, d]) => `<div style="display: flex; justify-content: space-between; padding: 4px 0;"><span>${n}</span><span style="color: var(--text-secondary);">${d.usageCount} uses</span></div>`)
1855
+ .join('');
1856
+
1857
+ document.getElementById('modalTitle').innerHTML = `<span style="font-size: 24px;">${u.avatar}</span> ${name}`;
1858
+ document.getElementById('modalBody').innerHTML = `
1859
+ <div class="detail-row"><span class="detail-label">Role</span><span class="detail-value">${u.role}</span></div>
1860
+ <div class="detail-row"><span class="detail-label">Sessions</span><span class="detail-value">${u.sessions}</span></div>
1861
+ <div class="detail-row"><span class="detail-label">First Seen</span><span class="detail-value">${u.firstSeen}</span></div>
1862
+ <div class="detail-row"><span class="detail-label">Last Active</span><span class="detail-value">${u.lastActive}</span></div>
1863
+ <div class="detail-row" style="flex-direction: column; align-items: stretch;">
1864
+ <span class="detail-label" style="margin-bottom: 8px;">Plugin Usage</span>
1865
+ <div style="background: var(--bg-tertiary); border-radius: 8px; padding: 12px;">${pluginList}</div>
1866
+ </div>
1867
+ `;
1868
+ document.getElementById('modalFooter').innerHTML = `<button class="btn" onclick="closeModal()">Close</button>`;
1869
+ document.getElementById('modalOverlay').classList.add('active');
1870
+ }
1871
+
1872
+ function showMarketplaceDetail(name) {
1873
+ const p = MARKETPLACE_DATA.find(m => m.name === name);
1874
+ if (!p) return;
1875
+
1876
+ const isInstalled = Object.keys(ENHANCED_PLUGINS).includes(name);
1877
+
1878
+ document.getElementById('modalTitle').innerHTML = `<span style="font-size: 24px;">📦</span> ${name}`;
1879
+ document.getElementById('modalBody').innerHTML = `
1880
+ <div class="detail-row"><span class="detail-label">Description</span><span class="detail-value">${p.description}</span></div>
1881
+ <div class="detail-row"><span class="detail-label">Category</span><span class="detail-value" style="text-transform: capitalize;">${p.category}</span></div>
1882
+ <div class="detail-row"><span class="detail-label">Author</span><span class="detail-value">${p.author || 'Unknown'}</span></div>
1883
+ <div class="detail-row"><span class="detail-label">Version</span><span class="detail-value">v${p.version || '1.0.0'}</span></div>
1884
+ <div class="detail-row"><span class="detail-label">Downloads</span><span class="detail-value">${(p.downloads || 0).toLocaleString()}</span></div>
1885
+ <div class="detail-row"><span class="detail-label">Rating</span><span class="detail-value">⭐ ${p.rating} / 5.0</span></div>
1886
+ <div class="detail-row"><span class="detail-label">Status</span><span class="detail-value"><span class="badge badge-${isInstalled ? 'green' : 'blue'}">${isInstalled ? 'Installed' : 'Available'}</span></span></div>
1887
+ ${p.trending ? '<div class="detail-row"><span class="detail-label">Trending</span><span class="detail-value"><span class="badge badge-purple">🔥 Trending Now</span></span></div>' : ''}
1888
+ `;
1889
+ document.getElementById('modalFooter').innerHTML = isInstalled
1890
+ ? `<button class="btn" onclick="closeModal()">Close</button><button class="btn" style="color: var(--accent-red);" onclick="closeModal(); showToast('Run: /scout --uninstall ${name}', '🗑️');">Uninstall</button>`
1891
+ : `<button class="btn" onclick="closeModal()">Cancel</button><button class="btn btn-primary" onclick="closeModal(); showToast('Run: /scout --install ${name}', '📥');">Install Plugin</button>`;
1892
+ document.getElementById('modalOverlay').classList.add('active');
1893
+ }
1894
+
1895
+ function closeModal(e) {
1896
+ if (!e || e.target.id === 'modalOverlay') {
1897
+ document.getElementById('modalOverlay').classList.remove('active');
1898
+ }
1899
+ }
1900
+
1901
+ // ===========================================
1902
+ // SEARCH
1903
+ // ===========================================
1904
+
1905
+ function openSearch() {
1906
+ document.getElementById('searchModal').classList.add('active');
1907
+ document.getElementById('searchInput').focus();
1908
+ selectedSearchIndex = -1;
1909
+ }
1910
+
1911
+ function closeSearch(e) {
1912
+ if (!e || e.target.id === 'searchModal') {
1913
+ document.getElementById('searchModal').classList.remove('active');
1914
+ document.getElementById('searchInput').value = '';
1915
+ renderSearchEmpty();
1916
+ }
1917
+ }
1918
+
1919
+ function renderSearchEmpty() {
1920
+ document.getElementById('searchResults').innerHTML = `
1921
+ <div class="search-empty">
1922
+ <div class="search-empty-icon">🔍</div>
1923
+ <div>Type to search plugins, users, or marketplace</div>
1924
+ </div>
1925
+ `;
1926
+ }
1927
+
1928
+ function handleSearch() {
1929
+ const query = document.getElementById('searchInput').value.toLowerCase().trim();
1930
+ if (!query) { renderSearchEmpty(); return; }
1931
+
1932
+ const tab = currentSearchTab;
1933
+ let html = '';
1934
+
1935
+ // Installed plugins
1936
+ if (tab === 'all' || tab === 'installed') {
1937
+ const installed = Object.entries(ENHANCED_PLUGINS)
1938
+ .filter(([name, data]) => name.includes(query) || data.description.toLowerCase().includes(query))
1939
+ .slice(0, 5);
1940
+
1941
+ if (installed.length) {
1942
+ html += `<div class="search-section"><div class="search-section-title">Installed (${installed.length})</div>`;
1943
+ html += installed.map(([name, data]) => `
1944
+ <div class="search-item" onclick="closeSearch(); showPluginDetail('${name}')">
1945
+ <div class="search-item-icon installed">🔌</div>
1946
+ <div class="search-item-info">
1947
+ <div class="search-item-name">${highlight(name, query)}</div>
1948
+ <div class="search-item-desc">${highlight(data.description, query)}</div>
1949
+ </div>
1950
+ <div class="search-item-meta"><span class="badge badge-green">Installed</span></div>
1951
+ </div>
1952
+ `).join('');
1953
+ html += '</div>';
1954
+ }
1955
+ }
1956
+
1957
+ // Marketplace
1958
+ if (tab === 'all' || tab === 'marketplace') {
1959
+ const installedNames = Object.keys(ENHANCED_PLUGINS);
1960
+ const marketplace = MARKETPLACE_DATA
1961
+ .filter(p => !installedNames.includes(p.name))
1962
+ .filter(p => p.name.includes(query) || p.description.toLowerCase().includes(query))
1963
+ .slice(0, 5);
1964
+
1965
+ if (marketplace.length) {
1966
+ html += `<div class="search-section"><div class="search-section-title">Marketplace (${marketplace.length})</div>`;
1967
+ html += marketplace.map(p => `
1968
+ <div class="search-item" onclick="closeSearch(); showMarketplaceDetail('${p.name}')">
1969
+ <div class="search-item-icon marketplace">📦</div>
1970
+ <div class="search-item-info">
1971
+ <div class="search-item-name">${highlight(p.name, query)} ${p.trending ? '<span class="badge badge-purple" style="margin-left: 4px;">🔥</span>' : ''}</div>
1972
+ <div class="search-item-desc">${highlight(p.description, query)}</div>
1973
+ </div>
1974
+ <div class="search-item-meta">${formatNumber(p.downloads)}</div>
1975
+ </div>
1976
+ `).join('');
1977
+ html += '</div>';
1978
+ }
1979
+ }
1980
+
1981
+ // Users
1982
+ if (tab === 'all' || tab === 'users') {
1983
+ const users = Object.entries(ENHANCED_USERS)
1984
+ .filter(([name, data]) => name.includes(query) || data.role.toLowerCase().includes(query))
1985
+ .slice(0, 5);
1986
+
1987
+ if (users.length) {
1988
+ html += `<div class="search-section"><div class="search-section-title">Users (${users.length})</div>`;
1989
+ html += users.map(([name, data]) => `
1990
+ <div class="search-item" onclick="closeSearch(); showUserDetail('${name}')">
1991
+ <div class="search-item-icon" style="background: rgba(168, 85, 247, 0.15);">${data.avatar}</div>
1992
+ <div class="search-item-info">
1993
+ <div class="search-item-name">${highlight(name, query)}</div>
1994
+ <div class="search-item-desc">${highlight(data.role, query)}</div>
1995
+ </div>
1996
+ <div class="search-item-meta">${data.sessions} sessions</div>
1997
+ </div>
1998
+ `).join('');
1999
+ html += '</div>';
2000
+ }
2001
+ }
2002
+
2003
+ document.getElementById('searchResults').innerHTML = html || `
2004
+ <div class="search-empty">
2005
+ <div class="search-empty-icon">🔍</div>
2006
+ <div>No results for "${query}"</div>
2007
+ </div>
2008
+ `;
2009
+ selectedSearchIndex = -1;
2010
+ }
2011
+
2012
+ document.querySelectorAll('.search-tab').forEach(tab => {
2013
+ tab.addEventListener('click', () => {
2014
+ document.querySelectorAll('.search-tab').forEach(t => t.classList.remove('active'));
2015
+ tab.classList.add('active');
2016
+ currentSearchTab = tab.dataset.searchTab;
2017
+ handleSearch();
2018
+ });
2019
+ });
2020
+
2021
+ function updateSearchSelection(items) {
2022
+ items.forEach((item, i) => {
2023
+ item.classList.toggle('selected', i === selectedSearchIndex);
2024
+ if (i === selectedSearchIndex) item.scrollIntoView({ block: 'nearest' });
2025
+ });
2026
+ }
2027
+
2028
+ function highlight(text, query) {
2029
+ if (!query) return text;
2030
+ return text.replace(new RegExp(`(${query})`, 'gi'), '<strong style="color: var(--accent-green);">$1</strong>');
2031
+ }
2032
+
2033
+ // ===========================================
2034
+ // SETTINGS
2035
+ // ===========================================
2036
+
2037
+ function openSettings() {
2038
+ document.getElementById('settingsOverlay').classList.add('active');
2039
+ }
2040
+
2041
+ function closeSettings(e) {
2042
+ if (!e || e.target.id === 'settingsOverlay') {
2043
+ document.getElementById('settingsOverlay').classList.remove('active');
2044
+ }
2045
+ }
2046
+
2047
+ function saveSettings() {
2048
+ closeSettings();
2049
+ showToast('Settings saved', '✅');
2050
+ }
2051
+
2052
+ function toggleTheme() {
2053
+ currentTheme = currentTheme === 'dark' ? 'light' : 'dark';
2054
+ document.body.setAttribute('data-theme', currentTheme);
2055
+ document.getElementById('darkModeToggle').classList.toggle('active', currentTheme === 'dark');
2056
+ showToast(`${currentTheme === 'dark' ? 'Dark' : 'Light'} mode enabled`, currentTheme === 'dark' ? '🌙' : '☀️');
2057
+ }
2058
+
2059
+ // ===========================================
2060
+ // ACTIONS
2061
+ // ===========================================
2062
+
2063
+ function runScout() { showToast('Run in terminal: /scout', '🔍'); }
2064
+ function runAudit() { showToast('Run in terminal: /scout audit', '🔍'); }
2065
+ function executeAction(action) { showToast(`Run: ${action}`, '💡'); }
2066
+
2067
+ function exportData() {
2068
+ const data = { plugins: ENHANCED_PLUGINS, users: ENHANCED_USERS, analytics: ANALYTICS_DATA };
2069
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
2070
+ const url = URL.createObjectURL(blob);
2071
+ const a = document.createElement('a');
2072
+ a.href = url;
2073
+ a.download = `plugin-scout-${new Date().toISOString().split('T')[0]}.json`;
2074
+ a.click();
2075
+ URL.revokeObjectURL(url);
2076
+ showToast('Data exported!', '📤');
2077
+ }
2078
+
2079
+ // ===========================================
2080
+ // UTILITIES
2081
+ // ===========================================
2082
+
2083
+ function formatNumber(n) {
2084
+ if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
2085
+ if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
2086
+ return n.toString();
2087
+ }
2088
+
2089
+ function showToast(message, icon = '✅') {
2090
+ const toast = document.getElementById('toast');
2091
+ document.getElementById('toastMessage').textContent = message;
2092
+ document.getElementById('toastIcon').textContent = icon;
2093
+ toast.classList.add('show');
2094
+ setTimeout(() => toast.classList.remove('show'), 3000);
2095
+ }
2096
+ </script>
2097
+ </body>
2098
+ </html>