返回 CodeWhale
page.tsx
根目录 / web / app / [locale] / docs / web / page.tsx
1 import { buildPageMetadata } from "@/lib/page-meta";
2
3 export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
4 const { locale } = await params;
5 const isZh = locale === "zh";
6 return buildPageMetadata({
7 path: "/docs/web",
8 locale,
9 title: isZh ? "浏览器客户端 · Codewhale 文档" : "Browser Client · Codewhale Docs",
10 description: isZh
11 ? "仅回环的内嵌浏览器客户端:一次性引导、会话 Cookie 与本地信任边界。"
12 : "The loopback-only embedded browser client: one-time bootstrap, session cookie, and the local trust boundary.",
13 });
14 }
15
16 export default async function WebClientPage({ params }: { params: Promise<{ locale: string }> }) {
17 const { locale } = await params;
18 const isZh = locale === "zh";
19 const bodyClass = isZh
20 ? "text-ink-soft leading-[1.9] tracking-wide"
21 : "text-ink-soft leading-relaxed";
22
23 return (
24 <section className="space-y-10">
25 <section id="overview" className="scroll-mt-32">
26 <h2 className="font-display text-3xl mb-1">{isZh ? "浏览器客户端" : "Browser Client"}</h2>
27 <p className={`${bodyClass} mt-3`}>
28 {isZh ? (
29 <>
30 <code className="inline">codewhale web</code> 在 canonical 运行时 API
31 之上打开 Codewhale 内嵌的浏览器客户端。它是一个纯本地界面:服务器始终绑定{" "}
32 <code className="inline">127.0.0.1</code>,无法改绑到局域网地址,也无法在关闭运行时认证的情况下运行。默认地址是{" "}
33 <code className="inline">http://127.0.0.1:7878</code>;端口冲突时用{" "}
34 <code className="inline">codewhale web --port 8788</code>{" "}
35 换一个回环端口。Ctrl+C 停止进程,浏览器会话随之结束。
36 </>
37 ) : (
38 <>
39 <code className="inline">codewhale web</code> opens Codewhale's embedded browser client
40 over the canonical Runtime API. It is a local surface: the server always binds to{" "}
41 <code className="inline">127.0.0.1</code>, cannot be rebound to a LAN address, and cannot
42 run with Runtime authentication disabled. The default address is{" "}
43 <code className="inline">http://127.0.0.1:7878</code>; on a port collision, pick another
44 loopback port with <code className="inline">codewhale web --port 8788</code>. Stop the
45 process with Ctrl+C and the browser session ends with it.
46 </>
47 )}
48 </p>
49 <p className={`${bodyClass} mt-3`}>
50 {isZh
51 ? "当前客户端提供响应式的线程与搜索侧栏、由运行时持有的会话事实、transcript 与工具收据,以及输入区。它可以创建、选择、重命名和归档线程;发起或引导回合;中断工作;处理审批;回答运行时的用户输入请求。浏览器只是同一个本地运行时的另一视图——不会创建第二个云账号,不会把 provider 凭据复制进浏览器存储,也不会削弱已配置的审批与沙箱策略。"
52 : "The current client provides a responsive thread and search rail, Runtime-owned session facts, transcript and tool receipts, and a composer. It can create, select, rename, and archive threads; start or steer turns; interrupt work; resolve approvals; and answer Runtime user-input requests. The browser is another view of the same local Runtime — it does not create a second cloud account, copy provider credentials into browser storage, or weaken the configured approval and sandbox policies."}
53 </p>
54 </section>
55
56 <section id="auth" className="scroll-mt-32">
57 <h2 className="font-display text-2xl mb-1">{isZh ? "认证边界" : "Authentication boundary"}</h2>
58 <p className={`${bodyClass} mt-3`}>
59 {isZh
60 ? "启动 URL 携带的是一个随机、短寿命、一次性的引导凭证——绝不是运行时 bearer 令牌。一次回环请求把它换成 HttpOnly、SameSite=Strict、进程本地的会话 Cookie,并立即使该凭证失效。重用、过期、畸形或非回环的引导尝试都会失败关闭。运行时令牌不会出现在渲染的 HTML、浏览器存储、URL 查询或片段、或浏览器启动参数中。携带 Cookie 的状态变更请求还必须出示精确的本地 web 源;跨源浏览器请求会被拒绝。"
61 : "The browser-launch URL carries a random, short-lived, one-time bootstrap capability — never the Runtime bearer token. A loopback request exchanges it for an HttpOnly, SameSite=Strict, process-local session cookie and immediately invalidates the capability. Reused, expired, malformed, and non-loopback bootstrap attempts fail closed. The Runtime token is never placed in rendered HTML, browser storage, URL queries or fragments, or browser-launch arguments. Cookie-authenticated state-changing requests must also present the exact local web origin; cross-origin browser requests are rejected."}
62 </p>
63 </section>
64
65 <section id="local" className="scroll-mt-32">
66 <h2 className="font-display text-2xl mb-1">{isZh ? "本地就是本地" : "Local means local"}</h2>
67 <p className={`${bodyClass} mt-3`}>
68 {isZh ? (
69 <>
70 <code className="inline">codewhale web</code> 只接受{" "}
71 <code className="inline">--port</code>——没有 <code className="inline">--host</code>
72 ,也没有关闭认证的选项。不要把它当公开网站,也不要通过路由器转发、公开反向代理或隧道暴露它的端口。单独的{" "}
73 <code className="inline">codewhale app-server --mobile</code> 和{" "}
74 <code className="inline">--http</code>{" "}
75 模式有不同的部署与认证约定,操作它们(尤其是选择非回环绑定)之前请阅读运行时 API 文档。
76 </>
77 ) : (
78 <>
79 <code className="inline">codewhale web</code> accepts only{" "}
80 <code className="inline">--port</code> — there is no <code className="inline">--host</code>{" "}
81 and no insecure-auth option on this command. Do not treat it as a public website or expose
82 its port through router forwarding, a public reverse proxy, or a tunnel. The separate{" "}
83 <code className="inline">codewhale app-server --mobile</code> and{" "}
84 <code className="inline">--http</code> modes carry different deployment and authentication
85 contracts; read the Runtime API documentation before operating either one, especially
86 before selecting a non-loopback bind.
87 </>
88 )}
89 </p>
90 </section>
91
92 <section id="troubleshooting" className="scroll-mt-32">
93 <h2 className="font-display text-2xl mb-1">{isZh ? "常见问题" : "Troubleshooting"}</h2>
94 <p className={`${bodyClass} mt-3`}>
95 {isZh
96 ? "端口 7878 被占用时用 --port 换一个。浏览器无法打开时命令会报错退出,而不会留下可重用的引导凭证;检查系统默认浏览器设置后重新启动。页面能打开但 provider 不可用时,查 codewhale doctor 和 /provider——web 命令不配置也不迁移 provider 凭据。会话过期后重启 codewhale web 以签发新的进程本地会话;重用旧的引导 URL 本来就会失败。"
97 : "If port 7878 is occupied, pass an unused --port. If the browser cannot be opened, the command exits with an error rather than leaving a reusable bootstrap capability behind; check the OS default-browser setup and start again. If the page loads but a provider is unavailable, inspect codewhale doctor and /provider — the web command does not configure or move provider credentials. If a session expired, restart codewhale web to mint a new process-local session; reusing an old bootstrap URL is expected to fail."}
98 </p>
99 </section>
100
101 <section id="source" className="hairline-t pt-8">
102 <p className="text-sm text-ink-mute">
103 {isZh
104 ? "来源文档:docs/WEB.md · 更新时请同步修改 docs-map.ts。"
105 : "Source document: docs/WEB.md · Update docs-map.ts when changing."}
106 </p>
107 </section>
108 </section>
109 );
110 }
111
111 lines Plain Text