style(copy): punctuation rules and site-wide fix with a CI check (QA U11)

- glossary: 10 punctuation rules (full-width in Chinese, CJK/Latin spacing,
  full-width parens around Chinese, single ellipsis, 「」 quotes, period rules)
- scripts/check-copy-punctuation.mjs: checks string literals, templates and JSX
  text (not comments, types, keys, match/compare strings); --fix, --strict,
  --by-file; wired into deno task ci as check:copy in warn mode
- --fix applied to web, server and contracts; files other lanes were editing
  (subscriptions, sites, browser, agent, auth/account, inventory) left for them
- tests updated for the changed messages

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 20:09:29 +08:00
1 parent 9b017906cf
commit 52402864d6
143 files changed
+985 -606

No files matched your search

@@ -29,12 +29,12 @@ export const BUILTIN_AGENT_CHECKS: {
{
key: "check.pending",
name: "待处理巡检",
description: "检查待处理事项并给出建议(只读)",
description: "检查待处理事项并给出建议(只读)",
everyMs: 6 * HOUR,
config: {
goalTemplate:
"巡检待处理({{now}}):有 {{openDecisions}} 条未关闭的待处理事项。逐条查看证据,按紧急程度排序," +
"给出处理建议和理由。只读,不做任何变更。",
"巡检待处理({{now}}):有 {{openDecisions}} 条未关闭的待处理事项。逐条查看证据,按紧急程度排序," +
"给出处理建议和理由。只读,不做任何变更。",
capabilityAllowlist: [...INVESTIGATE_CAPABILITIES],
budget: { maxToolCalls: 20, maxDurationSec: 300 },
triggerCondition: "open_decisions",
@@ -43,12 +43,12 @@ export const BUILTIN_AGENT_CHECKS: {
{
key: "check.downloads",
name: "下载诊断",
description: "检查无进展或失败的下载并诊断;开启恢复后在授权内重试或重新校验",
description: "检查无进展或失败的下载并诊断;开启恢复后在授权内重试或重新校验",
everyMs: 2 * HOUR,
config: {
goalTemplate:
"巡检下载({{now}}):有 {{stalledDownloads}} 个下载任务无进展或失败。用只读能力查明原因(站点、做种、磁盘、任务错误)," +
"给出诊断与建议;若本次允许恢复,只在授权内做重试或强制重新校验,每个任务最多一次,不换源、不删除。",
"巡检下载({{now}}):有 {{stalledDownloads}} 个下载任务无进展或失败。用只读能力查明原因(站点、做种、磁盘、任务错误)," +
"给出诊断与建议;若本次允许恢复,只在授权内做重试或强制重新校验,每个任务最多一次,不换源、不删除。",
capabilityAllowlist: [...INVESTIGATE_CAPABILITIES],
budget: { maxToolCalls: 24, maxDurationSec: 420 },
triggerCondition: "stalled_downloads",
@@ -58,12 +58,12 @@ export const BUILTIN_AGENT_CHECKS: {
{
key: "check.weekly",
name: "订阅与站点周报",
description: "检查订阅缺集与站点健康,汇总写入待处理(只读)",
description: "检查订阅缺集与站点健康,汇总写入待处理(只读)",
everyMs: 7 * 24 * HOUR,
config: {
goalTemplate:
"生成本周巡检周报({{date}}):追踪中的订阅 {{activeSubscriptions}} 个。列出缺集的订阅及可能原因、" +
"健康异常的站点与 Feed,给出本周建议。只读。最后用不超过 300 字的中文汇总。",
"生成本周巡检周报({{date}}):追踪中的订阅 {{activeSubscriptions}} 个。列出缺集的订阅及可能原因、" +
"健康异常的站点与 Feed,给出本周建议。只读。最后用不超过 300 字的中文汇总。",
capabilityAllowlist: [...INVESTIGATE_CAPABILITIES],
budget: { maxToolCalls: 30, maxDurationSec: 600 },
triggerCondition: "subscriptions_active",
@@ -106,7 +106,7 @@ const isPlanOnly = (id: string) => {
/** agent_check 的执行体(内置与自定义共用) */
export async function runAgentCheck(ctx: ServerContext, c: JobRunContext): Promise<JobRunResult> {
const parsed = AgentCheckConfig.safeParse(c.config);
if (!parsed.success) throw new Error(`巡检参数无效:${parsed.error.issues[0]?.message ?? "未知"}`);
if (!parsed.success) throw new Error(`巡检参数无效:${parsed.error.issues[0]?.message ?? "未知"}`);
const cfg = parsed.data;
const f = await facts(ctx);
const unmet =
@@ -114,7 +114,7 @@ export async function runAgentCheck(ctx: ServerContext, c: JobRunContext): Promi
(cfg.triggerCondition === "stalled_downloads" && f.stalledDownloads === 0) ||
(cfg.triggerCondition === "subscriptions_active" && f.activeSubscriptions === 0);
// 手动执行不看触发条件
if (unmet && c.trigger === "schedule") return { status: "skipped", summary: "触发条件不满足,未唤醒 Agent" };
if (unmet && c.trigger === "schedule") return { status: "skipped", summary: "触发条件不满足,未唤醒 Agent" };
let mode: "execute" | "plan_only" = "plan_only";
let allowlist = cfg.capabilityAllowlist.filter(isPlanOnly);
@@ -124,7 +124,7 @@ export async function runAgentCheck(ctx: ServerContext, c: JobRunContext): Promi
if (grants.length > 0) {
mode = "execute";
allowlist = [...new Set([...(allowlist.length ? allowlist : INVESTIGATE_CAPABILITIES), ...RECOVER_CAPABILITIES])];
} else note = "(没有覆盖恢复动作的有效授权,改为只读)";
} else note = "(没有覆盖恢复动作的有效授权,改为只读)";
}
const goal = renderGoal(cfg.goalTemplate, c.now, f);
const dedupeKey = c.trigger === "manual" ? `schedule:${c.jobId}:manual:${c.runId}` : `schedule:${c.jobId}:${c.slot}`;