From 9d85609287889cbe216faea6c998a1ca1469b0c9 Mon Sep 17 00:00:00 2001 From: lanrtop Date: Sun, 4 Oct 2026 02:06:29 +0900 Subject: [PATCH] =?UTF-8?q?fix(onboard/parity):=20=E5=A4=84=E7=BD=AE=20P8g?= =?UTF-8?q?=20=E7=8B=AC=E7=AB=8B=E5=AE=A1=E6=9F=A5=E2=80=94=E2=80=94?= =?UTF-8?q?=E6=96=B0=E5=BB=BA=E5=85=A5=E5=8F=A3=E6=8C=89=E6=9C=89=E6=95=88?= =?UTF-8?q?=E6=A0=B9=E7=9B=AE=E5=BD=95=E5=BC=B9=E5=87=BA=E3=80=81Toast=20?= =?UTF-8?q?=E7=BD=AE=E4=BA=8E=E9=9D=A2=E6=9D=BF=E4=B9=8B=E4=B8=8A=E3=80=81?= =?UTF-8?q?bypass=20=E4=B8=8E=E9=94=99=E8=AF=AF=E9=98=B6=E6=AE=B5=E6=96=87?= =?UTF-8?q?=E6=A1=88=E5=A6=82=E5=AE=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .blueprint/modules/agent-client-parity.md | 3 +++ src/components/dashboard/OnboardPanel.tsx | 2 +- src/components/dashboard/ProjectModal.tsx | 4 +++- src/components/dashboard/onboardView.ts | 3 ++- src/components/ui/Toast.tsx | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.blueprint/modules/agent-client-parity.md b/.blueprint/modules/agent-client-parity.md index aec4ba6..38dfd61 100644 --- a/.blueprint/modules/agent-client-parity.md +++ b/.blueprint/modules/agent-client-parity.md @@ -338,6 +338,9 @@ skill 只是五个接入面之一,兼容层覆盖全部五面。 - depends: P8e - acceptance: "agent_verify: [pnpm typecheck && pnpm test] 视图纯函数:blocked 非空时确认按钮禁用并列出文件和原因;not_installed 和 not_applicable 显示为灰色说明、不显示为红色失败;bypassPermissions 和 Codex 信任单独列出;确认时携带 expected_digest。human_verify: ① 用临时 git 仓库新建项目,弹出接入预览;② 确认后 30 秒内看到分步结果、L1 矩阵和「待你提交的 N 个文件」;③ 另试一次在预览里取消,目录零改动;④ 在该目录新开 Claude Code、Codex、DSH 桌面 GUI 会话调 LJ_PROBE_NONEXISTENT,得「开发需求未登记」。" - 说明:新建 / 模板创建成功后弹出「接入预览」,create_project 本身保持无副作用;批量添加只提供批量入口、不自动接入;BlueprintModal 的「应用接入包」改为先 plan 再 apply。 +- 实现(2026-10-04,分支 feat/agent-client-parity-p8g,统筹会话主线程直做——两次委派卡死于一次性生成大文件):onboardView.ts 视图纯函数(计划预览、确认请求、报告、L1 矩阵;判定全取后端字段);OnboardPanel.tsx 全局挂载于 App、经 useUIStore.openOnboard 打开(新建弹窗保存即卸载,面板须独立存在),状态机 planning → preview → applying → report,过期响应按请求序号丢弃、接入中不可关闭,refused 附新计划可回预览重新确认;plan.rs 的 BlockedItem 序列化附派生字段 skippable(可跳过判定只在本体,反序列化忽略、不进 digest),commands.ts 同步;入口:ProjectModal 新建且按 platform 的有效根目录非空才弹(概念占位不弹),NewProjectModal 模板创建成功自动弹、完成页可再开,BatchAddModal 添加后列出有目录的新项目逐个「一键接入」,BlueprintModal「施加 Buff」改为同一面板(buff 已激活时另给「重新检查接入」),关闭后按报告刷新 buff 与 init prompt;project-context.yaml 同步 skippable 与 UI 投影。 +- 有意偏差:"① 呈现块拆到 OnboardSections.tsx(files 外新增,控制单文件规模)。② Toast 层级 z-50 → z-[70](审查 ②,否则接入提示被面板遮住)。③ 本地 confirm 函数改名 applyConfirmed:confirmUsage.test.ts 扫描 confirm( 防同步确认框,属正确的守卫。" +- review: "2026-10-04 独立只读审查 5b6c197,结论 merge,5 条:① [低] 新建入口按任一路径非空判是否弹面板,与后端按 platform 取有效根目录不同口径 → 已修。② [低] Toast z-50 被面板 z-[60] 遮住 → 已修。③ [低] 已有 permissions 又取消 bypass 时文案称会写 default → 已改文案(如实说明两种情况)。④ [信息] L1 格子着色在前端写死 codex_project_untrusted=待你操作,轻度复制判定 → 转后续小修(L1 格子带 pending_user 字段)。⑤ [信息] onboard_project 抛错后「取消」提示仍称不写入 → 已修(错误阶段换提示)。审查核实:确认带 plan.digest 与生成计划时的选项;refused 回预览时 planned 与新计划同一组选项(apply.rs 用请求选项重算);四条 agent_verify 有实断言。" ### ✅ P9 — DSH 桌面 GUI 按工作区连项目地址(会话级插件) - status: done diff --git a/src/components/dashboard/OnboardPanel.tsx b/src/components/dashboard/OnboardPanel.tsx index 581d9ad..a50df3e 100644 --- a/src/components/dashboard/OnboardPanel.tsx +++ b/src/components/dashboard/OnboardPanel.tsx @@ -165,7 +165,7 @@ function PanelFooter({ onClick={onCancel} disabled={phase.kind === "applying"} className={`${btnCls} border-gray-200 text-gray-600 hover:bg-gray-50`} - title="取消不写入任何文件" + title={phase.kind === "error" ? "关闭面板;若错误发生在确认接入之后,可能已有部分写入,请重新计划核对" : "取消不写入任何文件"} > 取消 diff --git a/src/components/dashboard/ProjectModal.tsx b/src/components/dashboard/ProjectModal.tsx index 566722e..0e627c2 100644 --- a/src/components/dashboard/ProjectModal.tsx +++ b/src/components/dashboard/ProjectModal.tsx @@ -95,7 +95,9 @@ const pickFolder = async (field: "wsl_path" | "win_path") => { qc.invalidateQueries({ queryKey: ["tagMaps"] }); closeEdit(); // create_project 本身无副作用;选了目录的新项目弹出接入预览(P8g),由人确认后才写入。不选目录的概念占位不接入 - if (isNew && (form.win_path?.trim() || form.wsl_path?.trim())) { + // 与后端登记同口径:按 platform 只看有效根目录那一列(另一列残留不算) + const effectiveRoot = form.platform === "wsl" ? form.wsl_path : form.win_path; + if (isNew && effectiveRoot?.trim()) { openOnboard({ projectId: form.id!, projectName: form.name?.trim() }); } } catch (e) { diff --git a/src/components/dashboard/onboardView.ts b/src/components/dashboard/onboardView.ts index 3af0c27..fd7d32a 100644 --- a/src/components/dashboard/onboardView.ts +++ b/src/components/dashboard/onboardView.ts @@ -279,7 +279,8 @@ function bypassView(plan: OnboardingPlan, planned: OnboardSelection, selection: return { ...base, label: "已按项目取消 bypassPermissions", - detail: "settings.json 缺 permissions 时写显式 defaultMode=default 记住选择,之后的重注入不会补回。", + detail: + "不写入 bypassPermissions。settings.json 缺 permissions 时会写显式 defaultMode=default 记住选择(之后的重注入不会补回);已有 permissions 则原样不动。", tone: "muted", toggleable: true, }; diff --git a/src/components/ui/Toast.tsx b/src/components/ui/Toast.tsx index fbc73d5..5abe75c 100644 --- a/src/components/ui/Toast.tsx +++ b/src/components/ui/Toast.tsx @@ -7,7 +7,7 @@ export function Toast() { const isError = toast.startsWith("❌"); return ( -
{toast}