返回 CodeWhale
page.tsx
根目录 / web / app / [locale] / runtime / page.tsx
1 import { Icon, type IconName } from "@/components/icon";
2 import { PageHeader, Section } from "@/components/page-header";
3 import { Status } from "@/components/status-badge";
4 import { getFacts } from "@/lib/facts";
5 import { getRuntime, pickText } from "@/lib/i18n/dictionaries";
6 import { buildPageMetadata } from "@/lib/page-meta";
7
8 const REPO_BLOB_BASE = "https://github.com/codewhale-hq/CodeWhale/blob/main";
9
10 export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
11 const { locale } = await params;
12 const t = getRuntime(locale);
13 return buildPageMetadata({
14 path: "/runtime",
15 locale,
16 title: t.metaTitle,
17 description: t.metaDescription,
18 });
19 }
20
21 interface Integration {
22 name: string;
23 icon: IconName;
24 experimental?: boolean;
25 desc: { en: string; zh: string };
26 href: string;
27 }
28
29 const INTEGRATIONS: Integration[] = [
30 {
31 name: "HTTP / SSE Runtime API",
32 icon: "terminal",
33 desc: {
34 en: "Full local HTTP + Server-Sent Events runtime API on 127.0.0.1:7878. Create threads, stream turns, manage background jobs, and control approval decisions — all from any HTTP client or the bundled mobile page.",
35 zh: "完整的本地 HTTP + Server-Sent Events Runtime API,监听 127.0.0.1:7878。创建线程、流式对话、管理后台任务、控制审批决策——任意 HTTP 客户端或内置手机页面皆可调用。",
36 },
37 href: `${REPO_BLOB_BASE}/docs/RUNTIME_API.md`,
38 },
39 {
40 name: "ACP (Agent Client Protocol)",
41 icon: "plug",
42 desc: {
43 en: "Baseline JSON-RPC adapter over stdio for compatible editor clients such as Zed. It supports initialize, new session, prompt, and cancel with text responses; shell and file tools, checkpoint replay, and session loading remain on the full Runtime API.",
44 zh: "面向 Zed 等兼容编辑器客户端的基础 JSON-RPC stdio 适配器。它支持初始化、新建会话、提示和取消,并返回文本响应;shell 与文件工具、检查点回放和会话加载仍由完整 Runtime API 提供。",
45 },
46 href: `${REPO_BLOB_BASE}/docs/RUNTIME_API.md`,
47 },
48 {
49 name: "MCP (Model Context Protocol)",
50 icon: "plug",
51 desc: {
52 en: "Connect Codewhale to external tools and services through configured MCP servers over stdio or HTTP/SSE, or expose Codewhale's own tools to another MCP client.",
53 zh: "通过已配置的 MCP 服务器(stdio 或 HTTP/SSE)将 Codewhale 连接到外部工具和服务,或把 Codewhale 自身工具暴露给其他 MCP 客户端。",
54 },
55 href: `${REPO_BLOB_BASE}/docs/MCP.md`,
56 },
57 {
58 name: "VS Code Extension",
59 icon: "monitor",
60 desc: {
61 en: "Early companion for the local runtime. It can open Codewhale in a terminal, start and check the Runtime API, and show read-only thread summaries and restore points. It does not yet provide full chat, inline edits, or editor actions.",
62 zh: "本地 Runtime 的早期配套扩展。它可以在终端中打开 Codewhale、启动并检查 Runtime API,以及显示只读线程摘要和还原点;目前尚不提供完整聊天、内联编辑或编辑器操作。",
63 },
64 href: "https://github.com/codewhale-hq/CodeWhale/tree/main/extensions/vscode",
65 },
66 {
67 name: "CodeWhale GUI (VS Code)",
68 icon: "monitor",
69 desc: {
70 en: "The community-maintained graphical frontend, in a separate repository: chat, threads, live file changes, and task tracking in a VS Code sidebar over this Runtime API. Install it from the VS Code Marketplace; the source is on GitHub.",
71 zh: "社区维护的图形前端,位于独立仓库:在 VS Code 侧边栏中基于此 Runtime API 进行对话、管理线程、查看实时文件变更与任务进度。可从 VS Code Marketplace 安装;源码见 GitHub。",
72 },
73 href: "https://marketplace.visualstudio.com/items?itemName=HengQuWorld.brotherwhale-vscode",
74 },
75 {
76 name: "Telegram Bridge",
77 icon: "message",
78 desc: {
79 en: "First-party Telegram bot bridge. Start a headless Codewhale session, then chat with it from any Telegram client — approvals, tool results, and completions surface inline.",
80 zh: "官方 Telegram 机器人桥接。启动无头 Codewhale 会话,在任何 Telegram 客户端中与之对话——审批、工具结果和完成状态内联展示。",
81 },
82 href: "https://github.com/codewhale-hq/CodeWhale/tree/main/integrations/telegram-bridge",
83 },
84 {
85 name: "Feishu / Lark Bridge",
86 icon: "message",
87 desc: {
88 en: "First-party Feishu / Lark bot bridge. Chat-native agent loop inside your Feishu workspace with approval cards, session linking, and audit trail.",
89 zh: "官方飞书 / Lark 机器人桥接。在飞书工作区内实现聊天原生 Agent 循环,支持审批卡片、会话关联和审计日志。",
90 },
91 href: "https://github.com/codewhale-hq/CodeWhale/tree/main/integrations/feishu-bridge",
92 },
93 {
94 name: "Weixin Bridge",
95 icon: "message",
96 experimental: true,
97 desc: {
98 en: "Experimental Weixin / WeChat bridge. Receive agent completions and approvals inside WeChat; early-stage and not recommended for production deployments.",
99 zh: "实验性微信桥接。在微信中接收 Agent 完成通知和审批;早期阶段,不建议用于生产环境。",
100 },
101 href: "https://github.com/codewhale-hq/CodeWhale/tree/main/integrations/weixin-bridge",
102 },
103 ];
104
105 const TRUST = [
106 {
107 title: { en: "Runs on your machine", zh: "本机运行" },
108 body: {
109 en: "The Runtime API binds 127.0.0.1 by default. The local runtime does not require a Codewhale account or hosted relay.",
110 zh: "Runtime API 默认仅监听 127.0.0.1。本地运行时不需要 Codewhale 账户或托管中继。",
111 },
112 },
113 {
114 title: { en: "Auth required", zh: "认证必需" },
115 body: {
116 en: "Runtime API routes (/v1/*) require a Bearer token. Pass --auth-token at startup or set CODEWHALE_RUNTIME_TOKEN. Only a loopback bind can turn this off, with --insecure-no-auth.",
117 zh: "Runtime API 路由(/v1/*)需要 Bearer Token。启动时传入 --auth-token,或设置 CODEWHALE_RUNTIME_TOKEN 环境变量。仅在回环地址上可用 --insecure-no-auth 关闭认证。",
118 },
119 },
120 {
121 title: { en: "Permissions user-controlled", zh: "权限用户控制" },
122 body: {
123 en: "Remote clients submit requests and approval decisions through the authenticated Runtime API. Local mode, permission posture, and sandbox policy still apply.",
124 zh: "远程客户端通过经过认证的 Runtime API 提交请求与审批决定。本地模式、权限姿态和沙箱策略仍然生效。",
125 },
126 },
127 {
128 title: { en: "Open protocols", zh: "开放协议" },
129 body: {
130 en: "The HTTP/SSE Runtime API, MCP surface, and baseline ACP stdio adapter serve different integration needs; choose the interface your compatible client supports.",
131 zh: "HTTP/SSE Runtime API、MCP 和基础 ACP stdio 适配器分别服务于不同集成场景;请根据客户端需要选择对应接口。",
132 },
133 },
134 ];
135
136 export default async function RuntimePage({ params }: { params: Promise<{ locale: string }> }) {
137 const { locale } = await params;
138 const t = getRuntime(locale);
139 const facts = await getFacts();
140
141 return (
142 <>
143 <PageHeader
144 seal="接"
145 kicker={t.kicker}
146 title={t.title}
147 titleAside={t.titleAside}
148 titleAsideLang={t.titleAsideLang}
149 lede={t.lede}
150 pose="run"
151 />
152
153 <div className="page-body">
154 <Section id="runtime-integrations" seal="集" title={t.integrationsTitle}>
155 <ul className="dir-list dir-list-card" role="list">
156 {INTEGRATIONS.map((item) => (
157 <li key={item.name}>
158 <a href={item.href} target="_blank" rel="noopener noreferrer" className="dir-row">
159 <span className="dir-mark" aria-hidden="true"><Icon name={item.icon} /></span>
160 <span className="dir-text">
161 <span className="dir-title">{item.name}</span>
162 <span className="dir-purpose">{pickText(item.desc, locale)}</span>
163 </span>
164 {item.experimental ? <Status tone="attention">{t.experimental}</Status> : null}
165 <span className="dir-action" aria-hidden="true"><Icon name="external" /></span>
166 </a>
167 </li>
168 ))}
169 </ul>
170 </Section>
171
172 <Section id="runtime-trust" layout="split" seal="信" title={t.trustTitle}>
173 <dl className="ruled-list ruled-list-stacked">
174 {TRUST.map((item) => (
175 <div key={item.title.en}>
176 <dt>{pickText(item.title, locale)}</dt>
177 <dd>{pickText(item.body, locale)}</dd>
178 </div>
179 ))}
180 </dl>
181 </Section>
182
183 <Section id="runtime-facts" layout="split" seal="数" title={t.factsTitle}>
184 <dl className="ruled-list">
185 <div>
186 <dt>{t.version}</dt>
187 <dd className="tabular">{facts.version ?? "—"}</dd>
188 </div>
189 <div>
190 <dt>{t.toolCount}</dt>
191 <dd className="tabular">{facts.toolCount ?? "—"}</dd>
192 </div>
193 <div>
194 <dt>{t.sandboxBackends}</dt>
195 <dd>{facts.sandboxBackends.length ? facts.sandboxBackends.join(" · ") : "—"}</dd>
196 </div>
197 </dl>
198 {/* Crate names and the source revision are for maintainers; they
199 sit behind Details. */}
200 <details className="group-card disclosure-row mt-4">
201 <summary>
202 {t.details}
203 <Icon name="chevron-down" className="disclosure-chevron" />
204 </summary>
205 <dl className="disclosure-body runtime-details">
206 <div>
207 <dt>Crates</dt>
208 <dd>{facts.crates.length ? `${facts.crates.length} · ${facts.crates.join(", ")}` : "—"}</dd>
209 </div>
210 <div>
211 <dt>{t.sourceRevision}</dt>
212 <dd><code className="inline">{facts.sourceRevision ?? "—"}</code></dd>
213 </div>
214 </dl>
215 </details>
216 </Section>
217
218 <section className="page-section">
219 <p className="status-line">
220 <span>{t.docsLead}</span>
221 <a href={`${REPO_BLOB_BASE}/docs/RUNTIME_API.md`} target="_blank" rel="noopener noreferrer" className="link">
222 {t.runtimeApiDoc}
223 </a>
224 <a href={`${REPO_BLOB_BASE}/docs/MCP.md`} target="_blank" rel="noopener noreferrer" className="link">
225 {t.mcpDoc}
226 </a>
227 </p>
228 </section>
229 </div>
230 </>
231 );
232 }
233
233 lines Plain Text