@zshuangmu/agenthub 0.4.14 → 0.4.16

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 (43) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +268 -268
  3. package/package.json +41 -41
  4. package/src/api-server.js +518 -244
  5. package/src/cli.js +714 -671
  6. package/src/commands/api.js +9 -9
  7. package/src/commands/doctor.js +335 -335
  8. package/src/commands/info.js +15 -15
  9. package/src/commands/install.js +56 -56
  10. package/src/commands/list.js +78 -78
  11. package/src/commands/pack.js +249 -156
  12. package/src/commands/publish-remote.js +9 -9
  13. package/src/commands/publish.js +7 -7
  14. package/src/commands/rollback.js +59 -59
  15. package/src/commands/search.js +14 -14
  16. package/src/commands/serve.js +9 -9
  17. package/src/commands/stats.js +105 -105
  18. package/src/commands/uninstall.js +76 -76
  19. package/src/commands/update.js +54 -54
  20. package/src/commands/verify.js +133 -133
  21. package/src/commands/versions.js +75 -75
  22. package/src/commands/web.js +9 -9
  23. package/src/index.js +18 -18
  24. package/src/lib/auth.js +301 -0
  25. package/src/lib/bundle-transfer.js +58 -58
  26. package/src/lib/colors.js +60 -60
  27. package/src/lib/database.js +450 -244
  28. package/src/lib/debug.js +135 -135
  29. package/src/lib/fs-utils.js +107 -50
  30. package/src/lib/html.js +2163 -1824
  31. package/src/lib/http.js +168 -168
  32. package/src/lib/install.js +60 -60
  33. package/src/lib/manifest.js +124 -124
  34. package/src/lib/openclaw-config.js +40 -40
  35. package/src/lib/permissions.js +105 -0
  36. package/src/lib/privacy-engine.js +220 -0
  37. package/src/lib/registry.js +130 -130
  38. package/src/lib/remote.js +11 -11
  39. package/src/lib/security-scanner.js +233 -233
  40. package/src/lib/signing.js +158 -0
  41. package/src/lib/version-manager.js +77 -77
  42. package/src/server.js +176 -176
  43. package/src/web-server.js +135 -135
package/src/lib/html.js CHANGED
@@ -1,1824 +1,2163 @@
1
- // i18n translations
2
- const i18n = {
3
- en: {
4
- title: "AgentHub - AI Agent Open Source Community",
5
- navHome: "Home",
6
- navStats: "Stats",
7
- heroTitle: "AgentHub",
8
- heroSubtitle: "The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.",
9
- statAgents: "Available Agents",
10
- statDownloads: "Total Downloads",
11
- statOpenSource: "Open Source",
12
- feature1Title: "Ready to Use",
13
- feature1Desc: "Skip complex configurations, get battle-tested AI Agent setups",
14
- feature2Title: "Instant Deploy",
15
- feature2Desc: "One-click install, deploy in minutes, start working immediately",
16
- feature3Title: "Version Control",
17
- feature3Desc: "Auto-update pushes, always stay with the latest capabilities",
18
- apiBoxTitle: "AI Auto-Discovery API",
19
- apiBoxDesc: "Let your AI assistant automatically discover and install Agents",
20
- sectionHotAgents: "Hot Agents",
21
- sectionViewAll: "View All →",
22
- searchPlaceholder: "Search Agents, skills, tags...",
23
- searchButton: "Search",
24
- downloads: "downloads",
25
- install: "Install",
26
- howToUse: "How to Use",
27
- step1Title: "Browse & Discover",
28
- step1Desc: "Find the Agent that fits your workflow",
29
- step2Title: "One-Click Install",
30
- step2Desc: "Run the install command, deploy in minutes",
31
- step3Title: "Start Working",
32
- step3Desc: "Your AI assistant is ready, start delegating tasks",
33
- noAgents: "No Agents yet",
34
- noAgentsHint: "Use <code>agenthub pack</code> to package your first Agent!",
35
- // Detail page
36
- backToHome: "← Back to Home",
37
- detailVersion: "Version",
38
- detailRuntime: "Runtime",
39
- detailDownloads: "Downloads",
40
- detailAuthor: "Author",
41
- detailInstall: "Install Command",
42
- personaTitle: "🎭 Personality",
43
- personaTraits: "Traits",
44
- personaExpertise: "Expertise",
45
- memoryTitle: "🧠 Memory Config",
46
- memoryPublic: "Public",
47
- memoryPortable: "Portable",
48
- memoryPrivate: "Private",
49
- memoryNoData: "No memory data",
50
- skillsTitle: "🔧 Skills",
51
- tagsTitle: "🏷️ Tags",
52
- requirementsTitle: "⚙️ System Requirements",
53
- requirementsNone: "No special requirements",
54
- requirementsEnv: "🔐 Environment variables required:",
55
- requirementsModel: "🤖 Recommended model:",
56
- requirementsRuntime: "⚡ Runtime version:",
57
- installMethodTitle: "📥 Installation",
58
- installMethodDesc: "Run in your workspace:",
59
- // Stats page
60
- statsTitle: "Statistics Center - AgentHub",
61
- statsHeader: "📊 Statistics Center",
62
- statsDesc: "AgentHub download statistics and data analysis",
63
- statsTotalAgents: "Agent Count",
64
- statsTotalDownloads: "Total Downloads",
65
- statsTotalLogs: "Download Logs",
66
- rankingTitle: "🏆 Download Ranking",
67
- rankingAgent: "Agent",
68
- rankingDownloads: "Downloads",
69
- rankingLastDownload: "Last Download",
70
- rankingRank: "Rank",
71
- recentTitle: "📋 Recent Downloads",
72
- recentAgent: "Agent",
73
- recentTime: "Time",
74
- recentTarget: "Target Path",
75
- noData: "No data",
76
- // Tags
77
- tagOps: "ops",
78
- tagEngineering: "engineering",
79
- tagContent: "content",
80
- tagProduct: "product",
81
- tagDefault: "default",
82
- },
83
- zh: {
84
- title: "AgentHub - AI Agent 开源社区",
85
- navHome: "首页",
86
- navStats: "统计",
87
- heroTitle: "AgentHub",
88
- heroSubtitle: "AI Agent 的开源应用市场。一句话打包上传 Agent 的全部能力,一键下载获得这些功力。",
89
- statAgents: "可用 Agent",
90
- statDownloads: "累计下载",
91
- statOpenSource: "开源免费",
92
- feature1Title: "开箱即用",
93
- feature1Desc: "跳过繁琐的配置,获取经过实战验证的 AI Agent 配置",
94
- feature2Title: "即装即用",
95
- feature2Desc: "一键安装,几分钟内部署完成,立即开始工作",
96
- feature3Title: "版本管理",
97
- feature3Desc: "自动更新推送,始终保持最新能力",
98
- apiBoxTitle: "🤖 AI 自动发现 API",
99
- apiBoxDesc: "让你的 AI 助手自动发现并安装 Agent",
100
- sectionHotAgents: "热门 Agent",
101
- sectionViewAll: "查看全部 →",
102
- searchPlaceholder: "搜索 Agent、技能、标签...",
103
- searchButton: "搜索",
104
- downloads: "次下载",
105
- install: "安装",
106
- howToUse: "如何使用",
107
- step1Title: "浏览发现",
108
- step1Desc: "找到适合你工作流程的 Agent",
109
- step2Title: "一键安装",
110
- step2Desc: "运行安装命令,几分钟内部署完成",
111
- step3Title: "开始工作",
112
- step3Desc: "你的 AI 助手已就绪,立即开始委托任务",
113
- noAgents: "暂无 Agent",
114
- noAgentsHint: "使用 <code>agenthub pack</code> 打包你的第一个 Agent 吧!",
115
- // Detail page
116
- backToHome: "← 返回首页",
117
- detailVersion: "版本",
118
- detailRuntime: "运行时",
119
- detailDownloads: "下载次数",
120
- detailAuthor: "作者",
121
- detailInstall: "安装命令",
122
- personaTitle: "🎭 性格简介",
123
- personaTraits: "特质",
124
- personaExpertise: "专长",
125
- memoryTitle: "🧠 记忆配置",
126
- memoryPublic: "公开",
127
- memoryPortable: "可移植",
128
- memoryPrivate: "私有",
129
- memoryNoData: "暂无记忆数据",
130
- skillsTitle: "🔧 技能",
131
- tagsTitle: "🏷️ 标签",
132
- requirementsTitle: "⚙️ 系统要求",
133
- requirementsNone: "无特殊要求",
134
- requirementsEnv: "🔐 需要配置环境变量:",
135
- requirementsModel: "🤖 推荐模型:",
136
- requirementsRuntime: "⚡ 运行时版本:",
137
- installMethodTitle: "📥 安装方式",
138
- installMethodDesc: "在你的工作区运行:",
139
- // Stats page
140
- statsTitle: "统计中心 - AgentHub",
141
- statsHeader: "📊 统计中心",
142
- statsDesc: "AgentHub 下载统计与数据分析",
143
- statsTotalAgents: "Agent 数量",
144
- statsTotalDownloads: "累计下载",
145
- statsTotalLogs: "下载记录",
146
- rankingTitle: "🏆 下载排行榜",
147
- rankingAgent: "Agent",
148
- rankingDownloads: "下载次数",
149
- rankingLastDownload: "最后下载",
150
- rankingRank: "排名",
151
- recentTitle: "📋 最近下载",
152
- recentAgent: "Agent",
153
- recentTime: "时间",
154
- recentTarget: "目标路径",
155
- noData: "暂无数据",
156
- // Tags
157
- tagOps: "运维",
158
- tagEngineering: "工程",
159
- tagContent: "内容",
160
- tagProduct: "产品",
161
- tagDefault: "默认",
162
- }
163
- };
164
-
165
- // Language toggle script
166
- const langScript = `
167
- <script>
168
- (function() {
169
- const defaultLang = 'en';
170
- const savedLang = localStorage.getItem('agenthub-lang') || defaultLang;
171
-
172
- function setLang(lang) {
173
- localStorage.setItem('agenthub-lang', lang);
174
- document.querySelectorAll('[data-i18n]').forEach(el => {
175
- const key = el.getAttribute('data-i18n');
176
- if (window.i18n && window.i18n[lang] && window.i18n[lang][key]) {
177
- el.textContent = window.i18n[lang][key];
178
- }
179
- });
180
- document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
181
- const key = el.getAttribute('data-i18n-placeholder');
182
- if (window.i18n && window.i18n[lang] && window.i18n[lang][key]) {
183
- el.placeholder = window.i18n[lang][key];
184
- }
185
- });
186
- // Update active button
187
- document.querySelectorAll('.lang-btn').forEach(btn => {
188
- btn.classList.toggle('active', btn.dataset.lang === lang);
189
- });
190
- // Update html lang attribute
191
- document.documentElement.lang = lang === 'zh' ? 'zh-CN' : 'en';
192
- }
193
-
194
- // Theme toggle function
195
- function setTheme(theme) {
196
- localStorage.setItem('agenthub-theme', theme);
197
- document.documentElement.setAttribute('data-theme', theme);
198
- // Update theme button icon
199
- const themeBtn = document.querySelector('.theme-btn');
200
- if (themeBtn) {
201
- themeBtn.textContent = theme === 'dark' ? '☀️' : '🌙';
202
- themeBtn.setAttribute('aria-label', theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
203
- }
204
- }
205
-
206
- function toggleTheme() {
207
- const currentTheme = localStorage.getItem('agenthub-theme') || 'light';
208
- setTheme(currentTheme === 'dark' ? 'light' : 'dark');
209
- }
210
-
211
- window.setLang = setLang;
212
- window.toggleTheme = toggleTheme;
213
- window.i18n = ${JSON.stringify(i18n)};
214
-
215
- document.addEventListener('DOMContentLoaded', () => {
216
- setLang(savedLang);
217
- // Initialize theme (default to light)
218
- const savedTheme = localStorage.getItem('agenthub-theme') || 'light';
219
- setTheme(savedTheme);
220
-
221
- // Copy to clipboard with fallback
222
- async function copyText(text) {
223
- if (navigator.clipboard?.writeText) {
224
- return navigator.clipboard.writeText(text);
225
- }
226
- const ta = Object.assign(document.createElement('textarea'), { value: text, style: 'position:fixed;opacity:0' });
227
- document.body.appendChild(ta);
228
- ta.select();
229
- document.execCommand('copy');
230
- ta.remove();
231
- }
232
-
233
- // Initialize copy buttons
234
- document.querySelectorAll('.api-code, .detail-install').forEach(el => {
235
- el.addEventListener('click', () => {
236
- const text = el.querySelector('.code-text')?.textContent.trim() || el.textContent.trim();
237
- const btn = el.querySelector('.copy-btn');
238
-
239
- copyText(text).then(() => {
240
- if (!btn) return;
241
- btn.textContent = '';
242
- btn.classList.add('copied');
243
- setTimeout(() => { btn.textContent = '📋'; btn.classList.remove('copied'); }, 1500);
244
- }).catch(e => console.error('Copy failed:', e));
245
- });
246
- });
247
- });
248
- })();
249
- </script>
250
- `;
251
-
252
- function page(title, body, options = {}) {
253
- const {
254
- description = "AgentHub - The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.",
255
- url = "https://agenthub.cyou/",
256
- type = "website",
257
- image = "https://agenthub.cyou/og-image.png"
258
- } = options;
259
-
260
- return `<!doctype html>
261
- <html lang="en">
262
- <head>
263
- <meta charset="utf-8" />
264
- <meta name="viewport" content="width=device-width, initial-scale=1" />
265
- <title>${title}</title>
266
-
267
- <!-- SEO Meta -->
268
- <meta name="description" content="${description}">
269
- <meta name="keywords" content="AI Agent, AgentHub, OpenClaw, AI marketplace, agent packaging, artificial intelligence, open source">
270
- <meta name="author" content="AgentHub Team">
271
- <meta name="robots" content="index, follow">
272
- <link rel="canonical" href="${url}">
273
-
274
- <!-- Open Graph -->
275
- <meta property="og:type" content="${type}">
276
- <meta property="og:title" content="${title}">
277
- <meta property="og:description" content="${description}">
278
- <meta property="og:url" content="${url}">
279
- <meta property="og:image" content="${image}">
280
- <meta property="og:site_name" content="AgentHub">
281
- <meta property="og:locale" content="en_US">
282
- <meta property="og:locale:alternate" content="zh_CN">
283
-
284
- <!-- Twitter Card -->
285
- <meta name="twitter:card" content="summary_large_image">
286
- <meta name="twitter:title" content="${title}">
287
- <meta name="twitter:description" content="${description}">
288
- <meta name="twitter:image" content="${image}">
289
-
290
- <!-- JSON-LD Structured Data -->
291
- <script type="application/ld+json">
292
- {
293
- "@context": "https://schema.org",
294
- "@type": "WebSite",
295
- "name": "AgentHub",
296
- "url": "https://agenthub.cyou/",
297
- "description": "${description.replace(/"/g, '\\"')}",
298
- "potentialAction": {
299
- "@type": "SearchAction",
300
- "target": "https://agenthub.cyou/?q={search_term_string}",
301
- "query-input": "required name=search_term_string"
302
- }
303
- }
304
- </script>
305
-
306
- <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🦀</text></svg>">
307
- <link rel="preconnect" href="https://fonts.googleapis.com">
308
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
309
- <link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@500;600;700&family=Geist:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&display=swap" rel="stylesheet">
310
- <style>
311
- /* Light theme (default) - Vibrant Sunset palette */
312
- :root {
313
- --color-1: #fd63a3;
314
- --color-2: #fe9800;
315
- --color-3: #ffb74d;
316
- --font-display: 'Geist Mono', 'SF Mono', 'Fira Code', monospace;
317
- --font-body: 'Geist', 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
318
- --bg-primary: #fffbf7;
319
- --bg-secondary: #fff5ed;
320
- --bg-card: #ffffff;
321
- --bg-card-hover: #fff8f3;
322
- --bg-code: #fff9f5;
323
- --text-primary: #2d1810;
324
- --text-secondary: #6b4a3a;
325
- --text-muted: #a08070;
326
- --accent: #fa709a;
327
- --accent-light: #ff9a8b;
328
- --accent-dark: #e85a80;
329
- --accent-glow: rgba(250, 112, 154, 0.12);
330
- --border: #f0d8c8;
331
- --header-bg: rgba(255, 251, 247, 0.95);
332
- --tag-ops: #fa709a;
333
- --tag-engineering: #ff9a8b;
334
- --tag-content: #fee140;
335
- --tag-product: #f5a623;
336
- }
337
-
338
- /* Dark theme - Vibrant sunset tones */
339
- [data-theme="dark"] {
340
- --color-1: #fd63a3;
341
- --color-2: #fe9800;
342
- --color-3: #ffb74d;
343
- --bg-primary: #1a1215;
344
- --bg-secondary: #251a1d;
345
- --bg-card: #2a1f22;
346
- --bg-card-hover: #352528;
347
- --bg-code: #251a1d;
348
- --text-primary: #fff5f0;
349
- --text-secondary: #d4b8a8;
350
- --text-muted: #8a7060;
351
- --accent: #ff9a8b;
352
- --accent-light: #ffb8a8;
353
- --accent-dark: #fa709a;
354
- --accent-glow: rgba(255, 154, 139, 0.15);
355
- --border: #3d2a28;
356
- --header-bg: rgba(26, 18, 21, 0.95);
357
- }
358
- * { box-sizing: border-box; margin: 0; padding: 0; }
359
- body {
360
- font-family: var(--font-body);
361
- background: var(--bg-primary);
362
- color: var(--text-primary);
363
- line-height: 1.6;
364
- min-height: 100vh;
365
- -webkit-font-smoothing: antialiased;
366
- -moz-osx-font-smoothing: grayscale;
367
- }
368
-
369
- /* Subtle background texture */
370
- body::before {
371
- content: '';
372
- position: fixed;
373
- inset: 0;
374
- background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.02'/%3E%3C/svg%3E");
375
- pointer-events: none;
376
- z-index: -1;
377
- }
378
-
379
- /* Animations */
380
- @keyframes fadeInUp {
381
- from { opacity: 0; transform: translateY(16px); }
382
- to { opacity: 1; transform: translateY(0); }
383
- }
384
- @keyframes fadeIn {
385
- from { opacity: 0; }
386
- to { opacity: 1; }
387
- }
388
- a { color: inherit; text-decoration: none; }
389
- .container {
390
- max-width: 1200px;
391
- margin: 0 auto;
392
- padding: 0 24px;
393
- }
394
-
395
- /* Header - ClawHub inspired minimal style */
396
- header {
397
- border-bottom: 1px solid var(--border);
398
- padding: 20px 0;
399
- position: sticky;
400
- top: 0;
401
- background: var(--header-bg);
402
- backdrop-filter: blur(16px);
403
- -webkit-backdrop-filter: blur(16px);
404
- z-index: 100;
405
- animation: fadeIn 0.5s ease-out;
406
- }
407
- .header-content {
408
- display: flex;
409
- align-items: center;
410
- justify-content: space-between;
411
- }
412
- .logo {
413
- display: flex;
414
- align-items: center;
415
- gap: 12px;
416
- font-family: var(--font-display);
417
- font-size: 20px;
418
- font-weight: 600;
419
- letter-spacing: -0.02em;
420
- transition: all 0.3s ease;
421
- }
422
- .logo:hover {
423
- transform: translateX(2px);
424
- }
425
- .logo-icon {
426
- font-size: 28px;
427
- filter: drop-shadow(0 2px 4px rgba(250, 112, 154, 0.3));
428
- transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
429
- }
430
- .logo:hover .logo-icon {
431
- transform: rotate(-10deg) scale(1.1);
432
- }
433
- .logo-tagline {
434
- font-size: 11px;
435
- font-weight: 500;
436
- color: var(--text-muted);
437
- font-family: var(--font-body);
438
- letter-spacing: 0.02em;
439
- margin-top: 2px;
440
- }
441
- .nav-links {
442
- display: flex;
443
- align-items: center;
444
- gap: 28px;
445
- }
446
- .nav-links a {
447
- color: var(--text-secondary);
448
- font-weight: 500;
449
- font-size: 14px;
450
- transition: color 0.2s;
451
- position: relative;
452
- }
453
- .nav-links a::after {
454
- content: '';
455
- position: absolute;
456
- bottom: -4px;
457
- left: 0;
458
- width: 0;
459
- height: 2px;
460
- background: linear-gradient(90deg, var(--color-1), var(--color-3));
461
- transition: width 0.25s ease;
462
- border-radius: 1px;
463
- }
464
- .nav-links a:hover {
465
- color: var(--text-primary);
466
- }
467
- .nav-links a:hover::after {
468
- width: 100%;
469
- }
470
- .nav-powered {
471
- display: flex;
472
- align-items: center;
473
- gap: 6px;
474
- padding: 8px 14px;
475
- background: var(--bg-secondary);
476
- border-radius: 8px;
477
- font-size: 12px;
478
- color: var(--text-muted);
479
- font-family: var(--font-display);
480
- }
481
- .nav-powered a {
482
- color: var(--color-1);
483
- font-weight: 600;
484
- }
485
- .nav-powered a::after {
486
- display: none;
487
- }
488
-
489
- /* Language Switcher - Coral themed */
490
- .lang-switcher {
491
- display: flex;
492
- background: var(--bg-secondary);
493
- border-radius: 8px;
494
- padding: 3px;
495
- gap: 2px;
496
- }
497
- .lang-btn {
498
- padding: 6px 12px;
499
- border: none;
500
- background: transparent;
501
- color: var(--text-muted);
502
- border-radius: 6px;
503
- cursor: pointer;
504
- font-size: 12px;
505
- font-weight: 600;
506
- font-family: var(--font-display);
507
- transition: all 0.2s;
508
- }
509
- .lang-btn:hover {
510
- color: var(--text-primary);
511
- }
512
- .lang-btn.active {
513
- background: linear-gradient(135deg, var(--color-1), var(--color-3));
514
- color: #ffffff;
515
- }
516
-
517
- /* Theme Switcher - Coral themed */
518
- .theme-btn {
519
- background: var(--bg-secondary);
520
- border: none;
521
- width: 36px;
522
- height: 36px;
523
- border-radius: 8px;
524
- cursor: pointer;
525
- font-size: 16px;
526
- display: flex;
527
- align-items: center;
528
- justify-content: center;
529
- transition: all 0.25s;
530
- margin-left: 6px;
531
- }
532
- .theme-btn:hover {
533
- background: var(--bg-card-hover);
534
- transform: scale(1.05);
535
- }
536
- .theme-btn:active {
537
- transform: scale(0.95);
538
- }
539
-
540
- /* Hero - Sunset gradient style */
541
- .hero {
542
- text-align: center;
543
- padding: 72px 20px 56px;
544
- position: relative;
545
- }
546
- .hero::before {
547
- content: '';
548
- position: absolute;
549
- top: -20px;
550
- left: 50%;
551
- transform: translateX(-50%);
552
- width: 800px;
553
- height: 500px;
554
- background: radial-gradient(ellipse at center, rgba(250, 112, 154, 0.08) 0%, rgba(254, 225, 64, 0.05) 40%, transparent 70%);
555
- pointer-events: none;
556
- z-index: -1;
557
- }
558
- .hero h1 {
559
- font-family: var(--font-display);
560
- font-size: clamp(40px, 8vw, 64px);
561
- font-weight: 700;
562
- margin-bottom: 16px;
563
- letter-spacing: -0.03em;
564
- background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 50%, var(--color-2) 100%);
565
- -webkit-background-clip: text;
566
- -webkit-text-fill-color: transparent;
567
- background-clip: text;
568
- animation: fadeInUp 0.6s ease-out;
569
- }
570
- .hero-subtitle {
571
- font-size: 17px;
572
- color: var(--text-secondary);
573
- max-width: 560px;
574
- margin: 0 auto 44px;
575
- line-height: 1.75;
576
- animation: fadeInUp 0.6s ease-out 0.1s backwards;
577
- }
578
- .hero-stats {
579
- display: flex;
580
- justify-content: center;
581
- gap: 56px;
582
- margin-bottom: 44px;
583
- animation: fadeInUp 0.6s ease-out 0.2s backwards;
584
- }
585
- .hero-stat {
586
- text-align: center;
587
- }
588
- .hero-stat-value {
589
- font-family: var(--font-display);
590
- font-size: 36px;
591
- font-weight: 700;
592
- background: linear-gradient(135deg, var(--color-1), var(--color-3));
593
- -webkit-background-clip: text;
594
- -webkit-text-fill-color: transparent;
595
- background-clip: text;
596
- letter-spacing: -0.02em;
597
- }
598
- .hero-stat-label {
599
- font-size: 11px;
600
- color: var(--text-muted);
601
- text-transform: uppercase;
602
- letter-spacing: 0.1em;
603
- font-weight: 600;
604
- margin-top: 4px;
605
- }
606
-
607
- /* Features - Warm coral accents */
608
- .features {
609
- display: grid;
610
- grid-template-columns: repeat(3, 1fr);
611
- gap: 16px;
612
- margin-bottom: 56px;
613
- }
614
- .feature-card {
615
- background: var(--bg-card);
616
- border: 1px solid var(--border);
617
- border-radius: 16px;
618
- padding: 28px 24px;
619
- text-align: center;
620
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
621
- position: relative;
622
- overflow: hidden;
623
- }
624
- .feature-card::before {
625
- content: '';
626
- position: absolute;
627
- top: 0;
628
- left: 0;
629
- right: 0;
630
- height: 3px;
631
- background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
632
- opacity: 0;
633
- transition: opacity 0.3s;
634
- }
635
- .feature-card:hover {
636
- border-color: var(--color-1);
637
- transform: translateY(-4px);
638
- box-shadow: 0 12px 32px rgba(250, 112, 154, 0.12);
639
- }
640
- .feature-card:hover::before {
641
- opacity: 1;
642
- }
643
- .feature-icon {
644
- font-size: 32px;
645
- margin-bottom: 14px;
646
- display: block;
647
- }
648
- .feature-title {
649
- font-family: var(--font-display);
650
- font-size: 14px;
651
- font-weight: 600;
652
- margin-bottom: 8px;
653
- letter-spacing: -0.01em;
654
- color: var(--text-primary);
655
- }
656
- .feature-desc {
657
- font-size: 13px;
658
- color: var(--text-secondary);
659
- line-height: 1.6;
660
- }
661
-
662
- /* Section - Coral themed */
663
- .section {
664
- margin-bottom: 56px;
665
- }
666
- .section-header {
667
- display: flex;
668
- align-items: center;
669
- justify-content: space-between;
670
- margin-bottom: 22px;
671
- }
672
- .section-title {
673
- font-family: var(--font-display);
674
- font-size: 20px;
675
- font-weight: 700;
676
- letter-spacing: -0.02em;
677
- }
678
- .section-link {
679
- color: var(--color-1);
680
- font-weight: 600;
681
- font-size: 14px;
682
- display: flex;
683
- align-items: center;
684
- gap: 6px;
685
- transition: all 0.25s;
686
- }
687
- .section-link:hover {
688
- gap: 10px;
689
- color: var(--color-3);
690
- }
691
-
692
- /* Agent Grid - Coral themed */
693
- .agent-grid {
694
- display: grid;
695
- grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
696
- gap: 18px;
697
- }
698
- .agent-card {
699
- background: var(--bg-card);
700
- border: 1px solid var(--border);
701
- border-radius: 16px;
702
- padding: 22px;
703
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
704
- cursor: pointer;
705
- animation: fadeInUp 0.5s ease-out backwards;
706
- position: relative;
707
- }
708
- .agent-card:nth-child(1) { animation-delay: 0.05s; }
709
- .agent-card:nth-child(2) { animation-delay: 0.1s; }
710
- .agent-card:nth-child(3) { animation-delay: 0.15s; }
711
- .agent-card:nth-child(4) { animation-delay: 0.2s; }
712
- .agent-card:nth-child(5) { animation-delay: 0.25s; }
713
- .agent-card:nth-child(6) { animation-delay: 0.3s; }
714
- .agent-card:nth-child(7) { animation-delay: 0.35s; }
715
- .agent-card:nth-child(8) { animation-delay: 0.4s; }
716
- .agent-card:hover {
717
- background: var(--bg-card-hover);
718
- border-color: var(--color-1);
719
- transform: translateY(-4px);
720
- box-shadow: 0 16px 40px rgba(250, 112, 154, 0.15);
721
- }
722
- .agent-card-featured {
723
- border-color: var(--color-1);
724
- background: linear-gradient(135deg, rgba(250, 112, 154, 0.03), rgba(255, 154, 139, 0.03));
725
- }
726
- .agent-card-featured:hover {
727
- box-shadow: 0 16px 40px rgba(250, 112, 154, 0.25);
728
- }
729
- .featured-badge {
730
- position: absolute;
731
- top: -8px;
732
- right: 12px;
733
- background: linear-gradient(135deg, var(--color-1), var(--color-3));
734
- color: white;
735
- padding: 4px 12px;
736
- border-radius: 12px;
737
- font-size: 12px;
738
- font-weight: 600;
739
- box-shadow: 0 4px 12px rgba(250, 112, 154, 0.3);
740
- }
741
- .agent-header {
742
- display: flex;
743
- align-items: flex-start;
744
- justify-content: space-between;
745
- margin-bottom: 12px;
746
- }
747
- .agent-name {
748
- font-family: var(--font-display);
749
- font-size: 16px;
750
- font-weight: 600;
751
- letter-spacing: -0.01em;
752
- transition: color 0.2s;
753
- }
754
- .agent-card:hover .agent-name {
755
- background: linear-gradient(135deg, var(--color-1), var(--color-3));
756
- -webkit-background-clip: text;
757
- -webkit-text-fill-color: transparent;
758
- background-clip: text;
759
- }
760
- .agent-version {
761
- background: linear-gradient(135deg, rgba(250, 112, 154, 0.12), rgba(255, 154, 139, 0.12));
762
- padding: 4px 10px;
763
- border-radius: 6px;
764
- font-size: 11px;
765
- font-family: var(--font-display);
766
- color: var(--color-1);
767
- font-weight: 600;
768
- }
769
- .agent-desc {
770
- color: var(--text-secondary);
771
- font-size: 14px;
772
- margin-bottom: 14px;
773
- line-height: 1.6;
774
- display: -webkit-box;
775
- -webkit-line-clamp: 2;
776
- -webkit-box-orient: vertical;
777
- overflow: hidden;
778
- }
779
- .agent-meta {
780
- display: flex;
781
- flex-wrap: wrap;
782
- gap: 6px;
783
- margin-bottom: 16px;
784
- }
785
- .agent-tag {
786
- padding: 4px 10px;
787
- border-radius: 6px;
788
- font-size: 11px;
789
- font-weight: 600;
790
- font-family: var(--font-display);
791
- }
792
- .tag-ops { background: rgba(250, 112, 154, 0.12); color: var(--color-1); }
793
- .tag-engineering { background: rgba(255, 154, 139, 0.12); color: var(--color-3); }
794
- .tag-content { background: rgba(254, 225, 64, 0.15); color: #c9a800; }
795
- .tag-product { background: rgba(245, 166, 35, 0.12); color: #e09000; }
796
- .tag-default { background: var(--bg-secondary); color: var(--text-muted); }
797
- .agent-footer {
798
- display: flex;
799
- align-items: center;
800
- justify-content: space-between;
801
- padding-top: 16px;
802
- border-top: 1px solid var(--border);
803
- }
804
- .agent-downloads {
805
- display: flex;
806
- align-items: center;
807
- gap: 6px;
808
- color: var(--text-muted);
809
- font-size: 13px;
810
- }
811
- .agent-install {
812
- background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 100%);
813
- color: #ffffff;
814
- padding: 8px 18px;
815
- border-radius: 8px;
816
- font-size: 12px;
817
- font-family: var(--font-display);
818
- font-weight: 600;
819
- transition: all 0.25s;
820
- box-shadow: 0 4px 12px rgba(250, 112, 154, 0.25);
821
- }
822
- .agent-install:hover {
823
- transform: translateY(-2px);
824
- box-shadow: 0 6px 20px rgba(250, 112, 154, 0.35);
825
- }
826
- .agent-install:active {
827
- transform: translateY(0);
828
- }
829
-
830
- /* API Box - Sunset gradient accent */
831
- .api-box {
832
- background: var(--bg-card);
833
- border: 1px solid var(--border);
834
- border-radius: 16px;
835
- padding: 32px;
836
- margin-bottom: 56px;
837
- position: relative;
838
- overflow: hidden;
839
- }
840
- .api-box::before {
841
- content: '';
842
- position: absolute;
843
- top: 0;
844
- left: 0;
845
- right: 0;
846
- height: 3px;
847
- background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
848
- }
849
- .api-box h3 {
850
- font-family: var(--font-display);
851
- font-size: 16px;
852
- margin-bottom: 8px;
853
- letter-spacing: -0.01em;
854
- }
855
- .api-box p {
856
- color: var(--text-secondary);
857
- margin-bottom: 20px;
858
- font-size: 14px;
859
- }
860
- .api-code {
861
- background: var(--bg-code);
862
- border: 1px solid var(--border);
863
- border-radius: 10px;
864
- padding: 16px 20px;
865
- font-family: var(--font-display);
866
- font-size: 13px;
867
- color: var(--color-1);
868
- overflow-x: auto;
869
- position: relative;
870
- cursor: pointer;
871
- display: flex;
872
- align-items: center;
873
- justify-content: space-between;
874
- gap: 12px;
875
- transition: all 0.25s;
876
- }
877
- .api-code:hover {
878
- border-color: var(--color-1);
879
- background: var(--bg-secondary);
880
- }
881
- .api-code .code-text {
882
- flex: 1;
883
- display: flex;
884
- align-items: center;
885
- gap: 10px;
886
- }
887
- .api-code .code-text::before {
888
- content: '$';
889
- color: var(--text-muted);
890
- flex-shrink: 0;
891
- }
892
- .api-code .copy-btn {
893
- background: transparent;
894
- border: 1px solid var(--border);
895
- border-radius: 6px;
896
- padding: 6px 10px;
897
- font-size: 12px;
898
- color: var(--text-muted);
899
- cursor: pointer;
900
- transition: all 0.2s;
901
- flex-shrink: 0;
902
- }
903
- .api-code .copy-btn:hover {
904
- background: var(--color-1);
905
- color: white;
906
- border-color: var(--color-1);
907
- }
908
- .api-code .copy-btn.copied {
909
- background: var(--color-2);
910
- border-color: var(--color-2);
911
- color: #2d1810;
912
- }
913
-
914
- /* Detail Page - Coral themed */
915
- .detail-header {
916
- background: var(--bg-card);
917
- border: 1px solid var(--border);
918
- border-radius: 20px;
919
- padding: 36px;
920
- margin-bottom: 24px;
921
- position: relative;
922
- overflow: hidden;
923
- }
924
- .detail-header::before {
925
- content: '';
926
- position: absolute;
927
- top: 0;
928
- left: 0;
929
- right: 0;
930
- height: 4px;
931
- background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
932
- }
933
- .detail-title {
934
- font-family: var(--font-display);
935
- font-size: 32px;
936
- font-weight: 700;
937
- margin-bottom: 10px;
938
- letter-spacing: -0.02em;
939
- background: linear-gradient(135deg, var(--color-1), var(--color-3));
940
- -webkit-background-clip: text;
941
- -webkit-text-fill-color: transparent;
942
- background-clip: text;
943
- }
944
- .detail-desc {
945
- font-size: 16px;
946
- color: var(--text-secondary);
947
- margin-bottom: 24px;
948
- line-height: 1.7;
949
- }
950
- .detail-grid {
951
- display: grid;
952
- grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
953
- gap: 14px;
954
- margin-bottom: 24px;
955
- }
956
- .detail-item {
957
- background: var(--bg-secondary);
958
- padding: 18px;
959
- border-radius: 12px;
960
- border: 1px solid transparent;
961
- transition: border-color 0.2s;
962
- }
963
- .detail-item:hover {
964
- border-color: var(--border);
965
- }
966
- .detail-label {
967
- font-size: 11px;
968
- color: var(--text-muted);
969
- text-transform: uppercase;
970
- letter-spacing: 0.08em;
971
- margin-bottom: 8px;
972
- font-weight: 600;
973
- }
974
- .detail-value {
975
- font-family: var(--font-display);
976
- font-size: 18px;
977
- font-weight: 600;
978
- letter-spacing: -0.01em;
979
- }
980
- .detail-install {
981
- background: var(--bg-code);
982
- border: 1px solid var(--border);
983
- color: var(--color-1);
984
- padding: 16px 20px;
985
- border-radius: 12px;
986
- font-family: var(--font-display);
987
- font-size: 14px;
988
- display: flex;
989
- align-items: center;
990
- gap: 12px;
991
- cursor: pointer;
992
- transition: all 0.25s;
993
- }
994
- .detail-install:hover {
995
- border-color: var(--color-1);
996
- background: var(--bg-secondary);
997
- }
998
- .detail-install .code-text {
999
- flex: 1;
1000
- display: flex;
1001
- align-items: center;
1002
- gap: 10px;
1003
- }
1004
- .detail-install .code-text::before {
1005
- content: "$";
1006
- color: var(--text-muted);
1007
- font-weight: bold;
1008
- }
1009
- .detail-install .copy-btn {
1010
- background: transparent;
1011
- border: 1px solid var(--border);
1012
- border-radius: 6px;
1013
- padding: 6px 12px;
1014
- font-size: 12px;
1015
- color: var(--text-muted);
1016
- cursor: pointer;
1017
- transition: all 0.2s;
1018
- flex-shrink: 0;
1019
- }
1020
- .detail-install .copy-btn:hover {
1021
- background: var(--color-1);
1022
- color: white;
1023
- border-color: var(--color-1);
1024
- }
1025
- .detail-install .copy-btn.copied {
1026
- background: var(--color-2);
1027
- border-color: var(--color-2);
1028
- color: #2d1810;
1029
- }
1030
- .install-label {
1031
- font-size: 11px;
1032
- color: var(--text-muted);
1033
- text-transform: uppercase;
1034
- letter-spacing: 0.08em;
1035
- margin-bottom: 10px;
1036
- font-weight: 600;
1037
- }
1038
- .install-methods {
1039
- display: flex;
1040
- flex-direction: column;
1041
- gap: 14px;
1042
- }
1043
- .install-box {
1044
- position: relative;
1045
- }
1046
- .install-box.primary .detail-install {
1047
- border-color: var(--color-1);
1048
- background: linear-gradient(135deg, rgba(250, 112, 154, 0.06), transparent);
1049
- }
1050
- .install-box .badge-new {
1051
- position: absolute;
1052
- top: -8px;
1053
- right: -8px;
1054
- background: linear-gradient(135deg, var(--color-1), var(--color-3));
1055
- color: white;
1056
- font-size: 10px;
1057
- padding: 3px 8px;
1058
- border-radius: 6px;
1059
- font-weight: 600;
1060
- }
1061
-
1062
- .section-card {
1063
- background: var(--bg-card);
1064
- border: 1px solid var(--border);
1065
- border-radius: 16px;
1066
- padding: 26px;
1067
- margin-bottom: 20px;
1068
- transition: border-color 0.25s;
1069
- }
1070
- .section-card:hover {
1071
- border-color: var(--border);
1072
- }
1073
- .section-card h3 {
1074
- font-family: var(--font-display);
1075
- font-size: 15px;
1076
- font-weight: 600;
1077
- margin-bottom: 16px;
1078
- display: flex;
1079
- align-items: center;
1080
- gap: 10px;
1081
- letter-spacing: -0.01em;
1082
- }
1083
- .back-link {
1084
- display: inline-flex;
1085
- align-items: center;
1086
- gap: 8px;
1087
- color: var(--text-secondary);
1088
- margin-bottom: 24px;
1089
- font-size: 14px;
1090
- transition: all 0.25s;
1091
- }
1092
- .back-link:hover {
1093
- color: var(--color-1);
1094
- gap: 12px;
1095
- }
1096
-
1097
- /* Memory bars - Coral themed */
1098
- .memory-bars {
1099
- display: flex;
1100
- gap: 3px;
1101
- height: 8px;
1102
- border-radius: 4px;
1103
- overflow: hidden;
1104
- margin-bottom: 12px;
1105
- }
1106
- .memory-bar { height: 100%; }
1107
- .memory-bar.public { background: var(--color-1); }
1108
- .memory-bar.portable { background: var(--color-3); }
1109
- .memory-bar.private { background: var(--color-2); }
1110
- .memory-legend {
1111
- display: flex;
1112
- gap: 20px;
1113
- font-size: 12px;
1114
- color: var(--text-secondary);
1115
- }
1116
- .memory-legend span {
1117
- display: flex;
1118
- align-items: center;
1119
- gap: 6px;
1120
- }
1121
- .memory-legend .dot {
1122
- width: 10px;
1123
- height: 10px;
1124
- border-radius: 50%;
1125
- }
1126
-
1127
- /* Skills & Tags - Coral themed */
1128
- .skills-list, .tags-list {
1129
- display: flex;
1130
- flex-wrap: wrap;
1131
- gap: 8px;
1132
- }
1133
- .badge {
1134
- padding: 6px 12px;
1135
- border-radius: 8px;
1136
- font-size: 12px;
1137
- font-family: var(--font-display);
1138
- font-weight: 600;
1139
- }
1140
- .badge-skill { background: rgba(250, 112, 154, 0.12); color: var(--color-1); }
1141
- .badge-tag { background: rgba(254, 225, 64, 0.15); color: #b89800; }
1142
-
1143
- /* Requirements - Coral themed */
1144
- .requirements-list {
1145
- list-style: none;
1146
- }
1147
- .requirements-list li {
1148
- padding: 12px 0;
1149
- border-bottom: 1px solid var(--border);
1150
- display: flex;
1151
- align-items: center;
1152
- gap: 10px;
1153
- font-size: 14px;
1154
- }
1155
- .requirements-list li:last-child {
1156
- border-bottom: none;
1157
- }
1158
- .env-var {
1159
- font-family: var(--font-display);
1160
- background: linear-gradient(135deg, rgba(250, 112, 154, 0.1), rgba(255, 154, 139, 0.1));
1161
- padding: 4px 10px;
1162
- border-radius: 6px;
1163
- color: var(--color-1);
1164
- font-size: 12px;
1165
- font-weight: 500;
1166
- }
1167
-
1168
- /* Stats Page - Coral themed */
1169
- .stats-table {
1170
- width: 100%;
1171
- border-collapse: collapse;
1172
- font-size: 14px;
1173
- }
1174
- .stats-table th, .stats-table td {
1175
- padding: 16px 14px;
1176
- text-align: left;
1177
- border-bottom: 1px solid var(--border);
1178
- }
1179
- .stats-table th {
1180
- font-family: var(--font-display);
1181
- color: var(--text-muted);
1182
- font-weight: 600;
1183
- font-size: 11px;
1184
- text-transform: uppercase;
1185
- letter-spacing: 0.08em;
1186
- }
1187
- .stats-table a {
1188
- color: var(--color-1);
1189
- font-family: var(--font-display);
1190
- font-weight: 500;
1191
- }
1192
- .stats-table a:hover {
1193
- text-decoration: underline;
1194
- }
1195
-
1196
- /* How it works - Coral themed */
1197
- .how-it-works {
1198
- display: grid;
1199
- grid-template-columns: repeat(3, 1fr);
1200
- gap: 24px;
1201
- margin-bottom: 56px;
1202
- }
1203
- .step {
1204
- text-align: center;
1205
- }
1206
- .step-number {
1207
- width: 48px;
1208
- height: 48px;
1209
- background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 100%);
1210
- color: #ffffff;
1211
- border-radius: 14px;
1212
- display: flex;
1213
- align-items: center;
1214
- justify-content: center;
1215
- font-family: var(--font-display);
1216
- font-size: 18px;
1217
- font-weight: 700;
1218
- margin: 0 auto 16px;
1219
- box-shadow: 0 8px 24px rgba(250, 112, 154, 0.25);
1220
- }
1221
- .step h4 {
1222
- font-family: var(--font-display);
1223
- font-size: 15px;
1224
- margin-bottom: 8px;
1225
- letter-spacing: -0.01em;
1226
- }
1227
- .step p {
1228
- color: var(--text-secondary);
1229
- font-size: 13px;
1230
- line-height: 1.6;
1231
- }
1232
-
1233
- /* Search - Coral themed */
1234
- .search-box {
1235
- display: flex;
1236
- background: var(--bg-card);
1237
- border: 2px solid var(--border);
1238
- border-radius: 14px;
1239
- padding: 6px;
1240
- max-width: 520px;
1241
- margin: 0 auto 36px;
1242
- transition: all 0.3s ease;
1243
- }
1244
- .search-box:focus-within {
1245
- border-color: var(--color-1);
1246
- box-shadow: 0 0 0 4px rgba(250, 112, 154, 0.1);
1247
- }
1248
- .search-box input {
1249
- flex: 1;
1250
- background: transparent;
1251
- border: none;
1252
- padding: 12px 16px;
1253
- font-size: 15px;
1254
- font-family: var(--font-body);
1255
- color: var(--text-primary);
1256
- outline: none;
1257
- }
1258
- .search-box input::placeholder {
1259
- color: var(--text-muted);
1260
- }
1261
- .search-box button {
1262
- background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 100%);
1263
- color: #ffffff;
1264
- border: none;
1265
- padding: 12px 24px;
1266
- border-radius: 10px;
1267
- font-family: var(--font-display);
1268
- font-size: 13px;
1269
- font-weight: 600;
1270
- cursor: pointer;
1271
- transition: all 0.25s;
1272
- }
1273
- .search-box button:hover {
1274
- box-shadow: 0 4px 16px rgba(250, 112, 154, 0.3);
1275
- }
1276
- .search-box button:active {
1277
- transform: scale(0.97);
1278
- }
1279
-
1280
- /* Empty state - Coral themed */
1281
- .empty-state {
1282
- text-align: center;
1283
- padding: 56px 20px;
1284
- color: var(--text-muted);
1285
- }
1286
- .empty-state h3 {
1287
- font-family: var(--font-display);
1288
- font-size: 18px;
1289
- margin-bottom: 8px;
1290
- color: var(--text-primary);
1291
- }
1292
- .empty-state p {
1293
- font-size: 14px;
1294
- }
1295
- .empty-state code {
1296
- background: var(--bg-secondary);
1297
- padding: 4px 10px;
1298
- border-radius: 6px;
1299
- font-family: var(--font-display);
1300
- font-size: 13px;
1301
- color: var(--color-1);
1302
- }
1303
-
1304
- /* Footer - Coral themed */
1305
- footer {
1306
- border-top: 1px solid var(--border);
1307
- padding: 36px 0;
1308
- margin-top: 64px;
1309
- background: var(--bg-secondary);
1310
- }
1311
- .footer-content {
1312
- display: flex;
1313
- justify-content: space-between;
1314
- align-items: center;
1315
- flex-wrap: wrap;
1316
- gap: 20px;
1317
- }
1318
- .footer-brand {
1319
- display: flex;
1320
- align-items: center;
1321
- gap: 12px;
1322
- }
1323
- .footer-brand-icon {
1324
- width: 32px;
1325
- height: 32px;
1326
- display: flex;
1327
- align-items: center;
1328
- justify-content: center;
1329
- font-size: 22px;
1330
- }
1331
- .footer-brand-text {
1332
- font-family: var(--font-display);
1333
- font-weight: 600;
1334
- font-size: 16px;
1335
- color: var(--text-primary);
1336
- }
1337
- .footer-powered {
1338
- display: flex;
1339
- align-items: center;
1340
- gap: 8px;
1341
- font-size: 13px;
1342
- color: var(--text-muted);
1343
- }
1344
- .footer-powered a {
1345
- color: var(--color-1);
1346
- font-weight: 600;
1347
- }
1348
- .footer-links {
1349
- display: flex;
1350
- gap: 24px;
1351
- }
1352
- .footer-links a {
1353
- color: var(--text-secondary);
1354
- font-size: 13px;
1355
- font-family: var(--font-display);
1356
- font-weight: 500;
1357
- transition: color 0.2s;
1358
- }
1359
- .footer-links a:hover {
1360
- color: var(--color-1);
1361
- }
1362
-
1363
- @media (max-width: 768px) {
1364
- .hero { padding: 48px 16px 40px; }
1365
- .hero h1 { font-size: clamp(32px, 7vw, 44px); }
1366
- .hero-subtitle { font-size: 15px; padding: 0 12px; }
1367
- .hero-stats { gap: 32px; flex-wrap: wrap; }
1368
- .hero-stat-value { font-size: 30px; }
1369
- .features { grid-template-columns: 1fr; gap: 14px; }
1370
- .how-it-works { grid-template-columns: 1fr; gap: 24px; }
1371
- .detail-grid { grid-template-columns: repeat(2, 1fr); }
1372
- .agent-grid { grid-template-columns: 1fr; }
1373
- .footer-content { flex-direction: column; text-align: center; gap: 20px; }
1374
-
1375
- /* Mobile navigation */
1376
- .header-content { flex-wrap: wrap; gap: 12px; }
1377
- .nav-links {
1378
- order: 3;
1379
- width: 100%;
1380
- justify-content: center;
1381
- gap: 16px;
1382
- flex-wrap: wrap;
1383
- }
1384
- .nav-links a { font-size: 13px; }
1385
- .nav-powered { display: none; }
1386
- .logo { font-size: 18px; }
1387
- .logo-icon { font-size: 24px; }
1388
- .logo-tagline { font-size: 10px; }
1389
- .container { padding: 0 16px; }
1390
- .detail-header { padding: 24px; }
1391
- .detail-title { font-size: 26px; }
1392
- .section-card { padding: 20px; }
1393
- .search-box { margin: 0 0 28px; }
1394
- .api-box { padding: 24px; }
1395
- .api-code { font-size: 12px; padding: 14px 16px; }
1396
- .stats-table th, .stats-table td { padding: 12px 10px; font-size: 13px; }
1397
- .step-number { width: 42px; height: 42px; font-size: 16px; }
1398
- .step h4 { font-size: 14px; }
1399
- }
1400
-
1401
- @media (max-width: 480px) {
1402
- .theme-btn { width: 32px; height: 32px; font-size: 14px; }
1403
- .hero-stat-value { font-size: 26px; }
1404
- .hero-stat-label { font-size: 10px; }
1405
- .nav-links { gap: 12px; }
1406
- .nav-links a { font-size: 12px; }
1407
- .section-title { font-size: 18px; }
1408
- .feature-card { padding: 22px 18px; }
1409
- .feature-icon { font-size: 28px; }
1410
- .detail-grid { grid-template-columns: 1fr; }
1411
- }
1412
- </style>
1413
- </head>
1414
- <body>
1415
- <header>
1416
- <div class="container header-content">
1417
- <a href="/" class="logo">
1418
- <span class="logo-icon">🦀</span>
1419
- <div>
1420
- <div>AgentHub</div>
1421
- <div class="logo-tagline">Crab-powered. Agent-ready.</div>
1422
- </div>
1423
- </a>
1424
- <nav class="nav-links">
1425
- <a href="/"><span data-i18n="navHome">Home</span></a>
1426
- <a href="/stats"><span data-i18n="navStats">Stats</span></a>
1427
- <a href="https://github.com/itshaungmu/AgentHub" target="_blank">GitHub</a>
1428
- <div class="nav-powered">
1429
- <span>🦀</span>
1430
- <span>Powered by</span>
1431
- <a href="https://github.com/openclaw" target="_blank">OpenClaw</a>
1432
- </div>
1433
- <div class="lang-switcher">
1434
- <button class="lang-btn active" data-lang="en" onclick="setLang('en')">EN</button>
1435
- <button class="lang-btn" data-lang="zh" onclick="setLang('zh')">中文</button>
1436
- </div>
1437
- <button class="theme-btn" onclick="toggleTheme()" aria-label="Switch theme">🌙</button>
1438
- </nav>
1439
- </div>
1440
- </header>
1441
- <main class="container">${body}</main>
1442
- <footer>
1443
- <div class="container footer-content">
1444
- <div class="footer-brand">
1445
- <div class="footer-brand-icon">🦀</div>
1446
- <span class="footer-brand-text">AgentHub</span>
1447
- </div>
1448
- <div class="footer-powered">
1449
- <span>Powered by</span>
1450
- <a href="https://github.com/openclaw" target="_blank">OpenClaw</a>
1451
- <span>•</span>
1452
- <span>Built with ❤️ for AI Agents</span>
1453
- </div>
1454
- <div class="footer-links">
1455
- <a href="https://github.com/openclaw" target="_blank">OpenClaw</a>
1456
- <a href="https://github.com/itshaungmu/AgentHub" target="_blank">AgentHub</a>
1457
- </div>
1458
- </div>
1459
- </footer>
1460
- </body>
1461
- </html>
1462
- ${langScript}`;
1463
- }
1464
-
1465
- export function renderAgentListPage({ query, agents, totalDownloads, apiBase }) {
1466
- const agentCount = agents.length;
1467
-
1468
- const features = `
1469
- <div class="features">
1470
- <div class="feature-card">
1471
- <div class="feature-icon">📦</div>
1472
- <div class="feature-title" data-i18n="feature1Title">Ready to Use</div>
1473
- <div class="feature-desc" data-i18n="feature1Desc">Skip complex configurations, get battle-tested AI Agent setups</div>
1474
- </div>
1475
- <div class="feature-card">
1476
- <div class="feature-icon">⚡</div>
1477
- <div class="feature-title" data-i18n="feature2Title">Instant Deploy</div>
1478
- <div class="feature-desc" data-i18n="feature2Desc">One-click install, deploy in minutes, start working immediately</div>
1479
- </div>
1480
- <div class="feature-card">
1481
- <div class="feature-icon">🔄</div>
1482
- <div class="feature-title" data-i18n="feature3Title">Version Control</div>
1483
- <div class="feature-desc" data-i18n="feature3Desc">Auto-update pushes, always stay with the latest capabilities</div>
1484
- </div>
1485
- </div>
1486
- `;
1487
-
1488
- const cards = agents.map(agent => {
1489
- const tags = agent.metadata?.tags || [];
1490
- const category = agent.metadata?.category || 'default';
1491
- const featured = agent.metadata?.featured;
1492
-
1493
- const tagClass = {
1494
- 'ops': 'tag-ops',
1495
- 'engineering': 'tag-engineering',
1496
- 'content': 'tag-content',
1497
- 'product': 'tag-product'
1498
- }[category] || 'tag-default';
1499
-
1500
- return `
1501
- <article class="agent-card${featured ? ' agent-card-featured' : ''}" onclick="window.location='/agents/${agent.slug}'">
1502
- ${featured ? '<span class="featured-badge">⭐</span>' : ''}
1503
- <div class="agent-header">
1504
- <a href="/agents/${agent.slug}" class="agent-name" onclick="event.stopPropagation()">${agent.name || agent.slug}</a>
1505
- <span class="agent-version">v${agent.version}</span>
1506
- </div>
1507
- <p class="agent-desc">${agent.description || 'A powerful AI Agent'}</p>
1508
- <div class="agent-meta">
1509
- <span class="agent-tag ${tagClass}">${category}</span>
1510
- ${tags.slice(0, 2).map(t => `<span class="agent-tag tag-default">${t}</span>`).join('')}
1511
- </div>
1512
- <div class="agent-footer">
1513
- <span class="agent-downloads">
1514
- <span>⬇️</span> ${agent.downloads || 0} <span data-i18n="downloads">downloads</span>
1515
- </span>
1516
- <span class="agent-install" data-i18n="install">Install</span>
1517
- </div>
1518
- </article>
1519
- `;
1520
- }).join('');
1521
-
1522
- const howItWorks = `
1523
- <div class="section">
1524
- <h2 class="section-title" style="text-align: center; margin-bottom: 32px;" data-i18n="howToUse">How to Use</h2>
1525
- <div class="how-it-works">
1526
- <div class="step">
1527
- <div class="step-number">1</div>
1528
- <h4 data-i18n="step1Title">Browse & Discover</h4>
1529
- <p data-i18n="step1Desc">Find the Agent that fits your workflow</p>
1530
- </div>
1531
- <div class="step">
1532
- <div class="step-number">2</div>
1533
- <h4 data-i18n="step2Title">One-Click Install</h4>
1534
- <p data-i18n="step2Desc">Run the install command, deploy in minutes</p>
1535
- </div>
1536
- <div class="step">
1537
- <div class="step-number">3</div>
1538
- <h4 data-i18n="step3Title">Start Working</h4>
1539
- <p data-i18n="step3Desc">Your AI assistant is ready, start delegating tasks</p>
1540
- </div>
1541
- </div>
1542
- </div>
1543
- `;
1544
-
1545
- const apiBox = `
1546
- <div class="api-box">
1547
- <h3 data-i18n="apiBoxTitle">🤖 AI Auto-Discovery API</h3>
1548
- <p data-i18n="apiBoxDesc">Let your AI assistant automatically discover and install Agents</p>
1549
- <div class="api-code" title="Click to copy">
1550
- <span class="code-text">curl -s https://raw.githubusercontent.com/itshaungmu/AgentHub/main/skills/agenthub-discover/SKILL.md</span>
1551
- <button class="copy-btn" title="Copy">📋</button>
1552
- </div>
1553
- </div>
1554
- `;
1555
-
1556
- return page(
1557
- "AgentHub - AI Agent Open Source Community",
1558
- `
1559
- <section class="hero">
1560
- <h1 data-i18n="heroTitle">AgentHub</h1>
1561
- <p class="hero-subtitle" data-i18n="heroSubtitle">The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.</p>
1562
- <div class="hero-stats">
1563
- <div class="hero-stat">
1564
- <div class="hero-stat-value">${agentCount}</div>
1565
- <div class="hero-stat-label" data-i18n="statAgents">Available Agents</div>
1566
- </div>
1567
- <div class="hero-stat">
1568
- <div class="hero-stat-value">${totalDownloads || 0}</div>
1569
- <div class="hero-stat-label" data-i18n="statDownloads">Total Downloads</div>
1570
- </div>
1571
- <div class="hero-stat">
1572
- <div class="hero-stat-value">100%</div>
1573
- <div class="hero-stat-label" data-i18n="statOpenSource">Open Source</div>
1574
- </div>
1575
- </div>
1576
- ${features}
1577
- </section>
1578
-
1579
- ${apiBox}
1580
-
1581
- <section class="section">
1582
- <div class="section-header">
1583
- <h2 class="section-title" data-i18n="sectionHotAgents">Hot Agents</h2>
1584
- <a href="/stats" class="section-link" data-i18n="sectionViewAll">View All →</a>
1585
- </div>
1586
- <form class="search-box" method="get" action="/">
1587
- <input type="search" name="q" value="${query ?? ""}" data-i18n-placeholder="searchPlaceholder" placeholder="Search Agents, skills, tags..." />
1588
- <button type="submit" data-i18n="searchButton">Search</button>
1589
- </form>
1590
- <div class="agent-grid">
1591
- ${cards || `<div class="empty-state"><h3 data-i18n="noAgents">No Agents yet</h3><p data-i18n="noAgentsHint">Use <code>agenthub pack</code> to package your first Agent!</p></div>`}
1592
- </div>
1593
- </section>
1594
-
1595
- ${howItWorks}
1596
- `,
1597
- {
1598
- description: "AgentHub - The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.",
1599
- url: "https://agenthub.cyou/"
1600
- }
1601
- );
1602
- }
1603
-
1604
- export function renderAgentDetailPage(manifest) {
1605
- const memoryInfo = manifest.includes?.memory || {};
1606
- const runtimeInfo = manifest.runtime || {};
1607
- const skills = manifest.includes?.skills || [];
1608
- const tags = manifest.metadata?.tags || [];
1609
- const requirements = manifest.requirements || {};
1610
- const persona = manifest.persona || {};
1611
-
1612
- const totalMemory = memoryInfo.count || 0;
1613
- const publicRatio = totalMemory > 0 ? (memoryInfo.public || 0) / totalMemory : 0;
1614
- const portableRatio = totalMemory > 0 ? (memoryInfo.portable || 0) / totalMemory : 0;
1615
- const privateRatio = totalMemory > 0 ? (memoryInfo.private || 0) / totalMemory : 0;
1616
-
1617
- const skillsHtml = skills.length > 0
1618
- ? skills.map(s => `<span class="badge badge-skill">${s}</span>`).join("")
1619
- : '<span style="color: var(--text-muted)">None</span>';
1620
-
1621
- const tagsHtml = tags.length > 0
1622
- ? tags.map(t => `<span class="badge badge-tag">${t}</span>`).join("")
1623
- : '<span style="color: var(--text-muted)">None</span>';
1624
-
1625
- const envVars = requirements.env || [];
1626
- const requirementsHtml = [];
1627
- if (envVars.length > 0) {
1628
- requirementsHtml.push('<li>🔐 <span data-i18n="requirementsEnv">Environment variables required:</span></li>');
1629
- for (const env of envVars) {
1630
- requirementsHtml.push(`<li style="padding-left: 20px;"><span class="env-var">${env}</span></li>`);
1631
- }
1632
- }
1633
- if (requirements.model) {
1634
- requirementsHtml.push(`<li>🤖 <span data-i18n="requirementsModel">Recommended model:</span> <span class="env-var">${requirements.model}</span></li>`);
1635
- }
1636
- if (requirements.openclaw) {
1637
- requirementsHtml.push(`<li>⚡ <span data-i18n="requirementsRuntime">Runtime version:</span> OpenClaw ${requirements.openclaw}</li>`);
1638
- }
1639
-
1640
- return page(
1641
- `${manifest.name || manifest.slug} - AgentHub`,
1642
- `
1643
- <a href="/" class="back-link" data-i18n="backToHome">← Back to Home</a>
1644
-
1645
- <div class="detail-header">
1646
- <h1 class="detail-title">${manifest.name || manifest.slug}</h1>
1647
- <p class="detail-desc">${manifest.description || 'A powerful AI Agent'}</p>
1648
- <div class="detail-grid">
1649
- <div class="detail-item">
1650
- <div class="detail-label" data-i18n="detailVersion">Version</div>
1651
- <div class="detail-value">${manifest.version}</div>
1652
- </div>
1653
- <div class="detail-item">
1654
- <div class="detail-label" data-i18n="detailRuntime">Runtime</div>
1655
- <div class="detail-value">${runtimeInfo.type || 'OpenClaw'}</div>
1656
- </div>
1657
- <div class="detail-item">
1658
- <div class="detail-label" data-i18n="detailDownloads">Downloads</div>
1659
- <div class="detail-value">⬇️ ${manifest.downloads || 0}</div>
1660
- </div>
1661
- <div class="detail-item">
1662
- <div class="detail-label" data-i18n="detailAuthor">Author</div>
1663
- <div class="detail-value">${manifest.author || 'Anonymous'}</div>
1664
- </div>
1665
- </div>
1666
- <div class="detail-install" title="Click to copy">
1667
- <span class="code-text">npx @zshuangmu/agenthub install ${manifest.slug} --target-workspace ./my-workspace</span>
1668
- <button class="copy-btn" title="Copy">📋</button>
1669
- </div>
1670
- </div>
1671
-
1672
- ${persona.summary ? `
1673
- <div class="section-card">
1674
- <h3 data-i18n="personaTitle">🎭 Personality</h3>
1675
- <p style="color: var(--text-secondary); line-height: 1.8;">${persona.summary}</p>
1676
- ${persona.traits?.length > 0 ? `<p style="margin-top: 12px;"><strong data-i18n="personaTraits">Traits:</strong> ${persona.traits.join(', ')}</p>` : ''}
1677
- ${persona.expertise?.length > 0 ? `<p><strong data-i18n="personaExpertise">Expertise:</strong> ${persona.expertise.join(', ')}</p>` : ''}
1678
- </div>
1679
- ` : ''}
1680
-
1681
- <div class="section-card">
1682
- <h3 data-i18n="memoryTitle">🧠 Memory Config</h3>
1683
- ${totalMemory > 0 ? `
1684
- <div class="memory-bars">
1685
- <div class="memory-bar public" style="flex: ${publicRatio}" title="Public"></div>
1686
- <div class="memory-bar portable" style="flex: ${portableRatio}" title="Portable"></div>
1687
- ${privateRatio > 0 ? `<div class="memory-bar private" style="flex: ${privateRatio}" title="Private"></div>` : ''}
1688
- </div>
1689
- <div class="memory-legend">
1690
- <span><span class="dot" style="background: var(--accent)"></span> <span data-i18n="memoryPublic">Public</span>: ${memoryInfo.public || 0}</span>
1691
- <span><span class="dot" style="background: var(--accent-light)"></span> <span data-i18n="memoryPortable">Portable</span>: ${memoryInfo.portable || 0}</span>
1692
- ${memoryInfo.private > 0 ? `<span><span class="dot" style="background: var(--tag-content)"></span> <span data-i18n="memoryPrivate">Private</span>: ${memoryInfo.private || 0}</span>` : ''}
1693
- </div>
1694
- ` : '<p style="color: var(--text-muted);" data-i18n="memoryNoData">No memory data</p>'}
1695
- </div>
1696
-
1697
- <div class="section-card">
1698
- <h3 data-i18n="skillsTitle">🔧 Skills</h3>
1699
- <div class="skills-list">${skillsHtml}</div>
1700
- </div>
1701
-
1702
- <div class="section-card">
1703
- <h3 data-i18n="tagsTitle">🏷️ Tags</h3>
1704
- <div class="tags-list">${tagsHtml}</div>
1705
- </div>
1706
-
1707
- <div class="section-card">
1708
- <h3 data-i18n="requirementsTitle">⚙️ System Requirements</h3>
1709
- ${requirementsHtml.length > 0 ? `<ul class="requirements-list">${requirementsHtml.join('')}</ul>` : '<p style="color: var(--text-muted);" data-i18n="requirementsNone">No special requirements</p>'}
1710
- </div>
1711
-
1712
- <div class="section-card">
1713
- <h3 data-i18n="installMethodTitle">📥 Installation</h3>
1714
- <p style="color: var(--text-secondary); margin-bottom: 16px;" data-i18n="installMethodDesc">Run in your workspace:</p>
1715
- <div class="install-methods">
1716
- <div class="install-box primary">
1717
- <span class="badge-new">推荐</span>
1718
- <div class="install-label">npx (无需预安装)</div>
1719
- <div class="detail-install" title="Click to copy">
1720
- <span class="code-text">npx @zshuangmu/agenthub install ${manifest.slug} --target-workspace ./my-workspace</span>
1721
- <button class="copy-btn" title="Copy">📋</button>
1722
- </div>
1723
- </div>
1724
- <div class="install-box">
1725
- <div class="install-label">已有 CLI</div>
1726
- <div class="detail-install" title="Click to copy">
1727
- <span class="code-text">agenthub install ${manifest.slug}@${manifest.version} --target-workspace ./my-workspace</span>
1728
- <button class="copy-btn" title="Copy">📋</button>
1729
- </div>
1730
- </div>
1731
- </div>
1732
- </div>
1733
- `,
1734
- {
1735
- description: manifest.description || `${manifest.name || manifest.slug} - AI Agent on AgentHub. ${manifest.persona?.summary || ''}`.slice(0, 160),
1736
- url: `https://agenthub.cyou/agents/${manifest.slug}`,
1737
- type: "article"
1738
- }
1739
- );
1740
- }
1741
-
1742
- export function renderStatsPage(statsData) {
1743
- const { stats, ranking, recent } = statsData;
1744
-
1745
- const rankingHtml = ranking.map((item, index) => `
1746
- <tr>
1747
- <td>${index + 1}</td>
1748
- <td><a href="/agents/${item.slug}">${item.slug}</a></td>
1749
- <td><strong>${item.downloads}</strong></td>
1750
- <td style="color: var(--text-muted)">${item.lastDownload || '-'}</td>
1751
- </tr>
1752
- `).join('');
1753
-
1754
- const recentHtml = recent.map(item => `
1755
- <tr>
1756
- <td><a href="/agents/${item.slug}">${item.slug}</a></td>
1757
- <td style="color: var(--text-muted)">${item.installedAt || '-'}</td>
1758
- <td><code style="color: var(--accent)">${item.targetWorkspace || '-'}</code></td>
1759
- </tr>
1760
- `).join('');
1761
-
1762
- return page(
1763
- "Statistics Center - AgentHub",
1764
- `
1765
- <a href="/" class="back-link" data-i18n="backToHome">← Back to Home</a>
1766
-
1767
- <div class="detail-header">
1768
- <h1 class="detail-title" data-i18n="statsHeader">📊 Statistics Center</h1>
1769
- <p class="detail-desc" data-i18n="statsDesc">AgentHub download statistics and data analysis</p>
1770
- <div class="detail-grid">
1771
- <div class="detail-item">
1772
- <div class="detail-label" data-i18n="statsTotalAgents">Agent Count</div>
1773
- <div class="detail-value">${stats.totalAgents}</div>
1774
- </div>
1775
- <div class="detail-item">
1776
- <div class="detail-label" data-i18n="statsTotalDownloads">Total Downloads</div>
1777
- <div class="detail-value">⬇️ ${stats.totalDownloads}</div>
1778
- </div>
1779
- <div class="detail-item">
1780
- <div class="detail-label" data-i18n="statsTotalLogs">Download Logs</div>
1781
- <div class="detail-value">${stats.totalLogs}</div>
1782
- </div>
1783
- </div>
1784
- </div>
1785
-
1786
- <div class="section-card">
1787
- <h3 data-i18n="rankingTitle">🏆 Download Ranking</h3>
1788
- <table class="stats-table">
1789
- <thead>
1790
- <tr>
1791
- <th data-i18n="rankingRank">Rank</th>
1792
- <th data-i18n="rankingAgent">Agent</th>
1793
- <th data-i18n="rankingDownloads">Downloads</th>
1794
- <th data-i18n="rankingLastDownload">Last Download</th>
1795
- </tr>
1796
- </thead>
1797
- <tbody>
1798
- ${rankingHtml || `<tr><td colspan="4" style="text-align: center; padding: 20px; color: var(--text-muted);" data-i18n="noData">No data</td></tr>`}
1799
- </tbody>
1800
- </table>
1801
- </div>
1802
-
1803
- <div class="section-card">
1804
- <h3 data-i18n="recentTitle">📋 Recent Downloads</h3>
1805
- <table class="stats-table">
1806
- <thead>
1807
- <tr>
1808
- <th data-i18n="recentAgent">Agent</th>
1809
- <th data-i18n="recentTime">Time</th>
1810
- <th data-i18n="recentTarget">Target Path</th>
1811
- </tr>
1812
- </thead>
1813
- <tbody>
1814
- ${recentHtml || `<tr><td colspan="3" style="text-align: center; padding: 20px; color: var(--text-muted);" data-i18n="noData">No data</td></tr>`}
1815
- </tbody>
1816
- </table>
1817
- </div>
1818
- `,
1819
- {
1820
- description: "AgentHub Statistics Center - View download rankings, recent activity, and platform analytics for AI Agents.",
1821
- url: "https://agenthub.cyou/stats"
1822
- }
1823
- );
1824
- }
1
+ // i18n translations
2
+ const i18n = {
3
+ en: {
4
+ title: "AgentHub - AI Agent Open Source Community",
5
+ navHome: "Home",
6
+ navStats: "Stats",
7
+ heroTitle: "AgentHub",
8
+ heroSubtitle: "The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.",
9
+ statAgents: "Available Agents",
10
+ statDownloads: "Total Downloads",
11
+ statOpenSource: "Open Source",
12
+ feature1Title: "Ready to Use",
13
+ feature1Desc: "Skip complex configurations, get battle-tested AI Agent setups",
14
+ feature2Title: "Instant Deploy",
15
+ feature2Desc: "One-click install, deploy in minutes, start working immediately",
16
+ feature3Title: "Version Control",
17
+ feature3Desc: "Auto-update pushes, always stay with the latest capabilities",
18
+ apiBoxTitle: "AI Auto-Discovery API",
19
+ apiBoxDesc: "Let your AI assistant automatically discover and install Agents",
20
+ sectionHotAgents: "Hot Agents",
21
+ sectionViewAll: "View All →",
22
+ searchPlaceholder: "Search Agents, skills, tags...",
23
+ searchButton: "Search",
24
+ downloads: "downloads",
25
+ install: "Install",
26
+ howToUse: "How to Use",
27
+ step1Title: "Browse & Discover",
28
+ step1Desc: "Find the Agent that fits your workflow",
29
+ step2Title: "One-Click Install",
30
+ step2Desc: "Run the install command, deploy in minutes",
31
+ step3Title: "Start Working",
32
+ step3Desc: "Your AI assistant is ready, start delegating tasks",
33
+ noAgents: "No Agents yet",
34
+ noAgentsHint: "Use <code>agenthub pack</code> to package your first Agent!",
35
+ // Detail page
36
+ backToHome: "← Back to Home",
37
+ detailVersion: "Version",
38
+ detailRuntime: "Runtime",
39
+ detailDownloads: "Downloads",
40
+ detailAuthor: "Author",
41
+ detailInstall: "Install Command",
42
+ personaTitle: "🎭 Personality",
43
+ personaTraits: "Traits",
44
+ personaExpertise: "Expertise",
45
+ memoryTitle: "🧠 Memory Config",
46
+ memoryPublic: "Public",
47
+ memoryPortable: "Portable",
48
+ memoryPrivate: "Private",
49
+ memoryNoData: "No memory data",
50
+ skillsTitle: "🔧 Skills",
51
+ tagsTitle: "🏷️ Tags",
52
+ requirementsTitle: "⚙️ System Requirements",
53
+ requirementsNone: "No special requirements",
54
+ requirementsEnv: "🔐 Environment variables required:",
55
+ requirementsModel: "🤖 Recommended model:",
56
+ requirementsRuntime: "⚡ Runtime version:",
57
+ installMethodTitle: "📥 Installation",
58
+ installMethodDesc: "Run in your workspace:",
59
+ // Stats page
60
+ statsTitle: "Statistics Center - AgentHub",
61
+ statsHeader: "📊 Statistics Center",
62
+ statsDesc: "AgentHub download statistics and data analysis",
63
+ statsTotalAgents: "Agent Count",
64
+ statsTotalDownloads: "Total Downloads",
65
+ statsTotalLogs: "Download Logs",
66
+ rankingTitle: "🏆 Download Ranking",
67
+ rankingAgent: "Agent",
68
+ rankingDownloads: "Downloads",
69
+ rankingLastDownload: "Last Download",
70
+ rankingRank: "Rank",
71
+ recentTitle: "📋 Recent Downloads",
72
+ recentAgent: "Agent",
73
+ recentTime: "Time",
74
+ recentTarget: "Target Path",
75
+ noData: "No data",
76
+ // Tags
77
+ tagOps: "ops",
78
+ tagEngineering: "engineering",
79
+ tagContent: "content",
80
+ tagProduct: "product",
81
+ tagDefault: "default",
82
+ },
83
+ zh: {
84
+ title: "AgentHub - AI Agent 开源社区",
85
+ navHome: "首页",
86
+ navStats: "统计",
87
+ heroTitle: "AgentHub",
88
+ heroSubtitle: "AI Agent 的开源应用市场。一句话打包上传 Agent 的全部能力,一键下载获得这些功力。",
89
+ statAgents: "可用 Agent",
90
+ statDownloads: "累计下载",
91
+ statOpenSource: "开源免费",
92
+ feature1Title: "开箱即用",
93
+ feature1Desc: "跳过繁琐的配置,获取经过实战验证的 AI Agent 配置",
94
+ feature2Title: "即装即用",
95
+ feature2Desc: "一键安装,几分钟内部署完成,立即开始工作",
96
+ feature3Title: "版本管理",
97
+ feature3Desc: "自动更新推送,始终保持最新能力",
98
+ apiBoxTitle: "🤖 AI 自动发现 API",
99
+ apiBoxDesc: "让你的 AI 助手自动发现并安装 Agent",
100
+ sectionHotAgents: "热门 Agent",
101
+ sectionViewAll: "查看全部 →",
102
+ searchPlaceholder: "搜索 Agent、技能、标签...",
103
+ searchButton: "搜索",
104
+ downloads: "次下载",
105
+ install: "安装",
106
+ howToUse: "如何使用",
107
+ step1Title: "浏览发现",
108
+ step1Desc: "找到适合你工作流程的 Agent",
109
+ step2Title: "一键安装",
110
+ step2Desc: "运行安装命令,几分钟内部署完成",
111
+ step3Title: "开始工作",
112
+ step3Desc: "你的 AI 助手已就绪,立即开始委托任务",
113
+ noAgents: "暂无 Agent",
114
+ noAgentsHint: "使用 <code>agenthub pack</code> 打包你的第一个 Agent 吧!",
115
+ // Detail page
116
+ backToHome: "← 返回首页",
117
+ detailVersion: "版本",
118
+ detailRuntime: "运行时",
119
+ detailDownloads: "下载次数",
120
+ detailAuthor: "作者",
121
+ detailInstall: "安装命令",
122
+ personaTitle: "🎭 性格简介",
123
+ personaTraits: "特质",
124
+ personaExpertise: "专长",
125
+ memoryTitle: "🧠 记忆配置",
126
+ memoryPublic: "公开",
127
+ memoryPortable: "可移植",
128
+ memoryPrivate: "私有",
129
+ memoryNoData: "暂无记忆数据",
130
+ skillsTitle: "🔧 技能",
131
+ tagsTitle: "🏷️ 标签",
132
+ requirementsTitle: "⚙️ 系统要求",
133
+ requirementsNone: "无特殊要求",
134
+ requirementsEnv: "🔐 需要配置环境变量:",
135
+ requirementsModel: "🤖 推荐模型:",
136
+ requirementsRuntime: "⚡ 运行时版本:",
137
+ installMethodTitle: "📥 安装方式",
138
+ installMethodDesc: "在你的工作区运行:",
139
+ // Stats page
140
+ statsTitle: "统计中心 - AgentHub",
141
+ statsHeader: "📊 统计中心",
142
+ statsDesc: "AgentHub 下载统计与数据分析",
143
+ statsTotalAgents: "Agent 数量",
144
+ statsTotalDownloads: "累计下载",
145
+ statsTotalLogs: "下载记录",
146
+ rankingTitle: "🏆 下载排行榜",
147
+ rankingAgent: "Agent",
148
+ rankingDownloads: "下载次数",
149
+ rankingLastDownload: "最后下载",
150
+ rankingRank: "排名",
151
+ recentTitle: "📋 最近下载",
152
+ recentAgent: "Agent",
153
+ recentTime: "时间",
154
+ recentTarget: "目标路径",
155
+ noData: "暂无数据",
156
+ // Tags
157
+ tagOps: "运维",
158
+ tagEngineering: "工程",
159
+ tagContent: "内容",
160
+ tagProduct: "产品",
161
+ tagDefault: "默认",
162
+ }
163
+ };
164
+
165
+ // Language toggle script
166
+ const langScript = `
167
+ <script>
168
+ (function() {
169
+ const defaultLang = 'en';
170
+ const savedLang = localStorage.getItem('agenthub-lang') || defaultLang;
171
+
172
+ function setLang(lang) {
173
+ localStorage.setItem('agenthub-lang', lang);
174
+ document.querySelectorAll('[data-i18n]').forEach(el => {
175
+ const key = el.getAttribute('data-i18n');
176
+ if (window.i18n && window.i18n[lang] && window.i18n[lang][key]) {
177
+ el.textContent = window.i18n[lang][key];
178
+ }
179
+ });
180
+ document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
181
+ const key = el.getAttribute('data-i18n-placeholder');
182
+ if (window.i18n && window.i18n[lang] && window.i18n[lang][key]) {
183
+ el.placeholder = window.i18n[lang][key];
184
+ }
185
+ });
186
+ document.querySelectorAll('.lang-btn').forEach(btn => {
187
+ btn.classList.toggle('active', btn.dataset.lang === lang);
188
+ });
189
+ document.documentElement.lang = lang === 'zh' ? 'zh-CN' : 'en';
190
+ }
191
+
192
+ function setTheme(theme) {
193
+ localStorage.setItem('agenthub-theme', theme);
194
+ document.documentElement.setAttribute('data-theme', theme);
195
+ const themeBtn = document.querySelector('.theme-btn');
196
+ if (themeBtn) {
197
+ themeBtn.textContent = theme === 'dark' ? '☀️' : '🌙';
198
+ themeBtn.setAttribute('aria-label', theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
199
+ }
200
+ }
201
+
202
+ function toggleTheme() {
203
+ const currentTheme = localStorage.getItem('agenthub-theme') || 'light';
204
+ setTheme(currentTheme === 'dark' ? 'light' : 'dark');
205
+ }
206
+
207
+ window.setLang = setLang;
208
+ window.toggleTheme = toggleTheme;
209
+ window.i18n = ${JSON.stringify(i18n)};
210
+
211
+ document.addEventListener('DOMContentLoaded', () => {
212
+ setLang(savedLang);
213
+ const savedTheme = localStorage.getItem('agenthub-theme') || 'light';
214
+ setTheme(savedTheme);
215
+
216
+ // Copy to clipboard
217
+ async function copyText(text) {
218
+ if (navigator.clipboard?.writeText) return navigator.clipboard.writeText(text);
219
+ const ta = Object.assign(document.createElement('textarea'), { value: text, style: 'position:fixed;opacity:0' });
220
+ document.body.appendChild(ta);
221
+ ta.select();
222
+ document.execCommand('copy');
223
+ ta.remove();
224
+ }
225
+
226
+ document.querySelectorAll('.api-code, .detail-install').forEach(el => {
227
+ el.addEventListener('click', () => {
228
+ const text = el.querySelector('.code-text')?.textContent.trim() || el.textContent.trim();
229
+ const btn = el.querySelector('.copy-btn');
230
+ copyText(text).then(() => {
231
+ if (!btn) return;
232
+ btn.textContent = '✓';
233
+ btn.classList.add('copied');
234
+ setTimeout(() => { btn.textContent = '📋'; btn.classList.remove('copied'); }, 1500);
235
+ }).catch(e => console.error('Copy failed:', e));
236
+ });
237
+ });
238
+
239
+ // === Client-side search & filter ===
240
+ const searchInput = document.getElementById('agent-search');
241
+ const categoryTabs = document.querySelectorAll('.category-tab');
242
+ const agentCards = document.querySelectorAll('.agent-card');
243
+ const loadMoreBtn = document.getElementById('load-more-btn');
244
+ const noResults = document.querySelector('.no-results');
245
+ let visibleCount = 0;
246
+ const PAGE_SIZE = 12;
247
+ let currentCategory = 'all';
248
+ let searchTerm = '';
249
+
250
+ function getFilteredCards() {
251
+ return Array.from(agentCards).filter(card => {
252
+ const matchCategory = currentCategory === 'all' || card.dataset.category === currentCategory;
253
+ const matchSearch = !searchTerm || card.textContent.toLowerCase().includes(searchTerm.toLowerCase());
254
+ return matchCategory && matchSearch;
255
+ });
256
+ }
257
+
258
+ function updateDisplay() {
259
+ const filtered = getFilteredCards();
260
+ agentCards.forEach(c => c.classList.add('hidden'));
261
+ filtered.forEach(c => c.classList.remove('hidden'));
262
+
263
+ visibleCount = Math.min(PAGE_SIZE, filtered.length);
264
+ filtered.slice(0, visibleCount).forEach(c => c.classList.remove('hidden'));
265
+
266
+ if (loadMoreBtn) {
267
+ loadMoreBtn.style.display = visibleCount < filtered.length ? 'inline-block' : 'none';
268
+ }
269
+ if (noResults) {
270
+ noResults.classList.toggle('show', filtered.length === 0);
271
+ }
272
+ }
273
+
274
+ if (searchInput) {
275
+ searchInput.addEventListener('input', (e) => {
276
+ searchTerm = e.target.value;
277
+ updateDisplay();
278
+ });
279
+ // Prevent form submit for client-side search
280
+ const form = searchInput.closest('form');
281
+ if (form) {
282
+ form.addEventListener('submit', (e) => {
283
+ e.preventDefault();
284
+ searchTerm = searchInput.value;
285
+ updateDisplay();
286
+ });
287
+ }
288
+ }
289
+
290
+ categoryTabs.forEach(tab => {
291
+ tab.addEventListener('click', () => {
292
+ categoryTabs.forEach(t => t.classList.remove('active'));
293
+ tab.classList.add('active');
294
+ currentCategory = tab.dataset.category;
295
+ updateDisplay();
296
+ });
297
+ });
298
+
299
+ if (loadMoreBtn) {
300
+ loadMoreBtn.addEventListener('click', () => {
301
+ const filtered = getFilteredCards();
302
+ visibleCount = Math.min(visibleCount + PAGE_SIZE, filtered.length);
303
+ filtered.slice(0, visibleCount).forEach(c => c.classList.remove('hidden'));
304
+ loadMoreBtn.style.display = visibleCount < filtered.length ? 'inline-block' : 'none';
305
+ });
306
+ }
307
+
308
+ updateDisplay();
309
+
310
+ // === Scroll reveal animation ===
311
+ const revealObserver = new IntersectionObserver((entries) => {
312
+ entries.forEach(entry => {
313
+ if (entry.isIntersecting) {
314
+ entry.target.classList.add('visible');
315
+ revealObserver.unobserve(entry.target);
316
+ }
317
+ });
318
+ }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
319
+
320
+ document.querySelectorAll('.reveal').forEach(el => revealObserver.observe(el));
321
+ });
322
+ })();
323
+ </script>
324
+ `;
325
+
326
+ function page(title, body, options = {}) {
327
+ const {
328
+ description = "AgentHub - The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.",
329
+ url = "https://agenthub.cyou/",
330
+ type = "website",
331
+ image = "https://agenthub.cyou/og-image.png"
332
+ } = options;
333
+
334
+ return `<!doctype html>
335
+ <html lang="en">
336
+ <head>
337
+ <meta charset="utf-8" />
338
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
339
+ <title>${title}</title>
340
+
341
+ <!-- SEO Meta -->
342
+ <meta name="description" content="${description}">
343
+ <meta name="keywords" content="AI Agent, AgentHub, OpenClaw, AI marketplace, agent packaging, artificial intelligence, open source">
344
+ <meta name="author" content="AgentHub Team">
345
+ <meta name="robots" content="index, follow">
346
+ <link rel="canonical" href="${url}">
347
+
348
+ <!-- Open Graph -->
349
+ <meta property="og:type" content="${type}">
350
+ <meta property="og:title" content="${title}">
351
+ <meta property="og:description" content="${description}">
352
+ <meta property="og:url" content="${url}">
353
+ <meta property="og:image" content="${image}">
354
+ <meta property="og:site_name" content="AgentHub">
355
+ <meta property="og:locale" content="en_US">
356
+ <meta property="og:locale:alternate" content="zh_CN">
357
+
358
+ <!-- Twitter Card -->
359
+ <meta name="twitter:card" content="summary_large_image">
360
+ <meta name="twitter:title" content="${title}">
361
+ <meta name="twitter:description" content="${description}">
362
+ <meta name="twitter:image" content="${image}">
363
+
364
+ <!-- JSON-LD Structured Data -->
365
+ <script type="application/ld+json">
366
+ {
367
+ "@context": "https://schema.org",
368
+ "@type": "WebSite",
369
+ "name": "AgentHub",
370
+ "url": "https://agenthub.cyou/",
371
+ "description": "${description.replace(/"/g, '\\"')}",
372
+ "potentialAction": {
373
+ "@type": "SearchAction",
374
+ "target": "https://agenthub.cyou/?q={search_term_string}",
375
+ "query-input": "required name=search_term_string"
376
+ }
377
+ }
378
+ </script>
379
+
380
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🦀</text></svg>">
381
+ <link rel="preconnect" href="https://fonts.googleapis.com">
382
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
383
+ <link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@500;600;700&family=Geist:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&display=swap" rel="stylesheet">
384
+ <style>
385
+ /* Light theme (default) - Vibrant Sunset palette */
386
+ :root {
387
+ --color-1: #fd63a3;
388
+ --color-2: #fe9800;
389
+ --color-3: #ffb74d;
390
+ --font-display: 'Geist Mono', 'SF Mono', 'Fira Code', monospace;
391
+ --font-body: 'Geist', 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
392
+ --bg-primary: #fffbf7;
393
+ --bg-secondary: #fff5ed;
394
+ --bg-card: #ffffff;
395
+ --bg-card-hover: #fff8f3;
396
+ --bg-code: #fff9f5;
397
+ --text-primary: #2d1810;
398
+ --text-secondary: #6b4a3a;
399
+ --text-muted: #a08070;
400
+ --accent: #fa709a;
401
+ --accent-light: #ff9a8b;
402
+ --accent-dark: #e85a80;
403
+ --accent-glow: rgba(250, 112, 154, 0.12);
404
+ --border: #f0d8c8;
405
+ --header-bg: rgba(255, 251, 247, 0.95);
406
+ --tag-ops: #fa709a;
407
+ --tag-engineering: #ff9a8b;
408
+ --tag-content: #fee140;
409
+ --tag-product: #f5a623;
410
+ }
411
+
412
+ /* Dark theme - Vibrant sunset tones */
413
+ [data-theme="dark"] {
414
+ --color-1: #fd63a3;
415
+ --color-2: #fe9800;
416
+ --color-3: #ffb74d;
417
+ --bg-primary: #1a1215;
418
+ --bg-secondary: #251a1d;
419
+ --bg-card: #2a1f22;
420
+ --bg-card-hover: #352528;
421
+ --bg-code: #251a1d;
422
+ --text-primary: #fff5f0;
423
+ --text-secondary: #d4b8a8;
424
+ --text-muted: #8a7060;
425
+ --accent: #ff9a8b;
426
+ --accent-light: #ffb8a8;
427
+ --accent-dark: #fa709a;
428
+ --accent-glow: rgba(255, 154, 139, 0.15);
429
+ --border: #3d2a28;
430
+ --header-bg: rgba(26, 18, 21, 0.95);
431
+ }
432
+ * { box-sizing: border-box; margin: 0; padding: 0; }
433
+ body {
434
+ font-family: var(--font-body);
435
+ background: var(--bg-primary);
436
+ color: var(--text-primary);
437
+ line-height: 1.6;
438
+ min-height: 100vh;
439
+ -webkit-font-smoothing: antialiased;
440
+ -moz-osx-font-smoothing: grayscale;
441
+ }
442
+
443
+ /* Subtle background texture */
444
+ body::before {
445
+ content: '';
446
+ position: fixed;
447
+ inset: 0;
448
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.02'/%3E%3C/svg%3E");
449
+ pointer-events: none;
450
+ z-index: -1;
451
+ }
452
+
453
+ /* Animations */
454
+ @keyframes fadeInUp {
455
+ from { opacity: 0; transform: translateY(20px); }
456
+ to { opacity: 1; transform: translateY(0); }
457
+ }
458
+ @keyframes fadeIn {
459
+ from { opacity: 0; }
460
+ to { opacity: 1; }
461
+ }
462
+ @keyframes gradientShift {
463
+ 0%, 100% { background-position: 0% 50%; }
464
+ 50% { background-position: 100% 50%; }
465
+ }
466
+ @keyframes float {
467
+ 0%, 100% { transform: translateY(0px); }
468
+ 50% { transform: translateY(-8px); }
469
+ }
470
+ @keyframes pulse {
471
+ 0%, 100% { opacity: 0.6; }
472
+ 50% { opacity: 1; }
473
+ }
474
+ @keyframes countUp {
475
+ from { opacity: 0; transform: translateY(10px); }
476
+ to { opacity: 1; transform: translateY(0); }
477
+ }
478
+ @keyframes shimmer {
479
+ 0% { background-position: -200% 0; }
480
+ 100% { background-position: 200% 0; }
481
+ }
482
+ @keyframes slideInRight {
483
+ from { opacity: 0; transform: translateX(20px); }
484
+ to { opacity: 1; transform: translateX(0); }
485
+ }
486
+
487
+ /* Scroll reveal */
488
+ .reveal {
489
+ opacity: 0;
490
+ transform: translateY(24px);
491
+ transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
492
+ }
493
+ .reveal.visible {
494
+ opacity: 1;
495
+ transform: translateY(0);
496
+ }
497
+ .reveal-delay-1 { transition-delay: 0.1s; }
498
+ .reveal-delay-2 { transition-delay: 0.2s; }
499
+ .reveal-delay-3 { transition-delay: 0.3s; }
500
+ a { color: inherit; text-decoration: none; }
501
+ .container {
502
+ max-width: 1200px;
503
+ margin: 0 auto;
504
+ padding: 0 24px;
505
+ }
506
+
507
+ /* Header - ClawHub inspired minimal style */
508
+ header {
509
+ border-bottom: 1px solid var(--border);
510
+ padding: 20px 0;
511
+ position: sticky;
512
+ top: 0;
513
+ background: var(--header-bg);
514
+ backdrop-filter: blur(16px);
515
+ -webkit-backdrop-filter: blur(16px);
516
+ z-index: 100;
517
+ animation: fadeIn 0.5s ease-out;
518
+ }
519
+ .header-content {
520
+ display: flex;
521
+ align-items: center;
522
+ justify-content: space-between;
523
+ }
524
+ .logo {
525
+ display: flex;
526
+ align-items: center;
527
+ gap: 12px;
528
+ font-family: var(--font-display);
529
+ font-size: 20px;
530
+ font-weight: 600;
531
+ letter-spacing: -0.02em;
532
+ transition: all 0.3s ease;
533
+ }
534
+ .logo:hover {
535
+ transform: translateX(2px);
536
+ }
537
+ .logo-icon {
538
+ font-size: 28px;
539
+ filter: drop-shadow(0 2px 4px rgba(250, 112, 154, 0.3));
540
+ transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
541
+ }
542
+ .logo:hover .logo-icon {
543
+ transform: rotate(-10deg) scale(1.1);
544
+ }
545
+ .logo-tagline {
546
+ font-size: 11px;
547
+ font-weight: 500;
548
+ color: var(--text-muted);
549
+ font-family: var(--font-body);
550
+ letter-spacing: 0.02em;
551
+ margin-top: 2px;
552
+ }
553
+ .nav-links {
554
+ display: flex;
555
+ align-items: center;
556
+ gap: 28px;
557
+ }
558
+ .nav-links a {
559
+ color: var(--text-secondary);
560
+ font-weight: 500;
561
+ font-size: 14px;
562
+ transition: color 0.2s;
563
+ position: relative;
564
+ }
565
+ .nav-links a::after {
566
+ content: '';
567
+ position: absolute;
568
+ bottom: -4px;
569
+ left: 0;
570
+ width: 0;
571
+ height: 2px;
572
+ background: linear-gradient(90deg, var(--color-1), var(--color-3));
573
+ transition: width 0.25s ease;
574
+ border-radius: 1px;
575
+ }
576
+ .nav-links a:hover {
577
+ color: var(--text-primary);
578
+ }
579
+ .nav-links a:hover::after {
580
+ width: 100%;
581
+ }
582
+ .nav-powered {
583
+ display: flex;
584
+ align-items: center;
585
+ gap: 6px;
586
+ padding: 8px 14px;
587
+ background: var(--bg-secondary);
588
+ border-radius: 8px;
589
+ font-size: 12px;
590
+ color: var(--text-muted);
591
+ font-family: var(--font-display);
592
+ }
593
+ .nav-powered a {
594
+ color: var(--color-1);
595
+ font-weight: 600;
596
+ }
597
+ .nav-powered a::after {
598
+ display: none;
599
+ }
600
+
601
+ /* Language Switcher - Coral themed */
602
+ .lang-switcher {
603
+ display: flex;
604
+ background: var(--bg-secondary);
605
+ border-radius: 8px;
606
+ padding: 3px;
607
+ gap: 2px;
608
+ }
609
+ .lang-btn {
610
+ padding: 6px 12px;
611
+ border: none;
612
+ background: transparent;
613
+ color: var(--text-muted);
614
+ border-radius: 6px;
615
+ cursor: pointer;
616
+ font-size: 12px;
617
+ font-weight: 600;
618
+ font-family: var(--font-display);
619
+ transition: all 0.2s;
620
+ }
621
+ .lang-btn:hover {
622
+ color: var(--text-primary);
623
+ }
624
+ .lang-btn.active {
625
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
626
+ color: #ffffff;
627
+ }
628
+
629
+ /* Theme Switcher - Coral themed */
630
+ .theme-btn {
631
+ background: var(--bg-secondary);
632
+ border: none;
633
+ width: 36px;
634
+ height: 36px;
635
+ border-radius: 8px;
636
+ cursor: pointer;
637
+ font-size: 16px;
638
+ display: flex;
639
+ align-items: center;
640
+ justify-content: center;
641
+ transition: all 0.25s;
642
+ margin-left: 6px;
643
+ }
644
+ .theme-btn:hover {
645
+ background: var(--bg-card-hover);
646
+ transform: scale(1.05);
647
+ }
648
+ .theme-btn:active {
649
+ transform: scale(0.95);
650
+ }
651
+
652
+ /* Hero - Sunset gradient style */
653
+ .hero {
654
+ text-align: center;
655
+ padding: 80px 20px 64px;
656
+ position: relative;
657
+ overflow: hidden;
658
+ }
659
+ .hero::before {
660
+ content: '';
661
+ position: absolute;
662
+ top: -40px;
663
+ left: 50%;
664
+ transform: translateX(-50%);
665
+ width: 900px;
666
+ height: 600px;
667
+ background: radial-gradient(ellipse at center, rgba(250, 112, 154, 0.1) 0%, rgba(254, 225, 64, 0.06) 30%, rgba(255, 183, 77, 0.04) 50%, transparent 70%);
668
+ pointer-events: none;
669
+ z-index: -1;
670
+ animation: pulse 6s ease-in-out infinite;
671
+ }
672
+ .hero::after {
673
+ content: '';
674
+ position: absolute;
675
+ top: 50%;
676
+ left: 50%;
677
+ transform: translate(-50%, -50%);
678
+ width: 600px;
679
+ height: 600px;
680
+ background: conic-gradient(from 0deg, transparent, rgba(250, 112, 154, 0.04), transparent, rgba(254, 152, 0, 0.04), transparent);
681
+ border-radius: 50%;
682
+ animation: spin 20s linear infinite;
683
+ pointer-events: none;
684
+ z-index: -1;
685
+ }
686
+ @keyframes spin { to { transform: translate(-50%, -50%) rotate(360deg); } }
687
+ .hero h1 {
688
+ font-family: var(--font-display);
689
+ font-size: clamp(42px, 8vw, 72px);
690
+ font-weight: 700;
691
+ margin-bottom: 20px;
692
+ letter-spacing: -0.04em;
693
+ background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 40%, var(--color-2) 70%, var(--color-1) 100%);
694
+ background-size: 200% auto;
695
+ -webkit-background-clip: text;
696
+ -webkit-text-fill-color: transparent;
697
+ background-clip: text;
698
+ animation: fadeInUp 0.6s ease-out, gradientShift 6s ease infinite;
699
+ }
700
+ .hero-subtitle {
701
+ font-size: 18px;
702
+ color: var(--text-secondary);
703
+ max-width: 600px;
704
+ margin: 0 auto 48px;
705
+ line-height: 1.8;
706
+ animation: fadeInUp 0.6s ease-out 0.1s backwards;
707
+ }
708
+ .hero-stats {
709
+ display: flex;
710
+ justify-content: center;
711
+ gap: 48px;
712
+ margin-bottom: 48px;
713
+ animation: fadeInUp 0.6s ease-out 0.2s backwards;
714
+ }
715
+ .hero-stat {
716
+ text-align: center;
717
+ padding: 16px 24px;
718
+ background: var(--bg-card);
719
+ border: 1px solid var(--border);
720
+ border-radius: 16px;
721
+ transition: all 0.3s ease;
722
+ min-width: 140px;
723
+ }
724
+ .hero-stat:hover {
725
+ border-color: var(--color-1);
726
+ transform: translateY(-2px);
727
+ box-shadow: 0 8px 24px rgba(250, 112, 154, 0.1);
728
+ }
729
+ .hero-stat-value {
730
+ font-family: var(--font-display);
731
+ font-size: 36px;
732
+ font-weight: 700;
733
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
734
+ -webkit-background-clip: text;
735
+ -webkit-text-fill-color: transparent;
736
+ background-clip: text;
737
+ letter-spacing: -0.02em;
738
+ }
739
+ .hero-stat-label {
740
+ font-size: 11px;
741
+ color: var(--text-muted);
742
+ text-transform: uppercase;
743
+ letter-spacing: 0.1em;
744
+ font-weight: 600;
745
+ margin-top: 6px;
746
+ }
747
+
748
+ /* Features - Warm coral accents */
749
+ .features {
750
+ display: grid;
751
+ grid-template-columns: repeat(3, 1fr);
752
+ gap: 18px;
753
+ margin-bottom: 56px;
754
+ }
755
+ .feature-card {
756
+ background: var(--bg-card);
757
+ border: 1px solid var(--border);
758
+ border-radius: 16px;
759
+ padding: 32px 24px;
760
+ text-align: center;
761
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
762
+ position: relative;
763
+ overflow: hidden;
764
+ }
765
+ .feature-card::before {
766
+ content: '';
767
+ position: absolute;
768
+ top: 0;
769
+ left: 0;
770
+ right: 0;
771
+ height: 3px;
772
+ background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
773
+ opacity: 0;
774
+ transition: opacity 0.3s;
775
+ }
776
+ .feature-card::after {
777
+ content: '';
778
+ position: absolute;
779
+ inset: 0;
780
+ background: linear-gradient(135deg, rgba(250, 112, 154, 0.03), transparent);
781
+ opacity: 0;
782
+ transition: opacity 0.3s;
783
+ }
784
+ .feature-card:hover {
785
+ border-color: var(--color-1);
786
+ transform: translateY(-6px);
787
+ box-shadow: 0 16px 40px rgba(250, 112, 154, 0.12);
788
+ }
789
+ .feature-card:hover::before {
790
+ opacity: 1;
791
+ }
792
+ .feature-card:hover::after {
793
+ opacity: 1;
794
+ }
795
+ .feature-icon {
796
+ font-size: 36px;
797
+ margin-bottom: 16px;
798
+ display: block;
799
+ animation: float 3s ease-in-out infinite;
800
+ }
801
+ .feature-card:nth-child(2) .feature-icon { animation-delay: 0.5s; }
802
+ .feature-card:nth-child(3) .feature-icon { animation-delay: 1s; }
803
+ .feature-title {
804
+ font-family: var(--font-display);
805
+ font-size: 15px;
806
+ font-weight: 600;
807
+ margin-bottom: 10px;
808
+ letter-spacing: -0.01em;
809
+ color: var(--text-primary);
810
+ }
811
+ .feature-desc {
812
+ font-size: 13px;
813
+ color: var(--text-secondary);
814
+ line-height: 1.7;
815
+ }
816
+
817
+ /* Section - Coral themed */
818
+ .section {
819
+ margin-bottom: 56px;
820
+ }
821
+ .section-header {
822
+ display: flex;
823
+ align-items: center;
824
+ justify-content: space-between;
825
+ margin-bottom: 22px;
826
+ }
827
+ .section-title {
828
+ font-family: var(--font-display);
829
+ font-size: 20px;
830
+ font-weight: 700;
831
+ letter-spacing: -0.02em;
832
+ }
833
+ .section-link {
834
+ color: var(--color-1);
835
+ font-weight: 600;
836
+ font-size: 14px;
837
+ display: flex;
838
+ align-items: center;
839
+ gap: 6px;
840
+ transition: all 0.25s;
841
+ }
842
+ .section-link:hover {
843
+ gap: 10px;
844
+ color: var(--color-3);
845
+ }
846
+
847
+ /* Agent Grid - Coral themed */
848
+ .agent-grid {
849
+ display: grid;
850
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
851
+ gap: 18px;
852
+ transition: all 0.3s ease;
853
+ }
854
+ .agent-card {
855
+ background: var(--bg-card);
856
+ border: 1px solid var(--border);
857
+ border-radius: 16px;
858
+ padding: 24px;
859
+ transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
860
+ cursor: pointer;
861
+ animation: fadeInUp 0.5s ease-out backwards;
862
+ position: relative;
863
+ overflow: hidden;
864
+ }
865
+ .agent-card::after {
866
+ content: '';
867
+ position: absolute;
868
+ bottom: 0;
869
+ left: 0;
870
+ right: 0;
871
+ height: 3px;
872
+ background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
873
+ transform: scaleX(0);
874
+ transition: transform 0.3s ease;
875
+ transform-origin: left;
876
+ }
877
+ .agent-card:nth-child(1) { animation-delay: 0.05s; }
878
+ .agent-card:nth-child(2) { animation-delay: 0.1s; }
879
+ .agent-card:nth-child(3) { animation-delay: 0.15s; }
880
+ .agent-card:nth-child(4) { animation-delay: 0.2s; }
881
+ .agent-card:nth-child(5) { animation-delay: 0.25s; }
882
+ .agent-card:nth-child(6) { animation-delay: 0.3s; }
883
+ .agent-card:nth-child(7) { animation-delay: 0.35s; }
884
+ .agent-card:nth-child(8) { animation-delay: 0.4s; }
885
+ .agent-card:hover {
886
+ background: var(--bg-card-hover);
887
+ border-color: var(--color-1);
888
+ transform: translateY(-6px);
889
+ box-shadow: 0 20px 48px rgba(250, 112, 154, 0.15);
890
+ }
891
+ .agent-card:hover::after {
892
+ transform: scaleX(1);
893
+ }
894
+ .agent-card-featured {
895
+ border-color: var(--color-1);
896
+ background: linear-gradient(135deg, rgba(250, 112, 154, 0.03), rgba(255, 154, 139, 0.03));
897
+ }
898
+ .agent-card-featured:hover {
899
+ box-shadow: 0 16px 40px rgba(250, 112, 154, 0.25);
900
+ }
901
+ .featured-badge {
902
+ position: absolute;
903
+ top: -8px;
904
+ right: 12px;
905
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
906
+ color: white;
907
+ padding: 4px 12px;
908
+ border-radius: 12px;
909
+ font-size: 12px;
910
+ font-weight: 600;
911
+ box-shadow: 0 4px 12px rgba(250, 112, 154, 0.3);
912
+ }
913
+ .agent-header {
914
+ display: flex;
915
+ align-items: flex-start;
916
+ justify-content: space-between;
917
+ margin-bottom: 12px;
918
+ }
919
+ .agent-name {
920
+ font-family: var(--font-display);
921
+ font-size: 16px;
922
+ font-weight: 600;
923
+ letter-spacing: -0.01em;
924
+ transition: color 0.2s;
925
+ }
926
+ .agent-card:hover .agent-name {
927
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
928
+ -webkit-background-clip: text;
929
+ -webkit-text-fill-color: transparent;
930
+ background-clip: text;
931
+ }
932
+ .agent-version {
933
+ background: linear-gradient(135deg, rgba(250, 112, 154, 0.12), rgba(255, 154, 139, 0.12));
934
+ padding: 4px 10px;
935
+ border-radius: 6px;
936
+ font-size: 11px;
937
+ font-family: var(--font-display);
938
+ color: var(--color-1);
939
+ font-weight: 600;
940
+ }
941
+ .agent-desc {
942
+ color: var(--text-secondary);
943
+ font-size: 14px;
944
+ margin-bottom: 14px;
945
+ line-height: 1.6;
946
+ display: -webkit-box;
947
+ -webkit-line-clamp: 2;
948
+ -webkit-box-orient: vertical;
949
+ overflow: hidden;
950
+ }
951
+ .agent-meta {
952
+ display: flex;
953
+ flex-wrap: wrap;
954
+ gap: 6px;
955
+ margin-bottom: 16px;
956
+ }
957
+ .agent-tag {
958
+ padding: 4px 10px;
959
+ border-radius: 6px;
960
+ font-size: 11px;
961
+ font-weight: 600;
962
+ font-family: var(--font-display);
963
+ }
964
+ .tag-ops { background: rgba(250, 112, 154, 0.12); color: var(--color-1); }
965
+ .tag-engineering { background: rgba(255, 154, 139, 0.12); color: var(--color-3); }
966
+ .tag-content { background: rgba(254, 225, 64, 0.15); color: #c9a800; }
967
+ .tag-product { background: rgba(245, 166, 35, 0.12); color: #e09000; }
968
+ .tag-default { background: var(--bg-secondary); color: var(--text-muted); }
969
+ .agent-footer {
970
+ display: flex;
971
+ align-items: center;
972
+ justify-content: space-between;
973
+ padding-top: 16px;
974
+ border-top: 1px solid var(--border);
975
+ }
976
+ .agent-downloads {
977
+ display: flex;
978
+ align-items: center;
979
+ gap: 6px;
980
+ color: var(--text-muted);
981
+ font-size: 13px;
982
+ }
983
+ .agent-install {
984
+ background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 100%);
985
+ color: #ffffff;
986
+ padding: 8px 18px;
987
+ border-radius: 8px;
988
+ font-size: 12px;
989
+ font-family: var(--font-display);
990
+ font-weight: 600;
991
+ transition: all 0.25s;
992
+ box-shadow: 0 4px 12px rgba(250, 112, 154, 0.25);
993
+ }
994
+ .agent-install:hover {
995
+ transform: translateY(-2px);
996
+ box-shadow: 0 6px 20px rgba(250, 112, 154, 0.35);
997
+ }
998
+ .agent-install:active {
999
+ transform: translateY(0);
1000
+ }
1001
+
1002
+ /* API Box - Sunset gradient accent */
1003
+ .api-box {
1004
+ background: var(--bg-card);
1005
+ border: 1px solid var(--border);
1006
+ border-radius: 16px;
1007
+ padding: 32px;
1008
+ margin-bottom: 56px;
1009
+ position: relative;
1010
+ overflow: hidden;
1011
+ }
1012
+ .api-box::before {
1013
+ content: '';
1014
+ position: absolute;
1015
+ top: 0;
1016
+ left: 0;
1017
+ right: 0;
1018
+ height: 3px;
1019
+ background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
1020
+ }
1021
+ .api-box h3 {
1022
+ font-family: var(--font-display);
1023
+ font-size: 16px;
1024
+ margin-bottom: 8px;
1025
+ letter-spacing: -0.01em;
1026
+ }
1027
+ .api-box p {
1028
+ color: var(--text-secondary);
1029
+ margin-bottom: 20px;
1030
+ font-size: 14px;
1031
+ }
1032
+ .api-code {
1033
+ background: var(--bg-code);
1034
+ border: 1px solid var(--border);
1035
+ border-radius: 10px;
1036
+ padding: 16px 20px;
1037
+ font-family: var(--font-display);
1038
+ font-size: 13px;
1039
+ color: var(--color-1);
1040
+ overflow-x: auto;
1041
+ position: relative;
1042
+ cursor: pointer;
1043
+ display: flex;
1044
+ align-items: center;
1045
+ justify-content: space-between;
1046
+ gap: 12px;
1047
+ transition: all 0.25s;
1048
+ }
1049
+ .api-code:hover {
1050
+ border-color: var(--color-1);
1051
+ background: var(--bg-secondary);
1052
+ }
1053
+ .api-code .code-text {
1054
+ flex: 1;
1055
+ display: flex;
1056
+ align-items: center;
1057
+ gap: 10px;
1058
+ }
1059
+ .api-code .code-text::before {
1060
+ content: '$';
1061
+ color: var(--text-muted);
1062
+ flex-shrink: 0;
1063
+ }
1064
+ .api-code .copy-btn {
1065
+ background: transparent;
1066
+ border: 1px solid var(--border);
1067
+ border-radius: 6px;
1068
+ padding: 6px 10px;
1069
+ font-size: 12px;
1070
+ color: var(--text-muted);
1071
+ cursor: pointer;
1072
+ transition: all 0.2s;
1073
+ flex-shrink: 0;
1074
+ }
1075
+ .api-code .copy-btn:hover {
1076
+ background: var(--color-1);
1077
+ color: white;
1078
+ border-color: var(--color-1);
1079
+ }
1080
+ .api-code .copy-btn.copied {
1081
+ background: var(--color-2);
1082
+ border-color: var(--color-2);
1083
+ color: #2d1810;
1084
+ }
1085
+
1086
+ /* Detail Page - Coral themed */
1087
+ .detail-header {
1088
+ background: var(--bg-card);
1089
+ border: 1px solid var(--border);
1090
+ border-radius: 20px;
1091
+ padding: 36px;
1092
+ margin-bottom: 24px;
1093
+ position: relative;
1094
+ overflow: hidden;
1095
+ }
1096
+ .detail-header::before {
1097
+ content: '';
1098
+ position: absolute;
1099
+ top: 0;
1100
+ left: 0;
1101
+ right: 0;
1102
+ height: 4px;
1103
+ background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
1104
+ }
1105
+ .detail-title {
1106
+ font-family: var(--font-display);
1107
+ font-size: 32px;
1108
+ font-weight: 700;
1109
+ margin-bottom: 10px;
1110
+ letter-spacing: -0.02em;
1111
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
1112
+ -webkit-background-clip: text;
1113
+ -webkit-text-fill-color: transparent;
1114
+ background-clip: text;
1115
+ }
1116
+ .detail-desc {
1117
+ font-size: 16px;
1118
+ color: var(--text-secondary);
1119
+ margin-bottom: 24px;
1120
+ line-height: 1.7;
1121
+ }
1122
+ .detail-grid {
1123
+ display: grid;
1124
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
1125
+ gap: 14px;
1126
+ margin-bottom: 24px;
1127
+ }
1128
+ .detail-item {
1129
+ background: var(--bg-secondary);
1130
+ padding: 18px;
1131
+ border-radius: 12px;
1132
+ border: 1px solid transparent;
1133
+ transition: border-color 0.2s;
1134
+ }
1135
+ .detail-item:hover {
1136
+ border-color: var(--border);
1137
+ }
1138
+ .detail-label {
1139
+ font-size: 11px;
1140
+ color: var(--text-muted);
1141
+ text-transform: uppercase;
1142
+ letter-spacing: 0.08em;
1143
+ margin-bottom: 8px;
1144
+ font-weight: 600;
1145
+ }
1146
+ .detail-value {
1147
+ font-family: var(--font-display);
1148
+ font-size: 18px;
1149
+ font-weight: 600;
1150
+ letter-spacing: -0.01em;
1151
+ }
1152
+ .detail-install {
1153
+ background: var(--bg-code);
1154
+ border: 1px solid var(--border);
1155
+ color: var(--color-1);
1156
+ padding: 16px 20px;
1157
+ border-radius: 12px;
1158
+ font-family: var(--font-display);
1159
+ font-size: 14px;
1160
+ display: flex;
1161
+ align-items: center;
1162
+ gap: 12px;
1163
+ cursor: pointer;
1164
+ transition: all 0.25s;
1165
+ }
1166
+ .detail-install:hover {
1167
+ border-color: var(--color-1);
1168
+ background: var(--bg-secondary);
1169
+ }
1170
+ .detail-install .code-text {
1171
+ flex: 1;
1172
+ display: flex;
1173
+ align-items: center;
1174
+ gap: 10px;
1175
+ }
1176
+ .detail-install .code-text::before {
1177
+ content: "$";
1178
+ color: var(--text-muted);
1179
+ font-weight: bold;
1180
+ }
1181
+ .detail-install .copy-btn {
1182
+ background: transparent;
1183
+ border: 1px solid var(--border);
1184
+ border-radius: 6px;
1185
+ padding: 6px 12px;
1186
+ font-size: 12px;
1187
+ color: var(--text-muted);
1188
+ cursor: pointer;
1189
+ transition: all 0.2s;
1190
+ flex-shrink: 0;
1191
+ }
1192
+ .detail-install .copy-btn:hover {
1193
+ background: var(--color-1);
1194
+ color: white;
1195
+ border-color: var(--color-1);
1196
+ }
1197
+ .detail-install .copy-btn.copied {
1198
+ background: var(--color-2);
1199
+ border-color: var(--color-2);
1200
+ color: #2d1810;
1201
+ }
1202
+ .install-label {
1203
+ font-size: 11px;
1204
+ color: var(--text-muted);
1205
+ text-transform: uppercase;
1206
+ letter-spacing: 0.08em;
1207
+ margin-bottom: 10px;
1208
+ font-weight: 600;
1209
+ }
1210
+ .install-methods {
1211
+ display: flex;
1212
+ flex-direction: column;
1213
+ gap: 14px;
1214
+ }
1215
+ .install-box {
1216
+ position: relative;
1217
+ }
1218
+ .install-box.primary .detail-install {
1219
+ border-color: var(--color-1);
1220
+ background: linear-gradient(135deg, rgba(250, 112, 154, 0.06), transparent);
1221
+ }
1222
+ .install-box .badge-new {
1223
+ position: absolute;
1224
+ top: -8px;
1225
+ right: -8px;
1226
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
1227
+ color: white;
1228
+ font-size: 10px;
1229
+ padding: 3px 8px;
1230
+ border-radius: 6px;
1231
+ font-weight: 600;
1232
+ }
1233
+
1234
+ .section-card {
1235
+ background: var(--bg-card);
1236
+ border: 1px solid var(--border);
1237
+ border-radius: 16px;
1238
+ padding: 26px;
1239
+ margin-bottom: 20px;
1240
+ transition: border-color 0.25s;
1241
+ }
1242
+ .section-card:hover {
1243
+ border-color: var(--border);
1244
+ }
1245
+ .section-card h3 {
1246
+ font-family: var(--font-display);
1247
+ font-size: 15px;
1248
+ font-weight: 600;
1249
+ margin-bottom: 16px;
1250
+ display: flex;
1251
+ align-items: center;
1252
+ gap: 10px;
1253
+ letter-spacing: -0.01em;
1254
+ }
1255
+ .back-link {
1256
+ display: inline-flex;
1257
+ align-items: center;
1258
+ gap: 8px;
1259
+ color: var(--text-secondary);
1260
+ margin-bottom: 24px;
1261
+ font-size: 14px;
1262
+ transition: all 0.25s;
1263
+ }
1264
+ .back-link:hover {
1265
+ color: var(--color-1);
1266
+ gap: 12px;
1267
+ }
1268
+
1269
+ /* Memory bars - Coral themed */
1270
+ .memory-bars {
1271
+ display: flex;
1272
+ gap: 3px;
1273
+ height: 8px;
1274
+ border-radius: 4px;
1275
+ overflow: hidden;
1276
+ margin-bottom: 12px;
1277
+ }
1278
+ .memory-bar { height: 100%; }
1279
+ .memory-bar.public { background: var(--color-1); }
1280
+ .memory-bar.portable { background: var(--color-3); }
1281
+ .memory-bar.private { background: var(--color-2); }
1282
+ .memory-legend {
1283
+ display: flex;
1284
+ gap: 20px;
1285
+ font-size: 12px;
1286
+ color: var(--text-secondary);
1287
+ }
1288
+ .memory-legend span {
1289
+ display: flex;
1290
+ align-items: center;
1291
+ gap: 6px;
1292
+ }
1293
+ .memory-legend .dot {
1294
+ width: 10px;
1295
+ height: 10px;
1296
+ border-radius: 50%;
1297
+ }
1298
+
1299
+ /* Skills & Tags - Coral themed */
1300
+ .skills-list, .tags-list {
1301
+ display: flex;
1302
+ flex-wrap: wrap;
1303
+ gap: 8px;
1304
+ }
1305
+ .badge {
1306
+ padding: 6px 12px;
1307
+ border-radius: 8px;
1308
+ font-size: 12px;
1309
+ font-family: var(--font-display);
1310
+ font-weight: 600;
1311
+ }
1312
+ .badge-skill { background: rgba(250, 112, 154, 0.12); color: var(--color-1); }
1313
+ .badge-tag { background: rgba(254, 225, 64, 0.15); color: #b89800; }
1314
+
1315
+ /* Requirements - Coral themed */
1316
+ .requirements-list {
1317
+ list-style: none;
1318
+ }
1319
+ .requirements-list li {
1320
+ padding: 12px 0;
1321
+ border-bottom: 1px solid var(--border);
1322
+ display: flex;
1323
+ align-items: center;
1324
+ gap: 10px;
1325
+ font-size: 14px;
1326
+ }
1327
+ .requirements-list li:last-child {
1328
+ border-bottom: none;
1329
+ }
1330
+ .env-var {
1331
+ font-family: var(--font-display);
1332
+ background: linear-gradient(135deg, rgba(250, 112, 154, 0.1), rgba(255, 154, 139, 0.1));
1333
+ padding: 4px 10px;
1334
+ border-radius: 6px;
1335
+ color: var(--color-1);
1336
+ font-size: 12px;
1337
+ font-weight: 500;
1338
+ }
1339
+
1340
+ /* Stats Page - Coral themed */
1341
+ .stats-table {
1342
+ width: 100%;
1343
+ border-collapse: collapse;
1344
+ font-size: 14px;
1345
+ }
1346
+ .stats-table th, .stats-table td {
1347
+ padding: 16px 14px;
1348
+ text-align: left;
1349
+ border-bottom: 1px solid var(--border);
1350
+ }
1351
+ .stats-table th {
1352
+ font-family: var(--font-display);
1353
+ color: var(--text-muted);
1354
+ font-weight: 600;
1355
+ font-size: 11px;
1356
+ text-transform: uppercase;
1357
+ letter-spacing: 0.08em;
1358
+ }
1359
+ .stats-table a {
1360
+ color: var(--color-1);
1361
+ font-family: var(--font-display);
1362
+ font-weight: 500;
1363
+ }
1364
+ .stats-table a:hover {
1365
+ text-decoration: underline;
1366
+ }
1367
+
1368
+ /* How it works - Coral themed */
1369
+ .how-it-works {
1370
+ display: grid;
1371
+ grid-template-columns: repeat(3, 1fr);
1372
+ gap: 32px;
1373
+ margin-bottom: 56px;
1374
+ position: relative;
1375
+ }
1376
+ .how-it-works::before {
1377
+ content: '';
1378
+ position: absolute;
1379
+ top: 36px;
1380
+ left: 16%;
1381
+ right: 16%;
1382
+ height: 2px;
1383
+ background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2));
1384
+ opacity: 0.2;
1385
+ z-index: 0;
1386
+ }
1387
+ .step {
1388
+ text-align: center;
1389
+ position: relative;
1390
+ z-index: 1;
1391
+ }
1392
+ .step-number {
1393
+ width: 52px;
1394
+ height: 52px;
1395
+ background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 100%);
1396
+ color: #ffffff;
1397
+ border-radius: 16px;
1398
+ display: flex;
1399
+ align-items: center;
1400
+ justify-content: center;
1401
+ font-family: var(--font-display);
1402
+ font-size: 20px;
1403
+ font-weight: 700;
1404
+ margin: 0 auto 18px;
1405
+ box-shadow: 0 8px 24px rgba(250, 112, 154, 0.25);
1406
+ transition: all 0.3s ease;
1407
+ }
1408
+ .step:hover .step-number {
1409
+ transform: scale(1.1) rotate(5deg);
1410
+ box-shadow: 0 12px 32px rgba(250, 112, 154, 0.35);
1411
+ }
1412
+ .step h4 {
1413
+ font-family: var(--font-display);
1414
+ font-size: 15px;
1415
+ margin-bottom: 8px;
1416
+ letter-spacing: -0.01em;
1417
+ }
1418
+ .step p {
1419
+ color: var(--text-secondary);
1420
+ font-size: 13px;
1421
+ line-height: 1.6;
1422
+ }
1423
+
1424
+ /* Category filter tabs */
1425
+ .category-filters {
1426
+ display: flex;
1427
+ flex-wrap: wrap;
1428
+ gap: 8px;
1429
+ margin-bottom: 20px;
1430
+ justify-content: center;
1431
+ }
1432
+ .category-tab {
1433
+ padding: 8px 18px;
1434
+ border-radius: 24px;
1435
+ border: 1px solid var(--border);
1436
+ background: var(--bg-card);
1437
+ color: var(--text-secondary);
1438
+ font-size: 13px;
1439
+ font-weight: 500;
1440
+ font-family: var(--font-display);
1441
+ cursor: pointer;
1442
+ transition: all 0.25s ease;
1443
+ }
1444
+ .category-tab:hover {
1445
+ border-color: var(--color-1);
1446
+ color: var(--color-1);
1447
+ background: var(--accent-glow);
1448
+ }
1449
+ .category-tab.active {
1450
+ background: linear-gradient(135deg, var(--color-1), var(--color-3));
1451
+ color: white;
1452
+ border-color: transparent;
1453
+ box-shadow: 0 4px 12px rgba(250, 112, 154, 0.25);
1454
+ }
1455
+ .category-tab .count {
1456
+ display: inline-block;
1457
+ background: rgba(255,255,255,0.2);
1458
+ padding: 1px 7px;
1459
+ border-radius: 10px;
1460
+ font-size: 11px;
1461
+ margin-left: 4px;
1462
+ }
1463
+ .category-tab.active .count {
1464
+ background: rgba(255,255,255,0.3);
1465
+ }
1466
+ .category-tab:not(.active) .count {
1467
+ background: var(--bg-secondary);
1468
+ }
1469
+
1470
+ /* Load more */
1471
+ .load-more-wrap {
1472
+ text-align: center;
1473
+ margin-top: 28px;
1474
+ }
1475
+ .load-more-btn {
1476
+ padding: 12px 36px;
1477
+ border-radius: 12px;
1478
+ border: 2px solid var(--border);
1479
+ background: var(--bg-card);
1480
+ color: var(--text-secondary);
1481
+ font-size: 14px;
1482
+ font-weight: 600;
1483
+ font-family: var(--font-display);
1484
+ cursor: pointer;
1485
+ transition: all 0.3s ease;
1486
+ }
1487
+ .load-more-btn:hover {
1488
+ border-color: var(--color-1);
1489
+ color: var(--color-1);
1490
+ transform: translateY(-2px);
1491
+ box-shadow: 0 8px 24px rgba(250, 112, 154, 0.12);
1492
+ }
1493
+ .load-more-btn:active {
1494
+ transform: translateY(0);
1495
+ }
1496
+ .agent-card.hidden {
1497
+ display: none;
1498
+ }
1499
+
1500
+ /* No results */
1501
+ .no-results {
1502
+ text-align: center;
1503
+ padding: 48px 20px;
1504
+ color: var(--text-muted);
1505
+ display: none;
1506
+ }
1507
+ .no-results.show {
1508
+ display: block;
1509
+ }
1510
+ .no-results-icon {
1511
+ font-size: 48px;
1512
+ margin-bottom: 12px;
1513
+ opacity: 0.5;
1514
+ }
1515
+
1516
+ /* Search - Coral themed */
1517
+ .search-box {
1518
+ display: flex;
1519
+ background: var(--bg-card);
1520
+ border: 2px solid var(--border);
1521
+ border-radius: 14px;
1522
+ padding: 6px;
1523
+ max-width: 520px;
1524
+ margin: 0 auto 36px;
1525
+ transition: all 0.3s ease;
1526
+ }
1527
+ .search-box:focus-within {
1528
+ border-color: var(--color-1);
1529
+ box-shadow: 0 0 0 4px rgba(250, 112, 154, 0.1);
1530
+ }
1531
+ .search-box input {
1532
+ flex: 1;
1533
+ background: transparent;
1534
+ border: none;
1535
+ padding: 12px 16px;
1536
+ font-size: 15px;
1537
+ font-family: var(--font-body);
1538
+ color: var(--text-primary);
1539
+ outline: none;
1540
+ }
1541
+ .search-box input::placeholder {
1542
+ color: var(--text-muted);
1543
+ }
1544
+ .search-box button {
1545
+ background: linear-gradient(135deg, var(--color-1) 0%, var(--color-3) 100%);
1546
+ color: #ffffff;
1547
+ border: none;
1548
+ padding: 12px 24px;
1549
+ border-radius: 10px;
1550
+ font-family: var(--font-display);
1551
+ font-size: 13px;
1552
+ font-weight: 600;
1553
+ cursor: pointer;
1554
+ transition: all 0.25s;
1555
+ }
1556
+ .search-box button:hover {
1557
+ box-shadow: 0 4px 16px rgba(250, 112, 154, 0.3);
1558
+ }
1559
+ .search-box button:active {
1560
+ transform: scale(0.97);
1561
+ }
1562
+
1563
+ /* Empty state - Coral themed */
1564
+ .empty-state {
1565
+ text-align: center;
1566
+ padding: 56px 20px;
1567
+ color: var(--text-muted);
1568
+ }
1569
+ .empty-state h3 {
1570
+ font-family: var(--font-display);
1571
+ font-size: 18px;
1572
+ margin-bottom: 8px;
1573
+ color: var(--text-primary);
1574
+ }
1575
+ .empty-state p {
1576
+ font-size: 14px;
1577
+ }
1578
+ .empty-state code {
1579
+ background: var(--bg-secondary);
1580
+ padding: 4px 10px;
1581
+ border-radius: 6px;
1582
+ font-family: var(--font-display);
1583
+ font-size: 13px;
1584
+ color: var(--color-1);
1585
+ }
1586
+
1587
+ /* Footer - Coral themed */
1588
+ footer {
1589
+ border-top: 1px solid var(--border);
1590
+ padding: 48px 0;
1591
+ margin-top: 80px;
1592
+ background: var(--bg-secondary);
1593
+ position: relative;
1594
+ }
1595
+ footer::before {
1596
+ content: '';
1597
+ position: absolute;
1598
+ top: 0;
1599
+ left: 0;
1600
+ right: 0;
1601
+ height: 3px;
1602
+ background: linear-gradient(90deg, var(--color-1), var(--color-3), var(--color-2), var(--color-1));
1603
+ background-size: 200% auto;
1604
+ animation: gradientShift 4s linear infinite;
1605
+ }
1606
+ .footer-content {
1607
+ display: flex;
1608
+ justify-content: space-between;
1609
+ align-items: center;
1610
+ flex-wrap: wrap;
1611
+ gap: 20px;
1612
+ }
1613
+ .footer-brand {
1614
+ display: flex;
1615
+ align-items: center;
1616
+ gap: 12px;
1617
+ }
1618
+ .footer-brand-icon {
1619
+ width: 36px;
1620
+ height: 36px;
1621
+ display: flex;
1622
+ align-items: center;
1623
+ justify-content: center;
1624
+ font-size: 24px;
1625
+ background: var(--accent-glow);
1626
+ border-radius: 10px;
1627
+ }
1628
+ .footer-brand-text {
1629
+ font-family: var(--font-display);
1630
+ font-weight: 600;
1631
+ font-size: 16px;
1632
+ color: var(--text-primary);
1633
+ }
1634
+ .footer-powered {
1635
+ display: flex;
1636
+ align-items: center;
1637
+ gap: 8px;
1638
+ font-size: 13px;
1639
+ color: var(--text-muted);
1640
+ }
1641
+ .footer-powered a {
1642
+ color: var(--color-1);
1643
+ font-weight: 600;
1644
+ transition: color 0.2s;
1645
+ }
1646
+ .footer-powered a:hover {
1647
+ color: var(--color-3);
1648
+ }
1649
+ .footer-links {
1650
+ display: flex;
1651
+ gap: 24px;
1652
+ }
1653
+ .footer-links a {
1654
+ color: var(--text-secondary);
1655
+ font-size: 13px;
1656
+ font-family: var(--font-display);
1657
+ font-weight: 500;
1658
+ transition: all 0.2s;
1659
+ }
1660
+ .footer-links a:hover {
1661
+ color: var(--color-1);
1662
+ }
1663
+
1664
+ @media (max-width: 768px) {
1665
+ .hero { padding: 48px 16px 40px; }
1666
+ .hero h1 { font-size: clamp(32px, 7vw, 44px); }
1667
+ .hero-subtitle { font-size: 15px; padding: 0 12px; }
1668
+ .hero-stats { gap: 16px; flex-wrap: wrap; }
1669
+ .hero-stat { min-width: 100px; padding: 12px 16px; }
1670
+ .hero-stat-value { font-size: 28px; }
1671
+ .features { grid-template-columns: 1fr; gap: 14px; }
1672
+ .how-it-works { grid-template-columns: 1fr; gap: 24px; }
1673
+ .how-it-works::before { display: none; }
1674
+ .detail-grid { grid-template-columns: repeat(2, 1fr); }
1675
+ .agent-grid { grid-template-columns: 1fr; }
1676
+ .footer-content { flex-direction: column; text-align: center; gap: 20px; }
1677
+
1678
+ /* Mobile navigation */
1679
+ .header-content { flex-wrap: wrap; gap: 12px; }
1680
+ .nav-links {
1681
+ order: 3;
1682
+ width: 100%;
1683
+ justify-content: center;
1684
+ gap: 16px;
1685
+ flex-wrap: wrap;
1686
+ }
1687
+ .nav-links a { font-size: 13px; }
1688
+ .nav-powered { display: none; }
1689
+ .logo { font-size: 18px; }
1690
+ .logo-icon { font-size: 24px; }
1691
+ .logo-tagline { font-size: 10px; }
1692
+ .container { padding: 0 16px; }
1693
+ .detail-header { padding: 24px; }
1694
+ .detail-title { font-size: 26px; }
1695
+ .section-card { padding: 20px; }
1696
+ .search-box { margin: 0 0 28px; }
1697
+ .api-box { padding: 24px; }
1698
+ .api-code { font-size: 12px; padding: 14px 16px; }
1699
+ .stats-table th, .stats-table td { padding: 12px 10px; font-size: 13px; }
1700
+ .step-number { width: 42px; height: 42px; font-size: 16px; }
1701
+ .step h4 { font-size: 14px; }
1702
+ .category-filters { gap: 6px; }
1703
+ .category-tab { padding: 6px 14px; font-size: 12px; }
1704
+ }
1705
+
1706
+ @media (max-width: 480px) {
1707
+ .theme-btn { width: 32px; height: 32px; font-size: 14px; }
1708
+ .hero-stat-value { font-size: 24px; }
1709
+ .hero-stat-label { font-size: 10px; }
1710
+ .hero-stats { gap: 10px; }
1711
+ .hero-stat { min-width: 80px; padding: 10px 12px; }
1712
+ .nav-links { gap: 12px; }
1713
+ .nav-links a { font-size: 12px; }
1714
+ .section-title { font-size: 18px; }
1715
+ .feature-card { padding: 22px 18px; }
1716
+ .feature-icon { font-size: 28px; }
1717
+ .detail-grid { grid-template-columns: 1fr; }
1718
+ }
1719
+ </style>
1720
+ </head>
1721
+ <body>
1722
+ <header>
1723
+ <div class="container header-content">
1724
+ <a href="/" class="logo">
1725
+ <span class="logo-icon">🦀</span>
1726
+ <div>
1727
+ <div>AgentHub</div>
1728
+ <div class="logo-tagline">Crab-powered. Agent-ready.</div>
1729
+ </div>
1730
+ </a>
1731
+ <nav class="nav-links">
1732
+ <a href="/"><span data-i18n="navHome">Home</span></a>
1733
+ <a href="/stats"><span data-i18n="navStats">Stats</span></a>
1734
+ <a href="https://github.com/itshaungmu/AgentHub" target="_blank">GitHub</a>
1735
+ <div class="nav-powered">
1736
+ <span>🦀</span>
1737
+ <span>Powered by</span>
1738
+ <a href="https://github.com/openclaw" target="_blank">OpenClaw</a>
1739
+ </div>
1740
+ <div class="lang-switcher">
1741
+ <button class="lang-btn active" data-lang="en" onclick="setLang('en')">EN</button>
1742
+ <button class="lang-btn" data-lang="zh" onclick="setLang('zh')">中文</button>
1743
+ </div>
1744
+ <button class="theme-btn" onclick="toggleTheme()" aria-label="Switch theme">🌙</button>
1745
+ </nav>
1746
+ </div>
1747
+ </header>
1748
+ <main class="container">${body}</main>
1749
+ <footer>
1750
+ <div class="container footer-content">
1751
+ <div class="footer-brand">
1752
+ <div class="footer-brand-icon">🦀</div>
1753
+ <span class="footer-brand-text">AgentHub</span>
1754
+ </div>
1755
+ <div class="footer-powered">
1756
+ <span>Powered by</span>
1757
+ <a href="https://github.com/openclaw" target="_blank">OpenClaw</a>
1758
+ <span>•</span>
1759
+ <span>Built with ❤️ for AI Agents</span>
1760
+ </div>
1761
+ <div class="footer-links">
1762
+ <a href="https://github.com/openclaw" target="_blank">OpenClaw</a>
1763
+ <a href="https://github.com/itshaungmu/AgentHub" target="_blank">AgentHub</a>
1764
+ </div>
1765
+ </div>
1766
+ </footer>
1767
+ </body>
1768
+ </html>
1769
+ ${langScript}`;
1770
+ }
1771
+
1772
+ export function renderAgentListPage({ query, agents, totalDownloads, apiBase }) {
1773
+ const agentCount = agents.length;
1774
+
1775
+ // Count agents per category
1776
+ const categoryCounts = {};
1777
+ agents.forEach(a => {
1778
+ const cat = a.metadata?.category || 'default';
1779
+ categoryCounts[cat] = (categoryCounts[cat] || 0) + 1;
1780
+ });
1781
+
1782
+ const features = `
1783
+ <div class="features">
1784
+ <div class="feature-card">
1785
+ <div class="feature-icon">📦</div>
1786
+ <div class="feature-title" data-i18n="feature1Title">Ready to Use</div>
1787
+ <div class="feature-desc" data-i18n="feature1Desc">Skip complex configurations, get battle-tested AI Agent setups</div>
1788
+ </div>
1789
+ <div class="feature-card">
1790
+ <div class="feature-icon">⚡</div>
1791
+ <div class="feature-title" data-i18n="feature2Title">Instant Deploy</div>
1792
+ <div class="feature-desc" data-i18n="feature2Desc">One-click install, deploy in minutes, start working immediately</div>
1793
+ </div>
1794
+ <div class="feature-card">
1795
+ <div class="feature-icon">🔄</div>
1796
+ <div class="feature-title" data-i18n="feature3Title">Version Control</div>
1797
+ <div class="feature-desc" data-i18n="feature3Desc">Auto-update pushes, always stay with the latest capabilities</div>
1798
+ </div>
1799
+ </div>
1800
+ `;
1801
+
1802
+ const cards = agents.map(agent => {
1803
+ const tags = agent.metadata?.tags || [];
1804
+ const category = agent.metadata?.category || 'default';
1805
+ const featured = agent.metadata?.featured;
1806
+
1807
+ const tagClass = {
1808
+ 'ops': 'tag-ops',
1809
+ 'engineering': 'tag-engineering',
1810
+ 'content': 'tag-content',
1811
+ 'product': 'tag-product'
1812
+ }[category] || 'tag-default';
1813
+
1814
+ return `
1815
+ <article class="agent-card hidden" data-category="${category}" onclick="window.location='/agents/${agent.slug}'">
1816
+ ${featured ? '<span class="featured-badge">⭐</span>' : ''}
1817
+ <div class="agent-header">
1818
+ <a href="/agents/${agent.slug}" class="agent-name" onclick="event.stopPropagation()">${agent.name || agent.slug}</a>
1819
+ <span class="agent-version">v${agent.version}</span>
1820
+ </div>
1821
+ <p class="agent-desc">${agent.description || 'A powerful AI Agent'}</p>
1822
+ <div class="agent-meta">
1823
+ <span class="agent-tag ${tagClass}">${category}</span>
1824
+ ${tags.slice(0, 2).map(t => `<span class="agent-tag tag-default">${t}</span>`).join('')}
1825
+ </div>
1826
+ <div class="agent-footer">
1827
+ <span class="agent-downloads">
1828
+ <span>⬇️</span> ${agent.downloads || 0} <span data-i18n="downloads">downloads</span>
1829
+ </span>
1830
+ <span class="agent-install" data-i18n="install">Install</span>
1831
+ </div>
1832
+ </article>
1833
+ `;
1834
+ }).join('');
1835
+
1836
+ // Category filter tabs
1837
+ const categoryFilters = `
1838
+ <div class="category-filters">
1839
+ <button class="category-tab active" data-category="all">All<span class="count">${agentCount}</span></button>
1840
+ ${Object.entries(categoryCounts).sort((a, b) => b[1] - a[1]).map(([cat, count]) => {
1841
+ const tagClass = {
1842
+ 'ops': 'tag-ops',
1843
+ 'engineering': 'tag-engineering',
1844
+ 'content': 'tag-content',
1845
+ 'product': 'tag-product'
1846
+ }[cat] || 'tag-default';
1847
+ return `<button class="category-tab" data-category="${cat}">${cat}<span class="count">${count}</span></button>`;
1848
+ }).join('')}
1849
+ </div>
1850
+ `;
1851
+
1852
+ const howItWorks = `
1853
+ <div class="section reveal">
1854
+ <h2 class="section-title" style="text-align: center; margin-bottom: 32px;" data-i18n="howToUse">How to Use</h2>
1855
+ <div class="how-it-works">
1856
+ <div class="step">
1857
+ <div class="step-number">1</div>
1858
+ <h4 data-i18n="step1Title">Browse & Discover</h4>
1859
+ <p data-i18n="step1Desc">Find the Agent that fits your workflow</p>
1860
+ </div>
1861
+ <div class="step">
1862
+ <div class="step-number">2</div>
1863
+ <h4 data-i18n="step2Title">One-Click Install</h4>
1864
+ <p data-i18n="step2Desc">Run the install command, deploy in minutes</p>
1865
+ </div>
1866
+ <div class="step">
1867
+ <div class="step-number">3</div>
1868
+ <h4 data-i18n="step3Title">Start Working</h4>
1869
+ <p data-i18n="step3Desc">Your AI assistant is ready, start delegating tasks</p>
1870
+ </div>
1871
+ </div>
1872
+ </div>
1873
+ `;
1874
+
1875
+ const apiBox = `
1876
+ <div class="api-box reveal">
1877
+ <h3 data-i18n="apiBoxTitle">🤖 AI Auto-Discovery API</h3>
1878
+ <p data-i18n="apiBoxDesc">Let your AI assistant automatically discover and install Agents</p>
1879
+ <div class="api-code" title="Click to copy">
1880
+ <span class="code-text">curl -s https://raw.githubusercontent.com/itshaungmu/AgentHub/main/skills/agenthub-discover/SKILL.md</span>
1881
+ <button class="copy-btn" title="Copy">📋</button>
1882
+ </div>
1883
+ </div>
1884
+ `;
1885
+
1886
+ return page(
1887
+ "AgentHub - AI Agent Open Source Community",
1888
+ `
1889
+ <section class="hero">
1890
+ <h1 data-i18n="heroTitle">AgentHub</h1>
1891
+ <p class="hero-subtitle" data-i18n="heroSubtitle">The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.</p>
1892
+ <div class="hero-stats">
1893
+ <div class="hero-stat">
1894
+ <div class="hero-stat-value">${agentCount}</div>
1895
+ <div class="hero-stat-label" data-i18n="statAgents">Available Agents</div>
1896
+ </div>
1897
+ <div class="hero-stat">
1898
+ <div class="hero-stat-value">${totalDownloads || 0}</div>
1899
+ <div class="hero-stat-label" data-i18n="statDownloads">Total Downloads</div>
1900
+ </div>
1901
+ <div class="hero-stat">
1902
+ <div class="hero-stat-value">100%</div>
1903
+ <div class="hero-stat-label" data-i18n="statOpenSource">Open Source</div>
1904
+ </div>
1905
+ </div>
1906
+ ${features}
1907
+ </section>
1908
+
1909
+ ${apiBox}
1910
+
1911
+ <section class="section">
1912
+ <div class="section-header">
1913
+ <h2 class="section-title" data-i18n="sectionHotAgents">Hot Agents</h2>
1914
+ <a href="/stats" class="section-link" data-i18n="sectionViewAll">View All →</a>
1915
+ </div>
1916
+ <form class="search-box" method="get" action="/">
1917
+ <input id="agent-search" type="search" name="q" value="${query ?? ""}" data-i18n-placeholder="searchPlaceholder" placeholder="Search Agents, skills, tags..." />
1918
+ <button type="submit" data-i18n="searchButton">Search</button>
1919
+ </form>
1920
+ ${categoryFilters}
1921
+ <div class="no-results">
1922
+ <div class="no-results-icon">🔍</div>
1923
+ <h3>No matching agents found</h3>
1924
+ <p>Try adjusting your search or filter</p>
1925
+ </div>
1926
+ <div class="agent-grid">
1927
+ ${cards || `<div class="empty-state"><h3 data-i18n="noAgents">No Agents yet</h3><p data-i18n="noAgentsHint">Use <code>agenthub pack</code> to package your first Agent!</p></div>`}
1928
+ </div>
1929
+ <div class="load-more-wrap">
1930
+ <button id="load-more-btn" class="load-more-btn">Load More Agents</button>
1931
+ </div>
1932
+ </section>
1933
+
1934
+ ${howItWorks}
1935
+ `,
1936
+ {
1937
+ description: "AgentHub - The Open Source Marketplace for AI Agents. Package and upload your Agent's full capabilities in one command, download and gain those powers with one click.",
1938
+ url: "https://agenthub.cyou/"
1939
+ }
1940
+ );
1941
+ }
1942
+
1943
+ export function renderAgentDetailPage(manifest) {
1944
+ const memoryInfo = manifest.includes?.memory || {};
1945
+ const runtimeInfo = manifest.runtime || {};
1946
+ const skills = manifest.includes?.skills || [];
1947
+ const tags = manifest.metadata?.tags || [];
1948
+ const requirements = manifest.requirements || {};
1949
+ const persona = manifest.persona || {};
1950
+
1951
+ const totalMemory = memoryInfo.count || 0;
1952
+ const publicRatio = totalMemory > 0 ? (memoryInfo.public || 0) / totalMemory : 0;
1953
+ const portableRatio = totalMemory > 0 ? (memoryInfo.portable || 0) / totalMemory : 0;
1954
+ const privateRatio = totalMemory > 0 ? (memoryInfo.private || 0) / totalMemory : 0;
1955
+
1956
+ const skillsHtml = skills.length > 0
1957
+ ? skills.map(s => `<span class="badge badge-skill">${s}</span>`).join("")
1958
+ : '<span style="color: var(--text-muted)">None</span>';
1959
+
1960
+ const tagsHtml = tags.length > 0
1961
+ ? tags.map(t => `<span class="badge badge-tag">${t}</span>`).join("")
1962
+ : '<span style="color: var(--text-muted)">None</span>';
1963
+
1964
+ const envVars = requirements.env || [];
1965
+ const requirementsHtml = [];
1966
+ if (envVars.length > 0) {
1967
+ requirementsHtml.push('<li>🔐 <span data-i18n="requirementsEnv">Environment variables required:</span></li>');
1968
+ for (const env of envVars) {
1969
+ requirementsHtml.push(`<li style="padding-left: 20px;"><span class="env-var">${env}</span></li>`);
1970
+ }
1971
+ }
1972
+ if (requirements.model) {
1973
+ requirementsHtml.push(`<li>🤖 <span data-i18n="requirementsModel">Recommended model:</span> <span class="env-var">${requirements.model}</span></li>`);
1974
+ }
1975
+ if (requirements.openclaw) {
1976
+ requirementsHtml.push(`<li>⚡ <span data-i18n="requirementsRuntime">Runtime version:</span> OpenClaw ${requirements.openclaw}</li>`);
1977
+ }
1978
+
1979
+ return page(
1980
+ `${manifest.name || manifest.slug} - AgentHub`,
1981
+ `
1982
+ <a href="/" class="back-link" data-i18n="backToHome">← Back to Home</a>
1983
+
1984
+ <div class="detail-header">
1985
+ <h1 class="detail-title">${manifest.name || manifest.slug}</h1>
1986
+ <p class="detail-desc">${manifest.description || 'A powerful AI Agent'}</p>
1987
+ <div class="detail-grid">
1988
+ <div class="detail-item">
1989
+ <div class="detail-label" data-i18n="detailVersion">Version</div>
1990
+ <div class="detail-value">${manifest.version}</div>
1991
+ </div>
1992
+ <div class="detail-item">
1993
+ <div class="detail-label" data-i18n="detailRuntime">Runtime</div>
1994
+ <div class="detail-value">${runtimeInfo.type || 'OpenClaw'}</div>
1995
+ </div>
1996
+ <div class="detail-item">
1997
+ <div class="detail-label" data-i18n="detailDownloads">Downloads</div>
1998
+ <div class="detail-value">⬇️ ${manifest.downloads || 0}</div>
1999
+ </div>
2000
+ <div class="detail-item">
2001
+ <div class="detail-label" data-i18n="detailAuthor">Author</div>
2002
+ <div class="detail-value">${manifest.author || 'Anonymous'}</div>
2003
+ </div>
2004
+ </div>
2005
+ <div class="detail-install" title="Click to copy">
2006
+ <span class="code-text">npx @zshuangmu/agenthub install ${manifest.slug} --target-workspace ./my-workspace</span>
2007
+ <button class="copy-btn" title="Copy">📋</button>
2008
+ </div>
2009
+ </div>
2010
+
2011
+ ${persona.summary ? `
2012
+ <div class="section-card">
2013
+ <h3 data-i18n="personaTitle">🎭 Personality</h3>
2014
+ <p style="color: var(--text-secondary); line-height: 1.8;">${persona.summary}</p>
2015
+ ${persona.traits?.length > 0 ? `<p style="margin-top: 12px;"><strong data-i18n="personaTraits">Traits:</strong> ${persona.traits.join(', ')}</p>` : ''}
2016
+ ${persona.expertise?.length > 0 ? `<p><strong data-i18n="personaExpertise">Expertise:</strong> ${persona.expertise.join(', ')}</p>` : ''}
2017
+ </div>
2018
+ ` : ''}
2019
+
2020
+ <div class="section-card">
2021
+ <h3 data-i18n="memoryTitle">🧠 Memory Config</h3>
2022
+ ${totalMemory > 0 ? `
2023
+ <div class="memory-bars">
2024
+ <div class="memory-bar public" style="flex: ${publicRatio}" title="Public"></div>
2025
+ <div class="memory-bar portable" style="flex: ${portableRatio}" title="Portable"></div>
2026
+ ${privateRatio > 0 ? `<div class="memory-bar private" style="flex: ${privateRatio}" title="Private"></div>` : ''}
2027
+ </div>
2028
+ <div class="memory-legend">
2029
+ <span><span class="dot" style="background: var(--accent)"></span> <span data-i18n="memoryPublic">Public</span>: ${memoryInfo.public || 0}</span>
2030
+ <span><span class="dot" style="background: var(--accent-light)"></span> <span data-i18n="memoryPortable">Portable</span>: ${memoryInfo.portable || 0}</span>
2031
+ ${memoryInfo.private > 0 ? `<span><span class="dot" style="background: var(--tag-content)"></span> <span data-i18n="memoryPrivate">Private</span>: ${memoryInfo.private || 0}</span>` : ''}
2032
+ </div>
2033
+ ` : '<p style="color: var(--text-muted);" data-i18n="memoryNoData">No memory data</p>'}
2034
+ </div>
2035
+
2036
+ <div class="section-card">
2037
+ <h3 data-i18n="skillsTitle">🔧 Skills</h3>
2038
+ <div class="skills-list">${skillsHtml}</div>
2039
+ </div>
2040
+
2041
+ <div class="section-card">
2042
+ <h3 data-i18n="tagsTitle">🏷️ Tags</h3>
2043
+ <div class="tags-list">${tagsHtml}</div>
2044
+ </div>
2045
+
2046
+ <div class="section-card">
2047
+ <h3 data-i18n="requirementsTitle">⚙️ System Requirements</h3>
2048
+ ${requirementsHtml.length > 0 ? `<ul class="requirements-list">${requirementsHtml.join('')}</ul>` : '<p style="color: var(--text-muted);" data-i18n="requirementsNone">No special requirements</p>'}
2049
+ </div>
2050
+
2051
+ <div class="section-card">
2052
+ <h3 data-i18n="installMethodTitle">📥 Installation</h3>
2053
+ <p style="color: var(--text-secondary); margin-bottom: 16px;" data-i18n="installMethodDesc">Run in your workspace:</p>
2054
+ <div class="install-methods">
2055
+ <div class="install-box primary">
2056
+ <span class="badge-new">推荐</span>
2057
+ <div class="install-label">npx (无需预安装)</div>
2058
+ <div class="detail-install" title="Click to copy">
2059
+ <span class="code-text">npx @zshuangmu/agenthub install ${manifest.slug} --target-workspace ./my-workspace</span>
2060
+ <button class="copy-btn" title="Copy">📋</button>
2061
+ </div>
2062
+ </div>
2063
+ <div class="install-box">
2064
+ <div class="install-label">已有 CLI</div>
2065
+ <div class="detail-install" title="Click to copy">
2066
+ <span class="code-text">agenthub install ${manifest.slug}@${manifest.version} --target-workspace ./my-workspace</span>
2067
+ <button class="copy-btn" title="Copy">📋</button>
2068
+ </div>
2069
+ </div>
2070
+ </div>
2071
+ </div>
2072
+ `,
2073
+ {
2074
+ description: manifest.description || `${manifest.name || manifest.slug} - AI Agent on AgentHub. ${manifest.persona?.summary || ''}`.slice(0, 160),
2075
+ url: `https://agenthub.cyou/agents/${manifest.slug}`,
2076
+ type: "article"
2077
+ }
2078
+ );
2079
+ }
2080
+
2081
+ export function renderStatsPage(statsData) {
2082
+ const { stats, ranking, recent } = statsData;
2083
+
2084
+ const rankingHtml = ranking.map((item, index) => `
2085
+ <tr>
2086
+ <td>${index + 1}</td>
2087
+ <td><a href="/agents/${item.slug}">${item.slug}</a></td>
2088
+ <td><strong>${item.downloads}</strong></td>
2089
+ <td style="color: var(--text-muted)">${item.lastDownload || '-'}</td>
2090
+ </tr>
2091
+ `).join('');
2092
+
2093
+ const recentHtml = recent.map(item => `
2094
+ <tr>
2095
+ <td><a href="/agents/${item.slug}">${item.slug}</a></td>
2096
+ <td style="color: var(--text-muted)">${item.installedAt || '-'}</td>
2097
+ <td><code style="color: var(--accent)">${item.targetWorkspace || '-'}</code></td>
2098
+ </tr>
2099
+ `).join('');
2100
+
2101
+ return page(
2102
+ "Statistics Center - AgentHub",
2103
+ `
2104
+ <a href="/" class="back-link" data-i18n="backToHome">← Back to Home</a>
2105
+
2106
+ <div class="detail-header">
2107
+ <h1 class="detail-title" data-i18n="statsHeader">📊 Statistics Center</h1>
2108
+ <p class="detail-desc" data-i18n="statsDesc">AgentHub download statistics and data analysis</p>
2109
+ <div class="detail-grid">
2110
+ <div class="detail-item">
2111
+ <div class="detail-label" data-i18n="statsTotalAgents">Agent Count</div>
2112
+ <div class="detail-value">${stats.totalAgents}</div>
2113
+ </div>
2114
+ <div class="detail-item">
2115
+ <div class="detail-label" data-i18n="statsTotalDownloads">Total Downloads</div>
2116
+ <div class="detail-value">⬇️ ${stats.totalDownloads}</div>
2117
+ </div>
2118
+ <div class="detail-item">
2119
+ <div class="detail-label" data-i18n="statsTotalLogs">Download Logs</div>
2120
+ <div class="detail-value">${stats.totalLogs}</div>
2121
+ </div>
2122
+ </div>
2123
+ </div>
2124
+
2125
+ <div class="section-card">
2126
+ <h3 data-i18n="rankingTitle">🏆 Download Ranking</h3>
2127
+ <table class="stats-table">
2128
+ <thead>
2129
+ <tr>
2130
+ <th data-i18n="rankingRank">Rank</th>
2131
+ <th data-i18n="rankingAgent">Agent</th>
2132
+ <th data-i18n="rankingDownloads">Downloads</th>
2133
+ <th data-i18n="rankingLastDownload">Last Download</th>
2134
+ </tr>
2135
+ </thead>
2136
+ <tbody>
2137
+ ${rankingHtml || `<tr><td colspan="4" style="text-align: center; padding: 20px; color: var(--text-muted);" data-i18n="noData">No data</td></tr>`}
2138
+ </tbody>
2139
+ </table>
2140
+ </div>
2141
+
2142
+ <div class="section-card">
2143
+ <h3 data-i18n="recentTitle">📋 Recent Downloads</h3>
2144
+ <table class="stats-table">
2145
+ <thead>
2146
+ <tr>
2147
+ <th data-i18n="recentAgent">Agent</th>
2148
+ <th data-i18n="recentTime">Time</th>
2149
+ <th data-i18n="recentTarget">Target Path</th>
2150
+ </tr>
2151
+ </thead>
2152
+ <tbody>
2153
+ ${recentHtml || `<tr><td colspan="3" style="text-align: center; padding: 20px; color: var(--text-muted);" data-i18n="noData">No data</td></tr>`}
2154
+ </tbody>
2155
+ </table>
2156
+ </div>
2157
+ `,
2158
+ {
2159
+ description: "AgentHub Statistics Center - View download rankings, recent activity, and platform analytics for AI Agents.",
2160
+ url: "https://agenthub.cyou/stats"
2161
+ }
2162
+ );
2163
+ }