Files
Yaowei Zheng d4faee3a1e Changelog, dev startup, README, AgentHub 0.4.0, model catalog, and landing site (#7)
Branch-length batch covering tooling, the model layer, the Web App and the public
surfaces. Highlights:

- Changelog: a per-release `changelog/<version>/` tree, grouped by the surface each
  change touches, with a root CHANGELOG.md holding one line per release.
- Dev startup: `scripts/dev-prebuild.mjs` serializes the skills+core prebuild behind a
  lock and keeps `pnpm install` current; `pnpm dev` runs server+web together.
- AgentHub 0.3.3 -> 0.4.0: OmniMessage complete payloads carry one opaque `fidelity`
  object in place of item-level `signature`/`phase`, threaded verbatim through Trace,
  replay and resume; malformed classification adapted to the new error types.
- Model layer: a model is always referenced by an explicit `(provider, model_id)` pair.
  The provider is never inferred, guessed or defaulted -- both the catalog inference and
  the unique-match config resolution are gone, and CLI, SDK, server routes and
  run_subagent all require the complete pair. Catalog gains the Qwen Token Plan, Qwen
  Pay-As-You-Go and Fireworks AI gateways, plus an expanded OpenRouter group.
- Web App: catalog preset sync and per-group speed test on the Models page, positional
  slash commands, a markdown renderer, skill-library update reminders, and a vertically
  centred draft page whose upward menus size themselves to the room available.
- Public surfaces: restructured READMEs, the penguin.ooo landing site and blog, refreshed
  benchmark results for both suites, and the demo videos playing on the landing page.

Includes the fixes from a full review of the branch: 23 confirmed findings, among them a
provider-inference bug that could send one vendor's API key to another vendor's endpoint,
and an Escape handler that destroyed the composer's contents unrecoverably.

Verified on the branch head: pnpm test (1127 passing, 7 packages), pnpm typecheck and
pnpm format:check clean, Playwright e2e 14/14.
2026-07-21 17:43:31 +08:00

440 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<!--
Finished-product mockup of the "one sentence → RAG app" example (a Claude Code docs
expert), rendered by capture-readme-demo.mjs into assets/readme/rag-app-<lang>-<theme>.webp.
Pure static page — no build, no server; ?lang=zh|en&theme=light|dark picks the variant.
Styling follows the web-design skill's Penguin visual language: solid backgrounds,
1px hairlines, system fonts, one brand-blue accent, pure-black dark mode.
-->
<head>
<meta charset="utf-8" />
<title>Claude Code Docs Expert</title>
<style>
:root {
color-scheme: light;
--brand-50: #e8f0fe;
--brand-100: #d2e3fc;
--brand-300: #8ab4f8;
--brand-500: #4285f4;
--brand-600: #1a73e8;
--brand-700: #0b57d0;
--bg: #ffffff;
--surface: #ffffff;
--surface-2: #f9fafb;
--border: #e5e7eb;
--control-border: #d1d5db;
--fg: #111827;
--fg-muted: #4b5563;
--fg-faint: #6b7280;
--accent-bg: #111827;
--accent-fg: #ffffff;
--bubble: #f3f4f6;
--code-bg: #f9fafb;
--chip-bg: #e8f0fe;
--chip-fg: #0b57d0;
--chip-border: #d2e3fc;
--dots: rgb(26 115 232 / 0.14);
}
.dark {
color-scheme: dark;
--bg: #000000;
--surface: #0d0d0d;
--surface-2: #0d0d0d;
--border: #1f1f1f;
--control-border: #303030;
--fg: #f3f4f6;
--fg-muted: #9ca3af;
--fg-faint: #6b7280;
--accent-bg: #f3f4f6;
--accent-fg: #111827;
--bubble: #1f1f1f;
--code-bg: #0d0d0d;
--chip-bg: #041e49;
--chip-fg: #8ab4f8;
--chip-border: #062e6f;
--dots: rgb(138 180 248 / 0.16);
}
* {
box-sizing: border-box;
margin: 0;
}
body {
font-family:
ui-sans-serif,
system-ui,
-apple-system,
"Segoe UI",
Roboto,
"PingFang SC",
"Microsoft YaHei",
sans-serif;
-webkit-font-smoothing: antialiased;
background: var(--bg);
color: var(--fg);
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
code,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
nav {
height: 56px;
flex: none;
display: flex;
align-items: center;
gap: 10px;
padding: 0 24px;
border-bottom: 1px solid var(--border);
background: color-mix(in srgb, var(--bg) 85%, transparent);
}
.logo {
width: 28px;
height: 28px;
border-radius: 8px;
background: var(--accent-bg);
color: var(--accent-fg);
display: grid;
place-items: center;
flex: none;
}
.logo svg {
width: 16px;
height: 16px;
}
.app-name {
font-size: 15px;
font-weight: 600;
letter-spacing: -0.01em;
}
.nav-chip {
font-size: 11px;
font-weight: 500;
color: var(--chip-fg);
background: var(--chip-bg);
border: 1px solid var(--chip-border);
border-radius: 9999px;
padding: 2px 10px;
}
.nav-right {
margin-left: auto;
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--fg-faint);
}
.dot {
width: 6px;
height: 6px;
border-radius: 9999px;
background: #10b981;
}
main {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
width: 100%;
max-width: 48rem;
margin: 0 auto;
padding: 0 24px;
}
/* Decorative dot grid fading out below the nav — the one flourish the design language
allows. The ::after overlay fades to the page background, so the tail disappears
cleanly in dark mode too (light dots on black stay visible far longer under a mask). */
.dots-band {
position: absolute;
inset: 56px 0 auto 0;
height: 150px;
background-image: radial-gradient(var(--dots) 1px, transparent 1px);
background-size: 22px 22px;
pointer-events: none;
}
.dots-band::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(
to bottom,
transparent 0%,
color-mix(in srgb, var(--bg) 55%, transparent) 55%,
var(--bg) 100%
);
}
.chat {
flex: 1;
min-height: 0;
overflow: hidden;
padding-top: 28px;
display: flex;
flex-direction: column;
gap: 20px;
position: relative;
}
.msg-user {
align-self: flex-end;
max-width: 85%;
background: var(--bubble);
border-radius: 12px;
padding: 9px 14px;
font-size: 14px;
line-height: 1.55;
}
.msg-assistant {
font-size: 14px;
line-height: 1.65;
color: var(--fg);
display: flex;
flex-direction: column;
gap: 10px;
}
.msg-assistant p {
max-width: 65ch;
}
.cite {
color: var(--brand-600);
font-size: 0.8em;
vertical-align: super;
font-weight: 600;
text-decoration: none;
}
.dark .cite {
color: var(--brand-300);
}
pre.block {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px 14px;
font-size: 13px;
line-height: 1.85;
overflow-x: auto;
}
pre.block .c {
color: var(--fg-faint);
}
.sources {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 2px;
}
.sources-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--fg-faint);
}
.source-chip {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--chip-fg);
background: var(--chip-bg);
border: 1px solid var(--chip-border);
border-radius: 9999px;
padding: 3px 11px;
text-decoration: none;
}
.source-chip .n {
font-weight: 600;
}
.source-chip .path {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 11px;
}
.bottom {
flex: none;
padding: 14px 0 20px;
display: flex;
flex-direction: column;
gap: 10px;
}
.suggests {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.suggest {
font-size: 12px;
color: var(--fg-muted);
border: 1px solid var(--border);
background: var(--surface);
border-radius: 9999px;
padding: 5px 12px;
}
.composer {
border: 1px solid var(--control-border);
background: var(--surface);
border-radius: 12px;
padding: 12px 12px 10px 14px;
display: flex;
align-items: flex-end;
gap: 10px;
}
.composer .ph {
flex: 1;
font-size: 14px;
color: var(--fg-faint);
padding: 4px 0 6px;
}
.send {
width: 32px;
height: 32px;
border-radius: 8px;
border: none;
background: var(--accent-bg);
color: var(--accent-fg);
display: grid;
place-items: center;
flex: none;
}
.hint {
font-size: 11px;
color: var(--fg-faint);
text-align: center;
}
</style>
</head>
<body>
<div class="dots-band"></div>
<nav>
<div class="logo" aria-hidden>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M4 19.5V6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v13.5" stroke="none" />
<path
d="M12 3c3.5 0 5.5 2.6 5.5 6.2 0 4.4 1.6 6.3 2.5 7.1-1.6 2.9-4.6 4.7-8 4.7s-6.4-1.8-8-4.7c.9-.8 2.5-2.7 2.5-7.1C6.5 5.6 8.5 3 12 3z"
/>
<circle cx="9.8" cy="8.6" r="0.6" fill="currentColor" stroke="none" />
<circle cx="14.2" cy="8.6" r="0.6" fill="currentColor" stroke="none" />
<path d="M10.6 11h2.8l-1.4 1.6z" fill="currentColor" stroke="none" />
</svg>
</div>
<span class="app-name" data-t="appName"></span>
<span class="nav-chip">RAG · claude-code-docs</span>
<div class="nav-right"><span class="dot"></span><span data-t="corpus"></span></div>
</nav>
<main>
<div class="chat">
<div class="msg-user" data-t="question"></div>
<div class="msg-assistant">
<p>
<span data-t="a1"></span>
<a class="cite" href="#">[1]</a><span data-t="a1b"></span>
</p>
<pre class="block"><span class="c" data-t="codeC1"></span>
claude mcp add github -- npx -y @modelcontextprotocol/server-github
<span class="c" data-t="codeC2"></span>
claude mcp list</pre>
<p>
<span data-t="a2"></span>
<a class="cite" href="#">[2]</a><span data-t="a2b"></span>
</p>
<div class="sources">
<span class="sources-label" data-t="sources"></span>
<a class="source-chip" href="#"
><span class="n">[1]</span><span class="path">docs/mcp.md</span
><span data-t="s1"></span
></a>
<a class="source-chip" href="#"
><span class="n">[2]</span><span class="path">docs/settings.md</span
><span data-t="s2"></span
></a>
</div>
</div>
</div>
<div class="bottom">
<div class="suggests">
<span class="suggest" data-t="q1"></span>
<span class="suggest" data-t="q2"></span>
<span class="suggest" data-t="q3"></span>
</div>
<div class="composer">
<div class="ph" data-t="placeholder"></div>
<button class="send" aria-hidden>
<svg
width="15"
height="15"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 19V5M6 11l6-6 6 6" />
</svg>
</button>
</div>
<div class="hint" data-t="hint"></div>
</div>
</main>
<script>
const T = {
en: {
appName: "Claude Code Docs Expert",
corpus: "674 chunks · BM25",
question: "How do I configure an MCP server for Claude Code?",
a1: "Add the server with the CLI, then verify it from inside Claude Code ",
a1b: ":",
codeC1: "# add a server (local scope by default)",
codeC2: "# verify",
a2: "Project-scoped servers live in .mcp.json at the project root and are shared with your team; user scope makes a server available across all your projects ",
a2b: ". Inside a session, /mcp shows each server's connection status.",
sources: "Sources",
s1: "— Add an MCP server",
s2: "— Settings & scopes",
q1: "What does CLAUDE.md do?",
q2: "How do I create a custom slash command?",
q3: "Where do hooks go?",
placeholder: "Ask about Claude Code…",
hint: "Answers cite the collected docs — click a source to open the original file.",
},
zh: {
appName: "Claude Code 配置专家",
corpus: "674 个片段 · BM25",
question: "如何为 Claude Code 配置 MCP 服务器?",
a1: "用 CLI 添加服务器,然后在 Claude Code 里验证 ",
a1b: ":",
codeC1: "# 添加服务器(默认 local 作用域)",
codeC2: "# 验证",
a2: "项目级服务器保存在项目根目录的 .mcp.json,可随仓库共享给团队;user 作用域则让服务器在你的所有项目中可用 ",
a2b: "。会话内可用 /mcp 查看各服务器的连接状态。",
sources: "来源",
s1: "— 添加 MCP 服务器",
s2: "— 设置与作用域",
q1: "CLAUDE.md 是做什么的?",
q2: "怎么创建自定义斜杠命令?",
q3: "Hooks 配置放在哪里?",
placeholder: "向 Claude Code 专家提问…",
hint: "回答引用采集的文档——点击来源即可打开原文。",
},
};
const params = new URLSearchParams(location.search);
const lang = params.get("lang") === "zh" ? "zh" : "en";
const theme = params.get("theme") === "dark" ? "dark" : "light";
document.documentElement.lang = lang === "zh" ? "zh" : "en";
if (theme === "dark") document.documentElement.classList.add("dark");
for (const el of document.querySelectorAll("[data-t]")) {
el.textContent = T[lang][el.dataset.t];
}
document.title = T[lang].appName;
</script>
</body>
</html>