fix(web): stale-closure + focus trap + 去边界强转 + a11y/性能打磨 + 类型化客户端

P1-6 useStyleLearn/useKimiOauth 修 stale-closure 依赖。
P1-7 CommandPalette/Drawer 加 focus trap(新 lib/a11y/focusTrap)。
P1-8 SSE 解析与 server.ts 去 as 强转改类型守卫/运行时校验。
P2 删冗余强转、开 noUncheckedIndexedAccess、Toast 清理+稳定 key、列表 key 稳定化、
  rel=noopener、useMemo 大文本、ConflictCard role=group、useInjection 加锁、
  client.test 真断言。
codegen 重生成 schema.d.ts + 消费 DimensionEntry/ReviewConflictView 强类型。
This commit is contained in:
Yaojia Wang
2026-06-21 19:32:49 +02:00
parent 016509c5c6
commit c6651b74b9
36 changed files with 792 additions and 140 deletions

View File

@@ -236,6 +236,7 @@ export interface paths {
* List Foreshadow
* @description 伏笔看板:按 `status` 过滤(缺省=全部),按 code 升序。
*
* 项目不存在 → 404与写端点一致避免不存在 project 返回误导性空 200
* `status` 非法(不在 OPEN/PARTIAL/CLOSED/OVERDUE→ VALIDATION 信封。四泳道前端
* 据 `status` 分组OVERDUE 泳道 + 逾期标记用 `expected_close_to`(看板字段已齐)。
*/
@@ -427,6 +428,7 @@ export interface paths {
* List Characters
* @description 已入库角色全量列表(设定库 Codex 真源;复用 C5 读侧 SqlCharacterRepo
*
* 项目不存在 → 404与写端点一致避免不存在 project 返回误导性空 200
* DB JSONB dict 列 → API list/str 反向解包(入库形变的逆向,见 `_existing_characters`)。
*/
get: operations["list_characters_projects__project_id__characters_get"];
@@ -453,6 +455,7 @@ export interface paths {
* List World Entities
* @description 已入库世界观实体全量列表(设定库 Codex 真源;复用 C5 读侧 SqlWorldEntityRepo
*
* 项目不存在 → 404与写端点一致
* DB `rules` JSONB dict `{"rules":[...]}` → 裸 listworldbuilder 形变的逆向)。
*/
get: operations["list_world_entities_projects__project_id__world_entities_get"];
@@ -813,6 +816,18 @@ export interface components {
*/
note?: string | null;
};
/**
* DimensionEntry
* @description 单个文风维度:名称 + 判定值 + 原文证据摘录(强类型,替代裸 dict[str, Any])。
*/
DimensionEntry: {
/** Name */
name: string;
/** Value */
value: string;
/** Evidence */
evidence?: string[];
};
/**
* DraftResponse
* @description 草稿保存结果(脱敏:只回元信息 + 长度,不回灌正文以外的衍生)。
@@ -879,6 +894,23 @@ export interface components {
/** Length */
length: number;
};
/** ErrorBody */
ErrorBody: {
/** Code */
code: string;
/** Message */
message: string;
/** Details */
details?: {
[key: string]: unknown;
};
/** Request Id */
request_id?: string | null;
};
/** ErrorEnvelope */
ErrorEnvelope: {
error: components["schemas"]["ErrorBody"];
};
/**
* ForeshadowBoardResponse
* @description GET /projects/:id/foreshadow?status=:伏笔看板(四泳道 + OVERDUE 字段齐)。
@@ -1077,6 +1109,35 @@ export interface components {
*/
excluded?: components["schemas"]["InjectionEntityRef"][];
};
/**
* JobResponse
* @description 长任务状态(`GET /jobs/{id}`):状态 + 进度 + 结果/错误。
*
* `result` 是任务成功后的非密摘要(如 `{"connected": true, ...}``error` 是失败后的
* 面向用户文案(已脱敏,绝不含 `str(exc)`,见 `services/job_runner._classify_job_error`)。
*/
JobResponse: {
/**
* Id
* Format: uuid
*/
id: string;
/** Kind */
kind: string;
/** Status */
status: string;
/**
* Progress
* @default 0
*/
progress: number;
/** Result */
result?: {
[key: string]: unknown;
} | null;
/** Error */
error?: string | null;
};
/**
* OAuthDisconnectResponse
* @description 断开:是否删到凭据行。
@@ -1171,7 +1232,7 @@ export interface components {
/** Theme */
theme?: string | null;
/** Selling Points */
selling_points?: unknown[];
selling_points?: string[];
/** Structure */
structure?: string | null;
};
@@ -1204,7 +1265,7 @@ export interface components {
/** Theme */
theme?: string | null;
/** Selling Points */
selling_points?: unknown[];
selling_points?: string[];
/** Structure */
structure?: string | null;
};
@@ -1268,6 +1329,31 @@ export interface components {
/** Refined */
refined: string;
};
/**
* ReviewConflictView
* @description 单条一致性冲突chapter_reviews.conflicts JSONB 子项;形对齐 SSE `conflict` 事件)。
*
* 强类型化此前的裸 `dict[str, Any]`,给 TS 客户端真实字段类型。容忍历史/缺省(默认值)。
*/
ReviewConflictView: {
/**
* Type
* @default
*/
type: string;
/**
* Where
* @default
*/
where: string;
/** Refs */
refs?: string[];
/**
* Suggestion
* @default
*/
suggestion: string;
};
/**
* ReviewHistoryItem
* @description 单条审稿留痕GET .../reviews 历史项snake_case
@@ -1288,9 +1374,7 @@ export interface components {
/** Chapter Version */
chapter_version?: number | null;
/** Conflicts */
conflicts?: {
[key: string]: unknown;
}[];
conflicts?: components["schemas"]["ReviewConflictView"][];
/** Foreshadow Sug */
foreshadow_sug?: {
[key: string]: unknown;
@@ -1397,17 +1481,14 @@ export interface components {
};
/**
* StyleFingerprintResponse
* @description 最新文风指纹(`GET /style`):完整 16 维 + 证据 + 版本(对齐 UX §6.9)。
* @description 最新文风指纹(`GET /style`):完整 16 维(名称/值/证据+ 版本(对齐 UX §6.9)。
*
* DB 存两列并行 dict`{name:value}` + `{name:[evidence]}`);响应合并为
* `list[DimensionEntry]`,给 TS 客户端强类型(替代弱类型 `dict[str, Any]`)。
*/
StyleFingerprintResponse: {
/** Dimensions */
dimensions?: {
[key: string]: unknown;
};
/** Evidence */
evidence?: {
[key: string]: unknown;
};
dimensions?: components["schemas"]["DimensionEntry"][];
/** Version */
version: number;
};
@@ -1616,9 +1697,16 @@ export interface operations {
[name: string]: unknown;
};
content: {
"application/json": {
[key: string]: unknown;
};
"application/json": components["schemas"]["JobResponse"];
};
};
/** @description job 不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
@@ -1705,6 +1793,15 @@ export interface operations {
"application/json": components["schemas"]["ProjectResponse"];
};
};
/** @description 资源不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {
@@ -1737,6 +1834,15 @@ export interface operations {
"application/json": components["schemas"]["InjectionResponse"];
};
};
/** @description 资源不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {
@@ -1773,6 +1879,15 @@ export interface operations {
"application/json": components["schemas"]["InjectionResponse"];
};
};
/** @description 资源不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {
@@ -1805,6 +1920,15 @@ export interface operations {
"application/json": components["schemas"]["DraftView"];
};
};
/** @description 资源不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {
@@ -1981,6 +2105,24 @@ export interface operations {
"application/json": components["schemas"]["AcceptResponse"];
};
};
/** @description 资源不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description 存在未裁决冲突 */
409: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {
@@ -1990,6 +2132,15 @@ export interface operations {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
/** @description LLM 不可用 */
503: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
};
};
list_foreshadow_projects__project_id__foreshadow_get: {
@@ -2248,6 +2399,15 @@ export interface operations {
"application/json": components["schemas"]["StyleFingerprintResponse"];
};
};
/** @description 项目或指纹不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {