copy: second-round copy review across console, settings, agent and server messages

- Trim descriptions, empty states, confirm buttons and toasts to facts
- Unify terms per glossary: 待处理/待识别/整理记录/运行记录/凭证/子会话/Agent 上游
- Subscription-login termsNote states facts only (borrowed client identity, ToS/ban risk)
- Shorter, concrete goal templates for built-in Agent checks
- Human-readable nouns instead of table names in instance CRUD errors
- Audit labels for pi_upstream / schedule / automation_grant actions
- Glossary: add 上游、订阅登录、凭证、定时任务、巡检、运行记录、子会话、停止、持续授权

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 13:29:42 +08:00
1 parent c67f6a9682
commit 31a54186c7
58 files changed
+200 -188

No files matched your search

+14 -12
View File
@@ -60,12 +60,12 @@ export function readableLoginError(provider: string, err: unknown): string {
const raw = err instanceof Error ? err.message : String(err);
if (/EADDRINUSE|address already in use/i.test(raw)) {
const port = OAUTH_CALLBACK_PORTS[provider] ?? raw.match(/:(\d{2,5})\b/)?.[1];
return `服务端回调端口${port ? ` ${port}` : ""} 被占用(可能另有登录进行中,或容器内有 Claude Code / Codex CLI 占用该端口),请释放端口或稍后重试`;
return `服务端回调端口${port ? ` ${port}` : ""} 被占用。结束占用该端口的进程(如另一个登录流程、Claude Code / Codex CLI)后重试`;
}
if (/cancel|abort/i.test(raw)) return "登录已取消";
if (/state mismatch/i.test(raw)) return "粘贴的地址与本次登录不匹配(state 不一致),请用本次打开的授权链接重新登录";
if (/state mismatch/i.test(raw)) return "粘贴的地址不属于本次登录(state 不一致)。用本次打开的授权链接重新登录";
if (/\b404\b/.test(raw) && provider === "openai-codex")
return "该账号未开启设备码登录(Codex 返回 404),请改用浏览器登录";
return "这个账号未开启设备码登录(Codex 返回 404)。改用浏览器登录";
return classifyUpstreamError(err).message;
}
@@ -105,10 +105,7 @@ export class OAuthSessions {
async start(row: PiUpstreamRow, req: { mode?: PiOAuthMode; enterpriseDomain?: string }): Promise<PiOAuthStartResult> {
const info = providerInfo(row.provider);
if (row.auth_kind !== "oauth" || !info?.oauth)
throw new ApiException(
"precondition_failed",
"该上游不是订阅登录型(authKind 需为 oauth,且 provider 支持订阅登录)",
);
throw new ApiException("precondition_failed", "这个上游不是订阅登录类型");
if (!row.enabled) throw new ApiException("precondition_failed", "上游已停用");
const mode = req.mode ?? info.oauth.modes[0]!;
if (!info.oauth.modes.includes(mode))
@@ -122,7 +119,7 @@ export class OAuthSessions {
if (busy.upstreamId !== row.id)
throw new ApiException(
"conflict",
`${info.name} 已有登录进行中(同一 provider 的登录需串行),请先完成或等待其过期(${new Date(busy.expiresAt).toISOString()})`,
`${info.name} 已有登录进行中。完成它,或等到 ${new Date(busy.expiresAt).toISOString()} 过期后重试`,
);
this.cancel(busy, "cancelled", "已被新的登录请求取代");
await busy.done.catch(() => undefined);
@@ -147,7 +144,7 @@ export class OAuthSessions {
pasteWaiters: [],
firstEvent: Promise.withResolvers<void>(),
done: Promise.resolve(),
timer: setTimeout(() => this.cancel(s, "expired", "登录会话已超时,请重新开始"), ttl),
timer: setTimeout(() => this.cancel(s, "expired", "登录会话已超时,重新开始登录"), ttl),
};
(s.timer as { unref?: () => void }).unref?.();
this.sessions.set(s.id, s);
@@ -195,7 +192,7 @@ export class OAuthSessions {
for (const w of s.pasteWaiters.splice(0)) w();
});
}
throw new Error("该登录流程需要额外输入(secret),服务端登录不支持");
throw new Error("这个登录流程需要额外输入(secret),服务端不支持");
}
private notify(s: Session, e: UpstreamAuthEvent) {
@@ -238,9 +235,14 @@ export class OAuthSessions {
): Promise<{ sessionId: string; state: PiOAuthState; message: string | null; progress: string[] }> {
const s = this.sessions.get(req.sessionId);
if (!s || s.upstreamId !== upstreamId)
return { sessionId: req.sessionId, state: "expired", message: "登录会话不存在或已过期,请重新开始", progress: [] };
return {
sessionId: req.sessionId,
state: "expired",
message: "登录会话不存在或已过期,重新开始登录",
progress: [],
};
if (req.pastedUrlOrCode && s.state === "pending") {
if (s.mode !== "browser") throw new ApiException("bad_request", "设备码登录不需要粘贴,等待授权完成即可");
if (s.mode !== "browser") throw new ApiException("bad_request", "设备码登录不需要粘贴,等待授权完成");
if (!s.paste) {
// manual_code 提示可能还没发出:短暂等待
await Promise.race([