Skip to content

1.0.0 explore - #2517

Merged
limityan merged 9 commits into
GCWing:1.0.0-explorefrom
zvzuola:1.0.0-explore
Aug 26, 2026
Merged

1.0.0 explore#2517
limityan merged 9 commits into
GCWing:1.0.0-explorefrom
zvzuola:1.0.0-explore

Conversation

@zvzuola

@zvzuola zvzuola commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

main 分支上 PR #2428 的全部 9 个提交同步到 1.0.0-explore 分支,引入「适配层围栏(adapter fence)」重构与 Peer-Device 能力增强。核心改动是把所有业务 @tauri-apps/api/core invoke() 调用收敛到 api.invoke()(ApiClient),由 eslint no-restricted-imports 强制围栏;同时为 Peer-Device 模式补齐 cancel_tool / tool_catalog 能力、声明式 host_type 字段,以及混合版本主机的兼容分类。

Type and Areas

Type: refactor / bug fix

Areas: web UI、desktop/Tauri、Rust core(peer-host)

Motivation / Impact

  • 消除直接 invoke 散落:前端业务代码不再直接调用 Tauri invoke,统一经适配层路由,使本地/peer 路由、错误处理、capability 门控有单一收口点,并为后续替换传输层留出空间。
  • Peer-Device 能力补齐:peer 主机现在可声明并消费 cancel_tooltool_catalog 能力,UI 据此区分「主机不支持目录 / 读取失败 / 真的没有工具」三种状态,不再把不支持错误掩盖为空列表。
  • 混合版本兼容:旧版 peer 主机(未声明新能力字段)通过 host_type 声明字段或 get_all_tools_info 回落探测进行分类,避免误判。
  • 对用户:Peer 模式下工具/中断按钮的可用性更准确;本地模式无感知变化。

Verification

  • npx tsc --noEmit — 干净(仅 @bitfun/ui 历史基线报错,非本次引入)
  • eslint — 0 error / 0 warning(含 no-restricted-imports 围栏规则)
  • vitest — 6 个文件 94/94 通过(peer-device、adapters、agents scene、terminal tool-cards、peerCapabilityResolution、peerDeviceSurfaceController)
  • cargo check — 0 错误
  • pnpm run check:core-boundaries — 通过(+ 129/129 边界测试,确认 LOCAL_ONLY_COMMANDS 在 CLI deny.rs + desktop peer_host_invoke.rs 间的镜像不变式成立)

Reviewer Notes

  • 冲突解决策略:explore 与 main 在同一功能上结构差异较大,故全程「保留 explore 渲染结构,整合 main 功能改进」——保留 useI18n(非 useTranslation)、renderCapabilityRow/renderMcpGroups 扁平行表格(非 main 的 GalleryZone)、loadDefaults useCallback 模式;整合 main 的三态能力解析、toolCatalogStatus/toolCatalogWritable 写入门控、host_type 字段、遗留主机分类、陈旧加载竞态保护(loadRequestIdRef)。
  • 能力集合取并集:PeerHostCapabilities = explore 独有 productControlV1/productControlNativeV1/productControlPresentationV1 + main 的 cancelTool/toolCatalog(三态 boolean|null)+ hostKind。Rust peer_mode_ping 广播全部并集。
  • LOCAL_ONLY_COMMANDS:保留 explore 需本地路由的 browser_webview_set_agent_target_state + mark_bitfun_control_*(main commit 7 已删但 explore 仍需);删除 main 移除的 computer_use_*/browser_control_*
  • 测试适配:AgentsScene.test.tsx「unsupported tool catalog」用例需在选中 agent 后点击 [data-detail-section="tools"] tab(explore 仅在该 section 激活时渲染工具区),已修正。
  • 兼容风险:无数据库/协议迁移,无破坏性 API 变更;null 三态对未探测主机保持乐观(向后兼容旧版 peer)。

包含的 9 个提交

  1. 6b01d378b 业务 invoke 走适配层,删除死代码 AgentService
  2. 90e059803 删除已确认零消费者的死代码
  3. dcbefd1c2 声明 Peer-Device-Mode 所有者,补齐适配层围栏
  4. 1aa33545b 将控制器拥有的命令镜像到 peer deny 列表
  5. a477eedd2 迁移后的测试指向 ApiClient mock 表面
  6. 38b610304 CLI peer 新增 cancel_tool + 工具目录路由,加固适配层
  7. 5cb8699cc browser/computer-use 路由到工具主机,加固 peer 适配层
  8. 0585146d8 通过 host_type 字段解决混合版本 peer 能力
  9. bdf7b7f6c 关闭 PR 2428 review 缺口

Checklist

  • 本 PR 聚焦,不含密钥、临时提示、生成草稿或无关产物
  • 上方已记录相关验证,或已说明跳过的检查
  • 用户可见字符串、文档、locales 已在适用处更新

Fixes #2428

zvzuola and others added 9 commits August 26, 2026 10:09
…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>
@limityan
limityan merged commit 57da322 into GCWing:1.0.0-explore Aug 26, 2026
12 checks passed
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