From 0e313405d62a16b2f3208d0163004ed8209612d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Sat, 3 Oct 2026 15:40:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E6=A0=A1=E9=AA=8C=E4=B8=8D=E5=86=8D=E7=94=A8?= =?UTF-8?q?=20prettier=20=E6=94=B9=E5=86=99=E7=94=9F=E6=88=90=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/check-generated-bindings.mjs:删掉生成后的 prettier 归一化,直接逐字节比较 ts-rs 原始输出 - .prettierignore 与 .eslintrc.cjs:四个 ts-rs 生成目录统一排除,禁止格式化工具二次改写 - .prettierrc.json:删除 contracts/generated 的 printWidth / singleQuote 覆盖 - .gitattributes:生成目录标 linguist-generated 并豁免 trailing-space,保证 git diff --check 通过 - 重新生成 AGC chat/generated 与 services/generated 的 51 个绑定,改为提交 ts-rs 原始输出(纯格式,语义不变) - docs/project-memory:记录生成绑定不再经 prettier 的口径,修正旧流程说明 --- .eslintrc.cjs | 4 + .gitattributes | 9 +- .prettierignore | 4 + .prettierrc.json | 11 +- .../generated/AuthClientInitFailed.ts | 2 +- .../services/generated/AuthNetworkFailure.ts | 4 +- .../services/generated/AuthNetworkReason.ts | 2 +- .../services/generated/AuthResponseInvalid.ts | 14 +- .../generated/AuthResponseInvalidReason.ts | 7 +- .../generated/AuthServiceUnavailable.ts | 2 +- .../src/services/generated/ClientAuthError.ts | 42 ++---- .../generated/ClientSessionPersistFailed.ts | 2 +- .../generated/PasswordLoginRejected.ts | 11 +- .../generated/PhoneCodeLoginRejected.ts | 11 +- .../generated/RuntimeSessionInstallFailed.ts | 2 +- .../services/generated/SendCodeRejected.ts | 11 +- .../services/generated/ServerAddressReason.ts | 9 +- .../generated/ServerAddressRejected.ts | 4 +- .../services/generated/UnexpectedRejection.ts | 5 +- .../chat/generated/ClientTurnIdMalformed.ts | 2 +- .../chat/generated/ConsumeResult.ts | 4 +- .../chat/generated/Deadline.ts | 2 +- .../chat/generated/EnqueueError.ts | 23 +-- .../chat/generated/EnvironmentNotReady.ts | 2 +- .../chat/generated/FailureStage.ts | 6 +- .../chat/generated/HistorySlice.ts | 22 ++- .../chat/generated/HostStateUnavailable.ts | 2 +- .../chat/generated/InputRejected.ts | 2 +- .../chat/generated/ModelCallFailed.ts | 4 +- .../chat/generated/ModelCallKind.ts | 13 +- .../chat/generated/NativeKind.ts | 14 +- .../chat/generated/PermissionRejected.ts | 2 +- .../chat/generated/ProjectRootUnanchored.ts | 2 +- .../chat/generated/QueueFull.ts | 2 +- .../chat/generated/QueueRemovalOutcome.ts | 2 +- .../chat/generated/QueueRemovalReason.ts | 2 +- .../chat/generated/SubscriptionBootstrap.ts | 22 ++- .../SuperErrorFromStringPlusStage.ts | 7 +- .../chat/generated/ThreadDeltaKind.ts | 2 +- .../chat/generated/ThreadEvent.ts | 136 +++++++----------- .../chat/generated/ThreadFileChange.ts | 12 +- .../chat/generated/ThreadItem.ts | 79 ++-------- .../chat/generated/ThreadRequestKind.ts | 5 +- .../chat/generated/TimedOut.ts | 4 +- .../chat/generated/TransportClosed.ts | 2 +- .../chat/generated/TurnCompletedStatus.ts | 6 +- .../chat/generated/TurnFailure.ts | 30 ++-- .../chat/generated/TurnInterrupted.ts | 2 +- .../chat/generated/Unclassified.ts | 2 +- .../generated/UserAttachmentReferencePart.ts | 8 +- .../chat/generated/UserContentPart.ts | 26 ++-- .../chat/generated/UserItem.ts | 4 +- .../chat/generated/UserMessageItem.ts | 10 +- .../chat/generated/UserRole.ts | 2 +- .../chat/generated/UserRuntimeRegionPart.ts | 12 +- ...¡划】DirectProject聊天真相源收敛-2026-09-16.md | 2 +- .../shared-memory/decision-log.md | 8 ++ docs/project-memory/shared-memory/pitfalls.md | 6 +- ...–½计划】DirectProject命令接单化-2026-09-23.md | 4 +- scripts/check-generated-bindings.mjs | 42 ++---- 60 files changed, 240 insertions(+), 455 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index cf2f89177..ae8275e7c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -164,6 +164,10 @@ module.exports = { 'server-rs/target-*', 'apps/desktop-shell/src-tauri/target', 'apps/ai-game-creator-shell/src/features/ui-editor/types/**', + // ts-rs 生成绑定:不接受 eslint --fix 二次改写,必须与原始输出逐字节一致 + 'packages/shared/src/contracts/generated/**', + 'apps/ai-game-creator-shell/src/view/project-development/chat/generated/**', + 'apps/ai-game-creator-shell/src/services/generated/**', 'apps/ai-game-creator-shell/src/features/project-workspace/generated/**', 'target', 'src/main.tsx', diff --git a/.gitattributes b/.gitattributes index 572a7e25f..a63eef88a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -24,5 +24,10 @@ *.anim text *.controller text -# Rust ts-rs 生成的共享契约:保留在仓库中供 TS 消费,但不作为手写源文件统计。 -packages/shared/src/contracts/generated/** linguist-generated=true +# ts-rs 生成绑定:保留在仓库中供 TS 消费,但不作为手写源文件统计。 +# ts-rs 原始输出在多行对象 / 枚举变体后带行尾空格,生成目录统一豁免行尾空白检查; +# 一致性由 `npm run check:generated-bindings` 逐字节比对原始输出来保证。 +packages/shared/src/contracts/generated/** linguist-generated=true whitespace=-trailing-space +apps/ai-game-creator-shell/src/features/ui-editor/types/** linguist-generated=true whitespace=-trailing-space +apps/ai-game-creator-shell/src/view/project-development/chat/generated/** linguist-generated=true whitespace=-trailing-space +apps/ai-game-creator-shell/src/services/generated/** linguist-generated=true whitespace=-trailing-space diff --git a/.prettierignore b/.prettierignore index 9ec6037f3..a32676e37 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,7 +3,11 @@ node_modules .git .codex-logs public/Icons +# ts-rs 生成绑定:一律以原始输出提交,禁止 prettier 二次改写 +packages/shared/src/contracts/generated/ apps/ai-game-creator-shell/src/features/ui-editor/types/ +apps/ai-game-creator-shell/src/view/project-development/chat/generated/ +apps/ai-game-creator-shell/src/services/generated/ apps/ai-game-creator-shell/src-tauri/resources/agc-skills/ media *.log diff --git a/.prettierrc.json b/.prettierrc.json index c4f9a8e5d..7d2081a95 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,14 +1,5 @@ { "singleQuote": true, "semi": true, - "trailingComma": "all", - "overrides": [ - { - "files": "packages/shared/src/contracts/generated/**/*.ts", - "options": { - "printWidth": 1000, - "singleQuote": false - } - } - ] + "trailingComma": "all" } diff --git a/apps/ai-game-creator-shell/src/services/generated/AuthClientInitFailed.ts b/apps/ai-game-creator-shell/src/services/generated/AuthClientInitFailed.ts index 73188e2d3..c66564189 100644 --- a/apps/ai-game-creator-shell/src/services/generated/AuthClientInitFailed.ts +++ b/apps/ai-game-creator-shell/src/services/generated/AuthClientInitFailed.ts @@ -3,4 +3,4 @@ /** * 认证网络客户端构建失败的原始错误明细。 */ -export type AuthClientInitFailed = { detail: string }; +export type AuthClientInitFailed = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/AuthNetworkFailure.ts b/apps/ai-game-creator-shell/src/services/generated/AuthNetworkFailure.ts index a852d6759..0715674b6 100644 --- a/apps/ai-game-creator-shell/src/services/generated/AuthNetworkFailure.ts +++ b/apps/ai-game-creator-shell/src/services/generated/AuthNetworkFailure.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { AuthNetworkReason } from './AuthNetworkReason'; +import type { AuthNetworkReason } from "./AuthNetworkReason"; /** * 连接登录服务的传输层失败原因。 */ -export type AuthNetworkFailure = { reason: AuthNetworkReason }; +export type AuthNetworkFailure = { reason: AuthNetworkReason, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/AuthNetworkReason.ts b/apps/ai-game-creator-shell/src/services/generated/AuthNetworkReason.ts index 73f2a73f9..193ee7a73 100644 --- a/apps/ai-game-creator-shell/src/services/generated/AuthNetworkReason.ts +++ b/apps/ai-game-creator-shell/src/services/generated/AuthNetworkReason.ts @@ -3,4 +3,4 @@ /** * 连接登录服务失败的具体原因。 */ -export type AuthNetworkReason = 'timeout' | 'unreachable'; +export type AuthNetworkReason = "timeout" | "unreachable"; diff --git a/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalid.ts b/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalid.ts index b9b57f307..0175ed188 100644 --- a/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalid.ts +++ b/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalid.ts @@ -1,13 +1,11 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { AuthResponseInvalidReason } from './AuthResponseInvalidReason'; +import type { AuthResponseInvalidReason } from "./AuthResponseInvalidReason"; /** * 登录响应契约破损的原因与服务端原文。 */ -export type AuthResponseInvalid = { - reason: AuthResponseInvalidReason; - /** - * 只有 `serverRejected` 可能带服务端原文;其余是 `null`。 - */ - serverMessage: string | null; -}; +export type AuthResponseInvalid = { reason: AuthResponseInvalidReason, +/** + * 只有 `serverRejected` 可能带服务端原文;其余是 `null`。 + */ +serverMessage: string | null, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalidReason.ts b/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalidReason.ts index cd7dd488f..57887317f 100644 --- a/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalidReason.ts +++ b/apps/ai-game-creator-shell/src/services/generated/AuthResponseInvalidReason.ts @@ -3,9 +3,4 @@ /** * 登录响应契约破损的具体原因。 */ -export type AuthResponseInvalidReason = - | 'notJson' - | 'invalidBody' - | 'missingRefreshCookie' - | 'missingUserIdentity' - | 'serverRejected'; +export type AuthResponseInvalidReason = "notJson" | "invalidBody" | "missingRefreshCookie" | "missingUserIdentity" | "serverRejected"; diff --git a/apps/ai-game-creator-shell/src/services/generated/AuthServiceUnavailable.ts b/apps/ai-game-creator-shell/src/services/generated/AuthServiceUnavailable.ts index 600fdcc93..4bd75d065 100644 --- a/apps/ai-game-creator-shell/src/services/generated/AuthServiceUnavailable.ts +++ b/apps/ai-game-creator-shell/src/services/generated/AuthServiceUnavailable.ts @@ -3,4 +3,4 @@ /** * 登录服务 5xx 的状态码。 */ -export type AuthServiceUnavailable = { status: number }; +export type AuthServiceUnavailable = { status: number, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts b/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts index 9e87dc86d..994aefb32 100644 --- a/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts +++ b/apps/ai-game-creator-shell/src/services/generated/ClientAuthError.ts @@ -1,35 +1,17 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { AuthClientInitFailed } from './AuthClientInitFailed'; -import type { AuthNetworkFailure } from './AuthNetworkFailure'; -import type { AuthResponseInvalid } from './AuthResponseInvalid'; -import type { AuthServiceUnavailable } from './AuthServiceUnavailable'; -import type { ClientSessionPersistFailed } from './ClientSessionPersistFailed'; -import type { PasswordLoginRejected } from './PasswordLoginRejected'; -import type { PhoneCodeLoginRejected } from './PhoneCodeLoginRejected'; -import type { RuntimeSessionInstallFailed } from './RuntimeSessionInstallFailed'; -import type { SendCodeRejected } from './SendCodeRejected'; -import type { ServerAddressRejected } from './ServerAddressRejected'; -import type { UnexpectedRejection } from './UnexpectedRejection'; +import type { AuthClientInitFailed } from "./AuthClientInitFailed"; +import type { AuthNetworkFailure } from "./AuthNetworkFailure"; +import type { AuthResponseInvalid } from "./AuthResponseInvalid"; +import type { AuthServiceUnavailable } from "./AuthServiceUnavailable"; +import type { ClientSessionPersistFailed } from "./ClientSessionPersistFailed"; +import type { PasswordLoginRejected } from "./PasswordLoginRejected"; +import type { PhoneCodeLoginRejected } from "./PhoneCodeLoginRejected"; +import type { RuntimeSessionInstallFailed } from "./RuntimeSessionInstallFailed"; +import type { SendCodeRejected } from "./SendCodeRejected"; +import type { ServerAddressRejected } from "./ServerAddressRejected"; +import type { UnexpectedRejection } from "./UnexpectedRejection"; /** * 变体名就是线上的分流键(`type`),带载荷的变体持有同名载荷类型。 */ -export type ClientAuthError = - | ({ type: 'serverAddressRejected' } & ServerAddressRejected) - | { type: 'phoneNumberInvalid' } - | { type: 'passwordMissing' } - | { type: 'loginCodeMissing' } - | ({ type: 'passwordLoginRejected' } & PasswordLoginRejected) - | { type: 'phoneOrPasswordMismatch' } - | ({ type: 'sendCodeRejected' } & SendCodeRejected) - | { type: 'smsCodeThrottled' } - | ({ type: 'phoneCodeLoginRejected' } & PhoneCodeLoginRejected) - | { type: 'sessionInvalidated' } - | { type: 'permissionDenied' } - | ({ type: 'authNetworkFailure' } & AuthNetworkFailure) - | ({ type: 'authServiceUnavailable' } & AuthServiceUnavailable) - | ({ type: 'unexpectedRejection' } & UnexpectedRejection) - | ({ type: 'authResponseInvalid' } & AuthResponseInvalid) - | ({ type: 'clientSessionPersistFailed' } & ClientSessionPersistFailed) - | ({ type: 'runtimeSessionInstallFailed' } & RuntimeSessionInstallFailed) - | ({ type: 'authClientInitFailed' } & AuthClientInitFailed); +export type ClientAuthError = { "type": "serverAddressRejected" } & ServerAddressRejected | { "type": "phoneNumberInvalid" } | { "type": "passwordMissing" } | { "type": "loginCodeMissing" } | { "type": "passwordLoginRejected" } & PasswordLoginRejected | { "type": "phoneOrPasswordMismatch" } | { "type": "sendCodeRejected" } & SendCodeRejected | { "type": "smsCodeThrottled" } | { "type": "phoneCodeLoginRejected" } & PhoneCodeLoginRejected | { "type": "sessionInvalidated" } | { "type": "permissionDenied" } | { "type": "authNetworkFailure" } & AuthNetworkFailure | { "type": "authServiceUnavailable" } & AuthServiceUnavailable | { "type": "unexpectedRejection" } & UnexpectedRejection | { "type": "authResponseInvalid" } & AuthResponseInvalid | { "type": "clientSessionPersistFailed" } & ClientSessionPersistFailed | { "type": "runtimeSessionInstallFailed" } & RuntimeSessionInstallFailed | { "type": "authClientInitFailed" } & AuthClientInitFailed; diff --git a/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts b/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts index 258f43fb0..b6f047440 100644 --- a/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts +++ b/apps/ai-game-creator-shell/src/services/generated/ClientSessionPersistFailed.ts @@ -3,4 +3,4 @@ /** * 本机凭据文件读写的原始错误明细。 */ -export type ClientSessionPersistFailed = { detail: string }; +export type ClientSessionPersistFailed = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/PasswordLoginRejected.ts b/apps/ai-game-creator-shell/src/services/generated/PasswordLoginRejected.ts index 450754f46..2296163ae 100644 --- a/apps/ai-game-creator-shell/src/services/generated/PasswordLoginRejected.ts +++ b/apps/ai-game-creator-shell/src/services/generated/PasswordLoginRejected.ts @@ -3,9 +3,8 @@ /** * `/api/auth/entry` 返回 400 时服务端给的原文。 */ -export type PasswordLoginRejected = { - /** - * 服务端原文可能缺失:缺失是 `null`,Rust 不编造兜底文案。 - */ - serverMessage: string | null; -}; +export type PasswordLoginRejected = { +/** + * 服务端原文可能缺失:缺失是 `null`,Rust 不编造兜底文案。 + */ +serverMessage: string | null, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/PhoneCodeLoginRejected.ts b/apps/ai-game-creator-shell/src/services/generated/PhoneCodeLoginRejected.ts index 403eaebbd..51ae18c75 100644 --- a/apps/ai-game-creator-shell/src/services/generated/PhoneCodeLoginRejected.ts +++ b/apps/ai-game-creator-shell/src/services/generated/PhoneCodeLoginRejected.ts @@ -3,9 +3,8 @@ /** * `/api/auth/phone/login` 返回 400 时服务端给的原文。 */ -export type PhoneCodeLoginRejected = { - /** - * 服务端原文可能缺失:缺失是 `null`,Rust 不编造兜底文案。 - */ - serverMessage: string | null; -}; +export type PhoneCodeLoginRejected = { +/** + * 服务端原文可能缺失:缺失是 `null`,Rust 不编造兜底文案。 + */ +serverMessage: string | null, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts b/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts index df2940b5d..98343be13 100644 --- a/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts +++ b/apps/ai-game-creator-shell/src/services/generated/RuntimeSessionInstallFailed.ts @@ -3,4 +3,4 @@ /** * 本机运行时会话安装 / 清理的原始错误明细。 */ -export type RuntimeSessionInstallFailed = { detail: string }; +export type RuntimeSessionInstallFailed = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/SendCodeRejected.ts b/apps/ai-game-creator-shell/src/services/generated/SendCodeRejected.ts index cdf2a07c0..54f8bd8df 100644 --- a/apps/ai-game-creator-shell/src/services/generated/SendCodeRejected.ts +++ b/apps/ai-game-creator-shell/src/services/generated/SendCodeRejected.ts @@ -3,9 +3,8 @@ /** * `/api/auth/phone/send-code` 返回 400 时服务端给的原文。 */ -export type SendCodeRejected = { - /** - * 服务端原文可能缺失:缺失是 `null`,Rust 不编造兜底文案。 - */ - serverMessage: string | null; -}; +export type SendCodeRejected = { +/** + * 服务端原文可能缺失:缺失是 `null`,Rust 不编造兜底文案。 + */ +serverMessage: string | null, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/ServerAddressReason.ts b/apps/ai-game-creator-shell/src/services/generated/ServerAddressReason.ts index c60ebb82b..85a950d40 100644 --- a/apps/ai-game-creator-shell/src/services/generated/ServerAddressReason.ts +++ b/apps/ai-game-creator-shell/src/services/generated/ServerAddressReason.ts @@ -3,11 +3,4 @@ /** * 服务地址校验失败的具体原因。 */ -export type ServerAddressReason = - | 'emptyOrTooLong' - | 'notAUrl' - | 'hasCredentials' - | 'hasPathOrQueryOrFragment' - | 'notHttps' - | 'unsupportedScheme' - | 'outsideChannel'; +export type ServerAddressReason = "emptyOrTooLong" | "notAUrl" | "hasCredentials" | "hasPathOrQueryOrFragment" | "notHttps" | "unsupportedScheme" | "outsideChannel"; diff --git a/apps/ai-game-creator-shell/src/services/generated/ServerAddressRejected.ts b/apps/ai-game-creator-shell/src/services/generated/ServerAddressRejected.ts index fdcc96aa0..94ac0c9bb 100644 --- a/apps/ai-game-creator-shell/src/services/generated/ServerAddressRejected.ts +++ b/apps/ai-game-creator-shell/src/services/generated/ServerAddressRejected.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ServerAddressReason } from './ServerAddressReason'; +import type { ServerAddressReason } from "./ServerAddressReason"; /** * 服务地址被拒的具体原因。 */ -export type ServerAddressRejected = { reason: ServerAddressReason }; +export type ServerAddressRejected = { reason: ServerAddressReason, }; diff --git a/apps/ai-game-creator-shell/src/services/generated/UnexpectedRejection.ts b/apps/ai-game-creator-shell/src/services/generated/UnexpectedRejection.ts index b2c4041eb..6e3d743db 100644 --- a/apps/ai-game-creator-shell/src/services/generated/UnexpectedRejection.ts +++ b/apps/ai-game-creator-shell/src/services/generated/UnexpectedRejection.ts @@ -3,7 +3,4 @@ /** * 其它未识别拒绝的状态码与服务端原文。 */ -export type UnexpectedRejection = { - status: number; - serverMessage: string | null; -}; +export type UnexpectedRejection = { status: number, serverMessage: string | null, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ClientTurnIdMalformed.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ClientTurnIdMalformed.ts index 7a09357f8..1d374f0df 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ClientTurnIdMalformed.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ClientTurnIdMalformed.ts @@ -3,4 +3,4 @@ /** * `clientTurnId` 的长度约束:上下限随载荷带出去,界面不自己数一份。 */ -export type ClientTurnIdMalformed = { minChars: number; maxChars: number }; +export type ClientTurnIdMalformed = { minChars: number, maxChars: number, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ConsumeResult.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ConsumeResult.ts index f31d8f49c..2b2143553 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ConsumeResult.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ConsumeResult.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ThreadEvent } from './ThreadEvent'; +import type { ThreadEvent } from "./ThreadEvent"; -export type ConsumeResult = { events: Array }; +export type ConsumeResult = { events: Array, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Deadline.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Deadline.ts index 25e71989c..a1e7d80bf 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Deadline.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Deadline.ts @@ -5,4 +5,4 @@ * * 跟着入队失败 / 回合失败载荷一起给前端,界面不靠文案区分这两条。 */ -export type Deadline = 'response-idle' | 'turn-hard-limit'; +export type Deadline = "response-idle" | "turn-hard-limit"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnqueueError.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnqueueError.ts index 011bcd996..b904681ab 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnqueueError.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnqueueError.ts @@ -1,10 +1,10 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ClientTurnIdMalformed } from './ClientTurnIdMalformed'; -import type { EnvironmentNotReady } from './EnvironmentNotReady'; -import type { HostStateUnavailable } from './HostStateUnavailable'; -import type { InputRejected } from './InputRejected'; -import type { PermissionRejected } from './PermissionRejected'; -import type { QueueFull } from './QueueFull'; +import type { ClientTurnIdMalformed } from "./ClientTurnIdMalformed"; +import type { EnvironmentNotReady } from "./EnvironmentNotReady"; +import type { HostStateUnavailable } from "./HostStateUnavailable"; +import type { InputRejected } from "./InputRejected"; +import type { PermissionRejected } from "./PermissionRejected"; +import type { QueueFull } from "./QueueFull"; /** * 命令边界的 typed 入队失败:变体名就是线上的分流键(`type`),前端只按它选通道,不解析文案。 @@ -13,13 +13,4 @@ import type { QueueFull } from './QueueFull'; * `clientTurnId` 校验 → 工作流恢复 → 用户条目冻结 → 前置条件 → 容量预判 → 工程准备 → 入队。 * 放行之后发生的失败不在这张表里(见 [`TurnError`])。 */ -export type EnqueueError = - | { type: 'clientTurnIdMissing' } - | ({ type: 'clientTurnIdMalformed' } & ClientTurnIdMalformed) - | ({ type: 'queueFull' } & QueueFull) - | { type: 'projectRootUnusable' } - | ({ type: 'permissionRejected' } & PermissionRejected) - | ({ type: 'inputRejected' } & InputRejected) - | { type: 'contentEmpty' } - | ({ type: 'environmentNotReady' } & EnvironmentNotReady) - | ({ type: 'hostStateUnavailable' } & HostStateUnavailable); +export type EnqueueError = { "type": "clientTurnIdMissing" } | { "type": "clientTurnIdMalformed" } & ClientTurnIdMalformed | { "type": "queueFull" } & QueueFull | { "type": "projectRootUnusable" } | { "type": "permissionRejected" } & PermissionRejected | { "type": "inputRejected" } & InputRejected | { "type": "contentEmpty" } | { "type": "environmentNotReady" } & EnvironmentNotReady | { "type": "hostStateUnavailable" } & HostStateUnavailable; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnvironmentNotReady.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnvironmentNotReady.ts index 176eeee06..848a2e7c7 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnvironmentNotReady.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/EnvironmentNotReady.ts @@ -5,4 +5,4 @@ * * **两张表共用**:入队侧是入队失败,回合侧是回合失败。 */ -export type EnvironmentNotReady = { detail: string }; +export type EnvironmentNotReady = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/FailureStage.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/FailureStage.ts index 2a534a956..314f31ec9 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/FailureStage.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/FailureStage.ts @@ -5,8 +5,4 @@ * * 线上取值跟着入队失败 / 回合失败载荷一起给前端(`art-preparation` 这类),所以也要导出。 */ -export type FailureStage = - | 'art-preparation' - | 'code-generation' - | 'browser-validation' - | 'version-registration'; +export type FailureStage = "art-preparation" | "code-generation" | "browser-validation" | "version-registration"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HistorySlice.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HistorySlice.ts index 22a93077c..b56f593e7 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HistorySlice.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HistorySlice.ts @@ -1,14 +1,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ThreadItem } from './ThreadItem'; +import type { ThreadItem } from "./ThreadItem"; -export type HistorySlice = { - /** - * 脱敏条目,顺序即文件顺序;与运行态事件里的条目同形。 - */ - items: Array; - hasMore: boolean; - /** - * 本次切片的原始 item id 锚点:无论切片里有没有可显示条目,分页都靠它向前。 - */ - firstItemId: string | null; -}; +export type HistorySlice = { +/** + * 脱敏条目,顺序即文件顺序;与运行态事件里的条目同形。 + */ +items: Array, hasMore: boolean, +/** + * 本次切片的原始 item id 锚点:无论切片里有没有可显示条目,分页都靠它向前。 + */ +firstItemId: string | null, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HostStateUnavailable.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HostStateUnavailable.ts index a7204cb86..d558145ad 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HostStateUnavailable.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/HostStateUnavailable.ts @@ -3,4 +3,4 @@ /** * 宿主执行账本取不到的原始解释。 */ -export type HostStateUnavailable = { detail: string }; +export type HostStateUnavailable = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/InputRejected.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/InputRejected.ts index ddb603f08..05c13bdb0 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/InputRejected.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/InputRejected.ts @@ -3,4 +3,4 @@ /** * 用户条目 / 创建类型不合法的原始解释。 */ -export type InputRejected = { detail: string }; +export type InputRejected = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallFailed.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallFailed.ts index 0665facb6..bebd8d9f5 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallFailed.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallFailed.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ModelCallKind } from './ModelCallKind'; +import type { ModelCallKind } from "./ModelCallKind"; /** * 模型调用失败的分类与平台层原文。 */ -export type ModelCallFailed = { kind: ModelCallKind; detail: string }; +export type ModelCallFailed = { kind: ModelCallKind, detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallKind.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallKind.ts index da4bdc291..b5ba63eb5 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallKind.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ModelCallKind.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { NativeKind } from './NativeKind'; +import type { NativeKind } from "./NativeKind"; /** * 模型调用失败(app-server 一次 `turn` 的结果)的分类,跟着入队失败 / 回合失败载荷一起给前端。 @@ -7,13 +7,4 @@ import type { NativeKind } from './NativeKind'; * 每个变体对应平台层 `LlmError` 的一个分支;前端拿它选语气,不拿它做流程分支。 * `native` 字段是原因文本里带出来的原生分类:有它时决策看原生分类,没有时看这个变体本身。 */ -export type ModelCallKind = - | { type: 'responseTimedOut'; attempts: number } - | { type: 'connectionFailed'; attempts: number } - | { type: 'transportBroken' } - | { type: 'streamUnavailable' } - | { type: 'requestRejected'; native: NativeKind | null } - | { type: 'upstreamFailed'; statusCode: number; native: NativeKind | null } - | { type: 'paidCreditsInsufficient' } - | { type: 'emptyResponse' } - | { type: 'payloadInvalid'; native: NativeKind | null }; +export type ModelCallKind = { "type": "responseTimedOut", attempts: number, } | { "type": "connectionFailed", attempts: number, } | { "type": "transportBroken" } | { "type": "streamUnavailable" } | { "type": "requestRejected", native: NativeKind | null, } | { "type": "upstreamFailed", statusCode: number, native: NativeKind | null, } | { "type": "paidCreditsInsufficient" } | { "type": "emptyResponse" } | { "type": "payloadInvalid", native: NativeKind | null, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/NativeKind.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/NativeKind.ts index 97849af52..b38ba07b2 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/NativeKind.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/NativeKind.ts @@ -9,16 +9,4 @@ * * 线上取值只给界面选语气用,前端不得拿它做流程分支。 */ -export type NativeKind = - | { type: 'context-window-exceeded' } - | { type: 'session-budget-exceeded' } - | { type: 'usage-limit-exceeded' } - | { type: 'request-too-large' } - | { type: 'stream-required' } - | { type: 'cyber-policy' } - | { type: 'sandbox-error' } - | { type: 'thread-rollback-failed' } - | { type: 'bad-request' } - | { type: 'unauthorized' } - | { type: 'active-turn-not-steerable' } - | { type: 'other'; kind: string }; +export type NativeKind = { "type": "context-window-exceeded" } | { "type": "session-budget-exceeded" } | { "type": "usage-limit-exceeded" } | { "type": "request-too-large" } | { "type": "stream-required" } | { "type": "cyber-policy" } | { "type": "sandbox-error" } | { "type": "thread-rollback-failed" } | { "type": "bad-request" } | { "type": "unauthorized" } | { "type": "active-turn-not-steerable" } | { "type": "other", kind: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/PermissionRejected.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/PermissionRejected.ts index 9d69d6a08..bd36bdd08 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/PermissionRejected.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/PermissionRejected.ts @@ -3,4 +3,4 @@ /** * 项目权限策略的原文(带被拒的点位)。 */ -export type PermissionRejected = { policyDetail: string }; +export type PermissionRejected = { policyDetail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ProjectRootUnanchored.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ProjectRootUnanchored.ts index 7820a1528..dd888d55e 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ProjectRootUnanchored.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ProjectRootUnanchored.ts @@ -3,4 +3,4 @@ /** * 项目目录锚不定的原始原因。 */ -export type ProjectRootUnanchored = { cause: string }; +export type ProjectRootUnanchored = { cause: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueFull.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueFull.ts index 59eea063e..61904ef17 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueFull.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueFull.ts @@ -3,4 +3,4 @@ /** * 待发消息队列上限:只落在宿主这一处(`MAX_PENDING_TURNS`)。 */ -export type QueueFull = { limit: number }; +export type QueueFull = { limit: number, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalOutcome.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalOutcome.ts index 109b6f6ba..07a82e74a 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalOutcome.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalOutcome.ts @@ -3,4 +3,4 @@ /** * 取消一条待发消息的结果。 */ -export type QueueRemovalOutcome = 'removed' | 'alreadyDispatched' | 'notFound'; +export type QueueRemovalOutcome = "removed" | "alreadyDispatched" | "notFound"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalReason.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalReason.ts index f965308e6..a66bf169a 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalReason.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/QueueRemovalReason.ts @@ -6,4 +6,4 @@ * typed 枚举,取值即语义:取消是用户在输入盒上撤掉这条消息,放行是它已经离开队列并成为回合 * (同一临界区里另有 `turn.started`)。界面按它分流,不解析字符串。 */ -export type QueueRemovalReason = 'cancelled' | 'dispatched'; +export type QueueRemovalReason = "cancelled" | "dispatched"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SubscriptionBootstrap.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SubscriptionBootstrap.ts index de5eb7404..fcfa6bbc5 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SubscriptionBootstrap.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SubscriptionBootstrap.ts @@ -1,14 +1,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ThreadEvent } from './ThreadEvent'; +import type { ThreadEvent } from "./ThreadEvent"; -export type SubscriptionBootstrap = { - subscriptionId: string; - /** - * 首屏历史锚点:`project.jsonl` 里最后一条原始 item id。 - */ - lastCompletedItemId: string | null; - /** - * 该 subscriber 此刻应当处理的运行态事件(游标已经在队尾)。 - */ - events: Array; -}; +export type SubscriptionBootstrap = { subscriptionId: string, +/** + * 首屏历史锚点:`project.jsonl` 里最后一条原始 item id。 + */ +lastCompletedItemId: string | null, +/** + * 该 subscriber 此刻应当处理的运行态事件(游标已经在队尾)。 + */ +events: Array, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SuperErrorFromStringPlusStage.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SuperErrorFromStringPlusStage.ts index 59d5e81b9..94050cfad 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SuperErrorFromStringPlusStage.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/SuperErrorFromStringPlusStage.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { FailureStage } from './FailureStage'; +import type { FailureStage } from "./FailureStage"; /** * 已知交付阶段的失败:`stage` 是 typed enum,`detail` 是产生层原文(字符串债)。 @@ -7,7 +7,4 @@ import type { FailureStage } from './FailureStage'; * 名字故意起得又长又扎眼(`Super…FromStringPlusStage`):与 [`SuperErrorEnumFromStringTyped`] * 同一笔债——`detail` 一天没 typed 化,它一天不配有个正常名字。 */ -export type SuperErrorFromStringPlusStage = { - stage: FailureStage; - detail: string; -}; +export type SuperErrorFromStringPlusStage = { stage: FailureStage, detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadDeltaKind.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadDeltaKind.ts index b414a0f81..30edebe27 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadDeltaKind.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadDeltaKind.ts @@ -3,4 +3,4 @@ /** * 增量正文属于哪类条目。 */ -export type ThreadDeltaKind = 'message' | 'reasoning'; +export type ThreadDeltaKind = "message" | "reasoning"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadEvent.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadEvent.ts index 6f3d2ec95..fd3894301 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadEvent.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadEvent.ts @@ -1,11 +1,11 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { QueueRemovalReason } from './QueueRemovalReason'; -import type { ThreadDeltaKind } from './ThreadDeltaKind'; -import type { ThreadItem } from './ThreadItem'; -import type { ThreadRequestKind } from './ThreadRequestKind'; -import type { TurnCompletedStatus } from './TurnCompletedStatus'; -import type { TurnFailure } from './TurnFailure'; -import type { UserItem } from './UserItem'; +import type { QueueRemovalReason } from "./QueueRemovalReason"; +import type { ThreadDeltaKind } from "./ThreadDeltaKind"; +import type { ThreadItem } from "./ThreadItem"; +import type { ThreadRequestKind } from "./ThreadRequestKind"; +import type { TurnCompletedStatus } from "./TurnCompletedStatus"; +import type { TurnFailure } from "./TurnFailure"; +import type { UserItem } from "./UserItem"; /** * Thread Manager 下发的运行态事件。 @@ -32,77 +32,51 @@ import type { UserItem } from './UserItem'; * + 历史切片、运行态一直为空时也能按身份认领开口条目,不必靠时间戳猜。缺失表示身份不可证明 * (旧事件、没有开口用户条目、取消时拿不到 clientTurnId),此时前端不得补造。 */ -export type ThreadEvent = - | { - type: 'turn.started'; - /** - * 本轮开始的阶段时间(毫秒):**放行**那一刻的宿主毫秒钟(逻辑回合的起点,不是 - * `turn/start` 的时刻)。 - */ - at?: number; - /** - * 本轮开口用户条目的 canonical itemId;缺失表示身份不可证明。 - */ - userItemId?: string; - } - | { - type: 'turn.completed'; - /** - * 终态语义:`completed` / `interrupted` / `aborted` 是正常收场,不带载荷;`failed` 是 - * **失败**,一定带 `failure` 载荷。正常收场的构造参数是 [`TurnOutcome`](不含 `Failed`), - * [`ThreadEvent::turn_completed`] 因此写不出"failed 但没有载荷"。 - */ - status: TurnCompletedStatus; - /** - * 失败载荷:只有 `status == "failed"` 才有;失败原因只从这里下发一次。 - */ - failure?: TurnFailure; - /** - * 本轮终态的阶段时间(毫秒):宿主写下终态的毫秒钟,或 `durationMs` + 高精度起点的派生值。 - */ - at?: number; - /** - * 本轮开口用户条目的 canonical itemId:与同一轮的 `turn.started` 同源;缺失表示不可证明。 - */ - userItemId?: string; - } - | { - type: 'item.started'; - item: ThreadItem; - /** - * 条目开始执行的原生阶段时间(毫秒);缺失时是宿主观测到该阶段的时间。 - */ - at?: number; - } - | { - type: 'item.completed'; - item: ThreadItem; - /** - * 条目结束的原生阶段时间(毫秒);缺失时是宿主观测到该阶段的时间。 - */ - at?: number; - } - | { type: 'item.delta'; itemId: string; kind: ThreadDeltaKind; delta: string } - | { type: 'request'; kind: ThreadRequestKind; requestId: string | null } - | { - type: 'queue.enqueued'; - /** - * 这条待发消息的回合身份;放行后同一轮的 `turn.started` / `turn.completed` 用它。 - */ - clientTurnId: string; - /** - * canonical 用户条目:前端据此派生 chip 文案,Rust 不渲染展示形状。 - */ - userItem: UserItem; - creationType?: string; - /** - * 入队那一刻的宿主毫秒钟。 - */ - at: number; - } - | { - type: 'queue.removed'; - clientTurnId: string; - reason: QueueRemovalReason; - at?: number; - }; +export type ThreadEvent = { "type": "turn.started", +/** + * 本轮开始的阶段时间(毫秒):**放行**那一刻的宿主毫秒钟(逻辑回合的起点,不是 + * `turn/start` 的时刻)。 + */ +at?: number, +/** + * 本轮开口用户条目的 canonical itemId;缺失表示身份不可证明。 + */ +userItemId?: string, } | { "type": "turn.completed", +/** + * 终态语义:`completed` / `interrupted` / `aborted` 是正常收场,不带载荷;`failed` 是 + * **失败**,一定带 `failure` 载荷。正常收场的构造参数是 [`TurnOutcome`](不含 `Failed`), + * [`ThreadEvent::turn_completed`] 因此写不出"failed 但没有载荷"。 + */ +status: TurnCompletedStatus, +/** + * 失败载荷:只有 `status == "failed"` 才有;失败原因只从这里下发一次。 + */ +failure?: TurnFailure, +/** + * 本轮终态的阶段时间(毫秒):宿主写下终态的毫秒钟,或 `durationMs` + 高精度起点的派生值。 + */ +at?: number, +/** + * 本轮开口用户条目的 canonical itemId:与同一轮的 `turn.started` 同源;缺失表示不可证明。 + */ +userItemId?: string, } | { "type": "item.started", item: ThreadItem, +/** + * 条目开始执行的原生阶段时间(毫秒);缺失时是宿主观测到该阶段的时间。 + */ +at?: number, } | { "type": "item.completed", item: ThreadItem, +/** + * 条目结束的原生阶段时间(毫秒);缺失时是宿主观测到该阶段的时间。 + */ +at?: number, } | { "type": "item.delta", itemId: string, kind: ThreadDeltaKind, delta: string, } | { "type": "request", kind: ThreadRequestKind, requestId: string | null, } | { "type": "queue.enqueued", +/** + * 这条待发消息的回合身份;放行后同一轮的 `turn.started` / `turn.completed` 用它。 + */ +clientTurnId: string, +/** + * canonical 用户条目:前端据此派生 chip 文案,Rust 不渲染展示形状。 + */ +userItem: UserItem, creationType?: string, +/** + * 入队那一刻的宿主毫秒钟。 + */ +at: number, } | { "type": "queue.removed", clientTurnId: string, reason: QueueRemovalReason, at?: number, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadFileChange.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadFileChange.ts index 5ef619872..2559d43ed 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadFileChange.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadFileChange.ts @@ -3,10 +3,8 @@ /** * 一条文件变更。 */ -export type ThreadFileChange = { - path: string; - /** - * `add` | `update` | `delete` - */ - kind: string; -}; +export type ThreadFileChange = { path: string, +/** + * `add` | `update` | `delete` + */ +kind: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadItem.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadItem.ts index d4c442a36..a2207f250 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadItem.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadItem.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ThreadFileChange } from './ThreadFileChange'; +import type { ThreadFileChange } from "./ThreadFileChange"; /** * 聊天视图的输入条目:一条 Codex 原始条目的原样投影(脱敏与限长在事件进前端状态时统一做)。 @@ -10,67 +10,16 @@ import type { ThreadFileChange } from './ThreadFileChange'; * 条目上的 `at` 是只用于显示的毫秒时间戳:ts-rs 默认把 `u64` 映射成 `bigint`, * 而 Tauri 的 JSON 通道传过来的是 `number`,因此统一标 `#[ts(as = "f64")]` 对齐。 */ -export type ThreadItem = - | { - itemType: 'message'; - /** - * 归一身份:全链路只有这一个 id。 - */ - itemId: string; - /** - * 原始 role(`user` / `assistant` / `system` / …);显示与否由前端判断。 - */ - role: string; - text: string; - at: number; - } - | { itemType: 'reasoning'; itemId: string; text: string; at: number } - | { - itemType: 'function_call'; - itemId: string; - name: string; - arguments: string; - at: number; - } - | { - itemType: 'function_call_output'; - itemId: string; - output: string; - at: number; - } - | { - itemType: 'commandExecution'; - itemId: string; - command: string; - output: string | null; - /** - * app-server 原始状态:`inProgress` / `completed` / `failed` / `declined` / … - */ - status: string | null; - exitCode: number | null; - at: number; - } - | { - itemType: 'fileChange'; - itemId: string; - changes: Array; - at: number; - } - | { - itemType: 'mcpToolCall'; - itemId: string; - tool: string; - arguments: string; - output: string | null; - status: string | null; - at: number; - } - | { - itemType: 'webSearch'; - itemId: string; - query: string | null; - output: string | null; - at: number; - } - | { itemType: 'contextCompaction'; itemId: string; at: number } - | { itemType: 'other'; itemId: string; rawType: string; at: number }; +export type ThreadItem = { "itemType": "message", +/** + * 归一身份:全链路只有这一个 id。 + */ +itemId: string, +/** + * 原始 role(`user` / `assistant` / `system` / …);显示与否由前端判断。 + */ +role: string, text: string, at: number, } | { "itemType": "reasoning", itemId: string, text: string, at: number, } | { "itemType": "function_call", itemId: string, name: string, arguments: string, at: number, } | { "itemType": "function_call_output", itemId: string, output: string, at: number, } | { "itemType": "commandExecution", itemId: string, command: string, output: string | null, +/** + * app-server 原始状态:`inProgress` / `completed` / `failed` / `declined` / … + */ +status: string | null, exitCode: number | null, at: number, } | { "itemType": "fileChange", itemId: string, changes: Array, at: number, } | { "itemType": "mcpToolCall", itemId: string, tool: string, arguments: string, output: string | null, status: string | null, at: number, } | { "itemType": "webSearch", itemId: string, query: string | null, output: string | null, at: number, } | { "itemType": "contextCompaction", itemId: string, at: number, } | { "itemType": "other", itemId: string, rawType: string, at: number, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadRequestKind.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadRequestKind.ts index 1b946a72b..83b0d57db 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadRequestKind.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/ThreadRequestKind.ts @@ -3,7 +3,4 @@ /** * 审批 / 提问请求与解决:本轮只透传,不并入聊天状态。 */ -export type ThreadRequestKind = - | 'approval.requested' - | 'ask.requested' - | 'request.resolved'; +export type ThreadRequestKind = "approval.requested" | "ask.requested" | "request.resolved"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TimedOut.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TimedOut.ts index 08e1e9c8f..189383a55 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TimedOut.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TimedOut.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { Deadline } from './Deadline'; +import type { Deadline } from "./Deadline"; /** * 撞上的那条上限。 */ -export type TimedOut = { deadline: Deadline }; +export type TimedOut = { deadline: Deadline, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TransportClosed.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TransportClosed.ts index 4320e7c5f..ed8b1657d 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TransportClosed.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TransportClosed.ts @@ -3,4 +3,4 @@ /** * 通道断开时那份宿主诊断(进程退出 / stderr 摘要)。 */ -export type TransportClosed = { diagnostic: string }; +export type TransportClosed = { diagnostic: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnCompletedStatus.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnCompletedStatus.ts index 3b9c3c203..fc42cfa41 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnCompletedStatus.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnCompletedStatus.ts @@ -6,8 +6,4 @@ * 正常收场是前三档、不带载荷;`Failed` **一定**带 [`TurnFailure`] 载荷,只由 * [`ThreadEvent::turn_completed_failed`] 写出。 */ -export type TurnCompletedStatus = - | 'completed' - | 'interrupted' - | 'aborted' - | 'failed'; +export type TurnCompletedStatus = "completed" | "interrupted" | "aborted" | "failed"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnFailure.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnFailure.ts index be016b8c9..a0f8a2996 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnFailure.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnFailure.ts @@ -1,13 +1,13 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { EnvironmentNotReady } from './EnvironmentNotReady'; -import type { HostStateUnavailable } from './HostStateUnavailable'; -import type { ModelCallFailed } from './ModelCallFailed'; -import type { ProjectRootUnanchored } from './ProjectRootUnanchored'; -import type { SuperErrorFromStringPlusStage } from './SuperErrorFromStringPlusStage'; -import type { TimedOut } from './TimedOut'; -import type { TransportClosed } from './TransportClosed'; -import type { TurnInterrupted } from './TurnInterrupted'; -import type { Unclassified } from './Unclassified'; +import type { EnvironmentNotReady } from "./EnvironmentNotReady"; +import type { HostStateUnavailable } from "./HostStateUnavailable"; +import type { ModelCallFailed } from "./ModelCallFailed"; +import type { ProjectRootUnanchored } from "./ProjectRootUnanchored"; +import type { SuperErrorFromStringPlusStage } from "./SuperErrorFromStringPlusStage"; +import type { TimedOut } from "./TimedOut"; +import type { TransportClosed } from "./TransportClosed"; +import type { TurnInterrupted } from "./TurnInterrupted"; +import type { Unclassified } from "./Unclassified"; /** * 失败终态的可下发载荷(`turn.completed.status == "failed"` 时必有,其余终态没有)。 @@ -20,14 +20,4 @@ import type { Unclassified } from './Unclassified'; * [`crate::agent::TurnErrorClassified::ShouldContinue`],所以控制流既不会出现在这里,前端也 * 不需要为它写分支。 */ -export type TurnFailure = - | ({ type: 'projectRootUnanchored' } & ProjectRootUnanchored) - | ({ type: 'environmentNotReady' } & EnvironmentNotReady) - | ({ type: 'hostStateUnavailable' } & HostStateUnavailable) - | ({ type: 'modelCallFailed' } & ModelCallFailed) - | ({ type: 'transportClosed' } & TransportClosed) - | ({ type: 'timedOut' } & TimedOut) - | ({ type: 'turnInterrupted' } & TurnInterrupted) - | ({ type: 'superErrorFromStringPlusStage' } & SuperErrorFromStringPlusStage) - | ({ type: 'unclassified' } & Unclassified) - | { type: 'hostDropped' }; +export type TurnFailure = { "type": "projectRootUnanchored" } & ProjectRootUnanchored | { "type": "environmentNotReady" } & EnvironmentNotReady | { "type": "hostStateUnavailable" } & HostStateUnavailable | { "type": "modelCallFailed" } & ModelCallFailed | { "type": "transportClosed" } & TransportClosed | { "type": "timedOut" } & TimedOut | { "type": "turnInterrupted" } & TurnInterrupted | { "type": "superErrorFromStringPlusStage" } & SuperErrorFromStringPlusStage | { "type": "unclassified" } & Unclassified | { "type": "hostDropped" }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnInterrupted.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnInterrupted.ts index e48e70469..9003001d1 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnInterrupted.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/TurnInterrupted.ts @@ -3,4 +3,4 @@ /** * app-server 判成中断的原始说明。 */ -export type TurnInterrupted = { detail: string }; +export type TurnInterrupted = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Unclassified.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Unclassified.ts index 2b6dcc982..6aa1cdb5e 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Unclassified.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/Unclassified.ts @@ -3,4 +3,4 @@ /** * 深层尚未 typed 的字符串错误:不知道发生在哪一段,只有一条宿主原文。 */ -export type Unclassified = { detail: string }; +export type Unclassified = { detail: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserAttachmentReferencePart.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserAttachmentReferencePart.ts index 07af7b9c6..91e4e0a4d 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserAttachmentReferencePart.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserAttachmentReferencePart.ts @@ -1,9 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type UserAttachmentReferencePart = { - name: string; - mediaType: string; - size: number; - localPath: string; - status: string; -}; +export type UserAttachmentReferencePart = { name: string, mediaType: string, size: number, localPath: string, status: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserContentPart.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserContentPart.ts index 67bbed055..1f23ca820 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserContentPart.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserContentPart.ts @@ -1,19 +1,11 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { UserAttachmentReferencePart } from './UserAttachmentReferencePart'; -import type { UserRuntimeRegionPart } from './UserRuntimeRegionPart'; +import type { UserAttachmentReferencePart } from "./UserAttachmentReferencePart"; +import type { UserRuntimeRegionPart } from "./UserRuntimeRegionPart"; -export type UserContentPart = - | { type: 'input_text'; text: string } - | { - type: 'agc_resource_reference'; - resourceId: string; - /** - * 这个引用被宿主解析出来的文本:素材摘要,加上引用的 UI 设计文档展开的代码上下文。 - * 入队冻结时写入一次,此后随条目持久化,prompt / 历史回读 / turn input 共用这一份。 - * 缺省合法(旧历史没有它照样解析),缺省时才退回按当前 manifest 现算。 - */ - resolvedText?: string | null; - } - | { type: 'agc_skill_reference'; name: string } - | ({ type: 'agc_runtime_region_reference' } & UserRuntimeRegionPart) - | ({ type: 'agc_attachment_reference' } & UserAttachmentReferencePart); +export type UserContentPart = { "type": "input_text", text: string, } | { "type": "agc_resource_reference", resourceId: string, +/** + * 这个引用被宿主解析出来的文本:素材摘要,加上引用的 UI 设计文档展开的代码上下文。 + * 入队冻结时写入一次,此后随条目持久化,prompt / 历史回读 / turn input 共用这一份。 + * 缺省合法(旧历史没有它照样解析),缺省时才退回按当前 manifest 现算。 + */ +resolvedText?: string | null, } | { "type": "agc_skill_reference", name: string, } | { "type": "agc_runtime_region_reference" } & UserRuntimeRegionPart | { "type": "agc_attachment_reference" } & UserAttachmentReferencePart; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserItem.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserItem.ts index d5d9664ea..be7d93b4e 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserItem.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserItem.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { UserMessageItem } from './UserMessageItem'; +import type { UserMessageItem } from "./UserMessageItem"; /** * DirectProject 本轮 user input 的唯一结构化入口。 */ -export type UserItem = { type: 'message' } & UserMessageItem; +export type UserItem = { "type": "message" } & UserMessageItem; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserMessageItem.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserMessageItem.ts index 945342a78..adb9f5889 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserMessageItem.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserMessageItem.ts @@ -1,9 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { UserContentPart } from './UserContentPart'; -import type { UserRole } from './UserRole'; +import type { UserContentPart } from "./UserContentPart"; +import type { UserRole } from "./UserRole"; -export type UserMessageItem = { - role: UserRole; - content: Array; - id: string; -}; +export type UserMessageItem = { role: UserRole, content: Array, id: string, }; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRole.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRole.ts index 06205c566..dbdefa551 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRole.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRole.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type UserRole = 'user'; +export type UserRole = "user"; diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRuntimeRegionPart.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRuntimeRegionPart.ts index f4316ad4f..0aa389f10 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRuntimeRegionPart.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/UserRuntimeRegionPart.ts @@ -1,13 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type UserRuntimeRegionPart = { - label: string; - runId: string | null; - versionId: string | null; - elementTag: string | null; - elementRole: string | null; - text: string | null; - width: number | null; - height: number | null; - resourceIds: Array; -}; +export type UserRuntimeRegionPart = { label: string, runId: string | null, versionId: string | null, elementTag: string | null, elementRole: string | null, text: string | null, width: number | null, height: number | null, resourceIds: Array, }; diff --git a/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md b/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md index a7948a8a4..6c434c4ee 100644 --- a/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md @@ -27,7 +27,7 @@ ## 验证命令 1. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_thread -- --nocapture` -2. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`(生成 `src/features/project-workspace/generated/`),随后用 `prettier --write` 格式化生成目录,避免未格式化的 ts-rs 输出混进提交 +2. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`(生成 ts-rs 绑定);生成物保持原始输出直接提交,不要再跑 prettier(见 `decision-log.md` 2026-10-03「生成绑定不再经 prettier」) 3. `npm run test -- apps/ai-game-creator-shell/tests/directThreadChat.test.ts apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts apps/ai-game-creator-shell/tests/directHistoryAnchorGate.test.ts` 4. `npm run test -- apps/ai-game-creator-shell/tests/appSurface.test.ts`(`project-development.suite.ts` 由该入口注册,不能作为独立测试入口;同时验证现役 Design Agent 的会话恢复与审批界面。) 5. TypeScript 类型检查与 ESLint(范围同前次 DirectProject 迁移)。 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 8c56c07ba..29d76aed1 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,13 @@ # 决策记录 +## 2026-10-03 生成绑定不再经 prettier:ts-rs 原始输出即提交形态 + +- 背景:`scripts/check-generated-bindings.mjs` 对 AGC 的 `chat/generated` / `services/generated` 在重生成后会就地跑一遍 `npx prettier --write` 再比较。这会直接改写生成文件,还把「Rust 声明真的变了」与「prettier 版本 / 配置造成的格式漂移」混在同一条告警里——本次报出的 `ThreadRequestKind.ts` / `TurnCompletedStatus.ts`「内容变化」无法复现为语义变化(已提交内容与当前 Rust 枚举一致),prettier 归一化把格式差异也报成了「与 Rust 声明不一致」;生成物被仓库格式化工具二次改写后,重跑 `cargo test export_bindings` 也不再幂等。 +- 决策:生成绑定一律以 ts-rs 原始输出提交,不接受 prettier / eslint 等工具二次改写。`check-generated-bindings.mjs` 删掉 prettier 步骤,直接逐字节比较原始输出;`packages/shared/src/contracts/generated`、`chat/generated`、`services/generated`、`features/ui-editor/types` 四个目录统一登记进 `.prettierignore` 与 `.eslintrc.cjs` 的 `ignorePatterns`;`.prettierrc.json` 里为 `contracts/generated` 设的 `printWidth: 1000` / `singleQuote: false` 覆盖随之删除。 +- 边界:ts-rs 原始输出在多行对象 / 枚举变体行尾带空格,`.gitattributes` 对四个生成目录设 `whitespace=-trailing-space`,CI 的 `git diff --check` 不再误报;手写文件的行尾空白检查不变。生成 `.ts` 仍提交进仓库供前端消费,并标 `linguist-generated=true`。 +- 影响范围:`scripts/check-generated-bindings.mjs`、`.prettierignore`、`.prettierrc.json`、`.eslintrc.cjs`、`.gitattributes`、`apps/ai-game-creator-shell/src/{view/project-development/chat,services}/generated/**`。 +- 验证:`cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`、`npm run check:generated-bindings`(shared-contracts 1 + AGC 104 = 105 个文件)、`npx prettier --check` 四个生成目录(全部跳过)、`npm run check:encoding`、`git diff --check`。 + ## 2026-10-03 回合错误的处置分类层与线程条目脱敏边界 - 背景:`TurnError::terminal_failure -> Option` 用一个 `None` 同时表达"没有失败"和"不是失败、要继续跑(返修 / 复核控制流)",调用方看到 `None` 只会理解成前者,`dispatch.rs` 两处只能 `.expect("回合失败必可投影成失败载荷")`;同时 ThreadManager 在搬运线程条目时做字段级脱敏与限长,前端要被截断,而且与失败载荷的脱敏是两套实现。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 77656637e..521c0a27b 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -8,7 +8,7 @@ - **原因**:① 登录已下沉 Rust,`login_client_with_password` 等命令失败返回 `Err(String)`,Tauri 以**裸字符串**拒绝 `invoke`,前端拿不到任何类型信息;② `shouldCaptureClientError` 对非 object 值走默认 `return true`,`handleLoginSubmit` 的 catch 把预期业务拒绝报进了错误池。技术方案里"预期 4xx 登录/鉴权失败不进池"的口径早就成立,是错误通道的实现方式违背了它。 - **处理(现行口径)**:命令错误一律按具体变体结构化(`Result<_, ClientAuthError>` + ts-rs 导出),认证命令统一经 `invokeClientAuth` 调用:结构化拒绝原样装进已有的 `ClientAuthErrorWrapper`(只有一个 `error` 字段,值是判别联合),UI 在 catch 里按具体变体分流——认得的业务 / 会话变体只给用户反馈,系统变体原样 `throw` 经 `unhandledrejection` 入池,非结构化拒绝原样抛出;删除 `shouldCaptureClientError`。详见 [`【ADR】AGC命令错误结构化与错误报告口径-2026-10-01`](../../adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md) 与 [`【ADR】AGC认证失败的JS侧载体与抛出时机-2026-10-01`](../../adr/【ADR】AGC认证失败的JS侧载体与抛出时机-2026-10-01.md)。 - **判据/取证**:`npx vitest run apps/ai-game-creator-shell/tests/authFailureReporting.test.tsx`——登录返回结构化业务变体时 `report_client_error` 不被调用;系统变体只上报一次(`source` 取全局 `unhandledrejection` handler 的显式入参;载体不再携带 `action`)。Rust 侧 `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml auth_error` 钉住变体 `type` 与 400/401/429/5xx/网络映射。 -- **形状约定**:`ClientAuthError` 顶层只放调用方要分流的类别,可枚举细分收进类型化枚举 `reason` 字段——无字段变体在 TS 里就是 `{ type: 'x' }`;带载荷变体是 `{ type: 'x' } & X`,`X` 由 ts-rs 导出到 `src/services/generated/X.ts`(Rust 侧是 newtype 变体持有同名结构体),细分原因枚举(`ServerAddressReason` / `AuthNetworkReason` / `AuthResponseInvalidReason`)同样由 ts-rs 生成。**不要手写这些类型**,也不要在前端再加一层分类 / 提示文案派生函数——判别一律写在 catch 子句里:`const failure = error.error; switch (failure.type)`,无字段 `case` 用本 catch 的固定文案,带载荷 `case` 先 `as X` 再读自己的字段,`reason` 是枚举时再 `switch (payload.reason)`,两处 `default` 都用 `expectNever` 保证漏接编译失败。改形状只能改 Rust 再跑 `cargo test` 重新导出,生成物随后交给 prettier;ts-rs 只写文件、不删文件,变体从有载荷改成无字段时要手动清掉孤立的 `X.ts`(本次 `AuthResponseServerRejected.ts` 就是这样删的)。 +- **形状约定**:`ClientAuthError` 顶层只放调用方要分流的类别,可枚举细分收进类型化枚举 `reason` 字段——无字段变体在 TS 里就是 `{ type: 'x' }`;带载荷变体是 `{ type: 'x' } & X`,`X` 由 ts-rs 导出到 `src/services/generated/X.ts`(Rust 侧是 newtype 变体持有同名结构体),细分原因枚举(`ServerAddressReason` / `AuthNetworkReason` / `AuthResponseInvalidReason`)同样由 ts-rs 生成。**不要手写这些类型**,也不要在前端再加一层分类 / 提示文案派生函数——判别一律写在 catch 子句里:`const failure = error.error; switch (failure.type)`,无字段 `case` 用本 catch 的固定文案,带载荷 `case` 先 `as X` 再读自己的字段,`reason` 是枚举时再 `switch (payload.reason)`,两处 `default` 都用 `expectNever` 保证漏接编译失败。改形状只能改 Rust 再跑 `cargo test` 重新导出,生成物保持 ts-rs 原始输出(不再经 prettier / eslint 二次改写,见本节「生成绑定」口径);ts-rs 只写文件、不删文件,变体从有载荷改成无字段时要手动清掉孤立的 `X.ts`(本次 `AuthResponseServerRejected.ts` 就是这样删的)。 - **Rust 侧不得把结构化错误降级成字符串**:`refresh_session_inner` 的非权威失败直接返回 `Err(ClientAuthError)`,视图不带 `errorMessage`;一旦折成 `String`,前端就只能拿文案判断,变体信息永久丢失。 - **关联**:`apps/ai-game-creator-shell/src-tauri/src/auth_session.rs`、`apps/ai-game-creator-shell/src/services/{clientAuth.ts,errorReporting.ts,platformSession.ts}`、`apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx`。 @@ -5795,8 +5795,8 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **处理(现行口径)**:不要把重写结果当改动提交。跑过 `cargo test` 或构建后只恢复 `apps/ai-game-creator-shell/src/view/project-development/chat/generated/DirectCodexUser*.ts` 的仓库版本,再删掉多出来的 `DirectCodexUserMessageEnvelope.ts`;不要恢复整个 `generated/` 目录,以免误删 DirectThread 的现役绑定。绑定与前端形状冲突时以**已提交的 DirectCodexUser 绑定 + 前端**为基准排查。 - **验证**:恢复仓库版本后 `npm run ai-game-creator-shell:typecheck` exit 0(`[skill-pack] OK`);保留重写结果时同一条命令 exit 2。release 构建本身还会在 `src/features/ui-editor/types/` 落下 `BindingChange.ts` / `BindingDTO.ts` 两个无人引用的生成产物;它们不属于前端契约,发现后直接删除,不提交。 - **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/`(ts-rs 导出源)、`apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts`、`apps/ai-game-creator-shell/scripts/build-release.mjs`(`beforeBuildCommand`)。 -- **2026-09-24 补充(纯格式 churn 的一档)**:直接运行 AGC 的测试二进制(含全量套件,里面带 `export_bindings`)同样会把 `src/view/project-development/chat/generated/DirectThread*.ts` 重写成 raw ts-rs 形态——双引号、行尾空格、`};` 变 `, };`——于是 `git diff --check` 报一片 trailing whitespace,而 `npm run check:generated-bindings`(只覆盖 `packages/shared/src/contracts/generated`)不会报警。处理:对这组文件跑一次 `npx prettier --write "apps/ai-game-creator-shell/src/view/project-development/chat/generated/*.ts"` 做归一化,再确认 `git diff --stat` 为空——为空就说明这一档只是格式 churn,没有语义变化;不要为它盲目 `git checkout` 整个目录。该目录目前没有自动漂移门禁,靠「跑完测试后归一化 + diff 检查」把关。 -- **2026-10-02 补充(过滤跑也躲不开)**:`cargo test` 的位置参数是**子串匹配**,`-- agent::thread_manager::` 这类"只跑几个模块"的过滤会连带命中 `agent::thread_manager::wire::failure::export_bindings_turnfailure`,于是照样重写 `chat/generated/` 与 `src/services/generated/`(后者是 auth 绑定)。要按模块跑又不碰生成目录,用 `cargo test --bin genarrative-ai-game-creator-shell -- agent:: --skip export_bindings`;已经被重写时,`chat/generated/` 跑一次 prettier 归一化,`src/services/generated/` 直接 `git checkout --`(那一侧没有本轮的语义改动)。 +- **2026-09-24 补充(纯格式 churn 的一档)**:直接运行 AGC 的测试二进制(含全量套件,里面带 `export_bindings`)同样会把 `src/view/project-development/chat/generated/DirectThread*.ts` 重写成 raw ts-rs 形态——双引号、行尾空格、`};` 变 `, };`——于是 `git diff --check` 报一片 trailing whitespace,而 `npm run check:generated-bindings`(只覆盖 `packages/shared/src/contracts/generated`)不会报警。处理(2026-10-03 更新,口径已变):不再跑 prettier 归一化——`chat/generated` 与 `services/generated` 的提交形态就是 ts-rs 原始输出;两个目录已进 `.prettierignore` + eslint `ignorePatterns`,`git diff --check` 由 `.gitattributes` 的 `whitespace=-trailing-space` 豁免,`npm run check:generated-bindings` 会逐字节比较原始输出。跑完 `cargo test` 后 `git diff` 为空即为幂等。 +- **2026-10-02 补充(过滤跑也躲不开)**:`cargo test` 的位置参数是**子串匹配**,`-- agent::thread_manager::` 这类"只跑几个模块"的过滤会连带命中 `agent::thread_manager::wire::failure::export_bindings_turnfailure`,于是照样重写 `chat/generated/` 与 `src/services/generated/`(后者是 auth 绑定)。要按模块跑又不碰生成目录,用 `cargo test --bin genarrative-ai-game-creator-shell -- agent:: --skip export_bindings`;已经被重写时不要再做 prettier 归一化:两个目录的提交形态就是原始输出,按需重新生成或 `git checkout --`,再用 `npm run check:generated-bindings` 确认无漂移。 ## 2026-09-16 Node 26 下 vitest 的 jsdom 用例拿不到 window.localStorage diff --git a/docs/technical/【实施计划】DirectProject命令接单化-2026-09-23.md b/docs/technical/【实施计划】DirectProject命令接单化-2026-09-23.md index 989095efb..4d84a1e4c 100644 --- a/docs/technical/【实施计划】DirectProject命令接单化-2026-09-23.md +++ b/docs/technical/【实施计划】DirectProject命令接单化-2026-09-23.md @@ -80,8 +80,8 @@ - `project.jsonl` 与项目主对话共用信封类型,不要为了"可见但不喂模型"新增行结构。 - 埋点 `settle` 早于成绩入库会静默丢事件(未来"进历史但不喂模型"的条目同理要落在注入侧,不在读取侧)。 -- `cargo test export_bindings` 会重写全部 `chat/generated/`(引号风格漂移),跑完要 `git checkout --` - 掉不是本次新增的文件。 +- `cargo test export_bindings` 会重写全部 `chat/generated/`;生成目录的提交形态就是 ts-rs 原始输出 + (2026-10-03 起已从 prettier / eslint 排除),跑完用 `git diff` 为空确认幂等,不要做 prettier 归一化。 - 本机 rust 全量 `--bins` 测试会挂在 mock server 的 `inet_csk_accept` 上,用 `--bins "agent::"` 之类过滤跑。 ## review 收口第二轮(2026-09-24) diff --git a/scripts/check-generated-bindings.mjs b/scripts/check-generated-bindings.mjs index 5039ab1d3..b30a70a2f 100644 --- a/scripts/check-generated-bindings.mjs +++ b/scripts/check-generated-bindings.mjs @@ -6,13 +6,13 @@ * 生成文件没重新跑」以外的情形,也很容易被本地未提交改动掩盖;比较生成前后快照更直接—— * 只要重新生成后的内容与现有内容不同,就说明仓库里的绑定是陈旧的。 * - * 覆盖两套 crate、三个目录: - * - `shared-contracts` → `packages/shared/src/contracts/generated`(原样落盘); - * - AGC shell → `chat/generated` + `services/generated`(随仓库统一走 prettier)。 + * 覆盖两套 crate、四个目录: + * - `shared-contracts` → `packages/shared/src/contracts/generated`; + * - AGC shell → `chat/generated` + `services/generated` + `features/ui-editor/types`。 * - * AGC 那两个目录是 prettier 格式化过的,而 ts-rs 输出的是双引号、不换行的原始形态;所以 - * 重生成后要按仓库格式再跑一遍 prettier 才能比较,否则每次都会报"格式不同"的假漂移。 - * 格式化范围只限这两个生成目录,不碰其它源码。 + * 生成文件一律以 ts-rs 原始输出提交,不接受 prettier / eslint 等工具二次改写:这些目录 + * 同时登记在 `.prettierignore` 与 `.eslintrc.cjs` 的 `ignorePatterns`,所以这里直接逐字节 + * 比较原始输出即可,不需要(也不允许)再跑格式化。 */ import { spawnSync } from 'node:child_process'; import fs from 'node:fs'; @@ -24,14 +24,10 @@ const repoRoot = path.resolve( '..', ); -// Windows 上 `npx` 以 `npx.cmd` 落地,`spawnSync` 不带 shell 时解析不到(ENOENT)。 -const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx'; - const SHARED_CONTRACTS_DIR = 'packages/shared/src/contracts/generated'; const AGC_CHAT_DIR = 'apps/ai-game-creator-shell/src/view/project-development/chat/generated'; const AGC_SERVICES_DIR = 'apps/ai-game-creator-shell/src/services/generated'; -// ui-editor 的绑定在 `.prettierignore` 里,ts-rs 原始输出就是提交形态,不需要再格式化。 const AGC_UI_EDITOR_DIR = 'apps/ai-game-creator-shell/src/features/ui-editor/types'; @@ -51,7 +47,6 @@ const targets = [ 'server-rs/Cargo.toml', 'export_bindings', ], - formatDirs: [], hint: 'cargo test --locked -p shared-contracts --features ts-bindings --manifest-path server-rs/Cargo.toml export_bindings', }, { @@ -64,10 +59,7 @@ const targets = [ 'apps/ai-game-creator-shell/src-tauri/Cargo.toml', 'export_bindings', ], - // ts-rs 落盘后按仓库格式跑一遍 prettier,比较的才是"提交时应有的内容" - // (ui-editor 的绑定被 `.prettierignore` 忽略,不在里面)。 - formatDirs: [AGC_CHAT_DIR, AGC_SERVICES_DIR], - hint: 'cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings && npx prettier --write apps/ai-game-creator-shell/src/view/project-development/chat/generated apps/ai-game-creator-shell/src/services/generated', + hint: 'cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings', }, ]; @@ -92,8 +84,8 @@ function snapshot(dir) { } function run(command, args) { - // Windows 上 `.cmd` / `.bat` 不带 shell 无法执行(Node 修 CVE-2024-27980 后直接 EINVAL), - // `npx.cmd` 也不例外;仓库既有脚本统一用 `shell: process.platform === 'win32'`。 + // Windows 上 `.cmd` / `.bat` 不带 shell 无法执行(Node 修 CVE-2024-27980 后直接 EINVAL); + // 仓库既有脚本统一用 `shell: process.platform === 'win32'`。 const result = spawnSync(command, args, { cwd: repoRoot, encoding: 'utf8', @@ -134,22 +126,6 @@ for (const target of targets) { if (result.stderr) console.error(result.stderr.trim()); continue; } - if (target.formatDirs.length > 0) { - const formatted = run(npxCommand, [ - 'prettier', - '--write', - ...target.formatDirs, - ]); - if (formatted.status !== 0) { - failed = true; - console.error( - `生成绑定校验无法运行:${target.label} 的 prettier 格式化失败`, - ); - if (formatted.stdout) console.error(formatted.stdout.trim()); - if (formatted.stderr) console.error(formatted.stderr.trim()); - continue; - } - } const after = new Map( target.dirs.flatMap((dir) => [...snapshot(dir).entries()]), );