Files
CLI-Anything/docs/hub/index-modern.html
T
2026-06-12 09:19:21 +00:00

2963 lines
97 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CLI-Anything Hub Atelier</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,700&amp;family=IBM+Plex+Sans:wght@400;500;600;700&amp;family=IBM+Plex+Mono:wght@400;500;600&amp;display=swap" rel="stylesheet">
<style>
:root {
--bg: #0d1016;
--bg-elevated: rgba(20, 25, 35, 0.9);
--panel: rgba(17, 22, 30, 0.78);
--panel-strong: rgba(24, 31, 43, 0.92);
--panel-soft: rgba(22, 28, 39, 0.62);
--border: rgba(173, 188, 214, 0.16);
--border-strong: rgba(219, 228, 245, 0.22);
--text: #f5f2ea;
--text-secondary: #b8c2d6;
--text-tertiary: #8190ab;
--ink: #08101c;
--accent: #5da8ff;
--accent-soft: rgba(93, 168, 255, 0.16);
--accent-glow: rgba(93, 168, 255, 0.24);
--amber: #f1b36b;
--amber-soft: rgba(241, 179, 107, 0.16);
--amber-glow: rgba(241, 179, 107, 0.24);
--green: #78d8aa;
--green-soft: rgba(120, 216, 170, 0.16);
--shadow-lg: 0 32px 80px rgba(0, 0, 0, 0.38);
--shadow-md: 0 18px 44px rgba(0, 0, 0, 0.25);
--radius-xl: 28px;
--radius-lg: 22px;
--radius-md: 16px;
--radius-sm: 12px;
--page-width: 1240px;
--deck-peek: clamp(44px, 7vw, 90px);
}
[data-theme="light"] {
--bg: #f2ede4;
--bg-elevated: rgba(250, 247, 241, 0.86);
--panel: rgba(255, 252, 245, 0.84);
--panel-strong: rgba(255, 250, 241, 0.95);
--panel-soft: rgba(246, 240, 229, 0.7);
--border: rgba(55, 63, 78, 0.12);
--border-strong: rgba(39, 45, 56, 0.18);
--text: #141a24;
--text-secondary: #465166;
--text-tertiary: #69758a;
--ink: #f7f1e8;
--accent: #1c65b8;
--accent-soft: rgba(28, 101, 184, 0.12);
--accent-glow: rgba(28, 101, 184, 0.18);
--amber: #a96419;
--amber-soft: rgba(169, 100, 25, 0.12);
--amber-glow: rgba(169, 100, 25, 0.16);
--green: #157c59;
--green-soft: rgba(21, 124, 89, 0.12);
--shadow-lg: 0 30px 80px rgba(61, 52, 38, 0.12);
--shadow-md: 0 16px 36px rgba(61, 52, 38, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
min-height: 100vh;
font-family: 'IBM Plex Sans', sans-serif;
color: var(--text);
background:
radial-gradient(circle at top left, rgba(93, 168, 255, 0.18), transparent 30%),
radial-gradient(circle at top right, rgba(241, 179, 107, 0.12), transparent 28%),
linear-gradient(180deg, #0d1016 0%, #0a0e15 40%, #0f131b 100%);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
[data-theme="light"] body {
background:
radial-gradient(circle at top left, rgba(28, 101, 184, 0.14), transparent 34%),
radial-gradient(circle at top right, rgba(169, 100, 25, 0.1), transparent 26%),
linear-gradient(180deg, #f2ede4 0%, #f6f2ea 42%, #ece5d8 100%);
}
body::before,
body::after {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
z-index: -2;
}
body::before {
background:
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
background-size: 36px 36px;
mask-image: linear-gradient(180deg, rgba(255,255,255,0.7), transparent 85%);
opacity: 0.42;
}
[data-theme="light"] body::before {
background:
linear-gradient(rgba(28, 34, 46, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(28, 34, 46, 0.05) 1px, transparent 1px);
opacity: 0.45;
}
body::after {
background-image:
radial-gradient(circle at 20% 20%, rgba(255,255,255,0.06) 0.7px, transparent 0.7px),
radial-gradient(circle at 80% 65%, rgba(255,255,255,0.05) 0.7px, transparent 0.7px);
background-size: 18px 18px, 22px 22px;
opacity: 0.18;
mix-blend-mode: soft-light;
}
a {
color: inherit;
}
button,
input {
font: inherit;
}
.page-shell {
position: relative;
padding-bottom: 4rem;
}
.page-shell::before {
content: '';
position: absolute;
top: 7rem;
left: 50%;
transform: translateX(-50%);
width: min(1320px, calc(100vw - 32px));
height: 820px;
border-radius: 40px;
background:
radial-gradient(circle at 14% 18%, rgba(93, 168, 255, 0.18), transparent 26%),
radial-gradient(circle at 84% 30%, rgba(241, 179, 107, 0.16), transparent 24%),
linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255,255,255,0));
filter: blur(6px);
pointer-events: none;
z-index: -1;
}
.nav {
width: min(var(--page-width), calc(100vw - 32px));
margin: 0 auto;
padding: 1.2rem 0 1rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
position: relative;
z-index: 2;
animation: slide-up 0.7s ease both;
}
.nav-brand {
display: inline-flex;
align-items: center;
gap: 0.9rem;
text-decoration: none;
}
.nav-mark {
width: 44px;
height: 44px;
border-radius: 14px;
display: inline-flex;
align-items: center;
justify-content: center;
background:
linear-gradient(145deg, rgba(93, 168, 255, 0.3), rgba(241, 179, 107, 0.18)),
var(--panel-strong);
border: 1px solid var(--border-strong);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.1), var(--shadow-md);
color: var(--text);
font-family: 'Fraunces', serif;
font-size: 1.1rem;
letter-spacing: 0.02em;
}
.nav-copy {
display: flex;
flex-direction: column;
gap: 0.08rem;
}
.nav-copy strong {
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.03em;
}
.nav-copy span {
color: var(--text-tertiary);
font-size: 0.78rem;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.nav-links {
display: flex;
align-items: center;
gap: 0.55rem;
flex-wrap: wrap;
justify-content: flex-end;
}
.nav-link,
.theme-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.45rem;
min-height: 42px;
padding: 0.75rem 1rem;
border-radius: 999px;
border: 1px solid var(--border);
background: var(--panel);
color: var(--text-secondary);
text-decoration: none;
backdrop-filter: blur(14px);
transition: transform 0.24s ease, border-color 0.24s ease, color 0.24s ease, background 0.24s ease, box-shadow 0.24s ease;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}
.nav-link:hover,
.theme-toggle:hover {
transform: translateY(-1px);
color: var(--text);
border-color: var(--border-strong);
background: var(--panel-strong);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.14);
}
.nav-link svg,
.theme-toggle svg {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.nav-link-stars {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.9rem;
padding: 0.14rem 0.52rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.1);
color: var(--text);
font-size: 0.73rem;
font-variant-numeric: tabular-nums;
line-height: 1.1;
}
.theme-toggle {
width: 42px;
padding: 0;
cursor: pointer;
}
.theme-toggle .icon-moon {
display: none;
}
[data-theme="light"] .theme-toggle .icon-moon {
display: block;
}
[data-theme="light"] .theme-toggle .icon-sun {
display: none;
}
.hero {
width: min(var(--page-width), calc(100vw - 32px));
margin: 0 auto;
padding: 2rem 0 2.4rem;
display: grid;
grid-template-columns: minmax(0, 1.18fr) minmax(320px, 0.82fr);
gap: 1.4rem;
align-items: stretch;
}
.hero-main,
.hero-rail {
position: relative;
background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.02));
border: 1px solid var(--border);
border-radius: var(--radius-xl);
overflow: hidden;
backdrop-filter: blur(20px);
box-shadow: var(--shadow-lg);
animation: slide-up 0.7s ease both;
}
.hero-main {
padding: 2rem;
}
.hero-main::before,
.hero-rail::before {
content: '';
position: absolute;
inset: 0;
background:
linear-gradient(140deg, rgba(93, 168, 255, 0.1), transparent 34%),
linear-gradient(320deg, rgba(241, 179, 107, 0.1), transparent 34%);
pointer-events: none;
}
.hero-kicker {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.45rem 0.8rem;
border-radius: 999px;
border: 1px solid rgba(93, 168, 255, 0.26);
background: rgba(93, 168, 255, 0.1);
color: var(--text-secondary);
font-size: 0.8rem;
letter-spacing: 0.16em;
text-transform: uppercase;
margin-bottom: 1rem;
}
.hero-kicker::before {
content: '';
width: 0.52rem;
height: 0.52rem;
border-radius: 999px;
background: linear-gradient(135deg, var(--accent), #b9dbff);
box-shadow: 0 0 0 5px rgba(93, 168, 255, 0.12);
}
.hero h1 {
font-family: 'Fraunces', serif;
font-size: clamp(3rem, 5.8vw, 5.5rem);
line-height: 0.94;
letter-spacing: -0.06em;
max-width: 9ch;
margin-bottom: 1.1rem;
}
.hero h1 em {
font-style: normal;
color: var(--accent);
}
.hero h1 span {
color: #d8cbb0;
}
[data-theme="light"] .hero h1 span {
color: #5e5241;
}
.hero-lead {
max-width: 62ch;
font-size: 1.06rem;
color: var(--text-secondary);
margin-bottom: 1.5rem;
}
.hero-lead strong {
color: var(--text);
}
.hero-actions {
display: flex;
gap: 0.8rem;
flex-wrap: wrap;
margin-bottom: 1.3rem;
}
.btn-primary,
.btn-secondary {
display: inline-flex;
align-items: center;
gap: 0.55rem;
padding: 0.88rem 1.18rem;
border-radius: 999px;
text-decoration: none;
font-weight: 600;
transition: transform 0.24s ease, box-shadow 0.24s ease, border-color 0.24s ease, background 0.24s ease, color 0.24s ease;
}
.btn-primary {
color: var(--ink);
background: linear-gradient(135deg, #e7f2ff, #f8d4a2);
box-shadow: 0 18px 34px rgba(31, 44, 64, 0.2);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 22px 42px rgba(31, 44, 64, 0.26);
}
.btn-secondary {
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
color: var(--text-secondary);
}
.btn-secondary:hover {
transform: translateY(-2px);
color: var(--text);
border-color: var(--border-strong);
background: rgba(255,255,255,0.06);
}
.btn-secondary svg {
width: 16px;
height: 16px;
}
.hero-notes {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.8rem;
margin-top: 1.2rem;
}
.hero-note {
padding: 1rem 1rem 0.95rem;
border-radius: var(--radius-md);
border: 1px solid var(--border);
background: rgba(255,255,255,0.025);
}
.hero-note strong {
display: block;
margin-bottom: 0.26rem;
font-size: 0.84rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--text);
}
.hero-note span {
color: var(--text-secondary);
font-size: 0.92rem;
}
.hero-rail {
padding: 1.3rem;
display: grid;
gap: 1rem;
animation-delay: 0.08s;
}
.rail-panel {
position: relative;
border-radius: var(--radius-lg);
border: 1px solid var(--border);
background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.02));
padding: 1.15rem;
overflow: hidden;
}
.rail-panel::before {
content: '';
position: absolute;
inset: auto 0 0 0;
height: 3px;
background: linear-gradient(90deg, var(--accent), transparent 72%);
opacity: 0.8;
}
.rail-panel--public::before {
background: linear-gradient(90deg, var(--amber), transparent 72%);
}
.rail-panel h3 {
font-size: 1rem;
margin-bottom: 0.28rem;
}
.rail-panel p {
color: var(--text-secondary);
font-size: 0.92rem;
margin-bottom: 0.9rem;
}
.install-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 0.65rem;
align-items: center;
padding: 0.85rem 0.95rem;
border-radius: var(--radius-sm);
border: 1px solid var(--border);
background: rgba(0,0,0,0.12);
margin-bottom: 0.65rem;
}
[data-theme="light"] .install-row {
background: rgba(255,255,255,0.52);
}
.chip-label {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 78px;
padding: 0.35rem 0.55rem;
border-radius: 999px;
background: var(--accent-soft);
color: var(--accent);
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.rail-panel--public .chip-label {
background: var(--amber-soft);
color: var(--amber);
}
.install-row code {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.78rem;
color: var(--text-secondary);
}
.copy-btn,
.card-copy-btn {
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
background: rgba(255,255,255,0.04);
color: var(--text);
border-radius: 999px;
padding: 0.52rem 0.9rem;
cursor: pointer;
transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}
.copy-btn:hover,
.card-copy-btn:hover {
transform: translateY(-1px);
border-color: var(--border-strong);
background: rgba(255,255,255,0.08);
}
.hero-prompt {
padding: 0.9rem 1rem;
border-radius: var(--radius-sm);
border: 1px dashed rgba(93, 168, 255, 0.28);
background: rgba(93, 168, 255, 0.08);
color: var(--text-secondary);
font-size: 0.9rem;
}
.hero-prompt strong {
color: var(--text);
}
.hero-prompt em {
color: #bddcff;
font-style: normal;
}
[data-theme="light"] .hero-prompt em {
color: var(--accent);
}
.cmd-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.65rem;
}
.cmd-item {
padding: 0.86rem 0.9rem;
border-radius: var(--radius-sm);
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
min-width: 0;
}
.cmd-name {
display: block;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.78rem;
color: var(--green);
margin-bottom: 0.22rem;
}
.cmd-desc {
display: block;
color: var(--text-secondary);
font-size: 0.85rem;
}
.stats {
width: min(var(--page-width), calc(100vw - 32px));
margin: 0 auto 1rem;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 0.9rem;
animation: slide-up 0.78s ease both;
animation-delay: 0.12s;
}
.stat {
padding: 1rem 1.05rem;
border-radius: var(--radius-lg);
border: 1px solid var(--border);
background: var(--panel);
backdrop-filter: blur(16px);
box-shadow: var(--shadow-md);
}
.stat-num {
font-family: 'Fraunces', serif;
font-size: clamp(1.9rem, 3vw, 2.6rem);
letter-spacing: -0.06em;
margin-bottom: 0.15rem;
}
.stat-label {
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.12em;
font-size: 0.72rem;
}
.deck-nav {
width: min(var(--page-width), calc(100vw - 32px));
margin: 0 auto 1rem;
padding: 0.8rem;
border-radius: var(--radius-xl);
border: 1px solid var(--border);
background: var(--panel);
backdrop-filter: blur(20px);
display: flex;
align-items: center;
gap: 0.8rem;
box-shadow: var(--shadow-md);
animation: slide-up 0.84s ease both;
animation-delay: 0.16s;
}
.deck-tab {
position: relative;
flex: 1;
min-width: 0;
padding: 1rem 1.1rem;
border-radius: 20px;
border: 1px solid transparent;
background: transparent;
color: var(--text-tertiary);
cursor: pointer;
text-align: left;
transition: transform 0.24s ease, border-color 0.24s ease, background 0.24s ease, color 0.24s ease, box-shadow 0.24s ease;
}
.deck-tab:hover {
color: var(--text-secondary);
background: rgba(255,255,255,0.03);
}
.deck-tab.active {
color: var(--text);
border-color: rgba(93, 168, 255, 0.22);
background:
linear-gradient(135deg, rgba(93, 168, 255, 0.14), rgba(255,255,255,0.04)),
rgba(255,255,255,0.02);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}
.deck-tab.deck-tab--public.active {
border-color: rgba(241, 179, 107, 0.22);
background:
linear-gradient(135deg, rgba(241, 179, 107, 0.14), rgba(255,255,255,0.04)),
rgba(255,255,255,0.02);
}
.deck-tab-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
margin-bottom: 0.24rem;
}
.deck-tab-title {
font-weight: 700;
letter-spacing: -0.02em;
font-size: 1rem;
}
.deck-count {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.1rem;
padding: 0.2rem 0.48rem;
border-radius: 999px;
font-size: 0.75rem;
background: rgba(255,255,255,0.08);
color: var(--text);
}
.deck-tab-subtitle {
color: var(--text-secondary);
font-size: 0.86rem;
line-height: 1.45;
display: block;
}
.deck-separator {
width: 1px;
align-self: stretch;
background: linear-gradient(180deg, transparent, var(--border), transparent);
}
.deck-arrow-btn {
display: inline-flex;
align-items: center;
gap: 0.55rem;
padding: 1rem 1.05rem;
border-radius: 20px;
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
color: var(--text-secondary);
cursor: pointer;
white-space: nowrap;
transition: transform 0.24s ease, border-color 0.24s ease, background 0.24s ease, color 0.24s ease;
}
.deck-arrow-btn:hover {
transform: translateY(-1px);
color: var(--text);
border-color: var(--border-strong);
background: rgba(255,255,255,0.08);
}
.deck-arrow-btn svg {
width: 16px;
height: 16px;
transition: transform 0.24s ease;
}
.deck-arrow-btn:hover svg {
transform: translateX(3px);
}
.deck-arrow-btn--back:hover svg {
transform: translateX(-3px);
}
.deck-stage {
width: min(var(--page-width), calc(100vw - 32px));
margin: 0 auto;
--deck-peek: clamp(44px, 7vw, 90px);
animation: slide-up 0.9s ease both;
animation-delay: 0.2s;
position: relative;
}
.deck-viewport {
--deck-panel-width: calc(100% - var(--deck-peek));
width: calc(100% + var(--deck-peek));
margin-right: calc(var(--deck-peek) * -1);
position: relative;
overflow: hidden;
isolation: isolate;
}
.deck-track {
display: flex;
width: max-content;
transition: transform 0.48s cubic-bezier(0.2, 0.9, 0.2, 1);
will-change: transform;
}
.deck-panel {
width: var(--deck-panel-width);
min-width: var(--deck-panel-width);
flex-shrink: 0;
border-radius: calc(var(--radius-xl) + 4px);
border: 1px solid var(--border);
background: var(--panel);
box-shadow: var(--shadow-lg);
backdrop-filter: blur(22px);
overflow: hidden;
position: relative;
}
.deck-panel::before {
content: attr(data-peek-label);
position: absolute;
top: 1.3rem;
right: 1.4rem;
color: rgba(255,255,255,0.06);
font-size: clamp(2rem, 4vw, 4rem);
font-weight: 700;
letter-spacing: -0.05em;
pointer-events: none;
}
[data-theme="light"] .deck-panel::before {
color: rgba(20, 26, 36, 0.06);
}
.deck-panel::after {
content: '';
position: absolute;
inset: 0;
opacity: 0;
pointer-events: none;
transition: opacity 0.28s ease;
z-index: 3;
}
.deck-panel--public {
box-shadow:
inset 1px 0 0 rgba(241, 179, 107, 0.18),
var(--shadow-lg);
}
.deck-track[data-active="harness"] .deck-panel--public::after {
background: linear-gradient(90deg, rgba(10, 14, 20, 0.56) 0%, rgba(10, 14, 20, 0.28) 48%, rgba(10, 14, 20, 0.05) 100%);
opacity: 1;
}
.deck-track[data-active="public"] .deck-panel--harness::after {
background: linear-gradient(270deg, rgba(10, 14, 20, 0.56) 0%, rgba(10, 14, 20, 0.28) 48%, rgba(10, 14, 20, 0.05) 100%);
opacity: 1;
}
[data-theme="light"] .deck-track[data-active="harness"] .deck-panel--public::after {
background: linear-gradient(90deg, rgba(248, 243, 234, 0.72) 0%, rgba(248, 243, 234, 0.36) 48%, rgba(248, 243, 234, 0.08) 100%);
}
[data-theme="light"] .deck-track[data-active="public"] .deck-panel--harness::after {
background: linear-gradient(270deg, rgba(248, 243, 234, 0.72) 0%, rgba(248, 243, 234, 0.36) 48%, rgba(248, 243, 234, 0.08) 100%);
}
.toolbar {
position: sticky;
top: 16px;
z-index: 6;
margin: 1.15rem;
padding: 0.75rem;
border-radius: var(--radius-lg);
border: 1px solid var(--border);
background: linear-gradient(180deg, rgba(14, 18, 26, 0.94), rgba(20, 26, 36, 0.84));
backdrop-filter: blur(22px);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.18);
}
[data-theme="light"] .toolbar {
background: linear-gradient(180deg, rgba(255, 251, 244, 0.96), rgba(247, 240, 231, 0.92));
}
.toolbar-top {
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
gap: 0.85rem;
align-items: center;
}
.search-shell,
.sort-shell,
.toolbar-status {
border-radius: var(--radius-md);
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
min-height: 64px;
}
.search-shell {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.95rem 1rem;
}
.search-shell svg {
width: 18px;
height: 18px;
color: var(--text-tertiary);
flex-shrink: 0;
}
.search-meta,
.sort-meta {
display: flex;
flex-direction: column;
gap: 0.12rem;
min-width: 0;
}
.control-kicker {
color: var(--text-tertiary);
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.12em;
}
.search {
width: 100%;
background: transparent;
border: 0;
color: var(--text);
outline: none;
font-size: 1rem;
margin-top: 0.12rem;
}
.search::placeholder {
color: var(--text-secondary);
}
.sort-shell {
position: relative;
min-width: 240px;
padding: 0.7rem;
}
.sort-trigger {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
margin-top: 0.2rem;
padding: 0.3rem 0.05rem 0.05rem;
border: 0;
background: transparent;
color: var(--text);
cursor: pointer;
}
.sort-current {
font-size: 0.98rem;
font-weight: 600;
}
.sort-chevron {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 999px;
border: 1px solid var(--border);
background: rgba(255,255,255,0.04);
transition: transform 0.24s ease, background 0.24s ease;
}
.sort-shell.open .sort-chevron {
transform: rotate(180deg);
background: rgba(255,255,255,0.08);
}
.sort-menu {
position: absolute;
top: calc(100% + 0.5rem);
right: 0.7rem;
width: min(300px, calc(100vw - 48px));
padding: 0.5rem;
border-radius: 18px;
border: 1px solid var(--border-strong);
background: rgba(11, 16, 24, 0.98);
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
z-index: 20;
transform-origin: top right;
animation: menu-in 0.16s ease;
}
[data-theme="light"] .sort-menu {
background: rgba(255, 251, 244, 0.98);
}
.sort-option {
width: 100%;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 0.6rem;
align-items: center;
text-align: left;
padding: 0.8rem 0.85rem;
border: 0;
border-radius: 14px;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
}
.sort-option:hover {
background: rgba(255,255,255,0.06);
color: var(--text);
transform: translateX(2px);
}
.sort-option strong {
display: block;
color: inherit;
font-size: 0.95rem;
margin-bottom: 0.08rem;
}
.sort-option span {
display: block;
font-size: 0.82rem;
color: var(--text-tertiary);
line-height: 1.4;
}
.sort-option-mark {
width: 26px;
height: 26px;
border-radius: 999px;
display: inline-flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.04);
border: 1px solid transparent;
color: transparent;
flex-shrink: 0;
}
.sort-option[aria-selected="true"] {
background: rgba(93, 168, 255, 0.12);
color: var(--text);
}
.sort-option[aria-selected="true"] .sort-option-mark {
color: var(--accent);
border-color: rgba(93, 168, 255, 0.24);
background: rgba(93, 168, 255, 0.08);
}
.toolbar-status {
min-width: 210px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0.9rem 1rem;
gap: 0.1rem;
}
.toolbar-status strong {
font-size: 1.02rem;
letter-spacing: -0.02em;
}
.toolbar-status span {
color: var(--text-tertiary);
font-size: 0.83rem;
}
.filter-row {
display: flex;
gap: 0.55rem;
flex-wrap: wrap;
padding-top: 0.9rem;
}
.filter-btn {
display: inline-flex;
align-items: center;
gap: 0.55rem;
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
color: var(--text-secondary);
border-radius: 999px;
padding: 0.56rem 0.9rem;
cursor: pointer;
transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease, color 0.18s ease;
}
.filter-btn:hover {
transform: translateY(-1px);
border-color: var(--border-strong);
color: var(--text);
}
.filter-btn em {
font-style: normal;
color: var(--text-tertiary);
font-size: 0.76rem;
padding: 0.1rem 0.4rem;
border-radius: 999px;
background: rgba(255,255,255,0.05);
}
.filter-btn.active {
background: linear-gradient(135deg, rgba(93, 168, 255, 0.16), rgba(255,255,255,0.05));
border-color: rgba(93, 168, 255, 0.26);
color: var(--text);
}
.filter-btn.active em {
color: var(--accent);
background: rgba(93, 168, 255, 0.12);
}
.public-panel-note {
margin: 0 1.15rem 0.2rem;
padding: 0.95rem 1.1rem;
border-radius: var(--radius-md);
border: 1px solid rgba(241, 179, 107, 0.2);
background: linear-gradient(90deg, rgba(241, 179, 107, 0.14), rgba(255,255,255,0.03));
color: var(--text-secondary);
display: flex;
align-items: center;
gap: 0.8rem;
}
.public-panel-note svg {
width: 18px;
height: 18px;
color: var(--amber);
flex-shrink: 0;
}
.grid {
padding: 0 1.15rem 1.3rem;
margin: 0;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1rem;
}
.deck-panel--harness .grid,
.deck-panel--harness .toolbar {
margin-right: calc(var(--deck-peek) * 0.58);
}
.card {
position: relative;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.95rem;
padding: 1.1rem;
border-radius: 22px;
border: 1px solid var(--border);
background:
linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.02)),
rgba(10, 14, 20, 0.3);
overflow: hidden;
transition: transform 0.26s ease, border-color 0.26s ease, box-shadow 0.26s ease, background 0.26s ease;
animation: card-in 0.42s ease both;
}
[data-theme="light"] .card {
background:
linear-gradient(180deg, rgba(255,255,255,0.6), rgba(255,255,255,0.34)),
rgba(252, 248, 240, 0.76);
}
.card::before {
content: '';
position: absolute;
inset: 0 auto auto 0;
width: 100%;
height: 3px;
background: linear-gradient(90deg, var(--accent), transparent 68%);
opacity: 0.9;
}
.card--public::before {
background: linear-gradient(90deg, var(--amber), transparent 68%);
}
.card:hover {
transform: translateY(-6px);
border-color: var(--border-strong);
box-shadow: 0 28px 56px rgba(0, 0, 0, 0.2);
background:
linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0.03)),
rgba(10, 14, 20, 0.34);
}
.card-topline {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
min-width: 0;
}
.card-family {
display: inline-flex;
align-items: center;
gap: 0.45rem;
color: var(--text-tertiary);
font-size: 0.74rem;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.card-family::before {
content: '';
width: 0.44rem;
height: 0.44rem;
border-radius: 999px;
background: var(--accent);
box-shadow: 0 0 0 4px rgba(93, 168, 255, 0.12);
}
.card--public .card-family::before {
background: var(--amber);
box-shadow: 0 0 0 4px rgba(241, 179, 107, 0.12);
}
.card-title {
font-size: 1.12rem;
font-weight: 700;
line-height: 1.24;
letter-spacing: -0.03em;
}
.card-title a {
color: var(--text);
text-decoration: none;
}
.card-title a:hover {
color: var(--accent);
}
.card-title a svg {
width: 12px;
height: 12px;
margin-left: 4px;
vertical-align: middle;
opacity: 0.45;
}
.card-meta {
display: flex;
align-items: center;
gap: 0.4rem;
flex-wrap: wrap;
justify-content: flex-end;
flex-shrink: 0;
}
.card-version,
.category-tag,
.public-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 28px;
padding: 0.22rem 0.55rem;
border-radius: 999px;
font-size: 0.72rem;
font-weight: 600;
border: 1px solid var(--border);
white-space: nowrap;
}
.card-version {
background: var(--green-soft);
color: var(--green);
border-color: rgba(120, 216, 170, 0.2);
font-family: 'IBM Plex Mono', monospace;
}
.category-tag {
background: rgba(255,255,255,0.04);
color: var(--text-secondary);
}
.public-badge {
border-color: rgba(241, 179, 107, 0.22);
background: var(--amber-soft);
color: var(--amber);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.card-desc {
color: var(--text-secondary);
font-size: 0.95rem;
}
.card-submeta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.card-date,
.card-requires,
.card-npx {
display: inline-flex;
align-items: flex-start;
gap: 0.38rem;
color: var(--text-tertiary);
font-size: 0.82rem;
line-height: 1.5;
flex-wrap: wrap;
min-width: 0;
}
.card-requires strong {
color: var(--text-secondary);
}
.card-npx code,
.card-requires code {
display: inline-block;
max-width: 100%;
overflow-wrap: anywhere;
word-break: break-word;
white-space: normal;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.79rem;
color: var(--text-secondary);
background: rgba(255,255,255,0.04);
border: 1px solid var(--border);
border-radius: 10px;
padding: 0.16rem 0.42rem;
}
.card-command-block {
padding: 0.9rem 0.9rem 0.9rem 0.9rem;
border-radius: 18px;
border: 1px solid var(--border);
background:
linear-gradient(180deg, rgba(93, 168, 255, 0.07), rgba(255,255,255,0.02)),
rgba(0,0,0,0.14);
position: relative;
}
.card--public .card-command-block {
background:
linear-gradient(180deg, rgba(241, 179, 107, 0.08), rgba(255,255,255,0.02)),
rgba(0,0,0,0.14);
}
.card-command-label {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
margin-bottom: 0.55rem;
color: var(--text-tertiary);
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.12em;
}
.card-command {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.8rem;
color: var(--text);
white-space: pre-wrap;
overflow-wrap: break-word;
word-break: normal;
line-height: 1.45;
padding-top: 0.1rem;
}
.card-command-comment {
display: block;
color: var(--text-tertiary);
font-style: italic;
margin-bottom: 0.24rem;
padding-right: 5.2rem;
}
.card-command-line {
display: block;
}
.card-command-line + .card-command-comment {
margin-top: 0.42rem;
}
.card-command-actions {
position: absolute;
top: 0.96rem;
right: 0.9rem;
}
.card-install-note {
font-size: 0.86rem;
color: var(--text-secondary);
line-height: 1.6;
padding: 0.88rem 0.9rem;
border-radius: 18px;
border: 1px dashed rgba(241, 179, 107, 0.2);
background: rgba(241, 179, 107, 0.08);
}
.card-footer {
margin-top: auto;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.card-links,
.card-contributor {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
align-items: center;
}
.card-links a,
.card-contributor a {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.38rem 0.62rem;
border-radius: 999px;
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
color: var(--text-secondary);
text-decoration: none;
font-size: 0.8rem;
transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.card-links a:hover,
.card-contributor a:hover {
color: var(--text);
border-color: var(--border-strong);
background: rgba(255,255,255,0.08);
}
.community-badge {
display: inline-flex;
align-items: center;
padding: 0.36rem 0.58rem;
border-radius: 999px;
background: rgba(255,255,255,0.04);
color: var(--text-tertiary);
font-size: 0.76rem;
border: 1px solid var(--border);
}
.empty {
grid-column: 1 / -1;
padding: 2rem;
border-radius: 22px;
border: 1px dashed var(--border-strong);
text-align: center;
color: var(--text-secondary);
background: rgba(255,255,255,0.03);
}
.footer {
width: min(var(--page-width), calc(100vw - 32px));
margin: 1.3rem auto 0;
padding: 1rem;
border-radius: var(--radius-xl);
border: 1px solid var(--border);
background: var(--panel);
backdrop-filter: blur(18px);
box-shadow: var(--shadow-md);
display: grid;
grid-template-columns: 1fr;
gap: 0.55rem;
}
.footer-band,
.footer-stats {
border-radius: var(--radius-lg);
border: 1px solid var(--border);
background: rgba(255,255,255,0.03);
padding: 0.72rem 0.85rem;
}
.footer-band {
display: flex;
flex-direction: column;
gap: 0.38rem;
}
.footer-label {
color: var(--text-tertiary);
font-size: 0.68rem;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.footer-copy {
color: var(--text-secondary);
font-size: 0.88rem;
line-height: 1.38;
}
.footer-copy a,
.footer-brand a {
color: var(--text);
text-decoration: none;
}
.footer-copy a:hover,
.footer-brand a:hover {
text-decoration: underline;
}
.footer-brand {
color: var(--text-tertiary);
font-size: 0.78rem;
line-height: 1.3;
}
.footer-stats {
display: flex;
justify-content: flex-start;
width: 100%;
margin: 0 auto;
padding: 0.1rem 0 0;
border: 0;
border-radius: 0;
background: transparent;
}
.footer-analytics-board {
display: flex;
align-items: baseline;
justify-content: flex-start;
flex-wrap: wrap;
gap: 0.24rem 0.72rem;
min-width: 0;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif;
font-size: 0.74rem;
line-height: 1.35;
color: var(--text-tertiary);
}
.analytics-kicker,
.analytics-row,
.analytics-key,
.metric-cell,
.metric-pair {
display: inline-flex;
align-items: center;
min-width: 0;
white-space: nowrap;
}
.analytics-kicker {
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--text-tertiary);
margin-right: 0.05rem;
}
.analytics-row {
gap: 0.38rem;
}
.analytics-key {
font-size: 0.68rem;
color: var(--text-tertiary);
font-variant-numeric: tabular-nums;
}
.analytics-title {
font-weight: 600;
color: var(--text-secondary);
}
.metric-cell {
gap: 0.22rem;
}
.metric-label {
color: var(--text-tertiary);
}
.metric-value,
.metric-pair strong {
font-size: 0.84rem;
line-height: 1;
color: var(--text);
font-variant-numeric: tabular-nums;
letter-spacing: -0.018em;
white-space: nowrap;
}
.metric-pair {
gap: 0.18rem;
color: var(--text-tertiary);
}
.metric-pair .human-value,
.metric-pair .agent-value {
color: var(--text);
}
.analytics-divider {
width: 1px;
height: 0.78rem;
background: var(--border);
flex: 0 0 auto;
transform: translateY(0.12rem);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(18px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes card-in {
from {
opacity: 0;
transform: translateY(16px) scale(0.985);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes menu-in {
from {
opacity: 0;
transform: translateY(-6px) scale(0.98);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@media (max-width: 1120px) {
.hero {
grid-template-columns: 1fr;
}
.stats {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.toolbar-top {
grid-template-columns: minmax(0, 1fr);
}
.sort-shell,
.toolbar-status {
min-width: 0;
}
.grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.footer {
grid-template-columns: 1fr;
}
}
@media (max-width: 860px) {
.nav {
padding-top: 1rem;
}
.nav-links {
gap: 0.45rem;
}
.hero-main {
padding: 1.35rem;
}
.hero-rail {
padding: 1rem;
}
.hero-notes {
grid-template-columns: 1fr;
}
.deck-nav {
flex-direction: column;
align-items: stretch;
}
.deck-separator {
width: 100%;
height: 1px;
}
.deck-arrow-btn {
justify-content: center;
}
.deck-panel--harness .grid,
.deck-panel--harness .toolbar {
margin-right: calc(var(--deck-peek) * 0.42);
}
.grid {
grid-template-columns: 1fr;
}
.footer-analytics-board { justify-content: flex-start; }
}
@media (max-width: 640px) {
.nav {
flex-direction: column;
align-items: stretch;
}
.nav-brand,
.nav-links {
justify-content: center;
}
.hero {
padding-top: 1.1rem;
}
.hero-main,
.hero-rail,
.toolbar,
.footer,
.stat {
border-radius: 20px;
}
.hero h1 {
max-width: none;
}
.hero-actions,
.cmd-grid {
grid-template-columns: 1fr;
}
.hero-actions {
flex-direction: column;
}
.btn-primary,
.btn-secondary,
.nav-link,
.deck-arrow-btn {
justify-content: center;
}
.install-row {
grid-template-columns: 1fr;
}
.chip-label {
min-width: 0;
width: fit-content;
}
.stats {
grid-template-columns: 1fr 1fr;
}
.toolbar,
.public-panel-note {
margin-left: 0.9rem;
margin-right: 0.9rem;
}
.deck-panel--harness .grid,
.deck-panel--harness .toolbar {
margin-right: 0.9rem;
}
.grid {
padding-left: 0.9rem;
padding-right: 0.9rem;
}
.footer-stats {
padding: 0.5rem 0.68rem;
}
.analytics-divider { display: none; }
}
</style>
<!-- Analytics provider is configured in the footer script. -->
</head>
<body>
<div class="page-shell">
<nav class="nav">
<a class="nav-brand" href="#">
<span class="nav-mark">C</span>
<span class="nav-copy">
<strong>CLI-Anything Hub</strong>
<span>Registry Atelier</span>
</span>
</a>
<div class="nav-links">
<a class="nav-link" href="https://github.com/HKUDS/CLI-Anything/blob/main/skills/cli-hub-meta-skill/SKILL.md" target="_blank">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5.5 18.5 9.8-9.8"/><path d="m13.7 6.9 3.4 3.4"/><path d="M18 4v2.4"/><path d="M16.8 5.2h2.4"/><path d="M7.5 4.8v2"/><path d="M6.5 5.8h2"/><path d="M18.2 15.8v2"/><path d="M17.2 16.8h2"/></svg>
SKILL.md
</a>
<a class="nav-link" href="https://github.com/HKUDS/CLI-Anything" target="_blank">
<svg viewBox="0 0 98 96" fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6C29.304 70.25 17.9 66.013 17.9 47.02c0-5.52 1.94-10.046 5.127-13.58-.486-1.302-2.264-6.437.486-13.34 0 0 4.206-1.302 13.59 5.216 3.963-1.14 8.17-1.628 12.34-1.628 4.17 0 8.376.568 12.34 1.628 9.384-6.518 13.59-5.216 13.59-5.216 2.75 6.903.972 12.038.486 13.34 3.268 3.534 5.127 8.06 5.127 13.58 0 19.074-11.485 23.15-22.328 24.29 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"/></svg>
GitHub
<span class="nav-link-stars" data-github-stars aria-label="GitHub star count">--</span>
</a>
<a class="nav-link" href="https://arxiv.org/abs/2606.03854" target="_blank" rel="noopener noreferrer">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 3.5h8.2L19 7.3v12A1.7 1.7 0 0 1 17.3 21H7a2 2 0 0 1-2-2V5.5a2 2 0 0 1 2-2z"/><path d="M15 3.5v4h4"/><path d="M8.5 11.2h7"/><path d="M8.5 14.5h7"/><path d="M8.5 17.8h4.5"/><path d="M10 3.5v5l1.7-1.1L13.4 8.5v-5"/></svg>
Tech Report
</a>
<a class="nav-link" href="https://github.com/HKUDS/CLI-Anything/blob/main/CONTRIBUTING.md" target="_blank">Contribute</a>
<button class="theme-toggle" onclick="toggleTheme()" aria-label="Toggle theme">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
</div>
</nav>
<section class="hero">
<div class="hero-main">
<div class="hero-kicker">Agent-native CLI Registry</div>
<h1><em>CLI</em> tools for <span>software, APIs, and autonomous agents.</span></h1>
<p class="hero-lead"><strong>Any software. Any codebase. Any Web API.</strong> Install an orchestration hub that can discover, explain, install, update, and remove CLIs across first-party harnesses and public ecosystems.</p>
<div class="hero-actions">
<a class="btn-primary" href="https://github.com/HKUDS/CLI-Anything/blob/main/skills/cli-hub-meta-skill/SKILL.md" target="_blank">Get Agent SKILL</a>
<a class="btn-secondary" href="https://github.com/HKUDS/CLI-Anything" target="_blank">
<svg viewBox="0 0 98 96" fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6C29.304 70.25 17.9 66.013 17.9 47.02c0-5.52 1.94-10.046 5.127-13.58-.486-1.302-2.264-6.437.486-13.34 0 0 4.206-1.302 13.59 5.216 3.963-1.14 8.17-1.628 12.34-1.628 4.17 0 8.376.568 12.34 1.628 9.384-6.518 13.59-5.216 13.59-5.216 2.75 6.903.972 12.038.486 13.34 3.268 3.534 5.127 8.06 5.127 13.58 0 19.074-11.485 23.15-22.328 24.29 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"/></svg>
Star on GitHub
</a>
<a class="btn-secondary" href="https://github.com/HKUDS/CLI-Anything/blob/main/.github/PULL_REQUEST_TEMPLATE.md" target="_blank">PR Template</a>
</div>
<div class="hero-prompt">
<strong>Prompt for your agent:</strong>
<em>"Find the right CLI in CLI-Hub, install it, and finish the task end-to-end."</em>
</div>
<div class="hero-notes">
<div class="hero-note">
<strong>One Surface</strong>
<span>Harness CLIs and public CLIs live in one discovery layer, with source-aware install flows.</span>
</div>
<div class="hero-note">
<strong>Agent Ready</strong>
<span>Give the registry to an AI agent and let it browse, search, install, and invoke the right tooling.</span>
</div>
<div class="hero-note">
<strong>Contributor Friendly</strong>
<span>Add a new software target, refine a public entry, or ship an agent harness without redesigning the hub.</span>
</div>
</div>
</div>
<aside class="hero-rail">
<section class="rail-panel">
<h3>Empower your agent</h3>
<p>Install the meta-skill once, then let the agent choose the right CLI from the registry.</p>
<div class="install-row">
<span class="chip-label">npx skills</span>
<code>npx skills add HKUDS/CLI-Anything --skill cli-hub-meta-skill -g -y</code>
<button class="copy-btn" onclick="copyCmd(this, 'npx skills add HKUDS/CLI-Anything --skill cli-hub-meta-skill -g -y')">Copy</button>
</div>
<div class="install-row">
<span class="chip-label">OpenClaw</span>
<code>openclaw skills install cli-anything-hub</code>
<button class="copy-btn" onclick="copyCmd(this, 'openclaw skills install cli-anything-hub')">Copy</button>
</div>
<div class="install-row">
<span class="chip-label">Nanobot</span>
<code>nanobot skills install cli-anything-hub</code>
<button class="copy-btn" onclick="copyCmd(this, 'nanobot skills install cli-anything-hub')">Copy</button>
</div>
</section>
<section class="rail-panel rail-panel--public">
<h3>Work directly from your shell</h3>
<p>Install the hub locally and manage both harness CLIs and public CLIs with one command surface.</p>
<div class="install-row">
<span class="chip-label">PyPI</span>
<code>pip install cli-anything-hub</code>
<button class="copy-btn" onclick="copyCmd(this, 'pip install cli-anything-hub')">Copy</button>
</div>
<div class="cmd-grid">
<div class="cmd-item"><span class="cmd-name">cli-hub list</span><span class="cmd-desc">Browse both registries</span></div>
<div class="cmd-item"><span class="cmd-name">cli-hub search</span><span class="cmd-desc">Find by keyword</span></div>
<div class="cmd-item"><span class="cmd-name">cli-hub install</span><span class="cmd-desc">Install from the right source</span></div>
<div class="cmd-item"><span class="cmd-name">cli-hub info</span><span class="cmd-desc">Inspect commands and metadata</span></div>
<div class="cmd-item"><span class="cmd-name">cli-hub update</span><span class="cmd-desc">Refresh installed tools</span></div>
<div class="cmd-item"><span class="cmd-name">cli-hub uninstall</span><span class="cmd-desc">Remove cleanly</span></div>
</div>
</section>
</aside>
</section>
<section class="stats">
<div class="stat">
<div class="stat-num" id="cli-count">&mdash;</div>
<div class="stat-label">Combined CLIs</div>
</div>
<div class="stat">
<div class="stat-num" id="category-count">&mdash;</div>
<div class="stat-label">Categories</div>
</div>
<div class="stat">
<div class="stat-num" id="deck-count-harness">&mdash;</div>
<div class="stat-label">Harness Catalog</div>
</div>
<div class="stat">
<div class="stat-num" id="deck-count-public">&mdash;</div>
<div class="stat-label">Public Catalog</div>
</div>
</section>
<div class="deck-nav">
<button class="deck-tab active" data-deck="harness" onclick="switchDeck('harness')">
<span class="deck-tab-top">
<span class="deck-tab-title">CLI-Anything CLIs</span>
<span class="deck-count" id="deck-count-pill-harness">&mdash;</span>
</span>
<span class="deck-tab-subtitle">Agent harnesses for apps, APIs, and software ecosystems you can operate end-to-end.</span>
</button>
<button class="deck-tab deck-tab--public" data-deck="public" onclick="switchDeck('public')">
<span class="deck-tab-top">
<span class="deck-tab-title">Public CLIs</span>
<span class="deck-count" id="deck-count-pill-public">&mdash;</span>
</span>
<span class="deck-tab-subtitle">Official and third-party CLIs from npm, brew, bundled installers, and other public channels.</span>
</button>
<span class="deck-separator"></span>
<button class="deck-arrow-btn" id="deck-toggle" onclick="toggleDeck()">
<span>Jump to Public CLIs</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
</button>
</div>
<div class="deck-stage">
<div class="deck-viewport">
<div class="deck-track" id="deck-track" data-active="harness">
<section class="deck-panel deck-panel--harness" data-peek-label="Harness">
<div class="toolbar">
<div class="toolbar-top">
<label class="search-shell" for="search-harness">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<span class="search-meta">
<span class="control-kicker">Search harness CLIs</span>
<input class="search" type="text" placeholder="Search by software, category, description..." id="search-harness">
</span>
</label>
<div class="sort-shell" data-deck="harness">
<div class="sort-meta">
<span class="control-kicker">Sort mode</span>
</div>
<button class="sort-trigger" id="sort-trigger-harness" type="button" aria-haspopup="listbox" aria-expanded="false">
<span class="sort-current" id="sort-current-harness">Last updated</span>
<span class="sort-chevron">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</span>
</button>
<div class="sort-menu" id="sort-menu-harness" role="listbox" hidden>
<button class="sort-option" type="button" data-deck="harness" data-value="updated" role="option" aria-selected="true">
<span><strong>Last updated</strong><span>Put the freshest harness additions first.</span></span>
<span class="sort-option-mark"></span>
</button>
<button class="sort-option" type="button" data-deck="harness" data-value="name" role="option" aria-selected="false">
<span><strong>Name</strong><span>Alphabetical list for quick scanning.</span></span>
<span class="sort-option-mark"></span>
</button>
<button class="sort-option" type="button" data-deck="harness" data-value="category" role="option" aria-selected="false">
<span><strong>Category</strong><span>Group by software domain first.</span></span>
<span class="sort-option-mark"></span>
</button>
</div>
</div>
<div class="toolbar-status">
<strong id="result-count-harness">&mdash;</strong>
<span>Visible after filters and search</span>
</div>
</div>
<div class="filter-row" id="filters-harness"></div>
</div>
<div class="grid" id="grid-harness"></div>
</section>
<section class="deck-panel deck-panel--public" data-peek-label="Public">
<div class="toolbar">
<div class="toolbar-top">
<label class="search-shell" for="search-public">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<span class="search-meta">
<span class="control-kicker">Search public CLIs</span>
<input class="search" type="text" placeholder="Search by package, source, or description..." id="search-public">
</span>
</label>
<div class="sort-shell" data-deck="public">
<div class="sort-meta">
<span class="control-kicker">Sort mode</span>
</div>
<button class="sort-trigger" id="sort-trigger-public" type="button" aria-haspopup="listbox" aria-expanded="false">
<span class="sort-current" id="sort-current-public">Last updated</span>
<span class="sort-chevron">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</span>
</button>
<div class="sort-menu" id="sort-menu-public" role="listbox" hidden>
<button class="sort-option" type="button" data-deck="public" data-value="updated" role="option" aria-selected="true">
<span><strong>Last updated</strong><span>Put the freshest public CLIs first.</span></span>
<span class="sort-option-mark"></span>
</button>
<button class="sort-option" type="button" data-deck="public" data-value="name" role="option" aria-selected="false">
<span><strong>Name</strong><span>Alphabetical list for known public tools.</span></span>
<span class="sort-option-mark"></span>
</button>
<button class="sort-option" type="button" data-deck="public" data-value="category" role="option" aria-selected="false">
<span><strong>Category</strong><span>Group by domain before package source.</span></span>
<span class="sort-option-mark"></span>
</button>
</div>
</div>
<div class="toolbar-status">
<strong id="result-count-public">&mdash;</strong>
<span>Visible after filters and search</span>
</div>
</div>
<div class="filter-row" id="filters-public"></div>
</div>
<div class="public-panel-note">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
<span>Public CLIs remain the property of their software owners and maintainers. CLI-Hub only helps you discover and manage them from the correct installation source.</span>
</div>
<div class="grid" id="grid-public"></div>
</section>
</div>
</div>
</div>
<footer class="footer">
<div class="footer-band">
<div class="footer-label">Contribute</div>
<div class="footer-copy">Want to add or update a CLI? Read the <a href="https://github.com/HKUDS/CLI-Anything/blob/main/CONTRIBUTING.md" target="_blank">Contributing Guide</a>, use the <a href="https://github.com/HKUDS/CLI-Anything/blob/main/.github/PULL_REQUEST_TEMPLATE.md" target="_blank">PR Template</a>, and bring a new software surface into the hub.</div>
<div class="footer-brand">Powered by <a href="https://github.com/HKUDS/CLI-Anything" target="_blank">CLI-Anything</a></div>
</div>
<div class="footer-stats">
<div class="footer-analytics-board" aria-label="Traffic snapshot">
<span class="analytics-kicker">Traffic</span>
<span class="analytics-row">
<span class="analytics-title">Web</span>
<strong id="stat-web-unique" class="metric-value">...</strong>
</span>
<span class="analytics-divider" aria-hidden="true"></span>
<span class="analytics-row">
<span class="analytics-title">CLI</span>
<strong id="stat-cli-total" class="metric-value">...</strong>
<span class="metric-pair"><strong id="stat-cli-human" class="human-value">...</strong>/<strong id="stat-cli-agent" class="agent-value">...</strong></span>
</span>
</div>
</div>
</footer>
</div>
<script>
function getPreferredTheme() {
const stored = localStorage.getItem('theme');
if (stored) return stored;
return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
}
function applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
}
function toggleTheme() {
const current = document.documentElement.getAttribute('data-theme') || 'dark';
const next = current === 'dark' ? 'light' : 'dark';
applyTheme(next);
localStorage.setItem('theme', next);
}
applyTheme(getPreferredTheme());
window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
applyTheme(e.matches ? 'light' : 'dark');
}
});
const REPO = 'https://github.com/HKUDS/CLI-Anything';
const GITHUB_REPO_API = 'https://api.github.com/repos/HKUDS/CLI-Anything';
const GITHUB_STARS_BADGE_API = 'https://img.shields.io/github/stars/HKUDS/CLI-Anything.json';
const REPO_SKILLS_SOURCE = 'HKUDS/CLI-Anything';
const REGISTRY_URLS = [
'../../registry.json',
'https://raw.githubusercontent.com/HKUDS/CLI-Anything/main/registry.json'
];
const PUBLIC_REGISTRY_URLS = [
'../../public_registry.json',
'https://raw.githubusercontent.com/HKUDS/CLI-Anything/main/public_registry.json'
];
const DATES_URLS = [
'https://hkuds.github.io/CLI-Anything/registry-dates.json',
'../../registry-dates.json'
];
const EXTERNAL_LINK_SVG = '<svg viewBox="0 0 16 16" fill="currentColor"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5H4.56l6.72 6.72a.75.75 0 1 1-1.06 1.06L3.5 4.56v2.69a.75.75 0 0 1-1.5 0v-3.5A1.75 1.75 0 0 1 3.75 2Zm7.5 0h1A1.75 1.75 0 0 1 14 3.75v8.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-1a.75.75 0 0 1 1.5 0v1c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25h-1a.75.75 0 0 1 0-1.5Z"/></svg>';
const SORT_LABELS = {
updated: 'Last updated',
name: 'Name',
category: 'Category'
};
let harnessClis = [];
let publicClis = [];
let activeDeck = 'harness';
const deckState = {
harness: { filter: 'all', sort: 'updated', query: '' },
public: { filter: 'all', sort: 'updated', query: '' },
};
async function fetchJson(urls) {
for (const url of urls) {
try {
const resp = await fetch(url);
if (resp.ok) return await resp.json();
} catch (_) {
continue;
}
}
return null;
}
function formatCompactCount(value) {
return new Intl.NumberFormat('en', {
notation: 'compact',
maximumFractionDigits: value >= 10000 ? 0 : 1,
}).format(value);
}
function formatBadgeCount(value) {
if (typeof value !== 'string') return null;
const label = value.trim();
return label ? label.toUpperCase() : null;
}
function renderGitHubStars(label, title) {
document.querySelectorAll('[data-github-stars]').forEach((el) => {
el.textContent = label;
el.setAttribute('aria-label', title);
el.title = title;
});
}
async function loadGitHubStars() {
try {
try {
const badgeResp = await fetch(GITHUB_STARS_BADGE_API);
if (badgeResp.ok) {
const badge = await badgeResp.json();
const badgeLabel = formatBadgeCount(badge.message || badge.value);
if (badgeLabel) {
renderGitHubStars(badgeLabel, badgeLabel + ' GitHub stars');
return;
}
}
} catch (_) {}
const resp = await fetch(GITHUB_REPO_API, {
headers: { Accept: 'application/vnd.github+json' }
});
if (!resp.ok) return;
const repo = await resp.json();
const stars = repo.stargazers_count;
if (typeof stars !== 'number') return;
renderGitHubStars(formatCompactCount(stars), stars.toLocaleString('en-US') + ' GitHub stars');
} catch (_) {
// Keep fallback placeholder when GitHub API is unavailable.
}
}
async function loadRegistries() {
try {
const [harnessData, publicData, dates] = await Promise.all([
fetchJson(REGISTRY_URLS),
fetchJson(PUBLIC_REGISTRY_URLS),
fetchJson(DATES_URLS),
]);
if (!harnessData) throw new Error('Registry load failed');
harnessClis = harnessData.clis;
if (dates) harnessClis.forEach((c) => { c.last_modified = dates[c.name]; });
if (publicData && publicData.clis) {
publicClis = publicData.clis;
if (dates) publicClis.forEach((c) => { c.last_modified = dates[c.name]; });
}
const totalClis = harnessClis.length + publicClis.length;
const allCategories = [...new Set([...harnessClis, ...publicClis].map((c) => c.category))];
document.getElementById('cli-count').textContent = totalClis;
document.getElementById('category-count').textContent = allCategories.length;
document.getElementById('deck-count-harness').textContent = harnessClis.length;
document.getElementById('deck-count-public').textContent = publicClis.length;
document.getElementById('deck-count-pill-harness').textContent = harnessClis.length;
document.getElementById('deck-count-pill-public').textContent = publicClis.length;
buildFilters('harness', harnessClis);
buildFilters('public', publicClis);
updateSortUI('harness');
updateSortUI('public');
renderDeck('harness');
renderDeck('public');
} catch (_) {
document.getElementById('grid-harness').innerHTML =
'<div class="empty">Failed to load registry. <a href="' + REPO + '/blob/main/registry.json" style="color:var(--accent)">View source</a></div>';
}
}
const CATEGORY_LABELS = { ai: 'AI', '3d': '3D' };
function catLabel(cat) {
return CATEGORY_LABELS[cat] || cat.charAt(0).toUpperCase() + cat.slice(1);
}
function buildFilters(deck, clis) {
const container = document.getElementById('filters-' + deck);
const counts = clis.reduce((acc, cli) => {
acc[cli.category] = (acc[cli.category] || 0) + 1;
return acc;
}, {});
const categories = Object.keys(counts).sort();
container.innerHTML = '';
const allBtn = document.createElement('button');
allBtn.className = 'filter-btn active';
allBtn.dataset.cat = 'all';
allBtn.innerHTML = '<span>All</span><em>' + clis.length + '</em>';
allBtn.onclick = () => setFilter(deck, 'all');
container.appendChild(allBtn);
categories.forEach((cat) => {
const btn = document.createElement('button');
btn.className = 'filter-btn';
btn.dataset.cat = cat;
btn.innerHTML = '<span>' + esc(catLabel(cat)) + '</span><em>' + counts[cat] + '</em>';
btn.onclick = () => setFilter(deck, cat);
container.appendChild(btn);
});
}
function setFilter(deck, cat) {
deckState[deck].filter = cat;
document.querySelectorAll('#filters-' + deck + ' .filter-btn').forEach((b) => {
b.classList.toggle('active', b.dataset.cat === cat);
});
renderDeck(deck);
}
function updateSortUI(deck) {
document.getElementById('sort-current-' + deck).textContent = SORT_LABELS[deckState[deck].sort] || deckState[deck].sort;
document.querySelectorAll('.sort-option[data-deck="' + deck + '"]').forEach((option) => {
option.setAttribute('aria-selected', String(option.dataset.value === deckState[deck].sort));
});
}
function closeSortMenus(exceptDeck) {
document.querySelectorAll('.sort-shell').forEach((shell) => {
if (shell.dataset.deck === exceptDeck) return;
shell.classList.remove('open');
const deck = shell.dataset.deck;
document.getElementById('sort-trigger-' + deck).setAttribute('aria-expanded', 'false');
document.getElementById('sort-menu-' + deck).hidden = true;
});
}
function toggleSortMenu(deck) {
const shell = document.querySelector('.sort-shell[data-deck="' + deck + '"]');
const trigger = document.getElementById('sort-trigger-' + deck);
const menu = document.getElementById('sort-menu-' + deck);
const willOpen = menu.hidden;
closeSortMenus(deck);
shell.classList.toggle('open', willOpen);
trigger.setAttribute('aria-expanded', String(willOpen));
menu.hidden = !willOpen;
}
function setSort(deck, value) {
deckState[deck].sort = value;
updateSortUI(deck);
closeSortMenus();
renderDeck(deck);
}
function initSortMenus() {
['harness', 'public'].forEach((deck) => {
document.getElementById('sort-trigger-' + deck).addEventListener('click', (e) => {
e.stopPropagation();
toggleSortMenu(deck);
});
});
document.querySelectorAll('.sort-option').forEach((option) => {
option.addEventListener('click', (e) => {
e.stopPropagation();
setSort(option.dataset.deck, option.dataset.value);
});
});
document.addEventListener('click', () => closeSortMenus());
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeSortMenus();
});
}
function switchDeck(deck) {
activeDeck = deck;
const track = document.getElementById('deck-track');
track.dataset.active = deck;
updateDeckPosition();
document.querySelectorAll('.deck-tab').forEach((tab) => {
tab.classList.toggle('active', tab.dataset.deck === deck);
});
const toggle = document.getElementById('deck-toggle');
if (deck === 'harness') {
toggle.querySelector('span').textContent = 'Jump to Public CLIs';
toggle.querySelector('svg').innerHTML = '<polyline points="9 18 15 12 9 6"/>';
toggle.classList.remove('deck-arrow-btn--back');
} else {
toggle.querySelector('span').textContent = 'Jump to CLI-Anything CLIs';
toggle.querySelector('svg').innerHTML = '<polyline points="15 18 9 12 15 6"/>';
toggle.classList.add('deck-arrow-btn--back');
}
}
function toggleDeck() {
switchDeck(activeDeck === 'harness' ? 'public' : 'harness');
}
function updateDeckPosition() {
const stage = document.querySelector('.deck-stage');
const viewport = document.querySelector('.deck-viewport');
const track = document.getElementById('deck-track');
if (!stage || !viewport || !track) return;
const peek = parseFloat(getComputedStyle(stage).getPropertyValue('--deck-peek')) || 0;
const panelWidth = Math.max(viewport.clientWidth - peek, 0);
viewport.style.setProperty('--deck-panel-width', panelWidth + 'px');
track.style.transform = activeDeck === 'public'
? 'translateX(-' + Math.max(panelWidth - peek, 0) + 'px)'
: 'translateX(0)';
}
function updateResultCount(deck, visible, total) {
const label = visible + ' shown';
const suffix = visible === total ? 'Full catalog view' : 'Filtered from ' + total;
document.getElementById('result-count-' + deck).textContent = label;
document.getElementById('result-count-' + deck).nextElementSibling.textContent = suffix;
}
function renderDeck(deck) {
const clis = deck === 'harness' ? harnessClis : publicClis;
const state = deckState[deck];
const query = state.query.toLowerCase();
const filtered = clis.filter((c) => {
const matchFilter = state.filter === 'all' || c.category === state.filter;
const matchSearch = !query ||
c.display_name.toLowerCase().includes(query) ||
c.description.toLowerCase().includes(query) ||
c.name.toLowerCase().includes(query);
return matchFilter && matchSearch;
});
filtered.sort((a, b) => {
if (state.sort === 'updated') return (b.last_modified || '').localeCompare(a.last_modified || '');
if (state.sort === 'name') return a.display_name.localeCompare(b.display_name);
if (state.sort === 'category') return a.category.localeCompare(b.category) || a.display_name.localeCompare(b.display_name);
return 0;
});
updateResultCount(deck, filtered.length, clis.length);
const grid = document.getElementById('grid-' + deck);
if (!filtered.length) {
grid.innerHTML = '<div class="empty">No CLIs match your current search and filter settings.</div>';
return;
}
grid.innerHTML = (deck === 'harness' ? filtered.map(renderHarnessCard) : filtered.map(renderPublicCard)).join('');
}
function repoSkillId(skillPath) {
if (!skillPath || skillPath.startsWith('http')) return '';
const match = skillPath.match(/^skills\/([^/]+)\/SKILL\.md$/);
return match ? match[1] : '';
}
function normalizeNpxSkillsCmd(cmd) {
if (!cmd) return '';
const trimmed = cmd.trim();
if (!trimmed.startsWith('npx skills add ')) return '';
return trimmed
.replace(/\s+-g\b/g, '')
.replace(/\s+-y\b/g, '')
.trim() + ' -g -y';
}
function harnessSkillCmd(c) {
const skillId = repoSkillId(c.skill_md);
return skillId ? 'npx skills add ' + REPO_SKILLS_SOURCE + ' --skill ' + skillId + ' -g -y' : '';
}
function publicSkillCmd(c) {
return normalizeNpxSkillsCmd(c.skill_md);
}
function renderCommandStack(steps, sourceLabel) {
const display = steps.map((step) =>
'<span class="card-command-comment"># ' + esc(step.label.toLowerCase()) + '</span><span class="card-command-line">' + esc(step.cmd) + '</span>'
).join('');
const copyText = steps.map((step) =>
'# ' + step.label.toLowerCase() + '\n' + step.cmd
).join('\n');
return '<div class="card-command-block">' +
'<div class="card-command-label"><span>Install Commands</span><span>' + esc(sourceLabel) + '</span></div>' +
'<div class="card-command">' + display + '</div>' +
'<div class="card-command-actions"><button class="card-copy-btn" onclick=\'copyCmd(this, ' + JSON.stringify(copyText) + ')\'>Copy</button></div>' +
'</div>';
}
function renderHarnessCard(c) {
const requiresHtml = c.requires
? '<div class="card-requires"><strong>Requires</strong> ' + esc(c.requires) + '</div>'
: '';
const skillLink = c.skill_md
? '<a href="' + (c.skill_md.startsWith('http') ? c.skill_md : (REPO + '/blob/main/' + c.skill_md)) + '" target="_blank">Skill</a>'
: '';
const sourceLink = c.source_url
? '<a href="' + esc(c.source_url) + '" target="_blank">Source</a>'
: '<a href="' + REPO + '/tree/main/' + c.name + '/agent-harness" target="_blank">Source</a>';
const titleHtml = c.homepage
? '<a href="' + esc(c.homepage) + '" target="_blank">' + esc(c.display_name) + EXTERNAL_LINK_SVG + '</a>'
: esc(c.display_name);
const contributors = c.contributors || (c.contributor ? [{ name: c.contributor, url: c.contributor_url }] : []);
const isTeam = contributors.length === 1 && contributors[0].name === 'CLI-Anything-Team';
const contributorHtml = contributors.length
? '<div class="card-contributor">' +
contributors.map((ct) => '<a href="' + esc(ct.url) + '" target="_blank">' + esc(ct.name) + '</a>').join('') +
(isTeam ? '' : '<span class="community-badge">Community</span>') +
'</div>'
: '';
const dateHtml = c.last_modified ? '<div class="card-date">Updated ' + esc(c.last_modified) + '</div>' : '';
const linksHtml = sourceLink + (skillLink ? skillLink : '');
const installSteps = [
{ label: 'step 1 · install cli', cmd: 'cli-hub install ' + c.name, badge: 'CLI-Hub' }
];
const skillCmd = harnessSkillCmd(c);
if (skillCmd) installSteps.push({ label: 'step 2 · install skill', cmd: skillCmd, badge: 'npx skills' });
const installBlock = renderCommandStack(installSteps, 'CLI-Hub');
return `
<article class="card card--harness">
<div class="card-topline">
<span class="card-family">Harness CLI</span>
<div class="card-meta">
<span class="category-tag">${catLabel(c.category)}</span>
<span class="card-version">${esc(c.version)}</span>
</div>
</div>
<div class="card-title">${titleHtml}</div>
<div class="card-desc">${esc(c.description)}</div>
<div class="card-submeta">
${dateHtml}
${requiresHtml}
</div>
${installBlock}
<div class="card-footer">
<div class="card-links">${linksHtml}</div>
${contributorHtml}
</div>
</article>`;
}
function formatPublicManager(c) {
const manager = (c.package_manager || c.install_strategy || 'public').toLowerCase();
const labelMap = { npm: 'npm', brew: 'brew', bundled: 'bundled' };
const label = labelMap[manager] || manager;
return '<span class="public-badge public-badge--' + esc(manager) + '">' + esc(label) + '</span>';
}
function publicDirectCmd(c) {
return c.direct_cmd || c.entry_point || c.npx_cmd || '';
}
function renderPublicCard(c) {
const isBundled = (c.install_strategy || c.package_manager) === 'bundled';
const dateHtml = c.last_modified ? '<div class="card-date">Updated ' + esc(c.last_modified) + '</div>' : '';
const requiresHtml = c.requires
? '<div class="card-requires"><strong>Requires</strong> ' + esc(c.requires) + '</div>'
: '';
const titleHtml = c.homepage
? '<a href="' + esc(c.homepage) + '" target="_blank">' + esc(c.display_name) + EXTERNAL_LINK_SVG + '</a>'
: esc(c.display_name);
const sourceLink = c.source_url ? '<a href="' + esc(c.source_url) + '" target="_blank">Source</a>' : '';
const contributors = c.contributors || [];
const contributorHtml = contributors.length
? '<div class="card-contributor">' +
contributors.map((ct) => '<a href="' + esc(ct.url) + '" target="_blank">' + esc(ct.name) + '</a>').join('') +
'</div>'
: '';
const directCmd = c.install_cmd || publicDirectCmd(c);
const directCmdHtml = directCmd && !isBundled
? '<div class="card-npx">Direct command: <code>' + esc(directCmd) + '</code></div>'
: '';
const installNotesHtml = c.install_notes ? '<div class="card-npx">' + esc(c.install_notes) + '</div>' : '';
const installSteps = isBundled
? []
: [{ label: 'step 1 · install cli', cmd: 'cli-hub install ' + c.name, badge: 'CLI-Hub' }];
const skillCmd = publicSkillCmd(c);
if (skillCmd) installSteps.push({ label: 'step 2 · install skill', cmd: skillCmd, badge: 'npx skills' });
const installBlock = isBundled
? '<div class="card-install-note">Bundled with the upstream application. Install or update the parent app and enable its CLI integration.</div>'
: renderCommandStack(installSteps, 'Source aware');
return `
<article class="card card--public">
<div class="card-topline">
<span class="card-family">Public CLI</span>
<div class="card-meta">
${formatPublicManager(c)}
<span class="category-tag">${catLabel(c.category)}</span>
</div>
</div>
<div class="card-title">${titleHtml}</div>
<div class="card-desc">${esc(c.description)}</div>
<div class="card-submeta">
${dateHtml}
${requiresHtml}
${directCmdHtml}
${installNotesHtml}
</div>
${installBlock}
<div class="card-footer">
<div class="card-links">${sourceLink}</div>
${contributorHtml}
</div>
</article>`;
}
function copyCmd(btn, cmd) {
navigator.clipboard.writeText(cmd).then(() => {
const original = btn.textContent;
btn.textContent = 'Copied';
setTimeout(() => {
btn.textContent = original === 'Copied' ? 'Copy' : original;
}, 1400);
});
}
function esc(s) {
if (!s) return '';
const d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
document.getElementById('search-harness').addEventListener('input', (e) => {
deckState.harness.query = e.target.value;
renderDeck('harness');
});
document.getElementById('search-public').addEventListener('input', (e) => {
deckState.public.query = e.target.value;
renderDeck('public');
});
window.addEventListener('resize', updateDeckPosition);
initSortMenus();
loadRegistries().then(updateDeckPosition);
(function() {
const ANALYTICS_PROVIDER = 'posthog';
const ANALYTICS_SITE = 'clianything.cc';
const COUNTED_HOSTS = new Set(['clianything.cc', 'www.clianything.cc']);
const ANALYTICS_TEST_RUN = new URLSearchParams(location.search).get('analytics_test_run') || '';
const POSTHOG_CONFIG = {
projectToken: 'phc_ovP8d5bmjpn8YZnTo7pb6rE3TikcAMgmNVt75o3Ywejz',
apiHost: 'https://us.i.posthog.com',
defaults: '2026-01-30',
personProfiles: 'identified_only',
};
const UMAMI_CONFIG = {
sendUrl: 'https://cloud.umami.is/api/send',
websiteId: 'a076c661-bed1-405c-a522-813794e688b4',
};
const OFFICIAL_AGENT_UA_RULES = [
{ id: 'openai-oai-searchbot', category: 'official_ai_agent', regex: /\bOAI-SearchBot\b/i },
{ id: 'openai-gptbot', category: 'official_ai_agent', regex: /\bGPTBot\b/i },
{ id: 'openai-chatgpt-user', category: 'official_ai_agent', regex: /\bChatGPT-User\b/i },
{ id: 'anthropic-claudebot', category: 'official_ai_agent', regex: /\bClaudeBot\b/i },
{ id: 'anthropic-claude-user', category: 'official_ai_agent', regex: /\bClaude-User\b/i },
{ id: 'anthropic-claude-searchbot', category: 'official_ai_agent', regex: /\bClaude-SearchBot\b/i },
{ id: 'perplexity-bot', category: 'official_ai_agent', regex: /\bPerplexityBot\b/i },
{ id: 'perplexity-user', category: 'official_ai_agent', regex: /\bPerplexity-User\b/i },
{ id: 'google-vertex-bot', category: 'official_ai_agent', regex: /\bGoogle-CloudVertexBot\b/i },
];
const AGENT_TOOL_UA_RULES = [
{ id: 'claude-code', category: 'agent_tool', regex: /\bclaude(?:[ -]?code)\b/i },
{ id: 'codex', category: 'agent_tool', regex: /\bcodex\b/i },
{ id: 'cursor', category: 'agent_tool', regex: /\bcursor\b/i },
{ id: 'cline', category: 'agent_tool', regex: /\bcline\b/i },
{ id: 'aider', category: 'agent_tool', regex: /\baider\b/i },
{ id: 'continue', category: 'agent_tool', regex: /\bcontinue\b/i },
{ id: 'openhands', category: 'agent_tool', regex: /\bopenhands\b/i },
{ id: 'openclaw', category: 'agent_tool', regex: /\bopenclaw\b/i },
{ id: 'nanobot', category: 'agent_tool', regex: /\bnanobot\b/i },
{ id: 'browser-use', category: 'agent_tool', regex: /\bbrowser[- ]use\b/i },
{ id: 'stagehand', category: 'agent_tool', regex: /\bstagehand\b/i },
];
const AUTOMATION_UA_RULES = [
{ id: 'headless-browser', category: 'automation_runtime', regex: /\bHeadlessChrome\b|\bHeadless\b/i },
{ id: 'playwright', category: 'automation_runtime', regex: /\bPlaywright\b/i },
{ id: 'puppeteer', category: 'automation_runtime', regex: /\bPuppeteer\b/i },
{ id: 'selenium', category: 'automation_runtime', regex: /\bSelenium\b/i },
{ id: 'phantomjs', category: 'automation_runtime', regex: /\bPhantomJS\b|\bPhantom\b/i },
];
const SCRIPTED_CLIENT_UA_RULES = [
{ id: 'python-requests', category: 'scripted_client', regex: /\bpython-requests\b/i },
{ id: 'python-httpx', category: 'scripted_client', regex: /\bpython-httpx\b/i },
{ id: 'axios', category: 'scripted_client', regex: /\baxios\b/i },
{ id: 'node-fetch', category: 'scripted_client', regex: /\bnode-fetch\b/i },
{ id: 'undici', category: 'scripted_client', regex: /\bundici\b/i },
{ id: 'go-http-client', category: 'scripted_client', regex: /\bGo-http-client\b/i },
{ id: 'curl', category: 'scripted_client', regex: /\bcurl\b/i },
{ id: 'wget', category: 'scripted_client', regex: /\bwget\b/i },
];
const CATEGORY_PRIORITY = ['official_ai_agent', 'agent_tool', 'automation_runtime', 'scripted_client'];
let humanConfirmed = false;
let posthogReady = false;
const pendingPosthogEvents = [];
function isTrackedHost() {
return COUNTED_HOSTS.has(location.hostname);
}
function applyVisitorStats(stats) {
const formatK = (val) => {
const n = Number(val) || 0;
if (!n) return '0K';
return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
};
document.getElementById('stat-web-unique').textContent = formatK(stats.web_unique_visitors);
document.getElementById('stat-cli-total').textContent = formatK(stats.cli_hub_total);
document.getElementById('stat-cli-human').textContent = formatK(stats.cli_hub_human);
document.getElementById('stat-cli-agent').textContent = formatK(stats.cli_hub_agent);
}
function readUaBrands() {
const brands = navigator.userAgentData && Array.isArray(navigator.userAgentData.brands)
? navigator.userAgentData.brands
: [];
return brands.map((brand) => brand.brand).join(' ');
}
function collectRuleSignals(ua, rules, signals) {
rules.forEach((rule) => {
if (rule.regex.test(ua)) {
signals.push(rule);
}
});
}
function collectRuntimeSignals(brands, signals) {
if (navigator.webdriver === true) {
signals.push({ id: 'webdriver', category: 'automation_runtime' });
}
if (/HeadlessChrome/i.test(brands)) {
signals.push({ id: 'ua-brand-headlesschrome', category: 'automation_runtime' });
}
if ('__playwright__binding__' in window || '__pwManual' in window) {
signals.push({ id: 'playwright-runtime', category: 'automation_runtime' });
}
if ('Cypress' in window) {
signals.push({ id: 'cypress-runtime', category: 'automation_runtime' });
}
if ('_phantom' in window || 'callPhantom' in window) {
signals.push({ id: 'phantom-runtime', category: 'automation_runtime' });
}
if ('domAutomation' in window || 'domAutomationController' in window) {
signals.push({ id: 'dom-automation', category: 'automation_runtime' });
}
}
function classifyVisitor() {
const ua = navigator.userAgent || '';
const brands = readUaBrands();
const signals = [];
collectRuleSignals(ua, OFFICIAL_AGENT_UA_RULES, signals);
collectRuleSignals(ua, AGENT_TOOL_UA_RULES, signals);
collectRuleSignals(ua, AUTOMATION_UA_RULES, signals);
collectRuleSignals(ua, SCRIPTED_CLIENT_UA_RULES, signals);
collectRuntimeSignals(brands, signals);
const seen = new Set();
const uniqueSignals = signals.filter((signal) => {
if (seen.has(signal.id)) return false;
seen.add(signal.id);
return true;
}).sort((left, right) => CATEGORY_PRIORITY.indexOf(left.category) - CATEGORY_PRIORITY.indexOf(right.category));
const primary = uniqueSignals[0] || null;
const isAgent = uniqueSignals.length > 0;
return {
ua,
brands,
webdriver: navigator.webdriver === true,
isAgent,
isAutomation: !!primary && (primary.category === 'automation_runtime' || primary.category === 'scripted_client'),
trafficType: isAgent ? 'agent' : 'human',
reason: primary ? primary.id : 'human',
category: primary ? primary.category : 'human',
signals: uniqueSignals.map((signal) => signal.id),
};
}
const visitor = classifyVisitor();
function analyticsContext(eventData) {
const base = {
source: 'web',
site: ANALYTICS_SITE,
host: location.hostname,
visitor_type: visitor.trafficType,
is_agent: visitor.isAgent,
is_automation: visitor.isAutomation,
agent_category: visitor.category,
agent_reason: visitor.reason,
agent_signals: visitor.signals.slice(0, 12),
ua: visitor.ua.slice(0, 200),
ua_brands: visitor.brands.slice(0, 200),
webdriver: visitor.webdriver,
};
if (ANALYTICS_TEST_RUN) {
base.test_run = ANALYTICS_TEST_RUN;
}
return { ...base, ...eventData };
}
function initPosthog() {
if (!isTrackedHost()) return;
!function(t,e){var o,n,p,r;e.__SV||(window.posthog&&window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split('.');2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement('script')).type='text/javascript',p.crossOrigin='anonymous',p.async=!0,p.src=s.api_host.replace('.i.posthog.com','-assets.i.posthog.com')+'/static/array.js',(r=t.getElementsByTagName('script')[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a='posthog',u.people=u.people||[],u.toString=function(t){var e='posthog';return'posthog'!==a&&(e+='.'+a),t||(e+=' (stub)'),e},u.people.toString=function(){return u.toString(1)+'.people (stub)'},o='init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug'.split(' '),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
window.posthog.init(POSTHOG_CONFIG.projectToken, {
api_host: POSTHOG_CONFIG.apiHost,
defaults: POSTHOG_CONFIG.defaults,
person_profiles: POSTHOG_CONFIG.personProfiles,
opt_out_useragent_filter: true,
loaded: function(posthog) {
posthogReady = true;
while (pendingPosthogEvents.length) {
const queued = pendingPosthogEvents.shift();
posthog.capture(queued.eventName, analyticsContext(queued.eventData));
}
},
});
}
function initUmami() {
if (!isTrackedHost()) return;
const script = document.createElement('script');
script.defer = true;
script.src = 'https://cloud.umami.is/script.js';
script.dataset.websiteId = UMAMI_CONFIG.websiteId;
document.head.appendChild(script);
}
function trackWithPosthog(eventName, eventData) {
if (!isTrackedHost() || !window.posthog) return;
if (!posthogReady || typeof window.posthog.capture !== 'function') {
pendingPosthogEvents.push({ eventName, eventData });
return;
}
window.posthog.capture(eventName, analyticsContext(eventData));
}
function trackWithUmami(eventName, eventData) {
if (!isTrackedHost()) return;
const payload = {
type: 'event',
payload: {
website: UMAMI_CONFIG.websiteId,
hostname: ANALYTICS_SITE,
url: location.pathname,
name: eventName,
data: analyticsContext(eventData),
},
};
fetch(UMAMI_CONFIG.sendUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
keepalive: true,
}).catch(() => {});
}
function trackAnalyticsEvent(eventName, eventData) {
if (ANALYTICS_PROVIDER === 'umami') {
trackWithUmami(eventName, eventData);
return;
}
trackWithPosthog(eventName, eventData);
}
if (ANALYTICS_PROVIDER === 'umami') {
initUmami();
} else {
initPosthog();
}
if (ANALYTICS_TEST_RUN) {
window.__CLI_ANYTHING_ANALYTICS__ = {
visitor: {
isAgent: visitor.isAgent,
isAutomation: visitor.isAutomation,
trafficType: visitor.trafficType,
category: visitor.category,
reason: visitor.reason,
signals: visitor.signals.slice(),
webdriver: visitor.webdriver,
ua: visitor.ua,
},
};
}
if (isTrackedHost() && visitor.isAgent) {
trackAnalyticsEvent('visit-agent', {
classification_source: 'initial-load',
});
}
function onHumanInteraction(event) {
if (humanConfirmed || !isTrackedHost() || visitor.trafficType !== 'human') return;
humanConfirmed = true;
trackAnalyticsEvent('visit-human', {
classification_source: 'user-interaction',
interaction: event.type,
});
['mousemove', 'touchstart', 'scroll', 'keydown', 'click'].forEach((evt) => {
document.removeEventListener(evt, onHumanInteraction);
});
}
['mousemove', 'touchstart', 'scroll', 'keydown', 'click'].forEach((evt) => {
document.addEventListener(evt, onHumanInteraction, { once: false, passive: true });
});
// ── Live analytics via Cloudflare Worker proxy ──
// Runtime stats are fetched once per page load and rendered as compact
// Cloudflare unique visitor and CLI-Hub usage counters.
const ANALYTICS_PROXY_URL = 'https://analytics.clianything.cc/';
const ZERO_STATS = {
web_unique_visitors: 0,
cli_hub_total: 0,
cli_hub_human: 0, cli_hub_agent: 0,
};
function normalizeStats(stats) {
const cliHubHuman = Number(stats && stats.cli_hub_human) || 0;
const cliHubAgent = Number(stats && stats.cli_hub_agent) || 0;
return {
web_unique_visitors: Number(stats && (stats.web_unique_visitors ?? stats.total)) || 0,
cli_hub_total: Number(stats && stats.cli_hub_total) || cliHubHuman + cliHubAgent,
cli_hub_human: cliHubHuman,
cli_hub_agent: cliHubAgent,
};
}
async function fetchWorkerStats() {
const response = await fetch(ANALYTICS_PROXY_URL + 'stats');
if (!response.ok) throw new Error('analytics stats http ' + response.status);
const data = await response.json();
return normalizeStats(data.stats || data);
}
async function fetchVisitorStats() {
return fetchWorkerStats();
}
function hasAnyStats(s) {
return Object.keys(ZERO_STATS).some((key) => (s[key] || 0) > 0);
}
async function refreshVisitorStats() {
const stats = await fetchVisitorStats();
if (!hasAnyStats(stats)) return false;
applyVisitorStats(stats);
return true;
}
async function loadVisitorStats() {
await refreshVisitorStats().catch(() => false);
}
loadVisitorStats();
if (typeof loadGitHubStars === 'function') {
loadGitHubStars();
}
})();
</script>
</body>
</html>