返回 CodeWhale
page.tsx
根目录 / web / app / [locale] / roadmap / page.tsx
1 import Link from "next/link";
2 import { getCachedRoadmap, type RoadmapItem } from "@/lib/roadmap-feed";
3 import { getEnv } from "@/lib/kv";
4 import { buildPageMetadata } from "@/lib/page-meta";
5
6 export const revalidate = 1800;
7
8 export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
9 const { locale } = await params;
10 const isZh = locale === "zh";
11 return buildPageMetadata({
12 path: "/roadmap",
13 locale,
14 title: isZh ? "路线图 · Codewhale" : "Roadmap · Codewhale",
15 description: isZh
16 ? "Codewhale 已完成、进行中、考虑中和明确不在范围内的工作。"
17 : "Current Codewhale work grouped by shipped, underway, considered, and deliberately out-of-scope directions.",
18 });
19 }
20
21 const tracksEn = [
22 {
23 title: "Shipped",
24 items: [
25 { title: "Canonical action tools", note: "Bash, File, Git, and Run; agent, remember, tasks, update_plan, work_update, and the synthetic tool_search complete the ten-name default-active policy. remember is present when built-in memory is enabled; Web is deferred and conditional." },
26 { title: "Sub-agent parallel execution", note: "agent; 64 concurrent sessions by default, configurable to 128, with bounded result handles" },
27 { title: "RLM batched processing", note: "Persistent sandboxed Python REPL with 1–16 cheap parallel children for long-input analysis" },
28 { title: "Three operating modes", note: "Plan (read-only), Act (execution), Operate (Fleet/Workflow orchestration); orthogonal Ask / Auto-Review / Full Access posture" },
29 { title: "OS command sandbox", note: "Seatbelt on macOS when available; opt-in bubblewrap on Linux when installed. Windows currently reports no OS sandbox." },
30 { title: "Durable sessions + tasks", note: "Save, resume, rollback; background task queue with replayable timelines under ~/.codewhale/tasks/" },
31 { title: "Bidirectional MCP", note: "Consume tools from external servers; expose as server via `codewhale mcp`; ~/.codewhale/mcp.json" },
32 { title: "Skills + unified slash palette", note: "~/.codewhale/skills/ auto-loading; /help, /mode, /status, /config, /trust, /feedback" },
33 { title: "OpenRouter provider", note: "OpenRouter integration with 300+ models across dozens of providers" },
34 { title: "OpenAI-compatible & local runtimes", note: "Generic `openai` route for any OpenAI-compatible gateway, plus vLLM, SGLang, and Ollama against your own localhost endpoints — no key required" },
35 { title: "Multi-provider support", note: "Hot-swap between providers (DeepSeek, OpenAI, Anthropic, OpenRouter) per session" },
36 { title: "Local web client", note: "Implemented in the v0.9.1 source candidate: `codewhale web` is a loopback-only browser client over the Runtime API behind a one-time bootstrap session boundary; approvals and user input recover across page reloads (#4423)" },
37 { title: "Opt-in product telemetry", note: "Off by default, and unanswered until a first-run notice asks — nothing is collected, and the telemetry directory is not even created, until you answer Enable. An enabled session posts counts and closed enums to the first-party endpoint https://telemetry.codewhale.net/v1/telemetry, a Cloudflare Worker whose full source is in the repo under telemetry-ingest/. Its storage has no IP, country, or geo column — that is structural, not a setting — nothing is logged, and Cloudflare's retention is a fixed three months. Set telemetry_endpoint = \"\" to stay enabled and contact nobody: batches then go to $CODEWHALE_HOME/telemetry/dryrun.jsonl and you can read exactly what would have been sent. Never prompts, completions, tool arguments, file contents, paths, repo or branch names, model ids, or credentials; the full schema is docs/TELEMETRY.md. Turn it off with `codewhale config set telemetry false` or CODEWHALE_TELEMETRY=0, which also deletes the random install id and every buffered event." },
38 ],
39 },
40 {
41 title: "Underway",
42 items: [
43 { title: "VS Code extension", note: "The repository ships a Phase 0 local-runtime companion: terminal launch, health checks, read-only thread summaries, and restore-point browsing. Full chat and editor actions are not part of this slice." },
44 { title: "Memory typed store", note: "The native store has shipped: Markdown is the durable source of truth, with a rebuildable SQLite FTS5 index over it. Graph-structured agent memory and multi-signal recall are still ahead (#534–#536)" },
45 { title: "Feishu / Lark bot", note: "First long-connection bridge over the runtime API shipped; richer chat features underway (#757)" },
46 { title: "Chinese-market & i18n", note: "Locale-aware UI, platform refinements, region-specific search backends (#755)" },
47 { title: "Hugging Face model discovery + Model Lab", note: "Browse, download, and manage models from Hugging Face Hub directly in the TUI" },
48 ],
49 },
50 {
51 title: "Considered",
52 items: [
53 { title: "Workrooms", note: "Durable, addressable agent-work threads over the Runtime API and user surfaces (#3209, docs/WORKROOM_ARCHITECTURE.md)" },
54 { title: "Exa web-search backend", note: "Bundled alternative to the existing DDG + Bing path (#431)" },
55 { title: "Homebrew core formula", note: "Tap exists; pursuing homebrew-core inclusion" },
56 { title: "Native Windows installer", note: "MSI / WinGet; Scoop manifest already ships" },
57 { title: "Unsloth / NeMo / Arcee fine-tune integration", note: "One-click fine-tuning workflows backed by Unsloth, NVIDIA NeMo, and Arcee toolkits" },
58 ],
59 },
60 {
61 title: "Ruled out",
62 items: [
63 { title: "Always-on or silent product telemetry", note: "There is now a first-party telemetry endpoint (https://telemetry.codewhale.net/v1/telemetry) and it is the shipped default — but it decides where an already-enabled session sends, never whether one collects. Product telemetry stays opt-in and off by default; nothing is collected until the first-run notice is answered with Enable, and CODEWHALE_TELEMETRY=0, telemetry = false, and a recorded decline are all hard floors. What stays ruled out: an always-on mode, per-keystroke or per-tool-call phone-home, silent collection with no notice, and any third-party ad or analytics SDK in the runtime binary. A selected hosted provider still receives the context required for its model turn; loopback routes can keep inference local." },
64 { title: "Mandatory hosted relay for local sessions", note: "The local runtime and bring-your-own-provider routes continue to work without sending sessions through a Codewhale service" },
65 { title: "Required account for the local runtime", note: "Installing and running Codewhale locally requires no account" },
66 { title: "Sponsored model promotion", note: "Model picker stays neutral — no paid placement" },
67 { title: "Public share links for local sessions", note: "The retired share-link direction (#471/#481) is not coming back; any future sharing design starts fresh." },
68 ],
69 },
70 {
71 title: "Open model platform",
72 items: [
73 { title: "Community model registry", note: "Discover, share, and rate community fine-tuned models with reproducible recipes" },
74 { title: "One-click deploy", note: "Deploy any model to RunPod, Replicate, or your own infra with a single command" },
75 { title: "Model evaluation dashboard", note: "Transparent, reproducible comparisons across providers, quantization levels, and hardware" },
76 ],
77 },
78 ];
79
80 const tracksZh = [
81 {
82 title: "已完成",
83 items: [
84 { title: "Canonical action 工具", note: "Bash、File、Git、Run、agent、remember、tasks、update_plan、work_update 与 synthetic tool_search 构成十个默认启用名称;remember 在启用内置记忆时出现,Web 按条件延迟加载" },
85 { title: "子 Agent 并行执行", note: "agent;默认 64 个并发会话,可配置到 128 个,通过 var_handle 有界读取结果" },
86 { title: "RLM 批量处理", note: "持久沙箱 Python REPL,支持 1–16 路廉价并行子调用,处理长文本分析" },
87 { title: "三种运行模式", note: "Plan(只读调查)、Act(执行)与 Operate(Fleet / Workflow 编排);Ask、Auto-Review 与 Full Access 权限姿态独立设置" },
88 { title: "OS 命令沙箱", note: "macOS 在可用时使用 Seatbelt;Linux 在安装后可显式启用 bubblewrap。Windows 当前报告无 OS 沙箱。" },
89 { title: "持久化会话 + 后台任务", note: "保存、恢复、回滚;后台任务队列,可回放时间线,位于 ~/.codewhale/tasks/" },
90 { title: "双向 MCP 协议", note: "消费外部服务器工具;通过 `codewhale mcp` 暴露为服务器;~/.codewhale/mcp.json" },
91 { title: "技能 + 统一命令面板", note: "~/.codewhale/skills/ 自动加载;/help、/mode、/status、/config、/trust、/feedback" },
92 { title: "OpenRouter 提供商", note: "原生集成 OpenRouter,支持 300+ 模型,覆盖数十个提供商" },
93 { title: "OpenAI 兼容与本地运行时", note: "通用 `openai` 路由可接入任意 OpenAI 兼容网关;vLLM、SGLang、Ollama 直连本地端点,无需密钥" },
94 { title: "多提供商支持", note: "按会话动态切换提供商(DeepSeek、OpenAI、Anthropic、OpenRouter)" },
95 { title: "本地 Web 客户端", note: "v0.9.1 源码候选版已实现:`codewhale web` 是基于 Runtime API 与一次性引导会话边界的回环地址浏览器客户端;审批与用户输入可在页面刷新后恢复(#4423)" },
96 { title: "可选加入的产品遥测", note: "默认关闭,首次运行的提示未回答前不会收集任何内容——在你回答“启用”之前,连遥测目录都不会被创建。启用后的会话会把计数与封闭枚举 POST 到第一方端点 https://telemetry.codewhale.net/v1/telemetry,那是一个 Cloudflare Worker,完整源码就在仓库的 telemetry-ingest/ 目录里。它的存储中没有 IP、国家或任何地理位置列——这是结构上不存在,而不是某个可以改回来的开关——不写任何日志,Cloudflare 的保留期固定为三个月。若想保持启用但不联系任何服务器,设置 telemetry_endpoint = \"\":批次会写入 $CODEWHALE_HOME/telemetry/dryrun.jsonl,你可以直接查看本应发送的全部内容。永远不收集 prompt、模型回复、工具参数、文件内容、路径、仓库或分支名、模型 id 与凭据;完整 schema 见 docs/TELEMETRY.md。用 `codewhale config set telemetry false` 或 CODEWHALE_TELEMETRY=0 关闭,同时会删除随机安装 id 与所有已缓冲事件。" },
97 ],
98 },
99 {
100 title: "进行中",
101 items: [
102 { title: "VS Code 扩展", note: "仓库已提供 Phase 0 本地 Runtime 配套扩展:终端启动、健康检查、只读线程摘要和还原点浏览;完整聊天与编辑器操作尚未包含在此版本中。" },
103 { title: "记忆类型化存储", note: "原生存储已发布:以 Markdown 作为持久化事实来源,并在其上建立可重建的 SQLite FTS5 索引。图结构 Agent 记忆与多信号召回仍在规划中(#534–#536)" },
104 { title: "飞书 / Lark 机器人", note: "基于 runtime API 的长连接桥接已发布首版;更丰富的对话能力进行中(#757)" },
105 { title: "中国市场与国际化改进", note: "本地化 UI、平台优化、区域搜索引擎(#755)" },
106 { title: "Hugging Face 模型发现 + 模型实验室", note: "在 TUI 中直接浏览、下载和管理 Hugging Face Hub 上的模型" },
107 ],
108 },
109 {
110 title: "考虑中",
111 items: [
112 { title: "Workrooms 工作间", note: "基于 Runtime API 与用户界面的持久、可寻址 Agent 工作线程(#3209,docs/WORKROOM_ARCHITECTURE.md)" },
113 { title: "Exa 网页搜索后端", note: "内建替代 DDG + Bing 的搜索路由(#431)" },
114 { title: "Homebrew 核心仓库", note: "Tap 已有;正在争取进入 homebrew-core" },
115 { title: "Windows 原生安装器", note: "MSI / WinGet;Scoop 清单已发布" },
116 { title: "Unsloth / NeMo / Arcee 微调集成", note: "一键微调工作流,由 Unsloth、NVIDIA NeMo 和 Arcee 工具链驱动" },
117 ],
118 },
119 {
120 title: "暂不考虑",
121 items: [
122 { title: "默认开启或静默的产品遥测", note: "现在确实存在第一方遥测端点(https://telemetry.codewhale.net/v1/telemetry),并且它是随产品发布的默认值——但它决定的只是「已启用的会话把批次发到哪里」,而不是「是否收集」。产品遥测依然是可选加入且默认关闭的:在首次运行提示被回答为“启用”之前不会收集任何内容,而 CODEWHALE_TELEMETRY=0、telemetry = false 以及已记录的“拒绝”都是硬性下限。仍被排除在外的是:常开模式、按键级或按工具调用级的回传、没有任何提示的静默收集,以及运行时二进制中的任何第三方广告或分析 SDK。选用托管 provider 时仍会发送本轮所需上下文,回环地址路由可让推理保持本地。" },
123 { title: "本地会话强制经过托管中继", note: "本地 Runtime 与自带提供商路由继续工作,无需把会话发送到 Codewhale 服务" },
124 { title: "本地 Runtime 强制注册账户", note: "本地安装和运行 Codewhale 不需要账户" },
125 { title: "赞助商模型推广", note: "模型选择器保持中立——无付费推荐位" },
126 { title: "本地会话的公开分享链接", note: "已停用的分享链接方向(#471/#481)不会恢复;未来的分享设计将重新开始。" },
127 ],
128 },
129 {
130 title: "开放模型平台",
131 items: [
132 { title: "社区模型注册中心", note: "发现、分享和评价社区微调模型,附带可复现的配方" },
133 { title: "一键部署", note: "一条命令将任意模型部署到 RunPod、Replicate 或自有基础设施" },
134 { title: "模型评测面板", note: "跨提供商、量化级别和硬件的透明、可复现对比" },
135 ],
136 },
137 ];
138
139 const roadmapText = (text: string) =>
140 text.replace(/^>\s*/, "").replaceAll("**", "").replaceAll("CodeWhale", "Codewhale");
141
142 export default async function RoadmapPage({ params }: { params: Promise<{ locale: string }> }) {
143 const { locale } = await params;
144 const isZh = locale === "zh";
145 const baseTracks = isZh ? tracksZh : tracksEn;
146
147 // Live feed: shipped from GitHub Releases; underway/considered/ruled-out from issue labels.
148 // Per-category fallback to the static items so unlabeled categories stay populated.
149 let tracks = baseTracks;
150 try {
151 const env = await getEnv();
152 const feed = await getCachedRoadmap(env.CURATED_KV, env.GITHUB_TOKEN);
153 if (feed) {
154 const liveByCategory: Record<string, RoadmapItem[]> = {
155 Shipped: feed.shipped,
156 Underway: feed.underway,
157 Considered: feed.considered,
158 "Ruled out": feed.ruledOut,
159 已完成: feed.shipped,
160 进行中: feed.underway,
161 考虑中: feed.considered,
162 暂不考虑: feed.ruledOut,
163 };
164 tracks = baseTracks.map((t) => {
165 const live = liveByCategory[t.title];
166 if (live && live.length > 0) {
167 return { ...t, items: live.map((it) => ({ title: it.title, note: it.note })) };
168 }
169 return t;
170 });
171 }
172 } catch {
173 /* keep static fallback */
174 }
175
176 const copy = isZh
177 ? {
178 eyebrow: "项目路线图",
179 title: "路线图",
180 introduction: "这里将已完成的仓库工作、正在推进的工作、仍在评估的方案和明确不在范围内的方向分开列出。路线图的“已完成”可包含已在源码候选版中实现的工作;安装页与首页另行标明最新已发布包。发布记录和 GitHub issues 会在可用时更新这些分类。",
181 sectionLabel: "当前状态",
182 sectionTitle: "按状态查看工作",
183 browseIssues: "浏览 open issues ↗",
184 count: (value: number) => `${value} 项`,
185 contributeLabel: "参与贡献",
186 contributeTitle: "路线图决策公开进行。",
187 contributeBody: "Bug 和范围明确的功能请求请使用 issues;尚在形成中的想法可以先在 Discussions 讨论;已有具体实现时,欢迎发送带测试或文档的 pull request。来自不同语言、平台和提供商的验证结果都能帮助维护者判断优先级。",
188 links: [
189 { title: "Issues", detail: "报告问题,或提出范围明确的工作。", href: "https://github.com/Hmbown/CodeWhale/issues" },
190 { title: "Discussions", detail: "在开始实现前讨论尚未成熟的想法。", href: "https://github.com/Hmbown/CodeWhale/discussions/new?category=ideas" },
191 { title: "Pull requests", detail: "审查现有改动,或发送一个范围清楚的补丁。", href: "https://github.com/Hmbown/CodeWhale/pulls" },
192 ],
193 }
194 : {
195 eyebrow: "Project roadmap",
196 title: "Roadmap",
197 introduction: "This page separates completed repository work from work in progress, proposals still being evaluated, and directions intentionally kept out of scope. Roadmap Shipped can include work implemented in a source candidate; the install page and homepage separately identify the latest published package. Release records and GitHub issues refresh these categories when available.",
198 sectionLabel: "Current status",
199 sectionTitle: "Work grouped by status",
200 browseIssues: "Browse open issues ↗",
201 count: (value: number) => `${value} ${value === 1 ? "item" : "items"}`,
202 contributeLabel: "Contribute",
203 contributeTitle: "Keep roadmap decisions in the open.",
204 contributeBody: "Use issues for bugs and well-scoped feature requests, Discussions for ideas that need shaping, and pull requests for concrete changes with tests or documentation. Verification across languages, platforms, and providers helps maintainers judge priority.",
205 links: [
206 { title: "Issues", detail: "Report a problem or propose scoped work.", href: "https://github.com/Hmbown/CodeWhale/issues" },
207 { title: "Discussions", detail: "Explore an early idea before implementation.", href: "https://github.com/Hmbown/CodeWhale/discussions/new?category=ideas" },
208 { title: "Pull requests", detail: "Review existing work or send a focused change.", href: "https://github.com/Hmbown/CodeWhale/pulls" },
209 ],
210 };
211
212 return (
213 <div className="roadmap-page">
214 <section className="community-welcome">
215 <div className="portal-current" aria-hidden="true" />
216 <div className="portal-container community-welcome-inner">
217 <div className="eyebrow">{copy.eyebrow}</div>
218 <h1>{copy.title}</h1>
219 <p>{copy.introduction}</p>
220 </div>
221 </section>
222
223 <section className="portal-section">
224 <div className="portal-container">
225 <div className="portal-docs-heading">
226 <div>
227 <span>{copy.sectionLabel}</span>
228 <h2>{copy.sectionTitle}</h2>
229 </div>
230 <Link href="https://github.com/Hmbown/CodeWhale/issues">{copy.browseIssues}</Link>
231 </div>
232 {tracks.map((track) => (
233 <section key={track.title} className="portal-section-grid py-10 hairline-t">
234 <div className="portal-section-copy">
235 <span>{copy.count(track.items.length)}</span>
236 <h2>{track.title}</h2>
237 </div>
238 <ul className="hairline-t">
239 {track.items.map((item) => (
240 <li key={`${item.title}-${item.note}`} className="py-4 hairline-b">
241 <h3 className="font-display text-base">{roadmapText(item.title)}</h3>
242 <p className={`mt-1 text-sm text-ink-soft ${isZh ? "leading-[1.9] tracking-wide" : "leading-relaxed"}`}>
243 {roadmapText(item.note)}
244 </p>
245 </li>
246 ))}
247 </ul>
248 </section>
249 ))}
250 </div>
251 </section>
252
253 <section className="portal-section portal-section-muted">
254 <div className="portal-container portal-section-grid">
255 <div className="portal-section-copy">
256 <span>{copy.contributeLabel}</span>
257 <h2>{copy.contributeTitle}</h2>
258 <p>{copy.contributeBody}</p>
259 </div>
260 <div className="portal-topic-list">
261 {copy.links.map((link) => (
262 <Link key={link.title} href={link.href}>
263 <strong>{link.title}</strong>
264 <span>{link.detail}</span>
265 <span aria-hidden="true">↗</span>
266 </Link>
267 ))}
268 </div>
269 </div>
270 </section>
271 </div>
272 );
273 }
274
274 lines Plain Text