awesome-templates
registry/index.html
无英文版
registry/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Agent Sandbox Registry</title>
<style>
:root {
--bg: #f3efe4;
--ink: #1c1915;
--muted: #5c564c;
--line: #d9d0c1;
--card: #fffdf8;
--accent: #9a3412;
--ok: #1f6b45;
--no: #8f2d2d;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font: 16px/1.5 "Iowan Old Style", Palatino, "Palatino Linotype", serif;
}
header, main { width: min(1100px, calc(100% - 32px)); margin: 0 auto; }
header { padding: 40px 0 12px; }
h1 { font-size: 40px; line-height: 1.1; margin: 0 0 8px; letter-spacing: -0.03em; }
h2 { font-size: 22px; margin: 36px 0 10px; }
p.lead { max-width: 68ch; color: var(--muted); margin: 0; }
a { color: var(--accent); }
.bar { display: flex; gap: 8px; flex-wrap: wrap; margin: 18px 0; }
input, button {
font: inherit;
border: 1px solid var(--line);
background: var(--card);
color: var(--ink);
border-radius: 999px;
padding: 8px 14px;
}
input { min-width: min(100%, 280px); }
button[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
table { width: 100%; border-collapse: collapse; background: var(--card); }
th, td { text-align: left; vertical-align: top; padding: 10px 12px; border-bottom: 1px solid var(--line); }
th { font-size: 13px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
.tag { display: inline-block; margin: 0 4px 4px 0; padding: 1px 7px; border: 1px solid var(--line); border-radius: 999px; font-size: 13px; }
.ok { color: var(--ok); }
.no { color: var(--no); }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
article { background: var(--card); border: 1px solid var(--line); padding: 14px 16px; }
article h3 { margin: 0 0 6px; font-size: 18px; }
article p { margin: 0 0 8px; }
code { font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; font-size: 0.92em; }
footer { width: min(1100px, calc(100% - 32px)); margin: 28px auto 48px; color: var(--muted); }
@media (max-width: 720px) {
h1 { font-size: 32px; }
table { display: block; overflow-x: auto; }
}
</style>
</head>
<body>
<header>
<h1>Agent Sandbox Registry</h1>
<p class="lead">这里列出当前 SDK 的五个 provider,以及 awesome-templates 里能被搜索到的模板。能安装、能创建、只是一个名字,这三件事是分开的。域名 registry.agent-sandbox.cn 还没有接到这页上。</p>
<div class="bar">
<input id="q" type="search" placeholder="搜索模板或 provider" aria-label="搜索" />
<button type="button" data-filter="all" aria-pressed="true">全部模板</button>
<button type="button" data-filter="platform">平台模板</button>
<button type="button" data-filter="docker">可构建镜像</button>
</div>
</header>
<main>
<h2>Provider</h2>
<div id="providers" class="cards"></div>
<h2>模板</h2>
<table>
<thead>
<tr>
<th>名称</th>
<th>说明</th>
<th>极速版</th>
<th>容器版</th>
<th>Cube</th>
<th>E2B</th>
<th>OpenSandbox</th>
</tr>
</thead>
<tbody id="rows"></tbody>
</table>
</main>
<footer>
数据来自本仓库的 <code>awesome-templates.yaml</code>。<code>providers</code> 字段当前 CLI 会忽略,<code>schema_version</code> 仍是 1。CLI 只能对极速版执行 <code>abx template install</code>。
</footer>
<script>
const labels = {
supported: "可安装",
builtin: "内置 id",
"preexisting-template-id": "已有 id 才行",
"push-image-then-pass-uri": "先推镜像",
"unsupported-needs-pty": "不支持终端",
unsupported: "不支持",
"image-python-3.12-slim": "映射到 slim",
"use-opensandbox-code-interpreter": "用另一镜像",
"image-opensandbox-code-interpreter": "镜像 URI"
};
const order = ["alicloud-express", "alicloud-container", "cubesandbox", "e2b", "opensandbox"];
let catalog = { providers: [], templates: [] };
let filter = "all";
function cell(value) {
const text = labels[value] || value || "—";
const cls = value === "supported" || value === "builtin" ? "ok" : (String(value).startsWith("unsupported") ? "no" : "");
return `<td class="${cls}">${text}</td>`;
}
function draw() {
const q = document.getElementById("q").value.trim().toLowerCase();
const rows = catalog.templates.filter((row) => {
const platform = ["base", "code-interpreter-v1", "desktop", "opensandbox-code-interpreter"].includes(row.name);
if (filter === "platform" && !platform) return false;
if (filter === "docker" && platform) return false;
const blob = `${row.name} ${row.description} ${(row.tags || []).join(" ")}`.toLowerCase();
return !q || blob.includes(q);
});
document.getElementById("rows").innerHTML = rows.map((row) => {
const p = row.providers || {};
return `<tr><td><code>${row.name}</code></td><td>${row.description}</td>${order.map((id) => cell(p[id])).join("")}</tr>`;
}).join("");
const pq = q;
document.getElementById("providers").innerHTML = catalog.providers.filter((p) => {
return !pq || `${p.id} ${p.name} ${p.templates} ${p.limits}`.toLowerCase().includes(pq);
}).map((p) => `
<article>
<h3>${p.name}</h3>
<p><code>${p.id}</code></p>
<p>${p.cli ? "CLI 可加载" : "仅 Python SDK,CLI 返回 E8001"}</p>
<p>${p.templates}</p>
<p>${p.limits}</p>
</article>
`).join("");
}
document.getElementById("q").addEventListener("input", draw);
for (const button of document.querySelectorAll("button[data-filter]")) {
button.addEventListener("click", () => {
filter = button.dataset.filter;
for (const other of document.querySelectorAll("button[data-filter]")) {
other.setAttribute("aria-pressed", other === button ? "true" : "false");
}
draw();
});
}
fetch("catalog.json").then((res) => res.json()).then((data) => { catalog = data; draw(); });
</script>
</body>
</html>