继续收敛 Direct 清单读取错误

保留项目清单读取和事件订阅正文

补充 Direct 状态条回归文档
This commit is contained in:
kdletters
2026-10-05 22:42:33 +08:00
parent ea70e3fe73
commit 2a160bca02
4 changed files with 25 additions and 6 deletions
@@ -106,8 +106,13 @@ export function DirectProjectChatView({
ensureConversationWriteAllowed,
ref,
}: DirectProjectChatViewProps) {
const { assets, projectId, refresh, versions } =
useDirectProjectManifest(projectPath);
const {
assets,
projectId,
error: manifestError,
refresh,
versions,
} = useDirectProjectManifest(projectPath);
const composerHandleRef = useRef<DirectProjectComposerHandle | null>(null);
const [runtimeNotice, setRuntimeNotice] = useState('');
const [settingsOpen, setSettingsOpen] = useState(false);
@@ -181,6 +186,7 @@ export function DirectProjectChatView({
const statusText =
runtimeNotice ||
statusNotice ||
manifestError ||
(projectPath
? `已打开:${projectNameFromPath(projectPath)}`
: '请选择工作区');
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { resolveTauriInvoke } from '../../../../app/tauri';
import { projectPathsMatchForInvalidation } from '../../../../features/project-summary/projectPath';
import { visibleClientErrorMessage } from '../../../../services/errorReporting';
import {
canSubscribeTauriEvents,
subscribeTauriEvent,
@@ -40,6 +41,7 @@ export function useDirectProjectManifest(projectPath: string | null) {
const [manifest, setManifest] = useState<GameCreationAppManifest | null>(
null,
);
const [error, setError] = useState<string | null>(null);
const projectPathRef = useRef(projectPath);
projectPathRef.current = projectPath;
const mountedRef = useRef(true);
@@ -70,8 +72,12 @@ export function useDirectProjectManifest(projectPath: string | null) {
return;
}
setManifest(nextManifest);
} catch {
// 清单读不到不能阻塞聊天:`@` 引用退化为空,回合仍以项目对话为准。
setError(null);
} catch (cause) {
// 清单读不到不能阻塞聊天:`@` 引用退化为空,但必须把正文交给状态条。
if (mountedRef.current && projectPathRef.current === nextProjectPath) {
setError(`项目清单读取失败:${visibleClientErrorMessage(cause)}`);
}
} finally {
inFlight.delete(nextProjectPath);
}
@@ -81,6 +87,7 @@ export function useDirectProjectManifest(projectPath: string | null) {
}, []);
useEffect(() => {
setError(null);
if (!projectPath) {
setManifest(null);
return;
@@ -115,8 +122,11 @@ export function useDirectProjectManifest(projectPath: string | null) {
}
unsubscribe = release;
})
.catch(() => {
// 拿不到订阅通道时清单只在项目打开和回合结束时刷新。
.catch((cause) => {
// 拿不到订阅通道时清单只在项目打开和回合结束时刷新,但不能静默隐藏 IPC 正文。
if (!disposed) {
setError(`项目清单事件订阅失败:${visibleClientErrorMessage(cause)}`);
}
});
return () => {
disposed = true;
@@ -127,6 +137,7 @@ export function useDirectProjectManifest(projectPath: string | null) {
return {
assets: directProjectChatAssets(manifest),
projectId: manifest?.projectId ?? null,
error,
refresh,
versions: manifest?.versions ?? NO_VERSIONS,
};
@@ -142,6 +142,7 @@ DirectProject 已经解决过同一类问题([`【ADR】DirectProject命令接
- 资源画布历史任务账本读取属于用户可见的恢复路径:异常正文必须进入提示条;只有响应形状错误这类没有底层异常的情况才使用明确的契约提示。
- 异步业务 facade 不得把底层异常折成“空结果”来逃避错误处理;只有真实的空回包、未配置或浏览器桥不可用等无正文事实允许返回空值,Tauri/网络/IPC 异常必须上抛到统一脱敏出口。
- 可选偏好可以安全回退默认值,但回退不能隐藏错误:偏好读写 IPC 失败必须同时保留安全正文、记录诊断并在当前输入上下文给出提示。
- Direct 项目清单读取失败可以保留聊天可用性,但不得把素材/版本候选置空后静默;清单读取和事件订阅正文必须进入项目状态条。
- Direct 活动回合事件桥注册失败即使仍有一次性快照,也必须标明事件更新通道已失联并展示安全正文,不能只显示旧快照而让用户误以为活动状态持续可靠。
- 首页富文本剪贴板读取的“无内容”与“原生 IPC 失败”必须区分;后者展示安全正文,不能静默当作空剪贴板。
- 账号邀请码复制与充值状态确认的失败提示也必须附安全正文;操作指引不能替换底层剪贴板、网络或支付查询原因。
@@ -63,6 +63,7 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时,
- 资源画布历史生成任务账本读取失败原来统一显示“暂时无法恢复历史任务”;现在保留 Tauri/文件读取正文,非数组响应仍单独保留契约错误提示。
- 发现默认 `requestChatPromptPolish` 还会把 Tauri 润色命令异常吞成 `null`,导致共享 hook 无法看到平台正文;现仅对空回包/桥不可用保留 `null`,原生异常继续上抛并统一脱敏。
- 润色提醒偏好读取失败原来被当成“未关闭”默认值,写入失败只进错误上报池;现把读取/保存的 IPC 正文显示在输入区状态提示中,同时仍维持安全默认和回退行为。
- Direct 项目清单首次读取和清单事件订阅失败原来只让 `@` 候选退化为空;现把脱敏后的读取/订阅正文送入项目聊天状态条。
- Direct 活动回合事件桥注册失败原来只退回启动快照,面板没有说明后续更新已失联;现保留事件桥 IPC 正文并在标题栏/活动项目面板显示。
- 首页富文本输入的原生剪贴板图片/文本读取失败原来直接按空剪贴板处理;现通过输入区错误提示保留脱敏后的剪贴板 IPC 正文。
- 账号邀请码复制和微信充值状态确认仍有固定“复制失败/暂时没能确认到账”路径;现保留剪贴板/支付查询错误正文并继续给操作指引。