Skip to content

refactor(web-ui): route business invokes through adapter layer and declare Peer-Device-Mode owners - #2428

Open
zvzuola wants to merge 9 commits into
GCWing:mainfrom
zvzuola:chore/remove-dead-agent-service
Open

refactor(web-ui): route business invokes through adapter layer and declare Peer-Device-Mode owners#2428
zvzuola wants to merge 9 commits into
GCWing:mainfrom
zvzuola:chore/remove-dead-agent-service

Conversation

@zvzuola

@zvzuola zvzuola commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Route Web UI business-layer Tauri commands through the shared ApiClient adapter layer, remove confirmed dead code, and close the Peer-Device-Mode ownership and capability gaps identified during review.

This PR contains nine commits covering adapter-layer routing, dead-code removal, controller-local ownership rules, Desktop/CLI Peer capability parity, mixed-version compatibility, and tool-catalog state handling.

Type and Areas

Type: Refactor / architecture boundary / cleanup / Peer-Device-Mode parity

Areas: Web UI, frontend API adapters, Peer Device Mode, CLI Peer Host, Desktop Peer Host, core tool runtime, ESLint architecture enforcement

Motivation and Impact

Several Web UI business modules previously imported Tauri invoke directly, bypassing the shared adapter layer. That prevented consistent transport routing and could send commands to the wrong machine in Peer Device Mode.

This PR routes business commands through ApiClient, establishes explicit command ownership, adds CLI Peer capability parity, and removes confirmed zero-consumer legacy code.

Adapter-Layer Enforcement

  • Route migrated business commands through api.invoke.
  • Block direct static invoke imports from @tauri-apps/api/core in business code.
  • Block dynamic import('@tauri-apps/api/core') bypasses through the ESLint fence.
  • Keep direct platform invocation limited to infrastructure adapters and the documented PeerHostInvokeBridge exception.
  • Remove the global ESLint ignore that previously excluded src/shared/context-system/core/types/**.
  • Add an ESLint regression test covering static and dynamic imports in ordinary business code, Context types, and adapter exceptions.

Peer-Device-Mode Ownership

  • Keep controller-owned app-shell commands local to the controller.
  • Keep Insights, Companion Pet, i18n, Announcement, IDE result reporting, Browser/WebView UI, DevTools, diagnostics, and desktop-pet commands out of Peer Host routing.
  • Mirror controller-local ownership in the frontend adapter, Desktop Peer Host deny list, and CLI Peer Host deny list.
  • Exclude side-effectful Announcement get_* commands from automatic Peer read retries.
  • Keep check_path_exists supported on CLI Peer.
  • Preserve explicit unsupported behavior and frontend fallback for lsp_detect_project.
  • Preserve full-file fallback behavior for get_file_editor_sync_hash.
  • Keep controller-side file selection and remote file transfer ownership explicit instead of passing controller paths to Peer Hosts.

CLI and Desktop Peer Capability Parity

  • Add CLI Peer support for cancel_tool.
  • Add CLI Peer support for get_all_tools_info.
  • Share the tool catalog DTO and construction logic through the core runtime.
  • Advertise cancel_tool and tool_catalog from current Desktop and CLI Peer Hosts.
  • Route Terminal Interrupt through the active Peer transport with high priority.
  • Classify Browser Control and Computer Use status commands as retryable reads.
  • Keep Browser Control and Computer Use execution on the Tool Host while preserving explicit unsupported behavior where required.

Mixed-Version Compatibility

  • Preserve missing capability fields as an explicit unknown state.
  • For a truly old host that omits host_type, cancel_tool, and tool_catalog, probe the existing read-only get_all_tools_info command.
  • Classify a successful array response as an old Desktop Host.
  • Classify the explicit old CLI unsupported response as an old CLI Host.
  • Cache the classification to avoid repeating the compatibility probe on every keepalive.
  • Clear stale classifications on disposal, presence loss, handshake failure, and replacement connections.
  • Bind capability probes to the active connection instance so a stale probe cannot update a replacement connection.

Tool Catalog and UI State

  • Preserve available, empty, unsupported, and failed catalog states.
  • Gate tool-catalog requests based on the active Peer Host capability.
  • Submit tool data and catalog status together only after the current request-id check succeeds.
  • Include the rendered Peer Device identity in catalog-loading dependencies.
  • Drop stale results when switching between devices with the same workspace path.
  • Prevent old catalog requests from overriding the current tool-management state.
  • In Assistant Defaults, short-circuit the entire MCP section for unsupported and failed catalog states.
  • Prevent registered MCP servers from being incorrectly displayed as having no tools after a catalog failure.
  • Allow tool writes, reset, and group operations only when the catalog is available or genuinely empty.
  • Remove the duplicate custom-agent refresh after deletion because custom-agent:updated already owns the refresh.

Dead-Code Removal

Remove confirmed zero-consumer legacy code, including:

  • The obsolete AgentService implementation and FlowChat integration.
  • Unused project and Git history APIs.
  • Unused agent constants and context-manager services.
  • Unused encryption and service barrel exports.
  • The unused file-tree integration example.

Active agent and tool operations continue through the existing FlowChat and runtime service paths.

Scope

Current PR head: a25ad0fed3fa48d17fa84d4994fa7c567ecc0b66

Current diff:

  • 9 commits
  • 79 files changed
  • 1,888 additions
  • 1,758 deletions

The change includes Web UI, frontend infrastructure, Desktop Peer Host, CLI Peer Host, core tool-runtime, and ESLint configuration changes. This is not a frontend-only change.

Verification

Local verification:

  • Focused Web UI Vitest: 5 test files passed, 87 tests passed.
  • Web UI ESLint: pnpm --dir src/web-ui exec eslint src passed.
  • git diff --check passed.
  • Legacy Desktop and legacy CLI compatibility fixtures passed.
  • Peer capability keepalive and replacement-connection race regression tests passed.
  • MCP unsupported/failed rendering and tool-catalog state handling were covered by the focused test suite.

Local type-check status:

  • pnpm run type-check:web remains blocked by a pre-existing generated API issue:
    @/generated/api does not export GitTrustReport.
  • This generated-directory issue predates this PR and is unrelated to the modified code.
  • The remote Frontend Build check is the authoritative build verification for the PR head.

Current GitHub check snapshot for head a25ad0fed3fa48d17fa84d4994fa7c567ecc0b66:

  • Success: Frontend Build
  • Success: CLI Tests on Ubuntu
  • Success: Shell Deploy Scripts
  • Success: Build Impact
  • Skipped: DSH Profile Packaging on Windows
  • Skipped: Impact-selected Linux / Relay Contract
  • In progress: CLI Tests on macOS
  • In progress: CLI Tests on Windows
  • In progress: Rust Build Check on Ubuntu
  • In progress: Rust Build Check on macOS
  • In progress: Rust Build Check on Windows

Reviewer Notes

  • PeerHostInvokeBridge remains an intentional exception because it runs on the Host side of Peer-Device Mode and forwards commands through the HostInvoke boundary.
  • Controller-owned commands remain denied on both Desktop and CLI Peer Hosts.
  • Tool Host commands use the active surface and do not silently fall back to controller-local execution.
  • Legacy Peer Hosts degrade explicitly when a capability cannot be determined.
  • Missing credentials, unsupported commands, transport failures, and empty catalogs remain distinct states.
  • Persisted user data and existing session records are not deleted or reset as part of compatibility handling.

Checklist

  • Business-layer Tauri commands use the shared adapter layer.
  • Peer command ownership is declared across frontend, Desktop Host, and CLI Host.
  • CLI Peer supports cancel_tool and get_all_tools_info.
  • Mixed-version capability handling is covered.
  • Tool catalog race and MCP rendering issues are covered.
  • Dead-code consumers were checked before removal.
  • Focused frontend tests pass.
  • Web UI ESLint passes.
  • git diff --check passes.

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:Request Changes。本次按当前 head f5e5d1281117c1038343b3b92fc022b39b2eb99a 重新检查了全部 23 个变更文件,并沿 Desktop 本地、Desktop Peer、CLI Peer 三条生产路径核对。删除项未发现真实消费者或副作用回归;当前需要处理 3 个阻断问题、3 个非阻断问题和 1 个低优先级一致性问题。

阻断问题

1. [P1] 新路由没有声明命令 owner,CLI Peer 上 22 条命令仅 1 条可执行

问题

insightsApi.ts:179I18nAPI.ts:24AgentCompanionPetService.ts:175AnnouncementService.ts:21FileContextImpl.tsx:45ImageContextImpl.tsx:89IdeControlEventBus.ts:112 改用 api.invoke 后,命令会随当前 surface 发往 Peer;这些命令都没有进入 peer-device-adapter.ts 的 local-only 表。逐条对照 src/apps/cli/src/peer_host/commands/mod.rs:24-138,22 条新增路由命令中只有 check_path_exists(第 69 行)受 CLI Peer Host 支持。

风险

控制端切到 CLI Peer 后,Insights、i18n、Companion Pet、Announcement、FileContext 的 fs_exists 和 IDE 结果上报都会返回 command ... is not supported on CLI peer host。其中部分调用会吞掉错误,用户只会看到设置重启后丢失、公告状态不保存或文件上下文被判无效。

建议

逐条确定 owner:属于控制端应用壳/本机资源的命令加入前端、Desktop Host、CLI Host 三处一致的 local-only 契约;确实属于 Peer 产品面的命令补齐 CLI capability/实现与明确的 unsupported gate。请增加覆盖这批命令的 Desktop/CLI Peer 支持矩阵测试。

2. [P1] Insights 的命令、进度和报告文件分落两台设备

问题

src/web-ui/src/infrastructure/api/insightsApi.ts:179generate_insights 发往 Peer,但 listenProgress 仍在第 207 行监听控制端本机 Tauri 事件,openReport 仍在第 211 行用控制端 openPath。Peer 事件 fan-out 白名单 src/apps/desktop/src/api/remote_connect_api.rs:571-589 没有 insights-progress。此外该长任务被当作普通 mutation,受 peer-device-adapter.ts:323-327 的 30 秒超时约束;后端最终返回的 html_report_path 是 Peer 上的绝对路径(src/crates/assembly/core/src/agentic/insights/service.rs:1454-1459)。

风险

Desktop A 查看 Desktop B 时生成报告:A 收不到进度,约 30 秒后可能得到超时,但 B 仍继续执行;即使之后读到结果,“打开 HTML”也会拿 B 的路径在 A 上打开。

建议

把远端 Insights 做成可追踪的启动任务,并补齐状态/结果查询、进度 fan-out(或轮询)和报告文件传输;在闭环完成前对 Peer Mode 显式 gate,避免产生未知结果的长任务。

3. [P1] Companion Pet 跨设备传递裸路径,导入和预览都会失败

问题

src/web-ui/src/infrastructure/config/components/SessionConfig.tsx:407-414 在控制端 A 用本机 dialog 选择 zip,随后 AgentCompanionPetService.ts:185 把 A 的绝对路径发给 Peer B。B 返回的 spritesheetPath 又在 AgentCompanionPetService.ts:162-167 通过 A 的 plugin-fs 读取。

风险

B 无法读取 A 选中的 zip;列表或导入返回的用户 Pet 也无法在 A 读取 B 的 spritesheet。Desktop Peer 的导入、预览链路因此直接不可用,CLI Peer 还会在命令分发阶段失败。

建议

使用显式文件上传/下载或字节流协议,并让预览资源经过同一 owner;若本次不实现跨设备文件传输,应在 Peer Mode 清晰禁用这些操作。

非阻断问题

4. [P2] 控制端应用状态会在 surface 切换后写到 Peer

问题

I18nAPI.ts:34 的语言持久化随活动 surface 路由:UI 在 A 立即切换语言,配置却写到 B;CLI B 则报 unsupported,且 I18nService.ts:280-285 会吞掉保存失败。Announcement 首次队列通常由 A 在启动时加载,但用户稍后切到 B 后,announcementStore.ts:80,89,99-101 的 seen/dismiss/never-show 会通过当前 adapter 写到 B。

风险

A 的语言重启后回退,同时可能意外改变 B 的语言;公告展示队列和持久状态属于不同设备,用户已经处理的卡片会再次出现,或修改了另一台设备的公告状态。

建议

把 UI locale 和应用壳 announcement 状态明确归为 controller-local;若产品希望它们跨设备同步,需要独立的同步契约,不能依赖当前 surface 隐式选 owner。

5. [P2] Announcement 的副作用型 get_* 被当作可重试读取

问题

AnnouncementService.ts:21,71 调用的 get_pending_announcements / get_announcement_tips 都会执行 scheduler;scheduler.rs:53-72 每次 run() 都增加并持久化 app_open_count。Peer 策略在 peer-device-adapter.ts:229-233get_ 前缀将它们归为可重试读,网络失败时可额外重试 4 次。

风险

一次用户操作可能多次推进 open-count 和版本调度,导致 AppNthOpen 等卡片提前、错过或重复展示。

建议

将 scheduler mutation 与纯读取拆开,或把这两个命令显式排除出 read retry;同时补充超时后重放的状态测试。

6. [P2] 新增 ESLint fence 没有覆盖它声明的边界

问题

src/web-ui/eslint.config.mjs:43 使用的 no-restricted-imports 只拦静态 import,现有生产代码仍可通过 import('@tauri-apps/api/core') 获取 invoke,例如 PanelController.ts:241。本 PR 修改的 FileContextImpl.tsx / ImageContextImpl.tsx 又落在顶层全局 ignore 的 src/shared/context-system/core/types/**(第 21 行),对它们连该 fence 都不会执行。

风险

PR 注释所述“重新引入 direct invoke 会让 build 失败”并不成立,后续代码可以无意绕过统一 adapter,重复本次跨 surface 问题。

建议

增加覆盖 ImportExpression 的规则,并把 Context 目录从全局 ignore 调整为只跳过无关规则、仍执行 transport fence;仅保留有 owner 说明的精确例外。

低优先级一致性问题

7. [P3] IDE control 的监听与成功/失败回报使用不同 owner

问题

IdeControlEventBus.ts:48-49 仍监听本机 ide-control-event,错误分支在第 112 行走当前 api.invoke,成功分支 PanelController.ts:241-242 仍动态导入并直调本机 invoke

风险

同一个 request 的成功和失败结果可能发到不同 host;当前这条链路也会继续绕过新增 lint fence。

建议

先明确 IDE control event 的 owner,再让监听和两条结果回报共用同一 transport,并补一条 Peer surface 切换测试。

验证

  • git diff --check:通过。
  • pnpm --dir src/web-ui exec eslint src:通过;单独验证动态 import 文件仍为 0 错误,Context 文件被全局 ignore。
  • peer-device-adapterinsightsStoreFlowChatManager:49/49 通过。
  • exact-head GitHub checks:Frontend Build 等均通过或按影响矩阵跳过;现有检查未覆盖上述跨设备 owner、长任务和裸路径语义。
  • 对删除的 API、service、crypto、constants、example 做了全树静态/动态消费者复核,未发现删除导致的新问题。

zvzuola added a commit to zvzuola/BitFun that referenced this pull request Aug 24, 2026
…gaps

Address PR GCWing#2428 review (CHANGES_REQUESTED):

- Declare LOCAL_ONLY owners for i18n/announcement/companion-pet/insights/
  IDE-control/browser/webview/devtools/desktop-pet commands routed to peer
  without an owner; cross-device routing regressed controller app-shell state.
- Add SIDE_EFFECTING_GET_COMMANDS so get_pending/get_announcement_tips
  (scheduler-mutating reads) are never auto-retried by the peer read path.
- Add no-restricted-syntax ImportExpression selector to the ESLint fence so
  dynamic import('@tauri-apps/api/core') bypasses fail the build too.
- Migrate all ~30 pre-existing dynamic-import sites to api.invoke (15 files);
  each command's peer-vs-local owner is declared to preserve behavior.
- FileContextImpl: fs_exists -> check_path_exists (peer-routed, CLI-peer
  supported) so file-tree path checks resolve on the rendered surface.
- PanelController: route report_ide_control_result success branch through
  api.invoke so both branches use the same LOCAL_ONLY transport.

Verified: eslint src -> 0 errors; peer-device-adapter.test.ts 39/39 passed.

Co-Authored-By: Claude <noreply@anthropic.com>

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:Request Changes。本次锁定当前 head 5abe1e2b5156879eba581a52c65bdb22ba1e3df9,复核了新增 3 个修复提交和完整最终 diff。上一轮关于 Insights、Companion Pet、i18n/Announcement、Announcement 重试和 IDE 结果归属的问题已经闭环;当前仍有 1 个阻断问题、2 个非阻断问题,以及 1 个低优先级的 PR 信息维护项。

1. [P1] CLI Peer 无法中断正在执行的 Terminal 工具

问题

TerminalToolCard.tsx:424 现在通过 api.invoke('cancel_tool') 把中断请求正确路由到当前 Peer,但 CLI Peer Host 的命令表只实现了 cancel_dialog_turnsrc/apps/cli/src/peer_host/commands/mod.rs:136 会让 cancel_tool 落入 unsupported 分支。

风险

控制端渲染 CLI Peer 会话时,用户点击 Terminal 卡片的 Interrupt,请求返回 command 'cancel_tool' is not supported on CLI peer host。前端只会恢复按钮并记录错误,Peer 上的命令继续运行,用户可见的中断操作实际无效。

建议

由 CLI Runtime owner 补齐逐工具取消 handler;如果当前 CLI Runtime 尚无这一契约,应依据 capability 隐藏该按钮,或明确退化为受支持的 Turn 取消,并增加 CLI Peer 交互测试。

2. [P2] CLI Peer 的工具目录会被静默显示为空

问题

useAgentsList.ts:187AssistantDefaultsPage.tsx:189 新迁移的 get_all_tools_info 会路由到 Peer。CLI Peer Host 没有该命令,同样落入 commands/mod.rs:136 的 unsupported 分支;两个调用点又把错误吞成 []

风险

切到 CLI Peer 后打开 Agents 或 Assistant Defaults,界面会错误显示没有可用工具,MCP/tool 配置能力也随之消失。用户无法区分“CLI Host 不支持”与“真实工具目录为空”。

建议

从 CLI 的真实 Runtime/tool catalog 返回同形 DTO;在 capability 补齐前至少显示明确的 unsupported 状态。请把本轮新增 routed 命令纳入 Desktop/CLI Peer 支持矩阵测试,避免仅验证 local-only 列表。

补充核对:lsp_detect_project 会被 CLI 的 lsp_ 策略明确拒绝并退化到前端检测;get_file_editor_sync_hash 无 CLI handler,会退化为完整文件读取;check_path_exists 已有 CLI handler。后两条目前有显式 fallback,不作为本轮阻断项。

3. [P2] ESLint adapter fence 仍绕过整个 Context types 目录

问题

eslint.config.mjs:25 仍在顶层全局 ignore 中排除了 src/shared/context-system/core/types/**。新增的 ImportExpression 规则可以拦截普通目录里的动态 import,但后续所有 fence 都不会应用到 FileContextImpl.tsxImageContextImpl.tsx 所在目录。

风险

本 PR 刚迁移的两个 Context 实现仍可重新引入任意直接 Tauri invoke,CI 不会阻止。实测 eslint --print-config src/shared/context-system/core/types/FileContextImpl.tsx 返回 undefined;相同动态-import 探针在普通源码路径会按预期报错。

建议

移除该目录的全局 ignore,把 legacy hooks 等豁免放到专用规则块,让 adapter fence 单独覆盖全部业务源码;再增加一个静态/动态 import fence fixture 或自测。

4. [P3] PR 描述已与当前 head 不一致

当前描述仍写着“frontend-only / no Rust changes”,验证部分绑定旧 head 433f6011,并称 Rust/CLI 检查被跳过。当前 head 已修改 Desktop/CLI 两个 Rust 文件,Rust Build、CLI Tests 和 Rust/CLI Validation 也都通过。建议合并前同步 Summary、Areas、Verification 和 Reviewer Notes,避免后续审阅者依据过期范围判断风险。

已确认闭环

  • Insights、Companion Pet、i18n/Announcement、IDE result 和新增 app-shell 命令均已明确为 controller-local,并在 FE、Desktop Host、CLI Host 三端建立拒绝边界。
  • 两个有副作用的 Announcement get_* 已明确排除 Peer 自动重试。
  • 动态 import('@tauri-apps/api/core') 在非忽略目录已被规则拦截;当前生产代码只剩 adapter 与有 owner 说明的 Host bridge 例外。
  • 删除的旧 service/API/crypto/constants/example 再次做了全树消费者复核,未发现删除回归。

验证

  • git diff --check:通过。
  • pnpm --dir src/web-ui exec eslint src:通过;同时用 --print-config 复现了 Context 全局 ignore。
  • peer-device-adapteruseDebugInspectoragentCompanionPetCommands:50/50 通过;独立复核的相关聚焦用例 68/68 通过。
  • pnpm run check:core-boundaries:通过。
  • exact-head GitHub checks:10/10 通过,包括 Frontend Build、Desktop/Rust 三平台构建和 CLI Tests。

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:Request changes。本次结论绑定 head 5abe1e2b5156879eba581a52c65bdb22ba1e3df9

我重新按 base...head 全量检查了 45 个变更文件、全部新增 api.invoke 命令的 Controller / Desktop Peer / CLI Peer 路由、删除项消费者与初始化副作用、ESLint 边界及最终 CI。当前确认以下问题需要一次性处理。

1. [P1] CLI Peer 上的 Terminal 中断不会停止目标命令

问题src/web-ui/src/flow_chat/tool-cards/TerminalToolCard.tsx:424 现在将 cancel_tool 路由到当前 Peer。Desktop Peer 可以执行该命令,但 CLI Peer 的 dispatch 只有 cancel_dialog_turn,没有 cancel_tool,最终进入 src/apps/cli/src/peer_host/commands/mod.rs:136 的 unsupported 分支。

风险:用户在 CLI Peer 会话中点击 Terminal 卡片的 Interrupt 后,前端只会恢复按钮并记录错误,目标机器上的进程继续运行。长时间或有副作用的 shell 命令无法可靠停止。

建议:把 cancel_tool 接到 CLI Runtime 现有的 cancellation owner,并补 Desktop / CLI Peer 行为等价测试。若当前没有逐工具取消契约,应基于 capability 隐藏该按钮,或明确退化为受支持的 turn cancellation,不能展示一个实际无效的中断操作。

2. [P2] CLI Peer 的工具目录被静默解释为空列表

问题src/web-ui/src/app/scenes/agents/hooks/useAgentsList.ts:187src/web-ui/src/app/scenes/profile/views/AssistantDefaultsPage.tsx:189 会把 get_all_tools_info 路由到 Peer。CLI Peer 没有该 handler,两个调用点又把 unsupported 错误吞成 []

风险:Agents / Assistant Defaults 会显示“没有可用工具”,MCP 和其他工具能力也随之消失。用户无法区分“CLI Host 暂不支持目录查询”和“运行时确实没有工具”,还可能基于错误目录保存配置。

建议:从 CLI 已组装的 Runtime / tool registry 返回与 Desktop 相同的只读 DTO;交付前至少增加 capability gate 和明确的 unsupported 状态,避免用空数组掩盖失败。

3. [P2] ESLint adapter fence 仍漏掉本 PR 刚迁移的 Context 目录

问题src/web-ui/eslint.config.mjs:25src/shared/context-system/core/types/** 放在全局 ignore 中,后续静态和动态 import fence 都不会应用。该目录包含本 PR 修改的 FileContextImpl.tsxImageContextImpl.tsx

风险:这些业务文件可以重新引入直接 Tauri invoke,ESLint 仍以 0 退出,继续绕过 ApiClient / Peer transport。实测同一探针放在普通业务目录会报错,以 Context 路径作为 --stdin-filename 时只得到 File ignored warning;--print-config 也返回空配置。

建议:移除该全局 ignore,仅在通用 React / TypeScript 规则块中豁免确有历史负担的规则,让 adapter fence 独立覆盖所有业务源码;再加一个配置级回归用例,锁住普通目录与这个 Context 目录。

4. [P3] PR 标题、描述和验证记录没有同步到最终 diff

问题:标题目前以 and dr… 截断;正文仍绑定旧 head 433f6011,称 Rust / CLI 检查跳过、没有 Rust/CLI 改动、命令名与 payload 均未变化。最终 diff 已修改 CLI/Desktop 两个 Rust 安全边界文件,所有 Rust/CLI 检查实际通过;FileContextImpl 也从 fs_exists({ path }) 改为 check_path_exists({ request: { path } })。正文还遗漏了后续动态调用迁移、其余删除项和 Peer owner 修复。

风险:Reviewer 会按错误的 frontend-only 范围和旧验证状态评估变更,无法准确审查安全边界与删除影响。

建议:合并前按最终 45 文件 diff 重写标题、Summary、Impact、Reviewer Notes 和 Verification,并绑定当前 head 与最终全绿检查。

已核实,无需继续反复修改的部分

  • Insights、Companion Pet、i18n、Announcement、IDE result、Browser/WebView、DevTools、桌面宠物和诊断等 Controller-owned 命令,已在前端、Desktop Host、CLI Host 三处保持 controller-local;Announcement 的副作用型 get_* 也已排除自动重试。
  • check_path_exists 在 CLI Peer 有明确 handler;lsp_detect_project 有明确 unsupported + 前端检测 fallback;get_file_editor_sync_hash 有全文读取 fallback。
  • 12 个删除文件及其 barrels 没有剩余真实消费者;旧 AgentService 的 listener map 无生产消费者,TodoWrite 已由现行 FlowChat tool-event 路径处理,删除本身未发现回归。
  • 未发现新增 ApiClient 静态 import 引入初始化闭环。

验证

  • git diff --check:通过。
  • Web UI ESLint:通过;另用正反探针确认了上述 Context ignore 缺口。
  • 8 个聚焦前端测试文件:86/86 通过。
  • check:core-boundaries:通过;对应测试 126/126 通过。
  • 当前 head 的 10 个 GitHub checks 全部成功。
  • 本地 type-check:web 被审查 worktree 缺失的 gitignored @/generated/api 阻断;远端当前 head 的 Frontend Build 已成功,因此未将其归因为 PR 失败。

@limityan
limityan dismissed their stale review August 25, 2026 02:19

Duplicate review submitted by mistake; retaining the earlier review.

zvzuola added a commit to zvzuola/BitFun that referenced this pull request Aug 25, 2026
…arden adapter fence

Address PR GCWing#2428 review round 3 (issues #1-GCWing#3):

1. CLI peer host lacked a `cancel_tool` route. Expose `cancel_tool` on
   `CoreAgentRuntimeCompatibility` (delegates to the coordinator), add the
   CLI dialog handler + dispatch branch, and advertise the `cancel_tool`
   capability in both desktop and CLI `peer_mode_ping`.

2. CLI peer host lacked a `get_all_tools_info` route and the tool-info DTO
   was duplicated between desktop and core. Add a shared `ToolInfoDto` +
   `build_tool_info`/`build_all_tools_info` in core (backed by the global
   tool registry), a thin CLI `tools` handler + dispatch branch, and the
   `tool_catalog` capability in both `peer_mode_ping` surfaces. Desktop's
   `tool_api` now aliases the core DTO instead of redefining it.

3. The ESLint adapter fence leaked: a global `ignores` entry for
   `src/shared/context-system/core/types/**` let direct/dynamic `invoke`
   imports pass lint there. Drop the blanket ignore and add a targeted
   override that exempts only `react-hooks/rules-of-hooks`; the fence
   rules now apply. Add a config-level regression test pinning that both
   the ordinary business dir and the context-system types dir block
   invoke, while the adapter exception still permits it.

Frontend: propagate `cancelTool`/`toolCatalog` capabilities through the
peer-device snapshot/context, gate the Terminal interrupt button and the
tool-catalog fetches (useAgentsList, AssistantDefaultsPage) on host
support; default to allowed when capabilities are unknown to avoid flicker.

Co-Authored-By: Claude <noreply@anthropic.com>

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:Request Changes。本次锁定 head 50b76516f1e4cad5d3219e4ee54887f362ee3cbf,重新检查了完整 62 文件最终 diff、Peer Device owner/capability、取消链路、工具目录、ESLint 边界、删除项消费者和 exact-head CI。CLI cancel_tool/工具目录路由以及 Context ESLint 围栏已经闭环;当前仍有 3 个阻断问题、3 个 P2 和 3 个低优先级问题。

阻断问题

1. [P1] Browser Control / Computer Use 的配置、执行状态和修复动作落在不同设备

问题

peer-device-adapter.ts:182-196browser_control_*computer_use_get_status 固定为 controller-local,Desktop/CLI Peer deny 表也拒绝这些命令;但 SessionConfig.tsx:571-621 仍通过可转发的 set_configai.computer_use_enabledai.browser_control_preferred_browser 写到当前 Peer。随后状态查询、浏览器启动/重启和权限修复又在控制端执行(SessionConfig.tsx:167-215, 580-604, 680-711ComputerUseToolCard.tsx:94-95)。Desktop Runtime 的 ComputerUse Tool 和 Browser Control 服务实际运行在 Peer Host,并读取 Peer 自己的配置与 OS 资源。

风险

控制端 A 查看 Desktop B 时,用户配置的是 B,却看到、启动和修复 A 的浏览器/系统权限;B 上的 Agent 仍可能因 B 的 CDP 或权限未准备好而失败。CLI Peer 还会呈现一个无法由当前 Host兑现的设置界面。

建议

将 Browser Control 和 Computer Use 的状态/准备/修复契约按运行 Tool 的 Host 路由:Desktop Peer 协商能力并在 B 执行;CLI Peer 明确显示 unsupported。browser_webview_* 等真正属于控制端嵌入式界面的命令可以继续 controller-local。增加 Desktop/CLI Peer owner 矩阵测试,覆盖配置、状态、启动和权限修复的同 Host 闭环。

2. [P1] cancel_tool 没有使用为交互操作保留的高优先级通道

问题

peer-device-adapter.ts:207-256 的高优先级集合包含 cancel_dialog_turn,遗漏了新增的 cancel_toolpeerInvokePriorityFor() 因此把它归为 normal。请求队列在 peer-device-adapter.ts:820-844 为 high 保留一个并发槽,normal 请求无法使用该槽。

风险

三个普通/低优先级 HostInvoke 占满非高优先级额度时,用户点击 Terminal Interrupt,取消请求仍需排队。弱网或读请求重试期间,目标机器上的长命令可能额外运行数十秒,继续产生副作用。

建议

cancel_tool 加入 high priority,并增加“普通队列已满时取消仍立即发送”的调度测试。

3. [P1] 工具目录请求没有绑定 Device Surface,切换设备后可能操作错误 Host 的数据

问题

useAgentsList.ts:329 只用 canQueryToolCatalogworkspacePath 触发刷新;AssistantDefaultsPage.tsx:227 只依赖 capability 布尔值。两台 Peer 都声明 toolCatalog=true 时,A → B 的切换不会触发重新加载;相同路径字符串也无法区分两台机器。未完成的 A 请求同样缺少 surface epoch 防护。

风险

界面可能继续展示 A 的工具/MCP 目录,后续配置 mutation 已经路由到 B,导致用户依据错误目录修改 B 的 Agent 配置。仓库的 Peer Device 设计明确要求 cache/request/capability identity 包含 DeviceSurfaceId

建议

local/deviceId surface identity 纳入加载依赖,并用 surface epoch/request id 丢弃旧设备返回的异步结果;增加 A/B 相同 workspace path、相同 capability 的切换测试。

其他需要修复的问题

4. [P2] 新 capability 字段会把旧 Desktop 的已有能力误判为不支持

旧 Desktop head 5abe1e2b... 已注册 cancel_toolget_all_tools_info,但旧 peer_mode_ping 没有新字段。PeerConnectionManager.ts:364-371=== true 将字段缺失直接解析为 false,新 Controller 因此会隐藏旧 Desktop 本来可用的 Interrupt 和工具目录;旧 CLI 又确实不支持这些命令,单靠缺失字段无法区分两类 Host。

建议增加明确的混合版本策略,例如 unknown 状态 + 标准 unsupported 响应,或 Host 类型/协议版本协商,并覆盖新版 Controller 对旧 Desktop、旧 CLI 的兼容测试。

5. [P2] unsupported、请求失败和真实空目录仍被折叠成 []

useAgentsList.ts:202-211AssistantDefaultsPage.tsx:201-218 都把不支持或失败转换成空数组,最终渲染普通“没有工具/MCP”状态。用户无法区分 Host 不支持、读取失败和 Runtime 确实为空,还可能基于错误状态保存配置。

建议保留 available / unsupported / failed 状态,分别显示真实空目录、不支持提示和可重试错误。

6. [P2] keepalive 更新 capability 后不一定发布 React 快照

PeerConnectionManager.ts:417-429 每次健康检查都会替换 capability,但 publish() 只在 recovered 为 true 时调用(第 431-437 行)。连接保持 ready、Host 返回的能力发生变化时,React 继续使用旧快照。

建议比较新旧 capability,只要变化就 publish,并增加 ready 状态下 capability 变化的 keepalive 测试。

低优先级问题

7. [P3] Core 新增两个无调用的 public 恒等函数

catalog.rs:73-85to_dynamic_tool_info / to_dynamic_mcp_tool_info 只返回输入且没有调用者。本地 Rust 定向测试稳定产生两条本 PR 新增的 unreachable-pub 警告。建议删除函数和未使用 import,避免无意义 API 表面。

8. [P3] ESLint 回归测试在 Windows 触发 Node DEP0190

eslint.fence.regression.test.ts:83-88 使用 shell: true 传递参数。测试通过,但 Windows 上稳定出现 Node 安全弃用警告。建议 Windows 执行 pnpm.cmd、其他平台执行 pnpm,统一保持 shell: false

9. [P3] PR 标题仍是字面截断状态

当前标题仍为 refactor(web-ui): route business invokes through adapter layer and dr…。正文已同步新 head,标题末尾仍是实际省略号;建议合并前改成完整、可检索的标题。

已确认闭环

  • CLI Peer 已实现 cancel_toolget_all_tools_info,当前版本 Host 的两条路由能够工作。
  • Desktop/CLI 工具目录共用同一 Core DTO;动态字段序列化与 Web contract 一致。
  • Context types 不再被 ESLint 全局忽略,静态和动态 Tauri invoke 探针都会被 fence 拦截。
  • 先前的 Insights、Companion Pet、i18n/Announcement、IDE result、Announcement 重试与删除项消费者问题已按最终代码复核闭环。

验证

  • Web UI 定向矩阵:6 个文件、77/77 通过。
  • pnpm exec eslint src:通过;同时稳定复现上述 DEP0190
  • CLI peer_mode_ping 定向测试:通过;稳定复现上述两个新增 Core 警告。
  • pnpm run check:core-boundariesgit diff --check:通过。
  • exact-head GitHub checks:10/10 成功。

zvzuola added a commit to zvzuola/BitFun that referenced this pull request Aug 25, 2026
…adapter surface

PR GCWing#2428 review GCWing#4 (limityan, 2026-08-25). All but the truncated PR-title P3.

P1:
- Browser Control / Computer Use now run on the host that runs the Tool:
  removed browser_control_*/computer_use_get_status/request_permissions/
  open_system_settings from FE + Desktop LOCAL_ONLY; CLI deny.rs already
  refuses them. Desktop Peer B bridges to its own webview (reads B's
  browser/OS); SessionConfig surfaces an explicit unsupported notice on a
  CLI Peer instead of silent invoke failures. browser_webview_* stays
  controller-local (embedded UI).
- cancel_tool joins HIGH_PRIORITY_COMMANDS so Terminal Interrupt takes the
  reserved high slot instead of queueing behind saturated normal work.
- Tool catalog request bound to Device Surface: renderedPeerDeviceId added
  to useAgentsList loadAgents deps + AssistantDefaultsPage effect, so A->B
  (same workspace + capability) reloads; requestId guard drops stale results.

P2:
- Capability versioning: cancelTool/toolCatalog become boolean|null (null =
  unknown/older host); consumers stay optimistic so an older Desktop keeps its
  working button/list instead of being gated off.
- Tool catalog status tri-state (available/unsupported/failed/empty) in
  useAgentsList + AssistantDefaultsPage; AssistantDefaultsPage distinguishes
  failure from a truly empty list.
- keepalive publishes a React snapshot when a ready peer's capabilities
  change (not only on recovery), via capabilitiesEqual().

P3:
- Remove two unreachable-pub identity fns + unused import from catalog.rs.
- eslint fence regression test runs the eslint JS bin via process.execPath
  with shell:false (was pnpm + shell:true -> Node DEP0190 on Windows).

Verified: eslint src clean; focus tests 72/72 (adapter 42, manager 19,
surface + fence); core-boundaries + 126 self-tests pass; cargo build
core/desktop clean; desktop peer_host_invoke 6/6; CLI cli_command_contracts
41/41. Pre-existing @generated/api type error and 2 flaky terminal_process
contract tests are unrelated.

Co-Authored-By: Claude <noreply@anthropic.com>
@zvzuola zvzuola changed the title refactor(web-ui): route business invokes through adapter layer and dr… refactor(web-ui): route business invokes through adapter layer and declare Peer-Device-Mode owners Aug 25, 2026

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:Request Changes。本次锁定 head cbed741c02f78d57b674b28e3c7a12c2b8c9521c,并逐项回溯 merge-base 41f4af303910b45f488bc78944ce91c452a273ee 与引入提交;已剔除基线旧问题和缺乏当前生产触发证据的推测。当前确认 1 个阻断问题、2 个 P2 和 1 个 P3。

1. [P1] 新 Controller 连接旧 CLI 时,Terminal Interrupt 仍会显示为可用但实际无效

问题PeerConnectionManager.ts:378-390 将旧 Host 未声明的新 capability 解析为 nullTerminalToolCard.tsx:401-414 又把 null 按“乐观支持”处理,因此 Interrupt 按钮仍然可见。旧 CLI(例如 5abe1e2b...)没有 cancel_tool handler;点击后仅在 TerminalToolCard.tsx:438-458 恢复按钮并记录错误,终端命令仍继续执行,用户也看不到失败提示。

风险:这是混合版本升级场景中的假成功操作,用户会误以为远端命令已被中断。该问题由本 PR 的 Peer 路由与 capability 兼容策略共同引入,当前生产路径可触发。

建议:为 Host 能力协商增加可判定的协议版本或 Host 类型;对未知 capability 采用一次探测并缓存结果,失败后显式进入 unsupported 状态。旧 Desktop/CLI 组合应补充混合版本测试,至少覆盖 Interrupt 的可见性、失败提示和命令是否真正停止。

2. [P2] Tool Catalog 的 unsupported / failed 状态没有完整进入 Agents 和 MCP 界面

问题useAgentsList.ts:648 已返回 toolCatalogStatus,但 AgentsScene.tsx:212-232 没有消费它;AssistantDefaultsPage.tsx:769-815 只在 Built-in Tools 区使用状态,MCP 区仍把失败或不支持显示成普通空目录。连接旧 CLI 时,未知 capability 会先乐观调用,再被 catch 归类为 failed,无法表达“Host 不支持”。

风险:用户会把 Host 不支持、传输失败和真实空目录混为一谈;写入/重置入口也缺少统一的状态约束,容易继续发起必然失败的操作。

建议:让 Agents、Built-in Tools、MCP 共用同一套 loading / ready / unsupported / failed 展示与操作门禁;unsupported 给出明确说明,failed 提供重试,非 ready 状态禁用写入和重置。对旧 Host 的已知缺失能力应归类为 unsupported,不要落入通用失败。

3. [P2] 新路由到 Peer 的 Browser/Computer Use 读取命令仍被按 mutation 策略执行

问题peer-device-adapter.ts:265-325 的只读分类只识别精确命令或以 read_ / list_ / get_ 开头的名称。本 PR 新增 Peer 路由的 browser_control_get_statusbrowser_control_list_browserscomputer_use_get_status 都无法命中,最终在 peer-device-adapter.ts:930 走 30 秒、零重试的 mutation policy。

风险:Desktop Peer 设置页的纯状态读取在弱网或短暂断连时等待更久且无法自动重试,表现会比其他只读查询明显更差。现有测试只覆盖 owner,没有覆盖请求策略。

建议:把这三个纯读取命令纳入只读契约,最好由命令元数据显式声明 read/mutation,避免继续依赖字符串前缀;补充策略测试。launchrestart 和权限请求等真实副作用命令继续保持不可重试。

4. [P3] PR 描述仍绑定旧版本,已无法准确说明当前变更

问题:描述仍写 head 50b76516...、6 commits、62 files,并声称 Browser/WebView 保持 Controller-local;当前实际是 head cbed741c...、7 commits、69 files,Browser Control 与 Computer Use 已调整为 Tool Host 路由。

建议:更新变更摘要、owner 表、提交/文件统计和验证证据,明确 Browser Control、Computer Use 与 Browser WebView 当前各自的 owner;验证结果绑定当前 head。

已复核的旧反馈

前一版提出的 cancel 优先级、keepalive 发布、死代码、ESLint 启动方式、标题,以及 Insights/Companion Pet/Announcement/IDE result/deletion consumers 等问题,在当前 head 均已关闭,本次没有重复列为新问题。Surface 切换异步竞态也经过生产链路复核:现有 reset/unmount 会在 transport commit 前清空 Scene,目前证据不足,因此不提交该项。

验证

  • 当前 head 的 GitHub checks:10/10 成功。
  • 前端相关测试:6 个文件,78/78 通过。
  • ESLint、i18n audit、check:core-boundariescargo check -p bitfun-core --no-default-featuresgit diff --check 均通过。

P1 修复并补齐混合版本验证后,可以继续复审;其余三项建议在同一轮一并收口。

zvzuola added a commit to zvzuola/BitFun that referenced this pull request Aug 25, 2026
Round-5 review fixes for PR GCWing#2428 (reviewer limityan, 2026-08-25).

P1 mixed-version cancel_tool:
- Add declarative `host_type: "desktop"|"cli"` to peer_mode_ping on both
  Rust sides (desktop peer_host_invoke.rs, cli control.rs).
- Parse into PeerHostCapabilities.hostKind (PeerConnectionManager.ts);
  null when an older host omits the field.
- New resolveCanCancelTool() (terminalToolCardState.ts): null capability
  resolves by hostKind — old CLI hides the button, old Desktop shows it,
  unknown stays optimistic. Replaces the inline IIFE in TerminalToolCard.
- Add a failure toast (toolCards.terminal.interruptFailed) in the catch path.

P2 mixed-version tool_catalog:
- New peerCapabilityResolution.ts with canQueryToolCatalogOnSurface()
  mirroring the cancel_tool resolution (null + cli -> unsupported).
  Replaces inline IIFEs in useAgentsList + AssistantDefaultsPage.
- Surface tool-catalog status: AgentsScene renders an unsupported/failed
  message (agentsOverview.toolsUnsupported/toolsFailed) and gates writes;
  AssistantDefaultsPage MCP zone distinguishes unsupported/failed/empty
  and disables all tool writes (Switch/reset/group-toggle) when not
  writable.

P2 browser/computer-use read reclassification:
- Add browser_control_get_status, browser_control_list_browsers,
  computer_use_get_status to RETRYABLE_READ_COMMANDS (prefix matching
  had misclassified them as mutations).

Tests on all sides: desktop peer_host_invoke host_type assertion, cli
peer_mode_ping_advertises_cli_host_type, PeerConnectionManager hostKind
parsing, terminalToolCardState resolveCanCancelTool cases, new
peerCapabilityResolution suite, adapter read reclassification, AgentsScene
unsupported-catalog rendering.

Co-Authored-By: Claude <noreply@anthropic.com>

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:Request Changes。本次锁定 head f3c3f9b59f904269a8eb8820009ea1f0745804d8,只审查相对上一轮 head cbed741c02f78d57b674b28e3c7a12c2b8c9521c 的新增提交,并回归上一轮问题。当前结果是:1 个问题由本轮更新激活,2 个上一轮代码问题仍未完整关闭,另有 1 个持续存在的 PR 元数据问题。

上一轮问题仍未关闭

1. [P1] host_type 无法识别真正的旧 CLI

问题host_typecancel_tool / tool_catalog capability 都是在新版本中加入的。真正的旧 CLI 响应会同时缺少这三个字段,PeerConnectionManager.ts:410-412 因此将 cancelTooltoolCataloghostKind 全部解析为 nullterminalToolCardState.ts:125peerCapabilityResolution.ts:36 又把 hostKind === null 按支持处理。

新增测试构造的是“缺 capability、但存在 hostKind: 'cli'”的组合;旧二进制无法返回这种响应,所以测试没有覆盖真实混合版本数据。

风险:新 Controller 连接旧 CLI 时,Interrupt 仍然显示;点击后虽然现在会弹出失败提示,但远端命令继续运行。Tool Catalog 也仍会发起调用,并被归类为 failed,无法表达 unsupported

建议:不要使用与 capability 同期新增的字段判断更老的 Host。三项均未知时采用保守策略,或使用旧版本已经存在的可靠信号;Tool Catalog 可以做安全探测并缓存结果。混合版本测试应直接复用旧 CLI 的完整 peer_mode_ping 响应 fixture。

2. [P2] MCP 已有注册服务器时,目录失败仍显示成“该服务器无工具”

问题AssistantDefaultsPage.tsx:793-810 只在 mcpServerIds.size === 0 时展示 unsupported / failed。只要存在注册服务器,就会进入服务器列表分支;目录读取失败产生的空列表最终在 AssistantDefaultsPage.tsx:830-834 显示为 mcpServerNoTools

风险:页面可能同时显示 MCP 服务器为 Connected,又声称该服务器没有工具,掩盖真实的目录读取失败。上一轮要求 MCP 区分 unsupported / failed / empty 的问题只修复了无注册服务器的情况。

建议:优先按 toolCatalogStatus 短路整个 MCP 区域;只有状态为 availableempty 时,再根据服务器和工具数量渲染正常内容。

本轮更新激活的问题

3. [P2] 旧 Tool Catalog 请求可以覆盖最新状态并锁住当前工具管理

问题useAgentsList.ts:228-240 在 request-id 校验前直接写入 toolCatalogStatus,而 useAgentsList.ts:293-295 的 guard 只保护最终数据。本轮提交首次让 AgentsScene.tsx:245-250 消费该状态并据此隐藏内容、禁用工具写入,因此原有的未保护状态写入现在会产生用户可见后果。

当前有确定的并发入口:CustomAgentAPI.ts:102-106 删除自定义 Agent 后同步发出 custom-agent:updated,监听器启动一次加载;删除流程随后又在 AgentsScene.tsx:595-598 显式调用 loadAgents()

风险:若旧请求晚到并失败,它会用 failed 覆盖新请求的成功状态,最终出现“当前工具数据已经加载,但页面显示失败并禁用管理”的矛盾状态,直到再次刷新。反向顺序也可能留下成功状态和空数据不一致。

建议:让 fetchTools() 返回 { tools, status },在 request-id 校验通过后统一提交目录数据与状态;同时合并删除流程触发的重复刷新。补充两个并发请求乱序完成的测试。

持续存在的元数据问题

4. [P3] PR 描述仍绑定旧版本

描述仍写 6 commits、62 files、+908/-1720、head 50b76516...;当前实际为 8 commits、79 files、+1657/-1743、head f3c3f9b5...。请同步变更摘要、owner 说明、统计和验证记录。

已确认关闭 / 验证

  • Browser Control / Computer Use 三个状态读取命令已正确归入 retryable read,后端路径确认无启动、权限提示或设置写入副作用。
  • 聚焦 Vitest:7 个文件、92 个测试通过。
  • i18n audit、聚焦生产 TypeScript ESLint、git diff --check 通过。
  • CLI peer_mode_ping 聚焦 Rust 测试 2/2 通过。
  • 当前 GitHub CI:Frontend Build、CLI 三平台、Rust Linux/macOS、Build Impact、Shell Deploy 已通过;Windows Rust Build 提交时仍在运行。

请先关闭 P1,并在同一轮处理两项 Tool Catalog 状态问题;修复后再复审。

zvzuola and others added 9 commits August 26, 2026 09:05
…op dead AgentService

- Add eslint no-restricted-imports fence: business code must reach the
  platform only via api.invoke (ApiClient); direct invoke from
  '@tauri-apps/api/core' is reserved for adapters/** and the intentional
  PeerHostInvokeBridge exception.
- Reroute 8 A-class modules (insights, i18n, companion pet, announcement,
  file/image context, ide-control event bus) from direct invoke to api.invoke.
- Delete the dead legacy agent-service.ts wrapper (no consumers) and its
  FlowChatManager field/import/initialization, the orphaned getAvailableAgents()
  method, and its test mock.

Co-Authored-By: Claude <noreply@anthropic.com>
Remove 11 files and prune the api barrel of entries with no real consumers
anywhere in src (verified by full-tree grep + dynamic import + bitfunAPI.<prop>
access). Follow-up to 433f601 which dropped the legacy agent-service.ts.

Deleted (11 files):
- infrastructure/services/ dead chain (5): business/agentService.ts,
  infra/contextManager.ts, infra/index.ts, api/index.ts (broken barrel
  exporting non-existent contextService), index.ts (barrel with no importer)
- infrastructure/api/service-api/ProjectAPI.ts + GitRepoHistoryAPI.ts
  (only referenced inside the dead bitfunAPI collection)
- shared/crypto/ (e2e-encryption.ts + index.ts, no @/shared/crypto import)
- infrastructure/agents/constants.ts (BUILTIN_SUB_AGENT_IDS/isBuiltinSubAgent)
- shared/context-menu-system/examples/FileTreeIntegrationExample.tsx

Barrel edit (infrastructure/api/index.ts): drop the dead bitfunAPI collection
object, its default export, the GitRepoHistory type re-export, and the
projectAPI/gitRepoHistoryAPI imports; keep the 23 re-exports that have real
consumers. Sync the eslint examples/** ignore to the deleted example dir.

Conservatively retained:
- ContextAPI.ts: contextAPI loses its only consumer (ContextManager) but
  wraps backend session commands (compress_context/save_session_data/...) —
  cross-layer decision, pruned from bitfunAPI but file kept.
- Method-level dead code (~60 methods across RemoteConnectAPI/MiniAppAPI/
  SubagentAPI/AgentAPI/etc): TS wrapper dead != Rust handler dead; deferred
  to a follow-up batch that checks the backend command table per method.

Verified: tsc --noEmit introduces no new errors (only a pre-existing,
unrelated websocket-adapter GitTrustReport import error remains); eslint src
clean; vitest failures pre-exist on baseline (jsdom localStorage env issue).

Co-Authored-By: Claude <noreply@anthropic.com>
…gaps

Address PR GCWing#2428 review (CHANGES_REQUESTED):

- Declare LOCAL_ONLY owners for i18n/announcement/companion-pet/insights/
  IDE-control/browser/webview/devtools/desktop-pet commands routed to peer
  without an owner; cross-device routing regressed controller app-shell state.
- Add SIDE_EFFECTING_GET_COMMANDS so get_pending/get_announcement_tips
  (scheduler-mutating reads) are never auto-retried by the peer read path.
- Add no-restricted-syntax ImportExpression selector to the ESLint fence so
  dynamic import('@tauri-apps/api/core') bypasses fail the build too.
- Migrate all ~30 pre-existing dynamic-import sites to api.invoke (15 files);
  each command's peer-vs-local owner is declared to preserve behavior.
- FileContextImpl: fs_exists -> check_path_exists (peer-routed, CLI-peer
  supported) so file-tree path checks resolve on the rendered surface.
- PanelController: route report_ide_control_result success branch through
  api.invoke so both branches use the same LOCAL_ONLY transport.

Verified: eslint src -> 0 errors; peer-device-adapter.test.ts 39/39 passed.

Co-Authored-By: Claude <noreply@anthropic.com>
The core-boundaries check enforces a one-way ownership boundary: every
command the FE adapter marks LOCAL_ONLY must also be refused by each peer
host, because an older or non-Web-UI controller can still HostInvoke them.
The previous commit added i18n/announcement/companion-pet/insights/IDE-
control/browser/webview/devtools/desktop-pet/diagnostics commands to the
FE deny list but not to the desktop and CLI peer-host deny lists, so CI's
"Check core boundaries" step failed.

Add the 37 controller-owned commands to both
src/apps/desktop/src/api/peer_host_invoke.rs and
src/apps/cli/src/peer_host/deny.rs, grouped with owner comments mirroring
the FE adapter. Being unimplemented on the CLI peer is not the boundary —
they are refused explicitly.

Verified: check-core-boundaries -> passed; check-core-boundaries.test ->
126/126; cargo test -p bitfun-desktop peer_host -> 6/6; cargo test --bin
bitfun peer_host -> 79/79.

Co-Authored-By: Claude <noreply@anthropic.com>
The dynamic-import migration moved useDebugInspector and
agentCompanionPetCommands off `@tauri-apps/api/core` and onto
`api.invoke`, but their tests still mocked `@tauri-apps/api/core`, so the
mock never intercepted the call. CI "Run web UI tests" failed:

- useDebugInspector.test.tsx: expected mocks.invoke to be called with
  'debug_devtools_available' but it was called 0 times.
- agentCompanionPetCommands.test.ts: api.invoke('show_main_window') hit the
  real ApiClient (WebSocket connection failed).

Repoint both tests at `@/infrastructure/api/service-api/ApiClient` (the
established pattern) and flush the post-invoke microtask in
useDebugInspector before dispatching keys, since the keydown listener now
registers right after the (synchronous) api.invoke resolves rather than
after the old dynamic-import microtask.

Verified: useDebugInspector 4/4, agentCompanionPetCommands 7/7.

Co-Authored-By: Claude <noreply@anthropic.com>
…arden adapter fence

Address PR GCWing#2428 review round 3 (issues #1-GCWing#3):

1. CLI peer host lacked a `cancel_tool` route. Expose `cancel_tool` on
   `CoreAgentRuntimeCompatibility` (delegates to the coordinator), add the
   CLI dialog handler + dispatch branch, and advertise the `cancel_tool`
   capability in both desktop and CLI `peer_mode_ping`.

2. CLI peer host lacked a `get_all_tools_info` route and the tool-info DTO
   was duplicated between desktop and core. Add a shared `ToolInfoDto` +
   `build_tool_info`/`build_all_tools_info` in core (backed by the global
   tool registry), a thin CLI `tools` handler + dispatch branch, and the
   `tool_catalog` capability in both `peer_mode_ping` surfaces. Desktop's
   `tool_api` now aliases the core DTO instead of redefining it.

3. The ESLint adapter fence leaked: a global `ignores` entry for
   `src/shared/context-system/core/types/**` let direct/dynamic `invoke`
   imports pass lint there. Drop the blanket ignore and add a targeted
   override that exempts only `react-hooks/rules-of-hooks`; the fence
   rules now apply. Add a config-level regression test pinning that both
   the ordinary business dir and the context-system types dir block
   invoke, while the adapter exception still permits it.

Frontend: propagate `cancelTool`/`toolCatalog` capabilities through the
peer-device snapshot/context, gate the Terminal interrupt button and the
tool-catalog fetches (useAgentsList, AssistantDefaultsPage) on host
support; default to allowed when capabilities are unknown to avoid flicker.

Co-Authored-By: Claude <noreply@anthropic.com>
…adapter surface

PR GCWing#2428 review GCWing#4 (limityan, 2026-08-25). All but the truncated PR-title P3.

P1:
- Browser Control / Computer Use now run on the host that runs the Tool:
  removed browser_control_*/computer_use_get_status/request_permissions/
  open_system_settings from FE + Desktop LOCAL_ONLY; CLI deny.rs already
  refuses them. Desktop Peer B bridges to its own webview (reads B's
  browser/OS); SessionConfig surfaces an explicit unsupported notice on a
  CLI Peer instead of silent invoke failures. browser_webview_* stays
  controller-local (embedded UI).
- cancel_tool joins HIGH_PRIORITY_COMMANDS so Terminal Interrupt takes the
  reserved high slot instead of queueing behind saturated normal work.
- Tool catalog request bound to Device Surface: renderedPeerDeviceId added
  to useAgentsList loadAgents deps + AssistantDefaultsPage effect, so A->B
  (same workspace + capability) reloads; requestId guard drops stale results.

P2:
- Capability versioning: cancelTool/toolCatalog become boolean|null (null =
  unknown/older host); consumers stay optimistic so an older Desktop keeps its
  working button/list instead of being gated off.
- Tool catalog status tri-state (available/unsupported/failed/empty) in
  useAgentsList + AssistantDefaultsPage; AssistantDefaultsPage distinguishes
  failure from a truly empty list.
- keepalive publishes a React snapshot when a ready peer's capabilities
  change (not only on recovery), via capabilitiesEqual().

P3:
- Remove two unreachable-pub identity fns + unused import from catalog.rs.
- eslint fence regression test runs the eslint JS bin via process.execPath
  with shell:false (was pnpm + shell:true -> Node DEP0190 on Windows).

Verified: eslint src clean; focus tests 72/72 (adapter 42, manager 19,
surface + fence); core-boundaries + 126 self-tests pass; cargo build
core/desktop clean; desktop peer_host_invoke 6/6; CLI cli_command_contracts
41/41. Pre-existing @generated/api type error and 2 flaky terminal_process
contract tests are unrelated.

Co-Authored-By: Claude <noreply@anthropic.com>
Round-5 review fixes for PR GCWing#2428 (reviewer limityan, 2026-08-25).

P1 mixed-version cancel_tool:
- Add declarative `host_type: "desktop"|"cli"` to peer_mode_ping on both
  Rust sides (desktop peer_host_invoke.rs, cli control.rs).
- Parse into PeerHostCapabilities.hostKind (PeerConnectionManager.ts);
  null when an older host omits the field.
- New resolveCanCancelTool() (terminalToolCardState.ts): null capability
  resolves by hostKind — old CLI hides the button, old Desktop shows it,
  unknown stays optimistic. Replaces the inline IIFE in TerminalToolCard.
- Add a failure toast (toolCards.terminal.interruptFailed) in the catch path.

P2 mixed-version tool_catalog:
- New peerCapabilityResolution.ts with canQueryToolCatalogOnSurface()
  mirroring the cancel_tool resolution (null + cli -> unsupported).
  Replaces inline IIFEs in useAgentsList + AssistantDefaultsPage.
- Surface tool-catalog status: AgentsScene renders an unsupported/failed
  message (agentsOverview.toolsUnsupported/toolsFailed) and gates writes;
  AssistantDefaultsPage MCP zone distinguishes unsupported/failed/empty
  and disables all tool writes (Switch/reset/group-toggle) when not
  writable.

P2 browser/computer-use read reclassification:
- Add browser_control_get_status, browser_control_list_browsers,
  computer_use_get_status to RETRYABLE_READ_COMMANDS (prefix matching
  had misclassified them as mutations).

Tests on all sides: desktop peer_host_invoke host_type assertion, cli
peer_mode_ping_advertises_cli_host_type, PeerConnectionManager hostKind
parsing, terminalToolCardState resolveCanCancelTool cases, new
peerCapabilityResolution suite, adapter read reclassification, AgentsScene
unsupported-catalog rendering.

Co-Authored-By: Claude <noreply@anthropic.com>
@zvzuola
zvzuola force-pushed the chore/remove-dead-agent-service branch from 9fb7071 to a25ad0f Compare August 26, 2026 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants