docs(plan): v0.2 adds Pi subagents and scheduled-jobs board

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-28 02:09:39 +08:00
1 parent b839ed4056
commit 16ab2a6c84
97 files changed
+592 -648

No files matched your search

+14 -14
View File
@@ -42,21 +42,21 @@ const SetupForm = AdminSetupRequest.extend({ confirm: z.string() }).refine((v) =
/** 后端错误码 → 文案(不直接透传后端 message,setup token 类除外) */
function errorText(err: unknown, mode: Mode): string {
if (!(err instanceof ApiRequestError)) return "发生未知错误,请重试";
if (!(err instanceof ApiRequestError)) return "请求失败,稍后重试";
switch (err.code) {
case "rate_limited":
return "失败次数过多,请 15 分钟后再试";
return "失败次数过多,15 分钟后再试";
case "upstream_unavailable":
return "无法连接服务,请检查服务端是否在运行";
return "连不上服务端,确认它在运行";
case "unauthorized":
if (mode === "totp") return "验证码错误或已使用,请等待下一个验证码";
if (mode === "setup") return "初始化口令无效,请以服务端日志里最新打印的为准";
if (mode === "totp") return "验证码错误或已用过,等下一个验证码再试";
if (mode === "setup") return "初始化口令无效,用服务端日志里最新的一条";
return "用户名或密码错误";
case "validation_failed":
case "bad_request":
return "输入格式不正确";
case "conflict":
return "管理员已初始化,请直接登录";
return "管理员已初始化,直接登录";
default:
return err.message || "登录失败";
}
@@ -130,7 +130,7 @@ export default function LoginPage() {
const fe: Record<string, string> = {};
for (const i of parsed.error.issues) fe[String(i.path[0])] ??= i.message;
if (fe.setupToken) fe.setupToken = "初始化口令至少 16 个字符";
if (fe.username && !username.trim()) fe.username = "请输入用户名";
if (fe.username && !username.trim()) fe.username = "输入用户名";
setFieldErrors(fe);
return;
}
@@ -152,8 +152,8 @@ export default function LoginPage() {
if (!parsed.success) {
const fe: Record<string, string> = {};
for (const i of parsed.error.issues) fe[String(i.path[0])] ??= i.message;
if (fe.username) fe.username = "请输入用户名";
if (fe.password) fe.password = "请输入密码";
if (fe.username) fe.username = "输入用户名";
if (fe.password) fe.password = "输入密码";
setFieldErrors(fe);
return;
}
@@ -169,7 +169,7 @@ export default function LoginPage() {
} catch (err) {
if (err instanceof ApiRequestError && err.code === "precondition_failed") {
setMode("setup");
setError("管理员尚未初始化,请先完成初始化");
setError("管理员尚未初始化");
} else {
setError(errorText(err, mode));
}
@@ -210,10 +210,10 @@ export default function LoginPage() {
<section className="hidden lg:block">
<p className="text-label font-semibold tracking-[0.18em] text-muted-foreground uppercase">媒体自动化</p>
<h1 className="mt-3 max-w-xl font-display text-display-sm leading-tight font-semibold text-foreground">
把想看的片子交代一句,剩下的交给流水线。
订阅、下载、整理入库
</h1>
<p className="mt-4 max-w-lg text-lead text-muted-foreground">
订阅、选片、下载、核验、入库,每一步都有记录可查;拿不准的事项会停下来等你决定。
每一步都有记录。拿不准的事项进待处理,等你决定。
</p>
<ul className="mt-8 space-y-3 text-body text-muted-foreground">
<li className="flex items-center gap-2.5">
@@ -222,7 +222,7 @@ export default function LoginPage() {
</li>
<li className="flex items-center gap-2.5">
<LockKeyhole className="h-4 w-4 text-foreground/70" />
凭证加密存储,任何页面都不回显
凭证加密存储,页面不回显
</li>
</ul>
</section>
@@ -235,7 +235,7 @@ export default function LoginPage() {
<div className="mt-4 flex gap-2.5 rounded-lg border border-border bg-foreground/[0.03] p-3 text-meta text-muted-foreground">
<Terminal className="mt-0.5 h-4 w-4 shrink-0" />
<p>
初始化口令只在服务端首次启动时打印到日志一次,可用
初始化口令在服务端日志里,用
<code className="mx-1 rounded-tight bg-foreground/[0.06] px-1 font-mono">
docker compose logs app | grep 'setup token'
</code>