diff --git a/docs/features/acp-client-desktop-web-ui.md b/docs/features/acp-client-desktop-web-ui.md new file mode 100644 index 0000000000..50e7f1eae1 --- /dev/null +++ b/docs/features/acp-client-desktop-web-ui.md @@ -0,0 +1,66 @@ +# ACP Client 能力增强(Desktop / Web UI)功能提案 + +> 状态:提案 / 待评审 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/crates/interfaces/acp/AGENTS.md`](../../src/crates/interfaces/acp/AGENTS.md) +> - [`docs/architecture/agent-runtime-services-design.md`](../architecture/agent-runtime-services-design.md) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) + +### 功能类型 + +- [ ] 新功能 +- [x] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [x] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun 已在 `src/crates/interfaces/acp` 实现 ACP Client 半区,桌面/Web UI 通过 `acp:` agentType 把外部 ACP agent 接入 flow_chat(见 `src/web-ui/src/flow_chat/utils/acpSession.ts`)。内置 preset 当前覆盖 `opencode` / `omp` / `claude-code` / `codex`(见 `src/crates/interfaces/acp/src/client/builtin_clients.rs`),但客户端接入、健康度、远程 workspace、模型/模式目录与工具/权限交互在 Desktop/Web UI 的呈现仍较碎片化,缺少统一的「客户端健康 → 会话建立 → 运行态」闭环体验。 +- 痛点:① 多客户端并发使用时缺乏统一的健康/可用性视图;② 远程 workspace 复用本地 ACP 客户端配置时,探测/安装/降级链路对用户不透明;③ 会话级 config option(如 fast-mode、thought_level)与原生 BitFun agent 的模型/模式目录存在呈现差异;④ permission RPC 与 tool card 桥接在 Web UI 上的确认/拒绝 UX 与原生工具不一致。 + +### 功能描述 + +- 在 Desktop/Web UI 增强并收敛 ACP Client 的端到端体验,覆盖四个环节: + 1. **客户端健康与接入**:统一展示已注册客户端(builtin + 用户自定义)的可用性探测结果(`AcpClientRequirementProbe` / `RemoteAcpClientRequirementSnapshot`),缺失 npm adapter / CLI 时提供一键安装或降级提示,远程 workspace 复用本地配置并显式标注探测阶段。 + 2. **会话生命周期**:复用 `AcpClientService` 的 NewSession / LoadSession / ResumeSession / CloseSession 路径,在 UI 上统一「创建 ACP 会话」入口(沿用 `nav-workspace-menu-create-acp-session` testid),并补齐 load/resume 失败时的可重试临时状态提示。 + 3. **运行态配置**:把 `AcpSessionConfigOption`(boolean / select)与 `AcpSessionModelOption` 在会话侧栏统一呈现,使 fast-mode、thought_level 等与原生 reasoning catalog 对齐(参考 `src/web-ui/src/flow_chat/utils/acpSessionConfig.ts` 的 projection 逻辑)。 + 4. **工具与权限交互**:对齐 `tool_card_bridge` 的外部 agent tool 命名/结果形状与原生 tool card;permission 请求的 approve/reject + option 选择在 Web UI 上与原生工具确认流一致。 +- 实现边界遵循 `src/crates/interfaces/acp/AGENTS.md`:ACP 协议/客户端生命周期、stdio/连接归属、配置持久化、远程探测、timeout 策略留在 `bitfun-acp`;只把稳定能力事实透出给 UI 层,不在 Web UI 内重定义 ACP 协议或外部 agent tool 契约(后者归 `bitfun-agent-tools`)。 + +### 期望效果 / 使用场景 + +1. 用户在工作区菜单选择「创建 ACP 会话」,弹出客户端选择器,实时显示每个客户端的探测状态(已就绪 / 缺少依赖 / 远程探测中),缺依赖可一键安装。 +2. 进入会话后,侧栏能看到当前会话的模型与配置选项(fast-mode、thought_level 等),切换后立即生效并反映在下一轮 turn 的事件流中。 +3. 外部 agent 发起 tool call 或 permission 请求时,Web UI 以与原生工具一致的卡片/确认弹窗呈现,用户 approve/reject(含 option 选择)后 ACP 客户端继续 turn。 +4. 切换到远程 workspace 时,ACP 客户端复用本地配置并在 UI 显式标注探测阶段与降级原因,失败时给出可重试动作而非通用错误。 + +### 设计草案 / 参考示例 + +- 客户端探测与一键安装:参考 `src/crates/interfaces/acp/src/client/requirements.rs` 的 `probe_executable` / `probe_npm_adapter` / `install_npm_cli_package` 与远程对应实现,UI 映射 `AcpClientStatus`。 +- 会话配置投影:参考 `src/web-ui/src/flow_chat/utils/acpSessionConfig.ts` 的 `resolveAcpReasoningState` / `resolveAcpFastModeState`,与原生 `ReasoningCatalogProjection` 对齐。 +- 工具桥接:参考 `src/crates/interfaces/acp/src/client/tool_card_bridge/`(tool_name / tool_params)与 `bitfun_agent_tools::ACP_TOOL_PREFIX`,结果形状走 `bitfun-agent-tools` 既有契约。 +- 生命周期/事件:参考 `src/crates/interfaces/acp/src/client/manager.rs` 的常量(启动 60s / permission 600s / close 5s 等)与 `AcpClientStreamEvent` 投影。 + +### 是否愿意贡献 + +- [ ] 我愿意参与开发 +- [x] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 现有基线(非本需求新增):内置 preset、会话创建/列举、模型与 config option、permission 响应、tool card 桥接、远程复用本地配置的底层链路已在 `bitfun-acp` 实现。本需求聚焦 Desktop/Web UI 的体验收敛与一致性增强,不新增 ACP 协议字段,不迁移 client 生命周期归属。 +- 边界约束:不得在 `core-types` / `runtime-ports` / `agent-tools` 内重定义 ACP 配置/探测;外部 agent tool 契约归 `bitfun-agent-tools`;ACP stdio/连接/通知投影留在 `interfaces/acp`。 +- 验证基线:`cargo check -p bitfun-acp` / `cargo test -p bitfun-acp`(Rust 侧);Web UI 侧用 `pnpm run type-check:web` 及 `src/web-ui/src/flow_chat/utils/acpSessionConfig.test.ts` / `acpSession.test.ts` 覆盖。 +- 如需更窄范围(仅某一环,如「客户端健康度面板」或「远程 workspace 探测透明化」),可拆为独立 issue。 diff --git a/docs/features/agent-memory-config.md b/docs/features/agent-memory-config.md new file mode 100644 index 0000000000..fbf7a0069e --- /dev/null +++ b/docs/features/agent-memory-config.md @@ -0,0 +1,89 @@ +# Agent 记忆功能配置(Memory Configuration)需求文档 + +> 状态:需求 / 提案 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/extensions/capability-runtime-integration-design.md`](../architecture/extensions/capability-runtime-integration-design.md)(Memory 能力边界:可替换 vs 权威归属) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md)(分层与平台适配边界) +> - [`docs/architecture/peer-device-mode.md`](../architecture/peer-device-mode.md)(远程 / Peer 记忆归属) +> - [`docs/features/privacy-statement.md`](privacy-statement.md)(隐私同意状态门禁) +> 现有实现参考: +> - `src/web-ui/src/locales/*/settings/memories.json`(Settings → Memory:Basics / Extraction / Consolidation 配置契约) +> - `src/crates/services/services-core/src/session/memory_workspace.rs`(记忆工作区服务) +> - `src/crates/contracts/product-domains/src/privacy.rs`(`collection_allowed` 同意状态门禁) + +### 功能类型 + +- [ ] 新功能 +- [x] 现有功能增强 +- [x] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [ ] 高(P1 - 重要功能,期望尽快实现) +- [x] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun 已有较成熟的记忆配置(Settings → Memory:Basics / Extraction / Consolidation 三段,覆盖自动生成、使用、提取资格、外部上下文策略、空闲 / 年龄 / 限额 / 并发 / 模型、合并候选与保留),但配置面仍有缺口。 +- **缺少记忆内容的检视 / 编辑 / 删除单条入口**:现有只有 `resetMemory`(全量重置),用户无法查看 / 编辑 / 删除单条记忆、无法看到来源 provenance(来自哪个会话 / 时间),治理与信任不足。 +- **provenance 与审计可见性缺失**:`capability-runtime-integration-design.md` 把"记忆来源、使用范围、版本、删除 / 撤销事实、权限、审计和注入决策"列为权威归属事实,但用户侧缺少审计视图(谁 / 何时写入 / 删除 / 注入)。 +- **per-scope / per-workspace 配置缺失**:现有配置似为全局;多工作区 / 多项目下记忆范围与隔离需可配置,否则 A 项目记忆可能注入 B 项目会话。 +- **隐私门禁可见性不足**:记忆提取自会话 transcript,可能含敏感内容;自动生成 / 使用 / 注入应受隐私同意状态门禁(fail-closed),未同意 / 受限模式不提取、不注入、不向云端发送,且用户需能看到该门禁状态。 +- **远程 / Peer 场景策略缺失**:远程控制下记忆以受控端为准;peer 主机记忆读写需 deny 表对齐,控制器不应静默读写 peer 记忆。 +- **多 surface / 鸿蒙 PC 覆盖**:记忆配置与记忆数据在 CLI / Web / MobileWeb / 鸿蒙 PC 的一致性需保证。 + +### 功能描述 + +- **记忆检视 / 编辑 / 删除**:在 Settings → Memory 增加"查看记忆"入口,列出当前记忆条目(含来源会话、提取时间、版本);支持单条编辑、删除、撤销(标记为不使用而非物理删除,保留撤销事实);保留 `resetMemory` 全量重置。 +- **provenance 与审计**:每条记忆带 provenance(来源会话 id / 时间 / 提取模型 / 版本);提供审计视图(写入 / 删除 / 注入 / 撤销事件,含操作者与时间),只读、可导出,作为治理证据。 +- **per-scope 配置**:支持按工作区 / 项目配置记忆范围与隔离(哪些会话贡献、记忆是否跨工作区共享);默认本地工作区隔离,跨工作区共享需显式开启。 +- **隐私门禁**:记忆的自动生成、使用、注入受隐私同意状态门禁;未同意 / 受限模式(`PrivacyNotAccepted`)fail-closed 不提取、不注入、不向云端发送;记忆重置同步清理;用户可在设置中看到该门禁状态。 +- **远程 / Peer 策略**:远程控制下记忆以受控端为准;peer 记忆读写 deny 表三端(桌面 / CLI / FE)对齐,控制器不静默读写 peer 记忆;远程不可用时给出清晰不支持态提示而非静默失败。 +- **外部上下文与注入控制**:扩展现有 `externalContextPolicy`;新增"注入范围"配置(哪些记忆可注入新会话、是否需确认),注入决策保留为权威归属事实,不旁路。 +- **保留与版本**:保留策略可配置(`maxUnusedDays` 等),版本化记忆便于回滚;删除 / 撤销走权威归属模块,不旁路。 +- **多 surface 一致**:配置语义与记忆数据在桌面 / CLI / Web / MobileWeb / 鸿蒙 PC 一致,仅暴露方式按平台适配;UI 走 adapter / infrastructure 层,不直接调 host API。 +- **平台无关 + 平台适配**:记忆配置 DTO 与策略平台无关(contracts / services 层),平台适配器暴露;鸿蒙 PC 通过适配器接入,语义与桌面一致。 + +### 期望效果 / 使用场景 + +1. 用户在 Settings → Memory 查看记忆条目列表,看到每条来源(会话 / 时间 / 提取模型),可单条编辑 / 删除 / 撤销,无需全量重置即可精细管理。 +2. 用户查看审计视图,看到记忆写入 / 删除 / 注入 / 撤销事件(操作者 / 时间),可导出作为合规与治理证据。 +3. 用户按工作区配置记忆范围与隔离;A 工作区记忆默认不注入 B 工作区会话,跨工作区共享需显式开启。 +4. 用户未同意隐私声明 / 处于受限模式时,记忆自动生成与注入 fail-closed 不执行,不向云端发送;用户可在设置中看到该门禁状态。 +5. 远程控制下,记忆以受控端为准;控制器不静默读写 peer 记忆,deny 表三端对齐,远程不可用时给出清晰提示。 +6. 鸿蒙 PC 上记忆配置语义与桌面一致,通过适配器接入。 + +### 设计草案 / 参考示例 + +- **现有参考实现**: + - [`docs/architecture/extensions/capability-runtime-integration-design.md`](../architecture/extensions/capability-runtime-integration-design.md):Memory 能力边界——可替换(存储实现 / 检索器 / 排序器 / 写入候选处理器 / 保留策略)vs 权威归属(来源 / 范围 / 版本 / 删除撤销 / 权限 / 审计 / 注入决策);Memory Retriever 适用失败回退组合规则。 + - `src/web-ui/src/locales/*/settings/memories.json`:Basics / Extraction / Consolidation 配置契约——本需求在其上扩展检视 / 编辑 / 审计 / per-scope / 隐私门禁 / 远程策略。 + - `src/crates/services/services-core/src/session/memory_workspace.rs`:记忆工作区服务——检视 / 编辑 / 删除 / 撤销 / 审计的权威归属层。 + - `src/crates/contracts/product-domains/src/privacy.rs`:`collection_allowed()` 同意状态门禁——记忆生成 / 注入须服从。 +- **行业参照**:Claude Code memory(`CLAUDE.md` / 记忆文件)、Cursor 记忆、ChatGPT memory 的查看 / 编辑 / 删除与 provenance / 审计。 +- **落地分层建议**(遵循仓库分层与边界): + 1. Contracts(`src/crates/contracts/product-domains`):记忆条目 DTO(provenance / 版本 / 状态)、审计事件 DTO、扩展配置 DTO——平台无关、行为轻量。 + 2. Services(`src/crates/services/services-core` 的 `memory_workspace` + `services-integrations`):记忆检视 / 编辑 / 删除 / 撤销、审计、per-scope、保留与版本——权威归属在此,不旁路。 + 3. Assembly(`src/crates/assembly`):按 delivery profile 装配记忆能力与配置。 + 4. Interfaces / App / UI(`src/apps` + `src/web-ui`):桌面 host 暴露记忆 command;Web UI 扩展 Settings → Memory(检视 / 编辑 / 审计 / per-scope / 隐私门禁状态);UI 走 adapter / infrastructure 层,不直接调 host API。 +- **关键约束**:可替换的是存储 / 检索 / 排序 / 写入候选 / 保留策略;权威归属(来源 / 范围 / 版本 / 删除撤销 / 权限 / 审计 / 注入决策)不得旁路;隐私门禁 fail-closed;远程 deny 表三端对齐;不新增第二套记忆归属模块。 + +### 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 本需求为现有记忆配置的**增强**(现有 Basics / Extraction / Consolidation 已可用),聚焦检视 / 编辑 / provenance / 审计 / per-scope / 隐私门禁 / 远程策略缺口。 +- 记忆内容可能含敏感信息(提取自会话 transcript),隐私门禁与审计是合规与信任前置;未同意 / 受限模式 fail-closed,不得静默提取或注入。 +- 远程 / Peer 遵循仓库"远程兼容"全局规则与 deny 表三端对齐原则(参见 `computer-use-refactor-plan.md` 的 M14 修复方向)。 +- 鸿蒙 PC 是平台移植目标,记忆配置通过适配器接入,不属当前桌面优先范围但需保证语义一致(见 [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md))。 +- 不为覆盖竞品矩阵而引入第二套记忆归属模块或 `MemoryProviderRegistry` 等空壳公共对象(见 `capability-runtime-integration-design.md` 组合规则门槛)。 diff --git a/docs/features/builtin-terminal-panel.md b/docs/features/builtin-terminal-panel.md new file mode 100644 index 0000000000..dbc7539ce9 --- /dev/null +++ b/docs/features/builtin-terminal-panel.md @@ -0,0 +1,113 @@ +# 内置终端面板(Built-in Terminal Panel)需求文档 + +> 状态:能力规格 / 需求 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/web-ui/src/tools/terminal/`](../../src/web-ui/src/tools/terminal/) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) +> - [`terminal-capability.md`](./terminal-capability.md) + +## 背景与需求描述 + +BitFun 桌面端在工具区提供一个**内置终端面板**,让用户在应用内直接与 shell 交互(区别于 Agent 经 `BashTool` / `ExecCommand` 调用的终端能力——见 `terminal-capability.md`)。面板基于 xterm.js 渲染,消费后端 `terminal-core` 的 PTY / 会话服务。 + +本需求定义内置终端面板的目标范围与行为契约:多会话 / 多标签、shell 配置、输入输出、resize、回放、外观、快捷键作用域、复制粘贴。 + +当前缺口与诉求: + +- 面板须支持多会话并行与切换,会话可命名 / 配置 profile; +- 输出渲染须高效(懒加载、虚拟化),大量输出不卡顿; +- resize 须去抖与重绘守卫,避免逐帧重排; +- 输入须排队与 IME 安全,粘贴须安全处理(多行 / 控制字符); +- 外观经 appearance 适配(xterm 颜色 / 字体),与全局主题一致; +- 快捷键在终端作用域内独立,不与编辑器 / 全局冲突; +- 远程工作区下面板连接受控端会话。 + +## 期望行为 + +### 1. 会话与标签 + +- 创建 / 切换 / 关闭终端会话,多会话并行; +- 手动 profile(`manualTerminalProfileService`):命名 shell / 启动目录 / 环境变量; +- 面板偏好(`terminalPanelPreferenceService`):默认 profile、布局位置、字号偏好等持久化。 + +### 2. 渲染与输出 + +- xterm 渲染(`xtermRendering`);输出渲染器懒加载(`LazyTerminalOutputRenderer`)减少首屏负担; +- 会话回放(`terminalReplay`):切换会话 / 重连时回放历史输出,保序不重不漏; +- 大量输出有缓冲与截断策略,不阻塞 UI。 + +### 3. 输入与粘贴 + +- 输入队列(`TerminalInputQueue`):IME 组合期间缓冲,组合结束再提交; +- 粘贴(`terminalPaste`):多行粘贴确认、控制字符过滤 / 转义,避免粘贴危险控制序列; +- 终端作用域快捷键(`data-shortcut-scope="terminal"`)拦截复制 / 粘贴,不冒泡到全局。 + +### 4. Resize 与重绘 + +- resize 去抖(`TerminalResizeDebouncer`)+ 重绘守卫(`resizeRepaintGuard`),避免逐 mousemove / 逐 resize 重排全工作区(吸取 F4 教训); +- 容器尺寸变化时按 PTY 列 / 行 resize。 + +### 5. 外观 + +- xterm 外观经 `XtermAppearanceAdapter` 投影 appearance token(前景 / 背景 / ANSI 调色板 / 字体 / 字号); +- 外观随主题切换即时刷新; +- 终端字号可独立于全局(如 `DEPLOY_TERMINAL_FONT_SIZE` 先例)。 + +### 6. 快捷键作用域 + +- 终端作用域内复制 / 粘贴 / 切换会话等快捷键独立,不继承 canvas / 编辑器作用域; +- IME 占用时 Escape 类快捷键不触发(对齐 ShortcutManager 行为)。 + +### 7. 远程工作区 + +- 远程控制另一台桌面时,面板连接受控端会话,输入 / 输出在受控端; +- 在 `remote_workspace_policy` 中声明终端面板相关命令远程策略,不支持时清晰提示。 + +## 非目标 / 范围外 + +- 不定义终端服务 / PTY / 会话后端(见 `terminal-capability.md`); +- 不定义远程 SSH 终端 UI(属 `remote-ssh`); +- 不覆盖 CLI/TUI 形态终端(属 `src/apps/cli`); +- 不在本需求内做终端主题包编辑器(属 appearance); +- 不替换 xterm.js 渲染内核。 + +## 建议的落地路径(基于现有分层) + +1. **Web UI 组件 (`src/web-ui/src/tools/terminal/`)** — 面板主要落点: + - `components/`(`Terminal.tsx` / `ConnectedTerminal.tsx` / `TerminalOutputRenderer` / `LazyTerminalOutputRenderer`); + - `services/`(`TerminalService` / `TerminalActionManager` / profile / preference 服务); + - `hooks/useTerminal`、`utils/`(渲染 / resize / 粘贴 / 输入队列 / 回放)。 +2. **Web UI appearance 适配 (`src/web-ui/src/infrastructure/appearance/adapters/XtermAppearanceAdapter.ts`)** — xterm 外观投影。 +3. **Web UI 快捷键 (`src/web-ui/src/infrastructure/services/ShortcutManager.ts`)** — 终端作用域与冲突检测。 +4. **后端 (`src/crates/services/terminal`)** — PTY / 会话服务(见 `terminal-capability.md`)。 +5. **App (`src/apps/desktop`)** — Tauri command 装配,远程策略声明。 + +### 分层与依赖边界要点 + +- UI 组件不直调 Tauri,走 `infrastructure/api` adapter; +- 复用既有 component-library 与 Zustand store,不新造前端原语; +- 外观 token 走 appearance,颜色审计失败时复用 token / 合并冗余 / 加最小 owner contract,不抬 baseline; +- 远程策略显式声明,不引入对远程工作区路径的隐式依赖。 + +## 设计草案 / 参考示例 + +- **渲染参考**:`xtermRendering` + `LazyTerminalOutputRenderer` 懒加载输出。 +- **回放参考**:`terminalReplay` 切换 / 重连保序回放。 +- **输入参考**:`TerminalInputQueue` IME 缓冲;`terminalPaste` 多行 / 控制字符安全处理。 +- **resize 参考**:`TerminalResizeDebouncer` + `resizeRepaintGuard` 避免逐帧重排。 +- **外观参考**:`XtermAppearanceAdapter` 投影 appearance token;`DEPLOY_TERMINAL_FONT_SIZE` 独立字号先例。 +- **快捷键参考**:`data-shortcut-scope="terminal"` + ShortcutManager 作用域冲突检测。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与 `terminal-capability.md` 的关系:本需求定义**应用内面板 UI**,后者定义**服务 / 能力**;面板消费后者。 +- 与外观的关系:终端外观经 appearance 适配,主题变更走颜色审计。 +- 与远程工作区的关系:面板连接受控端会话,远程策略显式声明,不支持时清晰提示。 +- 相关分层入口:`src/web-ui/AGENTS.md`、`src/apps/desktop/AGENTS.md`、`src/crates/services/terminal/AGENTS.md`。 diff --git a/docs/features/builtin-tools-capability.md b/docs/features/builtin-tools-capability.md new file mode 100644 index 0000000000..bc102b0459 --- /dev/null +++ b/docs/features/builtin-tools-capability.md @@ -0,0 +1,136 @@ +# 内置 Tools(Built-in Tools)能力支持需求文档 + +> 状态:能力规格 / 需求 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) +> - [`docs/architecture/agent-runtime-services-design.md`](../architecture/agent-runtime-services-design.md) +> - [`src/crates/execution/tool-provider-groups/AGENTS.md`](../../src/crates/execution/tool-provider-groups/AGENTS.md) +> - [`src/crates/assembly/core/AGENTS.md`](../../src/crates/assembly/core/AGENTS.md) + +## 背景与需求描述 + +BitFun Agent 要"进入真实环境"完成任务,必须能读 / 写文件、执行命令、检索代码、控制会话、操作浏览器与桌面、对接 MCP、覆盖鸿蒙开发链。这些能力以**工具(Tools)**形式暴露给模型,模型在对话回合中按 schema 调用,运行时校验权限、执行、回传结构化结果。 + +工具来源分三类,本需求只覆盖第一类: + +1. **内置 Tools(Built-in Tools)**——随产品编译、稳定契约、跨 delivery profile 可选的官方工具集; +2. **MCP 工具**——经 MCP 协议接入的外部工具(见 `core.integration` 的 MCP 子集,属扩展层,不在本需求); +3. **插件 / 脚本工具**——经 PluginRuntime / script-tool-runtime 接入的第三方工具(属扩展层,不在本需求)。 + +内置 Tools 需要满足的核心诉求: + +- **稳定契约**:每个工具的 name / schema / 入参 / 出参 / 权限语义稳定,模型可在多轮中稳定调用; +- **特征归属**:每个内置工具精确归属一个 feature group(如 `basic` / `git` / `mcp` / `browser-web` / `computer-use` / `image-analysis` / `miniapp` / `canvas` / `agent-control`),按 owner feature 编译,`default = []`; +- **按 profile 选装**:不同 delivery profile(Desktop / CLI / Server / Web / ACP / Sdk …)按 `ProductToolPlan` 显式选择哪些 provider group 生效,非桌面形态可裁剪; +- **fail-closed 装配**:产品计划请求了某 group 而二进制未编译该 group 时,必须装配失败,不得从编译期 feature 推断或静默降级; +- **可见与可控**:工具 manifest 在 prompt 中对模型可见(展开 / 折叠两态),权限、取消、`ToolUseContext` 语义在桌面 / MCP / ACP 各 catalog 行为一致; +- **跨平台与鸿蒙覆盖**:基础工具平台无关,鸿蒙开发链(构建 / 启动 / hdc 日志 / ArkTS 检查 / UI 校验)作为 `core.openharmony` 子集独立维护。 + +## 期望行为 + +### 1. 工具分组与特征归属 + +内置工具按 **provider group** 组织,每个 group 声明其 feature groups 与 tool names: + +| provider id | feature groups | 代表工具 | +| --- | --- | --- | +| `core.basic` | basic, image-analysis | `LS`、`Read`、`Write`、`Edit`、`Delete`、`Glob`、`Grep`、`view_image`、`analyze_image`、`ExecCommand` / `WriteStdin` / `ExecControl`、`GetTime`、`ListModels` | +| `core.agent` | agent-control, git | `Task`、`AgentWait`、`LaunchReviewAgent`、`Skill`、`AskUserQuestion`、`TodoWrite`、`get_goal` / `create_goal` / `update_goal`、`CreatePlan`、`submit_code_review`、`GetToolSpec`、`CallDeferredTool`、`GetFileDiff` | +| `core.canvas` | canvas | `CreateCanvas` / `ReadCanvas` / `UpdateCanvas` / `PatchCanvas` | +| `core.session` | agent-control | `SessionControl`、`SessionMessage`、`SessionHistory`、`Cron` | +| `core.integration` | browser-web, mcp, git, miniapp, computer-use | `WebSearch`、`WebFetch`、MCP 资源 / prompt 工具、`GenerativeUI`、`Git`、`Worktree`、`ReviewPlatform`、MiniApp / Appearance / Page 发布工具、`ControlHub`、`ComputerUse`、`Playbook` | +| `core.openharmony` | basic | `build_project`、`start_app`、`hdc_log`、`arkts_knowledge_search`、`check_arkts_files`、`check_cpp_files`、`switch_cwd`、`verify_ui`、`get_ui_verification_log`、`save_ui_screenshot` | + +- 一个 provider 可包含来自多个 feature owner 的工具;**工具到 feature group 的精确映射**由 `bitfun-tool-packs` 作为 owner 权威。 +- 编译期 availability 是**验证事实**而非运行时推断来源;materialization 必须在"计划请求了未编译 group"时 fail closed。 + +### 2. 装配与可见性 + +- `ProductToolPlan` 由 Product Assembly 提供**确切**计划,Core materialization 校验请求的 owner 是否已编译,**不得**从 Cargo feature 并集推断产品能力; +- Agent Runtime 基线计划恰好是 `Basic` + `AgentControl`,不是隐藏的 delivery profile; +- 工具 manifest 在 prompt 中按展开 / 折叠两态对模型可见;新增 / 迁移工具必须保持 collapsed 暴露、prompt stub、unlock 状态、取消、运行时限制与 Deep Review 工具流不变; +- `GetToolSpec` 在产品工具运行时边界执行,供模型按需获取工具规格。 + +### 3. 权限与取消 + +- 工具调用经权限门 / 确认门(confirmation gate)后才执行; +- turn、tool、subagent、harness step 都必须接收 cancellation,长任务工具(ExecCommand、Task、ComputerUse 等)支持中途取消; +- `ToolUseContext` 语义在桌面 / MCP / ACP 各 catalog 保持一致。 + +### 4. 跨平台与鸿蒙 + +- 基础工具(文件 / 检索 / 执行 / 时间 / 模型列表)平台无关; +- `core.openharmony` 子集覆盖鸿蒙开发链:构建(`build_project`)、启动(`start_app`)、设备日志(`hdc_log`)、ArkTS 知识检索与静态检查(`arkts_knowledge_search` / `check_arkts_files` / `check_cpp_files`)、UI 校验(`verify_ui` / `get_ui_verification_log` / `save_ui_screenshot`)、工作目录切换(`switch_cwd`); +- 鸿蒙子集作为独立 provider 维护,不与基础工具混编,便于按 profile 裁剪。 + +### 5. 远程工作区 + +- 远程控制另一台桌面时,工具执行归属受控端;控制端只发起与展示; +- 在 `remote_workspace_policy` 中声明每个内置工具(尤其写文件、执行命令、Git、ComputerUse)的远程策略,不支持时清晰提示而非静默失败。 + +### 6. 可扩展与稳定性 + +- 新增内置工具:指定唯一 feature group owner + 覆盖该 group 全列表的边界校验 + provider group 计划登记; +- 工具迁移必须保持产品注册表顺序、展开 / 折叠暴露、prompt stub、unlock 状态、取消、运行时限制、Deep Review 工具流; +- 工具 schema 变更视为破坏性变更,需走契约评审。 + +## 非目标 / 范围外 + +- 不在本需求内定义 MCP 工具接入协议(属 `core.integration` 的 MCP 子集,见 MCP runtime owner); +- 不在本需求内定义 PluginRuntime / script-tool-runtime 第三方工具(属扩展层); +- 不在本需求内定义 Skills / Hooks / MiniApp / 自定义 Agent 等其他扩展层; +- 不在本需求内做工具调用的模型适配层 / AI 序列化(属 adapters); +- 不覆盖 HarmonyOS PC CLI/TUI 形态(见 `platform-portability-design.md`,需单独立项); +- 不承诺工具结果的自动可视化渲染(MiniApp / Canvas 才负责界面呈现)。 + +## 建议的落地路径(基于现有分层) + +依据仓库的分层与边界规则,内置 Tools 的各部分应归属: + +1. **Contracts (`src/crates/contracts`)** — 工具调用 / 结果 / 权限 / `ToolUseContext` 的稳定 DTO 与 port trait,行为轻量、不向上依赖。 +2. **Execution / Tool Provider Groups (`src/crates/execution/tool-provider-groups`,包名 `bitfun-tool-packs`)** — 内置工具的**事实层**: + - feature group 元数据、稳定的 tool→feature 映射、product tool provider group plan、按 id 选择 provider group plan; + - **不拥有** manifest / 暴露契约、具体运行时 manifest 装配、`GetToolSpec` 执行、collapsed unlock 状态、snapshot 装饰、`ToolUseContext`; + - 边界:`default = []`,`product-full` 可聚合但不得静默启用新运行时行为;不依赖 core / service / app / Tauri / Git / MCP / 网络 / CLI UI。 +3. **Execution / Tool Contracts & Execution (`tool-contracts`、`tool-execution`)** — 工具契约、执行门、入参校验、结果呈现契约;低层文件 / 检索 / 工具 IO、ExecCommand 呈现事实、Computer Use 循环 / 重试策略、prompt-safe 工具上下文事实。 +4. **Assembly / Core (`src/crates/assembly/core`)** — 工具**具体实现与运行时 materialization**: + - `src/agentic/tools/implementations/` 下按 owner feature 编译各工具(`tools-image-analysis` / `tools-miniapp` / `tools-canvas` / `tools-computer-use` / `tools-browser-web` / `tools-agent-control` / `tools-mcp` / `tools-git`); + - 产品工具运行时边界执行 `GetToolSpec`、manifest 装配、展开 / 折叠暴露、unlock 状态、permission / `ToolUseContext` 语义; + - 校验请求的 owner 已编译,fail closed;不从 feature 并集推断产品能力。 +5. **Services (`src/crates/services`)** — 工具调用的具体 OS / 进程 / 文件系统 / Git / 终端 / MCP / 远端 SSH / 浏览器控制 / web 工具网络 provider 实现,按各自 owner feature 启用。 +6. **App / UI (`src/apps/desktop` + `src/web-ui`)** — 桌面宿主装配工具注册表、暴露权限确认 UI、工具调用展示;UI 组件不得直接调用工具运行时或 OS API,必须走 adapter / service 层。 + +### 分层与依赖边界要点 + +- 产品逻辑平台无关:工具契约、provider group 事实、feature 映射在 `tool-provider-groups` 与 `tool-contracts`,平台无关;具体实现与 IO 在 Core / Services; +- `tool-provider-groups` 不得依赖 core / concrete service / app;Core materialization 不得反向依赖 `tool-provider-groups` 的运行时状态(只用其计划事实); +- 新增内置工具 = 一个确切 feature group owner + group 全列表边界覆盖 + provider group 计划登记 + 实现按 owner feature 编译; +- 编译期 availability 是验证事实:计划请求未编译 group 时 fail closed,绝不从 Cargo feature 推断或检视运行时 / 权限 / 服务健康来"凑出"计划; +- 按 owner feature 过滤被 `ProductToolPlan` 省略的工具是**产品选择**,不是降级; +- HarmonyOS 子集(`core.openharmony`)独立维护,便于按 profile 裁剪与未来鸿蒙化专题推进。 + +## 设计草案 / 参考示例 + +- **provider group 计划参考**:`bitfun-tool-packs` 的 `PRODUCT_TOOL_PROVIDER_GROUP_PLAN` 把六个 provider(basic / agent / canvas / session / integration / openharmony)的 feature groups 与 tool names 登记为静态事实;新增工具在此登记,并保证 `try_product_tool_provider_group_plan_for_ids` 对未知 provider id 报错。 +- **feature 映射参考**:`tool_feature_group` 是 tool→feature 的 owner 权威映射;一个 provider 可跨多 feature owner(如 `core.integration` 跨 browser-web / mcp / git / miniapp / computer-use)。 +- **fail-closed 装配参考**:`unavailable_feature_groups` 报告请求但二进制未编译的 group;materialization 拿到该报告后必须失败,不静默降级。 +- **manifest 暴露参考**:展开 / 折叠两态 + `GetToolSpec` 按需取规格;迁移工具必须保持 collapsed 暴露、prompt stub、unlock 状态不变。 +- **取消参考**:turn / tool / subagent / harness step 都接收 cancellation;ExecCommand 的 `ExecControl` / `WriteStdin` / background output 是长任务取消的范本。 +- **鸿蒙子集参考**:`core.openharmony` 把 build / start / hdc / arkts / ui-verify 等鸿蒙开发链工具收口为一个 provider,便于按 delivery profile 裁剪,并与 `platform-portability-design.md` 的"每个鸿蒙差异独立建专题"原则一致。 +- **远程策略参考**:写文件 / 执行命令 / Git / ComputerUse 等高风险工具在 `remote_workspace_policy` 中逐工具声明远程策略。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 本需求严格遵循仓库"产品逻辑平台无关、再通过平台适配器暴露""优先事实与决策、具体 IO 下沉""编译期 availability 是验证事实而非推断来源"的规则。 +- 与 `skill-capability-support.md` 的关系:Skill 是 prompt / instruction 注入的扩展(L2),内置 Tools 是 Agent 直接调用的能力(L0);两者互补,`Skill` 工具本身是 `core.agent` 下的一个内置 Tool,用于显式调用 Skill。 +- 与 `gewu-market-integration.md` 的关系:市场分发的是 Skills / MiniApp / Appearance 等扩展资产;内置 Tools 随产品编译,不经市场分发。 +- 与 MCP / PluginRuntime 的关系:内置 Tools 是稳定官方集;MCP / 插件是外部扩展,经 `core.integration` 与 PluginRuntime 接入,不在本需求。 +- 远程工作区策略:内置工具(尤其写 / 执行 / Git / ComputerUse)的远程策略在 `remote_workspace_policy` 中逐工具显式声明,不支持时清晰提示。 +- 相关分层入口:`src/crates/contracts/AGENTS.md`、`src/crates/execution/tool-provider-groups/AGENTS.md`、`src/crates/execution/tool-contracts/AGENTS.md`、`src/crates/assembly/core/AGENTS.md`、`src/crates/services/AGENTS.md`。 diff --git a/docs/features/conversation-archiving-desktop-web-ui.md b/docs/features/conversation-archiving-desktop-web-ui.md new file mode 100644 index 0000000000..5fc0844f79 --- /dev/null +++ b/docs/features/conversation-archiving-desktop-web-ui.md @@ -0,0 +1,71 @@ +# 对话归档能力增强(Desktop / Web UI)功能提案 + +> 状态:提案 / 待评审 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/agent-runtime-lifecycle-sequence.md`](../architecture/agent-runtime-lifecycle-sequence.md) +> - [`docs/architecture/agent-runtime-services-design.md`](../architecture/agent-runtime-services-design.md) +> - [`docs/architecture/agent-runtime-deployment-design.md`](../architecture/agent-runtime-deployment-design.md) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) + +### 功能类型 + +- [ ] 新功能 +- [x] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [x] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun 已具备单会话归档基线:`AgentSessionManagementPort` 的 `archive_session` / `set_session_archived`、Web UI `archived-sessions` 设置 tab、`SessionStatus = 'active' | 'archived' | 'completed'`、`archive_session`/`unarchive_session` 经 websocket 映射到 `session/setArchived`、会话驱动(local/dispatch)实现 `archiveSession`、FlowChatStore 跳过已归档会话。但归档体验仍停留在「单条手动归档 → 设置页查看」的最小闭环,缺少批量、检索、留存策略与跨 surface 一致性。 +- 痛点:① 会话数量增长后只能逐条归档/取消归档,无批量操作;② 归档列表缺少按名称/内容/时间/工作区检索与筛选,找历史对话困难;③ 无自动归档与留存策略(如按闲置时长自动归档、超期自动清理),归档目录本身会膨胀;④ 归档对话不能导出/分享(markdown/transcript),跨设备或留档困难;⑤ 远程/Peer/ACP 等 surface 的归档可见性与一致性行为未对齐;⑥ 归档存储用量与归档数量对用户不透明。 + +### 功能描述 + +- 在 Desktop/Web UI 增强对话归档端到端体验,覆盖六个环节: + 1. **批量操作**:在会话列表与归档页支持多选归档 / 取消归档 / 删除,带二次确认;批量操作原子化,部分失败时返回失败项与原因而非整体回滚。 + 2. **检索与筛选**:归档列表支持按名称、内容片段、归档时间、原工作区、标签筛选与排序;复用既有会话元数据索引,不引入第二套 transcript 查询 API。 + 3. **自动归档与留存策略**:设置中可选自动归档策略(按闲置时长 / 按完成状态 / 按工作区),可选留存期(超期自动清理或仅提示);策略只写会话元数据标志与时间戳,运行时按策略扫描,不新建常驻调度器之外的的服务 owner。 + 4. **导出与分享**:归档对话支持导出为 markdown / transcript(只读,复用 `SessionTranscriptReader` 既有只读读取),导出不含运行时句柄或权限凭证;支持单条与批量导出。 + 5. **取消归档与恢复**:取消归档后会话回到活动列表,状态由 `archived` → `active`,保留元数据与 lineage;恢复冲突(如同名 / 已存在)给出可重试动作而非静默失败。 + 6. **跨 surface 一致性与可观测**:归档状态经稳定会话事实对齐远程 / Peer / ACP 入口(`Session archive` 当前不在 Shared deployment 协议内,需先明确各 surface 的归档可见性策略,缺失时返回类型化 `unsupported` 而非静默不一致);设置页展示归档数量与归档存储用量。 +- 实现边界遵循会话管理归属:归档是 `AgentSessionManagementPort` 的元数据级操作(`archive_session` / `set_session_archived` / `delete_session`),不等于删除,不构成通用 operation 查询 API;自动归档策略属产品级会话管理,不迁移到 `core-types` / `runtime-ports`;导出只消费 `SessionTranscriptReader` 只读事实,不在 UI 层重定义 transcript schema;远程归档可见性受 `agent-runtime-deployment-design.md` 既有约束(Shared GUI/Headless/ACP/SDK Host/Remote 的 Session archive 未交付),需以明确端口策略先行。 +- 非目标:不做通用「会话市场」或在线同步;不为本提案引入跨 workspace attach 或 transcript 分页(属 deployment 设计已明确的未交付项);不做归档对话的再编辑,归档为只读视图。 + +### 期望效果 / 使用场景 + +1. 用户在会话列表多选若干已完成对话,一键归档并二次确认;归档后从活动列表消失,进入归档页统一管理。 +2. 用户在归档页按名称或内容片段检索历史对话,按归档时间排序,快速定位后可查看只读 transcript 或取消归档回到活动列表。 +3. 用户开启「闲置 30 天自动归档」与「归档超 1 年提示清理」策略,归档目录自动收敛,无需手动维护。 +4. 用户将某归档对话导出为 markdown 存档或分享,导出内容为只读 transcript,不含运行时句柄或凭证。 +5. 远程 / Peer 端查看归档状态与桌面一致;若该 surface 暂不支持归档可见性,显式标注 `unsupported` 而非静默隐藏。 + +### 设计草案 / 参考示例 + +- 端口复用:归档/取消归档/删除走 `AgentSessionManagementPort` 的 `archive_session` / `set_session_archived` / `delete_session`;元数据 `SessionStatus = 'active' | 'archived' | 'completed'`。 +- 检索:复用既有会话元数据索引(`services-core` 的 session 存储布局/索引/删除),不新增通用 transcript 查询 API。 +- 导出:复用 `SessionTranscriptReader` 只读读取,产出 markdown / transcript,禁带运行时句柄与权限凭证。 +- 自动策略:产品级会话管理扫描 + 元数据标志/时间戳;不新建常驻调度器之外的服务 owner。 +- 跨 surface:归档可见性策略先行明确各入口(远程/Peer/ACP/SDK Host),缺失返回类型化 `unsupported`。 + +### 是否愿意贡献 + +- [ ] 我愿意参与开发 +- [x] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 现有基线(非本需求新增):单会话归档/取消归档、`archived-sessions` 设置 tab、`SessionStatus` 归档态、`session/setArchived` wire、local/dispatch 驱动 `archiveSession`、FlowChatStore 跳过已归档。本需求聚焦批量/检索/留存/导出/跨 surface 一致性的体验收敛。 +- 边界约束:归档是元数据级操作,不等于删除,不构成通用 operation 查询 API;自动归档策略不迁移到 `core-types` / `runtime-ports`;导出不重定义 transcript schema;远程归档可见性受 deployment 设计既有约束,Shared GUI/Headless/ACP/SDK Host/Remote 的 Session archive 当前未交付,需以明确端口策略先行而非隐式启用。 +- 验证基线(建议):Web UI 侧 `pnpm run type-check:web` 及归档相关单测(`websocket-adapter`、`FlowChatStore` 归档跳过、`ArchivedSessionsConfig`);Rust 侧归档端口属 `agent-runtime` / `session_management`,按其 AGENTS 选取最窄命令;跨 surface 变更按 `agent-runtime-deployment-design.md` 完成 focused review。 +- 若需扩展到「归档标签/文件夹」「归档对话再编辑」或「在线同步」,可作为本提案的后续增强单独评审,不在本范围内。 diff --git a/docs/features/editor-basic-settings.md b/docs/features/editor-basic-settings.md new file mode 100644 index 0000000000..584ff78b81 --- /dev/null +++ b/docs/features/editor-basic-settings.md @@ -0,0 +1,106 @@ +# 编辑器基本设置(Editor Basic Settings)需求文档 + +> 状态:能力规格 / 需求 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/web-ui/src/tools/editor/config/types.ts`](../../src/web-ui/src/tools/editor/config/types.ts) +> - [`src/web-ui/src/tools/editor/config/defaults.ts`](../../src/web-ui/src/tools/editor/config/defaults.ts) +> - [`src/web-ui/src/tools/editor/services/EditorOptionsBuilder.ts`](../../src/web-ui/src/tools/editor/services/EditorOptionsBuilder.ts) +> - [`src/web-ui/src/tools/editor/core/MonacoEditorCore.tsx`](../../src/web-ui/src/tools/editor/core/MonacoEditorCore.tsx) +> - [`font-size-setting.md`](./font-size-setting.md) + +## 背景与需求描述 + +BitFun 桌面端内置 Monaco 代码编辑器,提供文件查看 / 编辑、跨文件跳转(`EditorJumpService`)、diff(`MonacoDiffCore`)。编辑器选项经 `EditorOptionsBuilder` 由 `config/types` + `config/defaults` 构造,已支持 tabSize、wordWrap、lineNumbers、minimap 等基本项。 + +本需求定义编辑器**基本设置**的目标范围与行为契约,让用户按习惯配置编辑器,并保证 Agent 编辑工具(`Edit` / `Write`)与用户编辑器选项不互相干扰。 + +当前缺口与诉求: + +- 已有 tabSize / wordWrap / lineNumbers / minimap,但渲染空白、自动保存、括号配对着色、行高、字号、格式化等基本项须明确纳入设置; +- 设置须持久化、跨重启生效、随工作区可覆盖; +- diff 编辑器共享基础选项,须与普通编辑器一致; +- 编辑器选项变化须高效更新(`updateOptions`),不重建实例; +- Agent 的 `Edit` / `Write` 工具不受用户编辑器显示选项影响(显示与执行分离)。 + +## 期望行为 + +### 1. 基本设置项 + +- **缩进**:tabSize(默认 2)、是否空格转 tab; +- **换行**:wordWrap(off / on / wordWrapColumn / bounded); +- **行号**:lineNumbers(on / off / relative / interval); +- **缩略图**:minimap(enabled / side / size); +- **渲染空白**:renderWhitespace(none / boundary / selection / all); +- **字号 / 行高**:经 appearance(见 `font-size-setting.md`),编辑器独立可调; +- **括号配对着色 / 引导**:bracketPairColorization / guides; +- **自动保存 / 格式化(可选)**:首版可不启用,预留接口。 + +### 2. 持久化与覆盖 + +- 设置持久化到 config(如 `editor.*`),跨重启生效; +- 全局默认 + 工作区覆盖(工作区级优先); +- 切换工作区时按覆盖刷新选项(`updateOptions`),不重建编辑器。 + +### 3. diff 与跳转 + +- diff 编辑器共享基础选项(`MonacoDiffCore`,`diffWordWrap` 等基继承); +- 跨文件跳转(`EditorJumpService` / `EditorReadyManager`)行为不受显示选项影响; +- 行号 / 缩略图变化不破坏跳转定位。 + +### 4. 显示与执行分离 + +- 用户编辑器显示选项(行号 / 缩略图 / 换行)不影响 Agent `Edit` / `Write` 工具的执行语义; +- Agent 编辑工具走文件系统与 edit constraint guard,与 Monaco 显示选项解耦。 + +### 5. 更新与性能 + +- 选项变化经 `buildEditorOptions` 构造后 `editor.updateOptions(...)` 增量更新; +- 不因选项变化触发全工作区重渲染(吸取 F4 教训); +- `MonacoEditorCore` 的 `lineNumbers` / `minimap` ref 跟随设置刷新。 + +## 非目标 / 范围外 + +- 不定义 LSP 功能(跳转定义 / 重命名 / 诊断,属 LSP owner); +- 不做完整 VS Code 选项对齐,只覆盖基本阅读 / 编辑项; +- 不定义外观 / 主题(属 appearance); +- 不覆盖 CLI/TUI 编辑形态; +- 不定义 Agent `Edit` / `Write` 工具执行契约(属 builtin-tools)。 + +## 建议的落地路径(基于现有分层) + +1. **配置类型与默认 (`src/web-ui/src/tools/editor/config/types.ts`、`defaults.ts`)** — 设置项类型与默认值(tabSize / wordWrap / lineNumbers / minimap 等)。 +2. **选项构造 (`src/web-ui/src/tools/editor/services/EditorOptionsBuilder.ts`)** — 由 config 构造 Monaco options,含 diff 继承。 +3. **编辑器核心 (`src/web-ui/src/tools/editor/core/MonacoEditorCore.tsx`、`MonacoDiffCore.tsx`)** — `updateOptions` 增量刷新,ref 跟随。 +4. **外观适配 (`MonacoAppearanceAdapter`)** — 字号 / 字体 / 行高投影(见 `font-size-setting.md`)。 +5. **设置 UI (`src/web-ui/src/app/scenes/settings/`)** — 编辑器基本设置控件。 +6. **Config** — 持久化 `editor.*`,工作区覆盖。 + +### 分层与依赖边界要点 + +- UI 组件不直调 Tauri;编辑器选项纯前端; +- 复用 Monaco + EditorOptionsBuilder,不新造第二套选项体系; +- 外观 token 经 appearance 适配,颜色审计独立; +- 显示选项与 Agent 执行工具解耦; +- 选项变化不触发全工作区逐帧重渲染。 + +## 设计草案 / 参考示例 + +- **选项参考**:`EditorOptionsBuilder` 已构造 tabSize / wordWrap / lineNumbers / minimap / lineNumbersMinChars。 +- **默认值参考**:`config/defaults.ts`(tabSize: 2、wordWrap: 'off'、lineNumbers: 'on'、minimap 默认)。 +- **diff 继承参考**:`MonacoDiffCore` 共享 `showMinimap` / `showLineNumbers` ref。 +- **更新参考**:`MonacoEditorCore` 的 `editor.updateOptions(editorOptions)` 增量刷新。 +- **跳转参考**:`EditorJumpService` / `EditorReadyManager` 不受显示选项影响。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与 `font-size-setting.md` 的关系:编辑器字号经 appearance 适配,由字号设置驱动。 +- 与 Agent 编辑工具的关系:显示选项与 `Edit` / `Write` 执行解耦,互不干扰。 +- 与外观的关系:字体 / 字号 / 行高经 `MonacoAppearanceAdapter`,颜色经主题 token。 +- 相关分层入口:`src/web-ui/AGENTS.md`、`docs/architecture/theme-token-optimization.md`。 diff --git a/docs/features/font-size-setting.md b/docs/features/font-size-setting.md new file mode 100644 index 0000000000..f4be115c8c --- /dev/null +++ b/docs/features/font-size-setting.md @@ -0,0 +1,101 @@ +# 字体大小设置(Font Size Setting)需求文档 + +> 状态:提案 / 未做 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/web-ui/src/infrastructure/appearance/appearanceDomainTokens.ts`](../../src/web-ui/src/infrastructure/appearance/appearanceDomainTokens.ts) +> - [`src/web-ui/src/app/styles/nav-panel-font-scope.scss`](../../src/web-ui/src/app/styles/nav-panel-font-scope.scss) +> - [`src/web-ui/src/features/relay-deploy/RelayDeployWizard.tsx`](../../src/web-ui/src/features/relay-deploy/RelayDeployWizard.tsx) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) + +## 背景与需求描述 + +BitFun 桌面端的字号经 appearance token 体系驱动(`--bf-appearance-token-font-size-*` 分级),导航面板经 `nav-panel-font-scope.scss` 在 flow-chat 字号基础上降一档映射,个别场景(如 relay-deploy 终端)用独立 `DEPLOY_TERMINAL_FONT_SIZE`。但**缺少用户可调的全局字号 / 缩放设置**:用户无法根据视力、屏幕 DPI、个人偏好统一放大或缩小应用字号,只能接受 appearance 包预设。 + +当前缺口与诉求: + +- 无用户可调的全局字号缩放(zoom / font scale); +- 编辑器、终端、聊天三个长阅读区无法分别调字号; +- 高 DPI / 小屏下预设字号偏小,用户无法自助调整; +- 无障碍场景(视力差异)缺乏字号自适应。 + +本提案新增**用户字号设置**:全局缩放 + 每个长阅读区(编辑器 / 终端 / 聊天)独立字号,复用既有 appearance token 体系,不新造第二套字号变量。 + +## 期望行为 + +### 1. 全局字号缩放 + +- 在设置中提供全局字号缩放(如 80%–150% 或档位 sm/md/lg/xl),作用于 appearance 字号 token 基线; +- 缩放经 appearance runtime 即时刷新全应用,不需重启; +- 有上下限,避免过大破版或过小不可读。 + +### 2. 每阅读区独立字号 + +- 编辑器字号(Monaco `fontSize` / `lineHeight`)独立可调; +- 终端字号(xterm `fontSize`,对齐 `DEPLOY_TERMINAL_FONT_SIZE` 先例)独立可调; +- 聊天字号(flow-chat 字号 token)独立可调; +- 各区字号可"跟随全局"或"自定义",自定义优先级高于全局。 + +### 3. 持久化与外观集成 + +- 字号设置持久化到 config(如 `app.fontSize` / `appearance.fontSize.*`); +- 经 appearance runtime / compiler 投影到 CSS 变量与 Monaco / xterm 选项; +- 切换 appearance 包时保留用户字号覆盖; +- nav-panel-font-scope 的降档映射随全局基线同步缩放,保持相对关系。 + +### 4. 可访问性与边界 + +- 字号缩放不影响布局网格 / 间距 token(只缩字号族); +- 极端字号下布局不破:聊天输入、面板、对话框保持可用(吸取 F4 / F7 逐帧重排教训,避免缩放触发全工作区重渲染); +- 键盘可达等价路径(设置入口可键盘聚焦)。 + +### 5. i18n 与默认值 + +- 默认值随 appearance 包(已有的字号 token 基线); +- 文案走 i18n(`appearance.fontSize.*`),shared terms 进 `src/shared/i18n`。 + +## 非目标 / 范围外 + +- 不做 appearance 包 / 主题包的作者编辑器(属 appearance / 主题); +- 不改主题颜色 token(颜色审计独立); +- 不做每组件任意字号(已有 token 体系,不做更细粒度); +- 不覆盖 CLI/TUI 字号(属 `src/apps/cli/themes`); +- 不做字号跨设备云同步(属 remote connect)。 + +## 建议的落地路径(基于现有分层) + +1. **Appearance tokens (`src/web-ui/src/infrastructure/appearance/appearanceDomainTokens.ts`)** — 字号 token 基线,作为缩放锚点。 +2. **Appearance runtime / compiler (`src/web-ui/src/infrastructure/appearance/runtime/AppearanceService.ts`、`compiler/AppearanceCompiler.ts`)** — 应用全局缩放与每区覆盖,投影到 CSS 变量。 +3. **适配器 (`src/web-ui/src/infrastructure/appearance/adapters/MonacoAppearanceAdapter.ts`、`XtermAppearanceAdapter.ts`)** — 字号投影到 Monaco / xterm 选项。 +4. **Config** — 持久化 `app.fontSize` / `appearance.fontSize.*`。 +5. **设置 UI (`src/web-ui/src/app/scenes/settings/`)** — 字号缩放与每区字号控件。 +6. **nav-panel-font-scope** — 随全局基线同步降档。 + +### 分层与依赖边界要点 + +- UI 组件不直调 Tauri;字号纯前端 appearance 体系; +- 复用 appearance token 与 runtime,不新造第二套字号变量; +- 颜色 token 不变,颜色审计不受影响; +- 缩放不触发全工作区逐帧重渲染(CSS 变量驱动,吸取 F4 教训); +- i18n 文案走命名空间懒加载。 + +## 设计草案 / 参考示例 + +- **token 锚点参考**:`--bf-appearance-token-font-size-*`(xxs–4xl)分级,作为缩放基线。 +- **降档映射参考**:`nav-panel-font-scope.scss` 在 flow-chat 字号基础上降一档,保持相对关系。 +- **独立字号先例**:`DEPLOY_TERMINAL_FONT_SIZE` 为终端独立字号提供先例。 +- **适配器参考**:`MonacoAppearanceAdapter` / `XtermAppearanceAdapter` 已投影字体 / 字号,扩展即可。 +- **交互参考**:常见 IDE 的"字号缩放(Ctrl +/-)+ 设置面板每区字号"。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与 appearance 的关系:复用字号 token 与 runtime,不新造第二套变量;切换 appearance 包保留用户覆盖。 +- 与可访问性的关系:字号缩放是无障碍基础项,须保证极端字号下不破版。 +- 与终端 / 编辑器的关系:经 `XtermAppearanceAdapter` / `MonacoAppearanceAdapter` 投影,不绕过 appearance。 +- 相关分层入口:`src/web-ui/AGENTS.md`、`docs/architecture/theme-token-optimization.md`。 diff --git a/docs/features/gewu-market-integration.md b/docs/features/gewu-market-integration.md new file mode 100644 index 0000000000..f00793162c --- /dev/null +++ b/docs/features/gewu-market-integration.md @@ -0,0 +1,84 @@ +# 接入格物市场(Gewu Market)精品 Skills 功能提案 + +> 状态:提案 / 未集成 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) +> - [`deploy/miniapp-market/README.md`](../../deploy/miniapp-market/README.md) +> - [`src/crates/services/services-integrations/AGENTS.md`](../../src/crates/services/services-integrations/AGENTS.md) + +## 背景与需求描述 + +BitFun 的扩展能力分四层:自定义 Agent → MCP / Skills / Hooks → Mini Apps → 源码级改造。其中 **Skills** 是 prompt / resource / instruction 形态的轻量扩展,作为 agent definition 或 harness input 的一部分参与运行。 + +在 HarmonyOS 生态中,**格物市场** 是华为提供的精品 Skills 分发市场。`HUAWEI BitFun ADE` 的产品定位(见 `src/crates/services/services-integrations/src/privacy/assets/zh-CN.md`)明确包含"融合鸿蒙 Harness、**格物市场精品 Skills**、鸿蒙开发工具链及知识库"。当前仓库尚未接入格物市场,存在以下缺口: + +- 用户无法在 BitFun 内浏览 / 检索 / 安装格物市场上的精品 Skills,只能手动复制 Skill 文件到本地 Skills 根目录; +- Skills 的版本更新、来源校验、卸载清理没有受控流程,易残留过期或来源不明的 Skill; +- 开发者无法把自研精品 Skill 经由格物市场分发,只能各自托管; +- 与 MiniApp 市场(`market.openbitfun.com/miniapp`)、Skin 市场(`market.openbitfun.com/skin`)已建成的受控分发链相比,Skills 这条扩展路径缺少等价的接入能力。 + +因此希望在桌面端(`DeliveryProfile::Desktop` / `ProductFull`,并优先覆盖 HarmonyOS / `HUAWEI BitFun ADE` 形态)新增"接入格物市场精品 Skills"能力,作为 Skills 扩展层的官方分发通道。 + +## 期望行为 + +- 在 Settings 或扩展管理区提供"格物市场"入口,可浏览 / 检索精品 Skills 列表与详情; +- 一键安装到本地 Skills 根目录(与现有 `file_watch` 管理的 `bitfun-skills` 目录约定一致),安装后立即可被 Agent 运行时发现; +- 支持检查已安装 Skill 的版本,并在市场有新版本时提示更新;支持卸载并清理对应文件; +- 安装包下载附完整性校验(哈希 / 签名,参照 `miniapp-market-service/src/package.rs` 的校验策略),失败可回滚不残留半截文件; +- 支持开发者从 BitFun 把自研 Skill 提交到格物市场(投稿 / 更新 / 撤回),走格物市场自身的审核与发布流程; +- 账号体系优先复用格物市场 / HarmonyOS 账号体系,不强行新造登录;本地仅保存最小凭据,绝不把凭据写进日志或产物; +- 非桌面 / 非 HarmonyOS 形态(Server / Remote / Web / MobileWeb)默认不启用该能力,符合"按 delivery profile 选择 capability pack"的装配规则; +- 第三方 Skills 的隐私责任明确归属格物市场与 Skill 提供方,前端在安装前给出清晰提示(对齐现有隐私协议第 8 条表述)。 + +## 非目标 / 范围外 + +- 不自建第二个 Skills 市场;格物市场是分发方,BitFun 是消费方 / 投稿方; +- 不在本提案内接入 MiniApp / Skin 市场(已有独立服务); +- 不在本提案内做 Skill 运行时沙箱或权限收窄(Skill 作为 prompt / instruction 注入,安全模型与现有 Skills 一致); +- 不在本提案内做 Skill 的图形化编辑器或可视化构建; +- 不替换本地手动放置 Skill 的能力,市场安装只是补充分发通道; +- 不在本提案内覆盖 HarmonyOS PC CLI/TUI 形态(按 `platform-portability-design.md`,PC 终端 CLI/TUI 是未来目标,需单独立项)。 + +## 建议的落地路径(基于现有分层) + +依据仓库的分层与边界规则,建议落在: + +1. **Contracts (`src/crates/contracts`)** — 在 `core-types` / `runtime-ports` 中定义稳定的格物市场 DTO 与 port trait(如 `GewuSkillManifest`、`GewuSkillListResponse`、`GewuSkillInstallRequest`、`GewuSkillProgressEvent`、投稿相关 DTO),保持行为轻量、不向上依赖。格物市场作为外部系统,是**边界资源**,不得在 contracts 中耦合其私有协议字段。 +2. **Adapters (`src/crates/adapters`)** — 新增格物市场协议适配(HTTP 传输、格物市场私有 wire 翻译、鉴权握手、投稿 payload 构造),仅做协议翻译,不承载产品策略。参照现有 `ai-adapters` / `transport` 的边界。 +3. **Services (`src/crates/services/services-integrations`)** — 在新增的 `gewu-market` 集成族下实现 `GewuMarketService`:列表 / 详情 / 包下载 / 哈希校验 / 落盘 / 卸载 / 投稿,全部放在显式 feature(如 `gewu-market`)后,`default = []`。下载 / 安装 / 校验逻辑应尽量复用 `miniapp-market-service` 已沉淀的包校验与 artifacts 存储约定,避免重复造轮子。 +4. **Assembly (`src/crates/assembly/product-capabilities`)** — 视情况新增 `ProductCapabilityId::GewuMarket`(或并入既有 Skills 扩展能力),按 profile 选择;HarmonyOS / Desktop / ProductFull 选入,其余不选。 +5. **Interfaces (`src/crates/interfaces`)** — 在 app-server 协议中暴露格物市场相关请求 / 响应(保持 camelCase wire shape,与 `cloud_speech` 风格一致)。 +6. **App / UI (`src/apps/desktop` + `src/web-ui`)** — 桌面 host 注册 `GewuMarketService` 实现并暴露 Tauri command;Web UI 新增市场浏览 / 安装 / 投稿 UI。注意:UI 组件不得直接调用格物市场 HTTP API,必须走 adapter / infrastructure 层。 + +### 分层与依赖边界要点 + +- 产品逻辑平台无关:核心 `GewuMarketService` 与 DTO / port 保持平台无关,格物市场私有协议、HarmonyOS 账号握手、Tauri command、Web UI 适配分别落在各自 owner 层; +- Services / Adapters 不得依赖 assembly / core facade / app / UI; +- 格物市场是边界资源,只有注册的 adapter / service 可调用它,其他层只消费 port 与稳定 contracts; +- 新增 feature 必须 `default = []`,避免把格物市场重运行时(HTTP / 鉴权 / 投稿)带入默认编译; +- 投稿链路与浏览 / 安装链路要在 service 内做职责隔离,避免投稿凭据意外流入只读浏览上下文。 + +## 设计草案 / 参考示例 + +- **参考本仓库已建成的市场链路**:MiniApp 市场(`miniapp-market-service`)与 Skin 市场(`skin-market-service`)已沉淀 SQLite + artifacts 存储 + GitHub OAuth + 桌面 Bearer token + 审核流程 + 备份 / 恢复演练 + Nginx vhost 的完整受控分发链。格物市场接入应复用其中**包校验、artifacts 目录约定、安装 / 卸载、版本对齐、进度事件**等中性能力,不复用其 GitHub OAuth(格物市场走自有账号体系)。 +- **包校验参考**:`miniapp-market-service/src/package.rs` 与 `artifacts.rs` 的哈希校验、原子落盘、失败回滚策略可作为 Skill 包安装的范本。 +- **Skills 根目录约定**:与 `file_watch` 服务管理的 `bitfun-skills` 目录一致,安装后由现有 file-watch 机制触发 Agent 运行时重新发现,不新造第二套发现链。 +- **交互参考**:MiniApp 市场网页(`market.openbitfun.com/miniapp`)的浏览 / 详情 / 一键安装 / "我的投稿"流程,可作为桌面端格物市场 UI 的交互参考。 +- **隐私边界**:格物市场与 Skill 提供方对第三方 Skill 的个人信息处理负责;BitFun 在安装前必须给出清晰提示,对齐 `src/crates/services/services-integrations/src/privacy/assets/zh-CN.md` 第 8 条。 +- **远程场景**:用户从一台设备远程控制另一台桌面时,格物市场安装应在受控端执行还是控制端发起,需要在 `src/apps/desktop/src/api/remote_workspace_policy.rs` 中声明明确策略(首版建议 control 端发起、target 端执行,并给出不支持态提示而非静默失败)。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 本提案严格遵循仓库"产品逻辑平台无关、再通过平台适配器暴露"与"外部系统是边界资源,只有注册 adapter / service 可调用"的规则。 +- 格物市场作为华为 HarmonyOS 生态资源,其私有 API、鉴权握手、投稿审核流程属于外部契约;接入前需与格物市场方对齐 API 规格、凭据发放与投稿审核 SLA,不在本提案内臆测其字段。 +- 与已建成的 MiniApp / Skin 市场链路(`deploy/miniapp-market/README.md`、`deploy/skin-market/README.md`)保持运维心智一致:专用 checkout、专用 artifacts / backups 目录、root-only secret、 leased push 部署 ref、健康检查与回滚演练等约定,若后续自建格物市场镜像或缓存层,应沿用而非另立。 +- HarmonyOS PC CLI/TUI 形态是未来平台目标(见 `platform-portability-design.md`),本提案不覆盖;如后续要覆盖,按该文件要求单独立项,不与桌面端 GUI 接入混为一谈。 +- 相关分层入口:`src/crates/contracts/AGENTS.md`、`src/crates/adapters/AGENTS.md`、`src/crates/services/services-integrations/AGENTS.md`、`src/crates/assembly/product-capabilities/AGENTS.md`。 diff --git a/docs/features/harmonyos-pc-airdrop.md b/docs/features/harmonyos-pc-airdrop.md new file mode 100644 index 0000000000..55c2163fd2 --- /dev/null +++ b/docs/features/harmonyos-pc-airdrop.md @@ -0,0 +1,103 @@ +# 鸿蒙 PC 隔空传送(HarmonyOS PC AirDrop)需求文档 + +> 状态:提案 / 未做 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) +> - [`docs/architecture/peer-device-mode.md`](../architecture/peer-device-mode.md) +> - [`tap-to-share-files.md`](./tap-to-share-files.md) +> - [`src/apps/ohos`](../../src/apps/ohos/) + +## 背景与需求描述 + +"隔空传送"指无需配对、发现附近设备后无线传输文件的能力(类 AirDrop)。BitFun 现有跨设备通道是自托管 relay(零知识、AES-GCM)与 Remote Connect / Peer Device Mode,需账号配对或联网到自部署服务器;缺少**免配对、近场发现、无线直传**的轻量传输。 + +当前缺口与诉求: + +- 用户无法在鸿蒙 PC 与附近设备(鸿蒙 PC / 手机 / 平板)之间免配对无线传文件,只能走 relay 配对 / 碰一碰近场轻触 / 远程工作区; +- 隔空传送发现附近设备后直传,不联网厂商云,与"自托管、零厂商云"定位一致; +- 接收侧须确认与完整性校验,不静默接收; +- 鸿蒙 PC GUI 是独立产品专题(见 `platform-portability-design.md`),隔空传送是其下能力子项,不提前决定 GUI 整体选型。 + +本提案新增**鸿蒙 PC 隔空传送**能力:发现附近设备、发起传输、接收确认、落盘校验,复用既有文件落点与校验链。 + +## 期望行为 + +### 1. 发现与传输 + +- 发起侧发现附近可传设备(鸿蒙 PC / 手机 / 平板),列表展示; +- 选中设备发起传输,接收侧弹出确认(来源、文件名、大小、类型); +- 用户确认后接收,不静默接收;可拒绝。 + +### 2. 落点与校验 + +- 接收文件落入当前工作区或用户指定目录(对齐拖拽落点); +- 完整性校验(哈希,对齐 market 包校验),失败可回滚不残留; +- 大文件 / 批量有进度与取消。 + +### 3. 隐私与安全 + +- 发现与传输不联网厂商云;凭据 / 设备标识最小化; +- 接收内容视为第三方来源,落盘前提示(对齐隐私协议第 8 条); +- 不自动执行接收文件,不自动打开可执行; +- 传输加密,对齐 relay 的零知识姿态(本地派生密钥)。 + +### 4. 平台与跨设备 + +- 优先 HarmonyOS 隔空投送 / 近场分享能力(华为官方 API 为准,本提案不臆测字段); +- 非 HarmonyOS 平台不支持时显式 unavailable,不静默回退到 relay; +- 与 relay / Remote Connect / Peer Device Mode / 碰一碰互补,不替换。 + +### 5. 远程与不可用态 + +- 隔空传送是本机近场交互,远程控制场景下声明本地执行; +- 目标鸿蒙版本 / 设备缺少近场发现 / 传输能力时显式 unsupported,不借用桌面 / 移动端 / Remote 代执行。 + +## 非目标 / 范围外 + +- 不替换 relay / Remote Connect / Peer Device Mode; +- 不在本提案内做碰一碰(近场轻触触发,见 `tap-to-share-files.md`); +- 不覆盖跨厂商 AirDrop 互操作(除非平台原生支持); +- 不预先决定鸿蒙 PC GUI 整体选型; +- 不做接收文件的自动解析 / 执行; +- 不覆盖手机 / 平板移动端本地传输(移动端是另一专题)。 + +## 建议的落地路径(基于现有分层) + +1. **Contracts (`src/crates/contracts`)** — 隔空传送 DTO / port(附近设备、文件元数据、进度、确认),行为轻量,不耦合 HarmonyOS 私有 API。 +2. **OHOS App (`src/apps/ohos`)** — HarmonyOS 隔空投送 / 近场分享适配;设备发现、传输握手、加密;鸿蒙私有协议不泄漏出适配层。 +3. **Services (`src/crates/services`)** — 接收文件落盘、哈希校验、临时文件清理(复用 market 包校验与 artifacts 约定)。 +4. **Web UI / ArkUI** — 设备发现列表、接收提示 UI、落点选择(复用拖拽落点)。 +5. **远程策略** — 隔空传送命令远程策略声明本地执行,在 `remote_workspace_policy` 登记。 + +### 分层与依赖边界要点 + +- 严格遵守 `platform-portability-design.md`:鸿蒙 PC GUI 是独立专题,隔空传送是其下能力子项; +- 平台差异只在 app/adapter/service 边界,共享 Runtime 不按 target triple 分叉业务; +- 缺失能力显式 unsupported,不静默借用桌面 / 移动端 / Remote 代执行; +- 不建立巨型 `ohos` feature 或第二套传输协议; +- 传输加密对齐 relay 零知识姿态,本地派生密钥,服务器不接触明文; +- 复用文件落点与校验,不新造第二套接收链。 + +## 设计草案 / 参考示例 + +- **平台能力参考**:HarmonyOS 隔空投送 / 近场分享 / 设备发现(华为官方文档为准)。 +- **落点参考**:拖拽落点(聊天输入 / 文件面板 / 工作区导航),隔空传送接收复用同构落点。 +- **校验参考**:market 包哈希校验、原子落盘、失败回滚。 +- **加密参考**:relay 的 Argon2id + AES-GCM 零知识姿态,本地派生密钥。 +- **隐私参考**:隐私协议第 8 条(第三方来源提示)。 +- **互补参考**:relay 适合跨网络 / 持久配对;隔空传送适合近场 / 免配对 / 无线直传;碰一碰适合近场轻触触发。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与 `tap-to-share-files.md` 的关系:碰一碰是近场轻触触发,隔空传送是发现附近设备无线传输,互补不替换。 +- 与 `harmonyos-pc-drag-drop.md` 的关系:三者都是鸿蒙 PC GUI 下的本地 / 近场交互能力子项,复用文件落点与校验。 +- 与 relay 的关系:relay 适合跨网络持久配对,隔空传送适合近场免配对无线直传,二者互补。 +- 与远程工作区的关系:隔空传送是本机近场交互,远程策略声明本地执行,不支持时清晰提示。 +- 相关分层入口:`src/apps/ohos`、`docs/architecture/platform-portability-design.md`、`docs/architecture/peer-device-mode.md`。 diff --git a/docs/features/harmonyos-pc-drag-drop.md b/docs/features/harmonyos-pc-drag-drop.md new file mode 100644 index 0000000000..f1005b2780 --- /dev/null +++ b/docs/features/harmonyos-pc-drag-drop.md @@ -0,0 +1,132 @@ +# 功能建议:鸿蒙 PC 支持拖拽(HarmonyOS PC Drag & Drop) + +> 状态:提案 / 未做 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) +> - [`src/web-ui/src/shared/types/drag.ts`](../../src/web-ui/src/shared/types/drag.ts) +> - [`src/web-ui/src/shared/services/DragManager.ts`](../../src/web-ui/src/shared/services/DragManager.ts) +> - [`src/apps/ohos/oh-rs-ability/src/main/ets/ability/type.ets`](../../src/apps/ohos/oh-rs-ability/src/main/ets/ability/type.ets) +> - [`src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets`](../../src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets) + +## 背景与需求描述 + +桌面端(Tauri / Web UI)已具备完整的拖拽交互:窗口拖动(`window_start_dragging` + `data-tauri-drag-region`)与内容拖放(`DragManager` + `DragPayload` / `IDropTarget` 协议,覆盖聊天输入文件拖入、工作区切换拖拽、文件面板拖入、Canvas 标签页拖拽、上下文项拖放等目标,自定义 MIME `application/x-bitfun-context`)。 + +鸿蒙 PC 是 BitFun 的目标平台之一。按 `platform-portability-design.md`,完整的鸿蒙 PC 支持同时包含本地 CLI/TUI 与 GUI,**GUI 是独立产品专题**,其 ArkUI/ArkWeb/HAP 技术选型只能在专题获批后设计。当前鸿蒙侧仅有: + +- `WebViewInitData.onDragAndDrop?: (event: string) => void` —— 一个未实现的拖放回调占位(`DefaultWebview.ets` / `ability/type.ets`); +- `window_start_dragging` —— 已注册为 ArkTS 函数(窗口拖动)。 + +但鸿蒙 PC GUI 的**内容拖拽**(系统文件管理器拖入应用、应用内拖拽、拖出至系统)尚无实现,存在以下缺口: + +- 用户无法把鸿蒙 PC 文件管理器中的文件拖入聊天 / 文件面板 / 工作区,只能走"打开对话框选择"的旧路径; +- 应用内标签页、工作区、上下文项的拖拽在鸿蒙 PC GUI 上缺失,跨平台体验不一致; +- 鸿蒙原生拖拽走 UDMF(统一数据管理框架)与 ArkUI drag 事件,与浏览器 DnD API 不是同一套,不能直接照搬 Web UI 实现; +- 现有 `onDragAndDrop` 占位若直接接上,会把鸿蒙私有事件形状泄漏进共享逻辑,违反"平台差异只在 app/adapter/service 边界"的规约。 + +本提案定义鸿蒙 PC 拖拽支持的目标范围、行为契约与分层归属,作为鸿蒙 PC GUI 专题下的一个能力子项,**不预先决定 GUI 专题的整体技术选型**。 + +## 期望行为 + +### 1. 窗口拖拽 + +- 拖动标题栏 / 拖拽区移动窗口,复用既有 `window_start_dragging` ArkTS 函数; +- 最大化 / 还原态下拖动行为符合鸿蒙 PC 窗口管理语义。 + +### 2. 系统到应用拖入 + +- 从鸿蒙 PC 文件管理器拖入文件 / 文件夹到聊天输入区,作为附件或引用注入会话(对齐桌面 `.bitfun-chat-input-drop-zone`); +- 拖入文件面板,落盘到当前工作区并刷新文件树(对齐桌面 `FilesPanel` drop + 传输进度); +- 拖入工作区导航项以切换 / 新建工作区(对齐桌面 `nav-workspace-drop-target`); +- 拖入只接受受支持类型,不接受时给出拒绝态视觉反馈,不静默吞掉。 + +### 3. 应用内拖拽 + +- Canvas 标签页在分组间拖拽定位(左 / 右 / 中,对齐桌面 `DropPosition` 与 `canvasStore.handleDrop`); +- 上下文项拖放到可接受目标(对齐桌面 `ContextDropZone` + `DragManager.handleDrop`); +- 应用内拖拽产生与桌面同形状的 `DragPayload`,目标按 `acceptedTypes` / `canAccept` 判定。 + +### 4. 应用到系统拖出(可选,首版可降级) + +- 从应用把文件 / 文本拖出到鸿蒙 PC 文件管理器或其他应用; +- 首版若不可行,明确报告 unsupported 并保留拖入能力,不静默降级。 + +### 5. 数据契约 + +- 鸿蒙侧拖拽经 UDMF 读写统一数据,在**适配层**翻译为与桌面同形状的 `DragPayload`(`id` / `sourceType` / `dataType` / `timestamp` / `data` / `metadata`); +- 源类型(`DragSourceType`)与数据类型(`ContextType`)保持跨平台一致;鸿蒙私有 UDMF 记录不进入共享逻辑; +- 自定义上下文负载走 `application/x-bitfun-context` MIME 等价物,在鸿蒙侧用 UDMF 自定义记录承载。 + +### 6. 视觉反馈 + +- 拖入悬停时高亮可接受目标、灰显不可接受目标(对齐桌面 `is-drop-target` / `--cannot-accept`); +- 拖拽预览(`PreviewData`)在鸿蒙 PC GUI 上有等价呈现; +- 接受 / 拒绝光标或等价态符合鸿蒙交互规范。 + +### 7. 不可用态 + +- 当目标鸿蒙版本 / 设备缺少 UDMF 或 ArkUI drag 能力时,显式报告 unsupported,**不得**静默回退到对话框选择或借用桌面 / 移动端代执行; +- 拖拽相关命令的远程工作区策略声明为本地交互(远程控制场景下拖拽只在受控端本地执行),不支持时清晰提示。 + +### 8. 性能与可访问性 + +- 拖拽悬停不引发全工作区逐帧重渲染(吸取桌面 F4 教训:拖侧栏逐 mousemove 重渲染); +- 键盘可达的等价路径(拖拽是补充,不是唯一入口); +- 大文件 / 批量拖入有进度与取消。 + +## 非目标 / 范围外 + +- 不在本提案内决定鸿蒙 PC GUI 专题的整体 ArkUI/ArkWeb/HAP 技术选型(由 GUI 专题负责); +- 不为鸿蒙建立第二套 `DragPayload` / `IDropTarget` 协议——复用桌面契约,只在适配层翻译; +- 不覆盖鸿蒙手机 / 平板移动端的拖拽(移动端是另一专题,不与 PC GUI 混写); +- 不覆盖鸿蒙 PC CLI/TUI 形态的拖拽(CLI/TUI 是另一交付形态); +- 不在本提案内做拖拽内容的 AI 解析或自动归类; +- 不替换桌面端既有拖拽实现,鸿蒙侧只是新增适配。 + +## 建议的落地路径(基于现有分层) + +依据 `platform-portability-design.md` 与仓库分层规则,鸿蒙 PC 拖拽应落在: + +1. **Contracts (`src/crates/contracts`)** — 若 `DragPayload` / `DragSourceType` / `ContextType` 需跨 Rust 与 ArkTS 共享,把它们从 `src/web-ui/src/shared/types/drag.ts` 提升为稳定契约(行为轻量,不耦合 UDMF 或浏览器 DnD)。当前若只在 UI 层共享,可暂留 web-ui,不强行下沉。 +2. **OHOS App (`src/apps/ohos`)** — 鸿蒙侧拖拽实现落点: + - ArkUI 组件 drag 事件处理器、UDMF 统一数据读写; + - 在 `WebViewInitData.onDragAndDrop` 占位上接真实实现(把 UDMF 事件翻译为统一 `DragPayload` 后回调); + - 窗口拖拽复用既有 `window_start_dragging`。 +3. **适配层边界** — 鸿蒙 UDMF / ArkUI drag 事件 ↔ 统一 `DragPayload` 的双向翻译;鸿蒙私有记录不泄漏出适配层。 +4. **Web UI / ArkUI 表面** — 拖放目标(聊天输入、文件面板、工作区导航、Canvas 标签页、上下文拖放区)在鸿蒙 PC GUI 上达到与桌面等价的覆盖。 +5. **远程策略** — 拖拽相关命令远程策略声明为本地交互(远程控制时拖拽在受控端本地执行),在 `remote_workspace_policy` 中显式登记。 + +### 分层与依赖边界要点 + +- 严格遵守 `platform-portability-design.md`:鸿蒙 PC GUI 是独立专题,本提案只定义拖拽能力子项,不提前决定 GUI 整体选型; +- 平台差异只在 app/adapter/service 边界出现,共享 Runtime 不按 target triple 分叉业务语义; +- 进入 OHOS 闭包的 `cfg(unix)` / `target_os = "linux"` 路径须重新取证,不得默认等同桌面 Linux; +- 缺失能力显式报告 unsupported,不静默借用桌面 / 移动端 / Remote 代执行; +- 不建立包含全部鸿蒙差异的巨型 `ohos` feature 或第二套拖拽协议; +- 拖拽是本地交互,远程场景声明本地执行策略,不支持时清晰提示。 + +## 设计草案 / 参考示例 + +- **协议参考**:桌面 `DragPayload` / `IDragSource` / `IDropTarget` / `DragEventPayload`(`src/web-ui/src/shared/types/drag.ts`)与 `DragManager`(`src/web-ui/src/shared/services/DragManager.ts`)是跨平台契约基准;鸿蒙侧只做 UDMF 翻译,不改协议形状。 +- **拖放目标覆盖矩阵**:聊天输入(`.bitfun-chat-input-drop-zone`)、工作区导航(`nav-workspace-drop-target`)、文件面板(`FilesPanel` drop + 传输进度)、Canvas 标签页(`DropPosition` 左/右/中)、上下文拖放区(`ContextDropZone`)——鸿蒙 PC GUI 首版至少覆盖前三项。 +- **窗口拖拽参考**:既有 `window_start_dragging` ArkTS 函数与桌面 `data-tauri-drag-region`。 +- **占位接续参考**:`WebViewInitData.onDragAndDrop?: (event: string) => void` 是已有钩子,在其上接 UDMF → `DragPayload` 翻译后回调,不新造第二套钩子。 +- **平台能力参考**:鸿蒙 UDMF(统一数据管理框架)与 ArkUI 组件 drag 事件是原生拖拽标准,授权与 API 以华为官方文档为准,本提案不臆测其字段。 +- **性能教训参考**:桌面 F4(拖侧栏逐 mousemove 全工作区重渲染)——鸿蒙侧拖拽悬停须避免同类逐帧重渲染。 +- **远程参考**:拖拽是本地交互,远程控制时在受控端本地执行,`remote_workspace_policy` 显式登记本地策略。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 本提案严格遵循 `platform-portability-design.md`:鸿蒙 PC GUI 是独立产品专题,拖拽是其下的能力子项;不提前决定 GUI 整体选型,不为过编译建立鸿蒙专用 Runtime 或复制业务逻辑。 +- 与桌面拖拽的关系:复用 `DragPayload` / `IDropTarget` 协议与拖放目标覆盖,只在适配层翻译 UDMF,不新造第二套协议;桌面实现不变。 +- 与移动端的关系:鸿蒙手机 / 平板拖拽是另一专题,本提案不覆盖,不与 PC GUI 混写。 +- 与 CLI/TUI 的关系:CLI/TUI 是鸿蒙 PC 的另一交付形态,拖拽属 GUI 交互,不在 CLI/TUI 范围。 +- 与远程工作区的关系:拖拽是本地交互,远程控制时在受控端本地执行;相关命令远程策略声明为本地,不支持时清晰提示而非静默失败。 +- 相关分层入口:`src/apps/ohos`、`src/web-ui/AGENTS.md`、`src/apps/desktop/AGENTS.md`、`docs/architecture/platform-portability-design.md`。 diff --git a/docs/features/keyboard-shortcuts.md b/docs/features/keyboard-shortcuts.md new file mode 100644 index 0000000000..0faa094b45 --- /dev/null +++ b/docs/features/keyboard-shortcuts.md @@ -0,0 +1,109 @@ +# 快捷键(Keyboard Shortcuts)需求文档 + +> 状态:能力规格 / 需求 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/web-ui/src/infrastructure/services/ShortcutManager.ts`](../../src/web-ui/src/infrastructure/services/ShortcutManager.ts) +> - [`src/web-ui/src/shared/types/shortcut.ts`](../../src/web-ui/src/shared/types/shortcut.ts) +> - [`src/web-ui/src/shared/constants/shortcuts.ts`](../../src/web-ui/src/shared/constants/shortcuts.ts) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) + +## 背景与需求描述 + +桌面端需要一个统一的快捷键体系:用户通过键盘高效触发面板切换、搜索、文件树操作、编辑器命令、终端复制粘贴等。BitFun 已有 `ShortcutManager` 单例 + `useShortcut` hook + 快捷键目录(`EDITOR_SHORTCUTS` / `FILETREE_SHORTCUTS` 等)+ 用户自定义覆盖(`app.keybindings`)+ 作用域(app / chat / editor / canvas / terminal)+ 冲突检测 + 设置 UI(`KeyboardShortcutsTab`)。 + +本需求定义快捷键能力的目标范围与行为契约,确保体系一致、可定制、不冲突、跨平台、IME 安全。 + +当前缺口与诉求: + +- 快捷键须有目录默认值,用户可覆盖,部分关键键不可自定义(`NON_USER_CUSTOMIZABLE_SHORTCUT_IDS`); +- 作用域须正确隔离:app 全局、editor / canvas / terminal 局部,焦点在终端时不继承 canvas; +- 跨平台:macOS Command ↔ 其他平台 Ctrl 自动映射,目录默认平台无关; +- IME 占用时不触发 Escape 类快捷键; +- Monaco 编辑器管理自己的 keybindings,不纳入产品快捷键体系; +- 调试快捷键(DevTools)旁路产品体系,开发工具不被用户配置影响。 + +## 期望行为 + +### 1. 目录与默认值 + +- 快捷键目录(`shortcuts.ts`)登记 id / 默认组合 / 作用域 / 是否允许输入态触发 / 是否可自定义; +- `useShortcut(id, config, callback)` 注册,自动清理;仅 id 或 config 变化才重新注册; +- 启动期 keybindings 走 bootstrap 路径(`global_config.app.keybindings`),不经首窗口 IPC。 + +### 2. 用户自定义 + +- 用户覆盖存于 config `app.keybindings`,版本化形态读写; +- `getEffectiveConfig` 合并目录默认与用户覆盖; +- 不可自定义键(`NON_USER_CUSTOMIZABLE_SHORTCUT_IDS`)拒绝覆盖。 + +### 3. 作用域与冲突 + +- 作用域经 `data-shortcut-scope` DOM 属性探测(`closest('[data-shortcut-scope]')`),回退 `app`; +- canvas 作用域包含 canvas-scoped 快捷键;终端作用域不继承 canvas; +- app 作用域全局活跃,可与局部作用域互相遮蔽——冲突检测(`checkConflicts`)在注册与设置 UI 中提示; +- 同作用域内同组合冲突时拒绝注册或提示。 + +### 4. 跨平台与按键解析 + +- macOS 逻辑 Ctrl 映射为 Command;目录默认平台无关(如 `editor.findInFile`); +- 数字行用 `event.code`(Digit1–Digit9)保证 Ctrl+digit 在 IME 下稳定; +- 括号键按物理 `code` 匹配,保证 Ctrl+Shift+[ 等稳定。 + +### 5. IME 与 Monaco + +- IME 占用时不运行 Escape 类快捷键; +- Monaco 管理自己的 keybindings(`MonacoLspAdapter` 内 `keybindings: [monacoApi.KeyCode.F12]` 等),产品 ShortcutManager 不接管 Monaco 内部。 + +### 6. 调试快捷键 + +- DevTools 等调试快捷键旁路产品 ShortcutManager,只在 Tauri 桌面环境注册,开发工具不受用户配置影响(`useDebugInspector`)。 + +### 7. 设置 UI + +- `KeyboardShortcutsTab` 展示所有快捷键(含未在运行时注册的)的有效配置,订阅注册 / 覆盖变化刷新; +- 录入新组合、冲突提示、重置默认。 + +## 非目标 / 范围外 + +- 不接管 Monaco 编辑器内部 keybindings; +- 不覆盖 CLI/TUI 形态的按键(ratatui/crossterm,属 `src/apps/cli`); +- 不定义全局 OS 级快捷键(系统级 hotkey); +- 不在本需求内做快捷键的跨设备云同步(属 remote connect)。 + +## 建议的落地路径(基于现有分层) + +1. **共享类型与常量 (`src/web-ui/src/shared/types/shortcut.ts`、`shared/constants/shortcuts.ts`)** — 快捷键目录、作用域、不可自定义清单。 +2. **基础设施 (`src/web-ui/src/infrastructure/services/ShortcutManager.ts` + `hooks/useShortcut.ts`)** — 注册 / 解析 / 冲突检测 / 用户覆盖 / 作用域探测。 +3. **设置 UI (`src/web-ui/src/app/scenes/settings/components/KeyboardShortcutsTab.tsx`)** — 配置录入与冲突提示。 +4. **Config (`app.keybindings`)** — 版本化用户覆盖存储。 +5. **调试 (`src/web-ui/src/infrastructure/debug/useDebugInspector.ts`)** — 旁路产品体系的调试快捷键。 + +### 分层与依赖边界要点 + +- UI 组件不直调 Tauri;快捷键纯前端体系,经 `useShortcut` hook 注册; +- 复用 ShortcutManager 单例,不新造第二套键管理; +- keybindings 走 bootstrap 配置路径,不经首窗口 IPC; +- Monaco 内部 keybindings 不纳入产品体系。 + +## 设计草案 / 参考示例 + +- **目录参考**:`EDITOR_SHORTCUTS` / `FILETREE_SHORTCUTS`,默认平台无关。 +- **作用域参考**:`data-shortcut-scope`(app / chat / editor / canvas / terminal);终端不继承 canvas。 +- **冲突检测参考**:`checkConflicts` 在注册与设置 UI 提示 app-scope 与 scoped 冲突。 +- **跨平台参考**:Ctrl→Command 映射、数字行用 `event.code`、括号按物理 `code`。 +- **IME 参考**:IME 占用时不触发 Escape 类。 +- **调试参考**:`useDebugInspector` 旁路产品体系,仅桌面环境注册。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与终端面板的关系:终端作用域快捷键(复制 / 粘贴 / 切换会话)独立,不继承 canvas。 +- 与编辑器的关系:Monaco 内部 keybindings 自管,产品快捷键不接管。 +- 与 i18n 的关系:快捷键描述文案(`keyboard.shortcuts.*`)走 i18n 命名空间懒加载。 +- 相关分层入口:`src/web-ui/AGENTS.md`。 diff --git a/docs/features/mcp-server-management-desktop-web-ui.md b/docs/features/mcp-server-management-desktop-web-ui.md new file mode 100644 index 0000000000..f75c6ff231 --- /dev/null +++ b/docs/features/mcp-server-management-desktop-web-ui.md @@ -0,0 +1,73 @@ +# MCP Server 管理与运行态(Desktop / Web UI)功能提案 + +> 状态:提案 / 待评审 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/crates/services/services-integrations/AGENTS.md`](../../src/crates/services/services-integrations/AGENTS.md) +> - [`src/crates/assembly/core/AGENTS.md`](../../src/crates/assembly/core/AGENTS.md) +> - [`docs/architecture/agent-runtime-services-design.md`](../architecture/agent-runtime-services-design.md) +> - [`src/apps/desktop/AGENTS.md`](../../src/apps/desktop/AGENTS.md) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) + +### 功能类型 + +- [x] 新功能 +- [ ] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [x] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- 用户希望把外部 MCP server(本地 stdio 进程、远程 SSE / streamable HTTP)作为可插拔工具源接入 BitFun agent,统一在会话中调用其工具、读取其 resource、使用其 prompt。当前缺少一个完整的「配置 → 启动 → 健康 → 重连 → 工具目录」管理面,用户难以在 Desktop/Web UI 内自助注册、诊断和运维 MCP server。 +- 痛点:① MCP server 配置散落、缺校验与导入能力,添加门槛高;② server 进程/远程连接的健康状态、启动失败原因对用户不透明,排查困难;③ 连接断开后无自动重连或退避策略,会话中途工具失效;④ 多 server 并存时缺乏统一启停、自动启动与运行态视图;⑤ 需 OAuth 的远程 server 授权流程缺失或割裂。 + +### 功能描述 + +- 在 Desktop/Web UI 提供 MCP server 的端到端管理面,覆盖六个环节: + 1. **配置与校验**:支持 stdio(command + args + env)、SSE、streamable HTTP 三种 transport;配置来源区分 local / remote;提供 JSON 配置(`mcpServers` 形态)的校验、格式化与从外部格式(如 Cursor)导入;配置持久化、可启用/禁用、可命名。 + 2. **生命周期管理**:支持 start / stop / restart / 启用-禁用 / auto-start;每次启动带超时;启动前校验前置条件(command 是否可用、远程 URL 是否可达、是否已授权),不可启动时给出 `start_disabled_reason` 而非静默失败。 + 3. **运行态与健康**:实时展示每个 server 的 status / status_message / server_type / transport / url / command_resolved_path / command_source / command_available;进程或连接异常时显式标注阶段(配置错误 / 启动超时 / 握手失败 / 运行中断 / 重连中)。 + 4. **重连与容错**:连接断开后按退避策略(基础延迟 → 上限)自动重连,重连计数与下次重试时间可见;重连上限或用户主动停止后转为终态并保留可手动重启入口;远程 server 重连不得污染本地 stdio 进程的清理边界。 + 5. **进程归属与隔离**:本地 stdio server 作为受管子进程托管,遵循仓库既定的 managed-descendant 清理边界(Unix 用独立进程组、Windows 用 kill-on-close Job Object,附加失败即 fail-closed),生命周期停机时回收子进程;该机制是生命周期收容,不是 OS 沙箱或资源限额,UI 需对残余风险保持明确。 + 6. **授权**:远程 server 支持 OAuth 授权引导(授权码回跳、凭证存储、授权状态 `auth_configured` / `auth_source` / `oauth_enabled` 可见),未授权时阻止启动并提供授权入口。 +- 实现边界遵循服务层与服务集成层规则:MCP config/process/transport 生命周期、server runtime state(registry / 连接池 / catalog cache / reconnect / runtime-only config)、lifecycle policy、OAuth 凭证存储与授权引导、具体协议依赖与结果内容渲染归 `bitfun-services-integrations`(`mcp` feature);Core 只保留兼容 facade 与产品级回调/会话/重连编排,不得重新引入具体协议依赖;MCP wire 类型可投影到执行层 tool bridge 描述符,但工具注册表装配、manifest 过滤、`GetToolSpec` 执行与 bridge 呈现/校验行为不在服务集成层。 +- Desktop/Web UI 只消费稳定的运行态事实与服务接口,不在 UI 层重定义 MCP 协议、transport 实现或外部工具契约。 + +### 期望效果 / 使用场景 + +1. 用户在设置中打开「MCP Servers」面板,点击新增:选择 transport(stdio/SSE/streamable HTTP),填写 command 或 URL,保存后即时校验并给出可读错误;支持从外部 JSON / Cursor 配置一键导入多个 server。 +2. 在面板中可见每个 server 的运行态:状态、transport、命令解析路径/来源、是否已授权、是否可启动;不可启动项显示原因(如 command 未找到、URL 不可达、未授权)。 +3. 用户对 stdio server 点「启动」:进程作为受管子进程拉起,握手成功后工具目录刷新并入会话;停止时子进程被可靠回收,不残留。 +4. 远程 streamable HTTP server 在网络抖动断开后自动按退避策略重连,面板显示「重连中(第 N 次,下次 Xs)」;超出上限转为「已断开」并提供手动重启。 +5. 需 OAuth 的远程 server 在首次启动前弹出授权引导,完成后授权状态回写,后续启动免再次授权;凭证存储位置对用户可见且可撤销。 + +### 设计草案 / 参考示例 + +- 配置形态:`mcpServers` JSON(server 名 → {command/args/env | url, transport, source, autoStart, enabled}),校验与格式化遵循 MCP JSON config 校验规则,支持 legacy type 归一(`stdio` / `local` / `sse` / `remote` / `http` → local|remote × stdio|sse|streamable-http)。 +- 运行态数据模型:每个 server 暴露 id / name / status / statusMessage / serverType / transport / enabled / autoStart / url? / authConfigured? / authSource? / oauthEnabled? / command? / commandAvailable? / commandSource? / commandResolvedPath? / startSupported / startDisabledReason?。 +- 重连策略:基础延迟 2s、上限 60s、轮询间隔 5s 的退避;可见重连计数与下次重试时间。 +- 进程归属:本地 stdio server 走 `services-core::process_tree` 的受管子进程清理边界(Unix 进程组 / Windows Job Object)。 +- 协议分层:transport(stdio / 远程 streamable HTTP)与服务/协议映射独立测试,远程 transport 契约测试与本地 stdio 解耦。 + +### 是否愿意贡献 + +- [ ] 我愿意参与开发 +- [x] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 本提案聚焦 server 管理与运行态;MCP tool 目录呈现/调用、resource/prompt 交互、远程 workspace MCP 等作为独立 facet,可另立提案,避免范围扩散。 +- 边界约束:不得在 `core-types` / `runtime-ports` 内重定义 MCP 配置/transport;具体协议依赖与结果渲染归 `bitfun-services-integrations` 的 `mcp` feature;工具注册表装配与 `GetToolSpec` 执行属更高层;UI 层只消费稳定运行态事实。 +- 安全与隔离声明:受管子进程清理是生命周期收容,不等于 OS 沙箱或 CPU/内存/文件/网络资源限额;产品策略必须在禁用相应 server 时明确报告 `policy-limited`,不得宣称已被沙箱拦截。 +- 验证基线(建议):`cargo check -p bitfun-services-integrations --no-default-features --features mcp`、`cargo test -p bitfun-services-integrations --no-default-features --features mcp --test mcp_contracts`、`pnpm run check:core-boundaries`;远程 streamable HTTP transport 契约测试独立;Desktop 侧 `cargo check -p bitfun-desktop && cargo test -p bitfun-desktop`;Web UI 侧 `pnpm run type-check:web`。 +- 若后续需把该能力下沉到 CLI/TUI 或移动端,应作为同级 adapter 单独评审,不在本提案内合并 surface。 diff --git a/docs/features/ohos-pc-app-update.md b/docs/features/ohos-pc-app-update.md new file mode 100644 index 0000000000..28700bb230 --- /dev/null +++ b/docs/features/ohos-pc-app-update.md @@ -0,0 +1,87 @@ +# 鸿蒙 PC 应用更新(HarmonyOS PC App Update)能力需求文档 + +> 状态:需求 / 提案 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md)(鸿蒙 PC 平台移植目标) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md)(分层与平台适配边界) +> - [`docs/architecture/peer-device-mode.md`](../architecture/peer-device-mode.md)(远程控制下更新归属) +> 现有实现参考: +> - `src/apps/cli/src/self_update.rs`(成熟自更新:清单 / 镜像源选择 / 吞吐量探测 / SHA256+签名 / 进度 / 重启) +> - `src/web-ui/src/infrastructure/update/`(桌面更新 store 状态契约) +> - `src/apps/desktop/src/api/ohos/update.rs`(已有 `check_app_update_ohos` 桥接入口) + +### 功能类型 + +- [x] 新功能 +- [x] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [x] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun 已有跨平台桌面(Tauri)、CLI(Linux self_update)、移动 / 平板鸿蒙 HAP(`src/apps/ohos`)等形态;鸿蒙 PC(HarmonyOS NEXT PC)是仓库明确的平台移植目标,但应用更新闭环尚未建立。 +- 鸿蒙 PC 上应用更新缺少完整流程:桌面侧已有 `check_app_update_ohos` 桥接,但仅把检查委托给 ArkTS 层,缺少统一的"检查 → 下载 → 校验 → 安装 → 重启 → 恢复"闭环。 +- 现有 CLI `self_update.rs` 已是成熟模式(发布清单、GitHub + OpenBitFun 镜像源、基于吞吐量的源选择、SHA256 + 签名 URL、分块下载进度、stall 检测与 fail-over、重启),鸿蒙 PC 自托管通道应复用其策略与常量,而非在鸿蒙侧重造一遍。 +- 缺少分发渠道策略:华为应用市场(AppGallery)系统更新 vs 自托管发布通道(GitHub release + OpenBitFun 镜像),二者适用条件与体验不同,需明确何时用哪个。 +- 缺少签名校验与完整性保护:鸿蒙 PC 安装包若不校验来源与签名,存在被替换安装包的风险。 +- 远程工作场景:远程控制下鸿蒙 PC 的更新应以受控端为准,控制端不得越权触发安装。 + +### 功能描述 + +- **检查更新**:应用启动后台静默检查,或由"检查更新"入口手动触发,查询发布清单获取最新版本信息;启动路径检查须有预算上限(不阻塞首屏),超时按"无更新"降级而非报错。 +- **多分发渠道策略**: + - 若已通过华为应用市场分发,优先走应用市场系统更新,复用系统更新体验与签名链; + - 自托管通道(GitHub release + OpenBitFun 镜像)作为补充 / 未上架场景,复用 CLI `self_update` 的清单格式、镜像源选择与吞吐量探测。 +- **版本清单与完整性**:清单带 `schema_version`、版本号、平台条目、资产(`filename` / `url` / `sha256_url` / `sig_url`);下载后校验 SHA256,有签名则校验签名;签名缺失按策略降级或 fail-closed 拒绝。 +- **下载与进度**:分块下载、按时间间隔上报进度(避免静默卡死)、断点续传、内存上限(防止恶意 / 错误源 OOM)、stall 检测与死链 fail-over 到镜像源。 +- **安装与重启**:鸿蒙 PC 通过系统安装能力安装 HAP / 安装包;安装完成后提示重启或按用户选择重启;尽量保留会话 / 设置状态以在重启后恢复。 +- **更新状态机**:`idle / checking / available / downloading / verifying / installing / installed / error / up-to-date`;执行状态与加载状态相互独立,UI 不出现无说明的空白态。 +- **降级与不可用态**:网络 / 镜像不可用、签名校验失败、系统安装被拒时,给出清晰错误信息与下一步建议,不静默失败;旧版本保持可用。 +- **平台无关 + 平台适配**:检查 / 下载 / 校验 / 状态逻辑平台无关(复用 services 层),鸿蒙 PC 特定的安装 / 系统更新能力通过平台适配器暴露;UI 走 adapter / infrastructure 层,不直接调用 host API。 +- **远程工作场景**:远程控制下更新以受控端为准;受控端不可更新或被系统策略拒绝时,给出清晰不支持态提示而非静默失败。 + +### 期望效果 / 使用场景 + +1. 鸿蒙 PC 用户启动应用,后台静默检查更新(有预算上限,不卡首屏);有新版本时在合适入口提示。 +2. 用户点"检查更新"手动触发,看到新版本说明、大小与来源;确认后下载并显示实时进度。 +3. 下载完成自动校验 SHA256 与签名;校验失败时明确报错,旧版本保持可用,不安装被替换的包。 +4. 校验通过后通过系统安装能力安装,完成后提示重启;重启后会话 / 设置可恢复。 +5. 多源(GitHub + OpenBitFun 镜像)按吞吐量自动选择,慢链 / 死链 fail-over 到镜像,避免单点失败。 +6. 远程控制下,鸿蒙 PC 更新以受控端为准,控制端不越权触发安装;受控端不可更新时给出清晰提示。 + +### 设计草案 / 参考示例 + +- **现有参考实现**: + - `src/apps/cli/src/self_update.rs`:清单 / 镜像源选择 / 吞吐量探测 / SHA256+签名 / 进度 / 重启——成熟模式,鸿蒙 PC 自托管通道应复用其策略与常量(`PROBE_WINDOW`、`HEALTHY_THROUGHPUT`、`STALL_THROUGHPUT`、`MAX_ARCHIVE_BYTES`、`PROGRESS_INTERVAL`、`AUTO_CHECK_BUDGET`)。 + - `src/web-ui/src/infrastructure/update/updateInstallStore.ts`:桌面更新 store 状态(`downloading` / `installed` / `error` + 进度)——UI 状态契约可复用。 + - `src/apps/desktop/src/api/ohos/update.rs`:`check_app_update_ohos` 已有桌面 → ArkTS 委托入口;鸿蒙 PC 应在此契约上补全完整闭环。 +- **行业参照**:HarmonyOS 应用内更新系统 API、华为应用市场更新流程、Tauri updater、Sparkle / appcast 的版本清单与签名校验。 +- **落地分层建议**(遵循仓库分层与边界): + 1. Contracts(`src/crates/contracts`):发布清单 DTO、更新状态枚举、资产契约(复用 CLI 清单 schema),平台无关、行为轻量。 + 2. Services(`src/crates/services/services-integrations`):清单获取 / 镜像源选择 / 下载 / 校验逻辑(复用 `self_update` 策略),平台无关。 + 3. Assembly(`src/crates/assembly`):按 delivery profile 装配鸿蒙 PC 更新能力,声明对应 capability pack。 + 4. Interfaces / App / UI(`src/apps` + `src/web-ui`):鸿蒙 PC host 暴露更新 command,ArkTS 侧实现系统安装;UI 走 adapter / infrastructure 层,不直接调 host API。 +- **签名与完整性**:鸿蒙 PC 安装包须支持签名(`sig_url`),校验失败 fail-closed 拒绝安装;签名缺失仅在明确策略允许时降级,且不得渲染为"校验通过"。 + +### 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 鸿蒙 PC 是仓库平台移植目标(见 [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md));本需求聚焦**鸿蒙 PC 应用更新**,不涉及鸿蒙 PC CLI/TUI——后者是另一个未来平台目标,需单独立项。 +- 分发渠道策略(AppGallery 上架 vs 自托管)需法务 / 合规确认后再定,本需求只定义能力与契约。 +- 严格复用 CLI `self_update` 模式与常量,避免在鸿蒙 PC 侧重造下载 / 校验 / 源选择逻辑;两处若行为分叉须保持同步(`self_update.rs` 注释已要求与 relay deploy 路径保持一致,本需求同此原则)。 +- 远程工作场景遵循仓库"远程兼容"全局规则:本地受限行为在远程场景需有明确不支持态提示,而非静默失败。 diff --git a/docs/features/ohos-pc-browser-use.md b/docs/features/ohos-pc-browser-use.md new file mode 100644 index 0000000000..5e328794f8 --- /dev/null +++ b/docs/features/ohos-pc-browser-use.md @@ -0,0 +1,89 @@ +# 鸿蒙 PC 浏览器使用(Browser Use)能力需求文档 + +> 状态:需求 / 提案 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/plans/computer-use-refactor-plan.md`](../plans/computer-use-refactor-plan.md)(浏览器/计算机使用重构决策:语义引用优先、ControlHub 唯一栈、`browser_control_enabled` 真实门控、M5/M14 修复) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md)(分层与平台适配边界) +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md)(鸿蒙 PC 平台移植目标) +> - [`docs/architecture/peer-device-mode.md`](../architecture/peer-device-mode.md)(远程控制下浏览器控制归属) +> 现有实现参考: +> - `src/crates/services/services-integrations` 的 `browser_control`(ControlHub Rust CDP 栈,绑定 Chromium `--remote-debugging-port=9222`) +> - `src/crates/adapters/webdriver`(WebDriver 协议适配器,platform evaluator 现仅 `windows` / `macos`) +> - `WebFetch` / `browser.fetch` / `read_article` 内容读取族与路由指导 + +### 功能类型 + +- [x] 新功能 +- [x] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [x] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun Agent 的浏览器使用(browser use)能力目前仅在桌面(Windows / macOS / Linux)通过 ControlHub Rust CDP 栈实现,绑定 Chromium `--remote-debugging-port=9222`,未覆盖鸿蒙 PC。 +- 鸿蒙 PC(HarmonyOS NEXT PC)浏览器为华为浏览器 / 系统 ArkWeb 内核,**不暴露标准 CDP 9222 调试端口**;现有 `launcher.rs` 与 WebDriver 平台 evaluator(仅 windows / macos)无法在鸿蒙 PC 启动或连接浏览器,导致鸿蒙 PC 上 Agent 无法读 / 写 / 交互操作网页,任务闭环受限。 +- `computer-use-refactor-plan.md` 已确立关键决策——"语义引用优先(a11y / DOM `snapshot@ref`)、坐标仅作能力门控降级""ControlHub 为唯一浏览器自动化栈""`ai.browser_control_enabled` 真实门控 + `browser_control` permission intent"——鸿蒙 PC 适配应**继承这些稳定契约**,只替换底层浏览器后端,不在鸿蒙侧另造一套交互范式(避免重演 C1 双栈并存)。 +- 鸿蒙 PC 上无登录态内容读取(WebFetch)已可用,但交互式浏览器控制(导航 / 点击 / 输入 / 快照)缺失,登录态抓取、表单提交、多步网页任务无法完成。 +- 远程工作场景:远程控制下鸿蒙 PC 的浏览器控制需遵循本地性语义(`browser_control_*` 应在三端 deny 表对齐,控制器不静默在 peer 主机启动浏览器)。 + +### 功能描述 + +- **鸿蒙 PC 浏览器控制后端**:实现一个鸿蒙 PC 专用的浏览器控制后端,**复用 ControlHub / browser_control 的稳定契约**(`snapshot@ref` 语义引用、action 集、稳定错误 code),底层通过鸿蒙浏览器 / ArkWeb 的调试能力(DevTools-like 协议或系统无障碍树)驱动,不依赖标准 CDP 9222。 +- **语义引用优先**:继承重构方案决策 2——优先 a11y 树 / DOM 引用(`snapshot@ref`),视觉坐标仅作能力门控降级;不在鸿蒙侧重造视觉 grounding 范式。 +- **复用稳定契约**:浏览器交互的 tool schema、action 名、参数(`{element: 人类可读描述, target: ref|selector}`)、错误 code 与桌面一致,保证模型跨平台行为一致;不在鸿蒙侧发明新 action 方言或新坐标系。 +- **WebDriver 平台 evaluator**:在 `src/crates/adapters/webdriver` 的 platform evaluator 中新增鸿蒙(ohos)实现(当前仅 windows / macos),承担截图、元素定位、求值等平台原语,与既有 evaluator 契约一致。 +- **能力门控**:鸿蒙 PC 复用 `ai.browser_control_enabled`(默认开)真实门控与 `browser_control` permission intent;关闭后浏览器控制域禁用且不影响桌面 computer use(两开关独立,对应 C5)。 +- **内容读取与交互分层**:路由指导在鸿蒙 PC 同样适用——`WebFetch`(无登录态读文)→ `browser.read_article` / `fetch`(登录态读)→ `browser connect` / `snapshot`(交互)→ `ComputerUse`(非可控浏览器 / 桌面)→ `open_builtin`(给用户看)。 +- **截图与隐私**:截图落盘走 debug 配置开关(默认关)+ 数量 / 天数轮转,继承重构方案 M5 修复;不在鸿蒙 PC 工作区无门控写截图。 +- **可控 vs 不可控浏览器边界**:继承决策 4——边界 guard 真正执行,区分 CDP / ArkWeb 可控浏览器与不可控浏览器;不可控浏览器走 ComputerUse 桌面视觉路径或受限模式并明确告知。 +- **降级与不可用态**:鸿蒙浏览器调试不可用、无障碍树缺失、用户使用不可控浏览器时,给出清晰错误与下一步,不静默失败;旧能力保持可用。 +- **平台无关 + 平台适配**:浏览器控制契约与路由逻辑平台无关(services / execution 层),鸿蒙 PC 浏览器后端通过平台适配器暴露;UI 走 adapter / infrastructure 层,不直接调用 host API。 +- **远程工作场景**:远程控制下鸿蒙 PC 浏览器控制以受控端为准;`browser_control_*` 在桌面 / CLI / FE 三端 deny 表对齐(对应 M14),控制器不静默在 peer 主机启动浏览器。 + +### 期望效果 / 使用场景 + +1. 鸿蒙 PC 用户让 Agent"打开某网页登录后抓取数据",Agent 通过鸿蒙浏览器后端导航、快照、点击、输入,复用与桌面同款的 action 与 `ref` 语义,模型行为跨平台一致。 +2. 鸿蒙 PC 上 `WebFetch` 读无登录态文章正常可用;需要登录态交互时自动升级到 `browser connect` / `snapshot`,路由与桌面一致。 +3. 用户在设置中关闭 `browser_control_enabled`,鸿蒙 PC 浏览器控制域禁用且桌面 computer use 不受影响;权限弹窗归属正确,不出现 peer 模式弹窗弹在控制端的混淆(对应 M13)。 +4. 鸿蒙浏览器调试不可用或用户使用不可控浏览器时,Agent 收到清晰错误(稳定 code + 恢复指令,如"ref stale, take a new snapshot")并提示替代路径,不静默失败。 +5. 远程控制下,鸿蒙 PC 浏览器控制以受控端为准,控制器不越权启动浏览器;deny 表三端对齐,contract test 守护。 + +### 设计草案 / 参考示例 + +- **现有参考实现**: + - [`docs/plans/computer-use-refactor-plan.md`](../plans/computer-use-refactor-plan.md):决策 2(语义引用优先)、决策 3(ControlHub 唯一栈)、决策 8(`browser_control_enabled` 真实门控)、M5(截图门控)、M14(deny 表对齐)——鸿蒙适配须继承。 + - `src/crates/services/services-integrations` 的 `browser_control`:ControlHub Rust CDP 栈与 `launcher.rs`——稳定契约来源;鸿蒙后端实现同一契约而非并行第二栈。 + - `src/crates/adapters/webdriver`:WebDriver 协议适配器,platform evaluator 现仅 windows / macos——新增 ohos evaluator 的归属层。 + - `WebFetch` / `browser.fetch` / `read_article`:内容读取族与路由指导——鸿蒙 PC 直接复用。 +- **行业参照**:browser-use(a11y 三树合并 + index 句柄,成功率来源)、playwright-mcp(aria snapshot + ref,坐标隔离在 vision capability)、HarmonyOS ArkWeb 调试能力、华为浏览器 DevTools。 +- **落地分层建议**(遵循仓库分层与边界): + 1. Contracts / Execution(`src/crates/contracts` + `src/crates/execution`):浏览器控制稳定契约(`snapshot@ref`、action、错误 code)平台无关,复用现有,不新增鸿蒙专属契约。 + 2. Adapters(`src/crates/adapters/webdriver`):新增鸿蒙 platform evaluator(截图 / 定位 / 求值原语)。 + 3. Services(`src/crates/services/services-integrations` 的 `browser_control`):新增鸿蒙浏览器后端(启动 / 连接 / 快照 / 交互),不依赖 CDP 9222;ControlHub 唯一栈的鸿蒙实现。 + 4. Assembly(`src/crates/assembly`):按 delivery profile 装配鸿蒙 PC 浏览器控制 capability。 + 5. Interfaces / App / UI(`src/apps` + `src/web-ui`):鸿蒙 PC host 暴露 browser control command;UI 走 adapter / infrastructure 层,不直接调 host API。 +- **关键约束**:复用重构方案稳定契约与决策,**不在鸿蒙侧另造交互范式**;鸿蒙浏览器后端是 ControlHub 唯一栈的鸿蒙实现,不是第二套并行栈(避免 C1 重演)。 + +### 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 鸿蒙 PC 是仓库平台移植目标(见 [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md));本需求聚焦**鸿蒙 PC 应用**的浏览器使用,不涉及鸿蒙 PC CLI/TUI——后者是另一未来平台目标,需单独立项。 +- **依赖前置**:建议在 `computer-use-refactor-plan` 落地其稳定契约(`snapshot@ref`、稳定错误 code、`browser_control_enabled` 门控、M5 / M14 修复)后再做鸿蒙后端,避免在旧 god-tool 与漂移 deny 表上适配。 +- **可行性风险**:鸿蒙浏览器调试能力(ArkWeb DevTools / 系统无障碍树)需调研确认可用性;若系统不提供可控调试入口,browser use 可能需降级为 ComputerUse 桌面视觉路径或受限模式,并明确告知用户而非静默失败。 +- C6(Firefox / Safari 锁死)在鸿蒙不直接适用(鸿蒙浏览器为 ArkWeb 内核),但"可控 vs 不可控浏览器"边界 guard 仍需真正执行。 +- 远程工作场景遵循仓库"远程兼容"全局规则与 deny 表三端对齐原则;`browser_control_*` 须补入三端 deny 表并有 contract test 守护。 diff --git a/docs/features/pc-voice-input.md b/docs/features/pc-voice-input.md new file mode 100644 index 0000000000..b3a7f88a68 --- /dev/null +++ b/docs/features/pc-voice-input.md @@ -0,0 +1,75 @@ +# 桌面端 PC 语音输入(voice-input)功能提案 + +> 状态:提案 / 未集成 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) +> - [`src/crates/assembly/product-capabilities/AGENTS.md`](../../src/crates/assembly/product-capabilities/AGENTS.md) +> - [`src/crates/services/services-integrations/AGENTS.md`](../../src/crates/services/services-integrations/AGENTS.md) + +## 背景与需求描述 + +BitFun 目前是一个跨平台桌面 AI Agent(Windows / macOS / Linux,并正在进行 HarmonyOS 端口移植),用户与 Agent 的交互仅限文本输入。在编码、办公、长任务审查等场景下,纯文本输入存在以下痛点: + +- 长段需求 / 会议纪要 / 口述文档时,手打效率低、打断思考流; +- 在 Computer Use、浏览器操作、桌面执行等"手已被占用"场景下,无法边操作边输入; +- 无障碍场景(视障、肢体受限用户)缺乏语音替代输入路径; +- 与"自托管、零厂商云"的产品定位不符的方案是直接接公有云 ASR。 + +因此希望在桌面端(`DeliveryProfile::Desktop` / `ProductFull`)新增一个 `voice-input` 产品能力,让用户可以通过麦克风把语音转写为文本后注入当前会话输入框,作为文本输入的补充(而非替代)。 + +## 期望行为 + +- 在会话输入区提供"语音输入"入口(按住说话 / 点击录音两种模式可选); +- 录音会话具备完整生命周期:开始 → 采集 → 取消 / 结束 → 转写 → 文本回填到输入框; +- 支持在 Settings 中开关该能力、选择识别模型、配置麦克风设备、设置最长录音时长; +- 默认走**本地 ASR**(模型在用户机器上运行),保证隐私与离线可用;可选项:接入云端 ASR(已有 `cloud_speech` 配置形态可复用 wire 契约); +- 录音时长、采样率、临时音频文件路径等都有明确上限与清理策略,避免磁盘残留; +- 远端 / Server / Web / MobileWeb 等非桌面 delivery profile 默认不启用该能力,符合现有"按 profile 选择 capability pack"的装配规则。 + +## 非目标 / 范围外 + +- 不在本提案内做 TTS(语音播报 Agent 回复); +- 不做"始终在听"的唤醒词检测(hotword / wake-word),首版只做显式触发的按需录音; +- 不替换文本输入为主交互方式,语音只是补充输入通道; +- 不在本提案内做语音命令(voice command)语义解析,只产出转写文本交给现有会话。 + +## 建议的落地路径(基于现有分层) + +依据仓库的分层与边界规则,建议落在: + +1. **Contracts (`src/crates/contracts`)** — 在 `core-types` / `runtime-ports` 中定义稳定的语音转写 DTO 与 port trait(`SpeechTranscribeRequest`、`SpeechListModelsResponse`、`SpeechModelStatus`、`SpeechModelProgressEvent` 等),保持行为轻量、不向上依赖。 +2. **Services (`src/crates/services/services-integrations`)** — 在新增的 `speech` 集成族下实现 `SpeechService`:模型下载 / 安装、麦克风采集会话、本地 ASR 推理路由、临时音频文件 IO 与清理,全部放在显式 feature(如 `speech`)后,`default = []`。 +3. **Assembly (`src/crates/assembly/product-capabilities`)** — 新增 `ProductCapabilityId::VoiceInput` 与 `VOICE_INPUT_CAPABILITY_PACK`,并将其加入 `DEFAULT_PRODUCT_CAPABILITY_PACKS`(ProductFull / Desktop),其余 profile 不选。 +4. **Interfaces (`src/crates/interfaces`)** — 在 app-server 协议中暴露语音相关请求 / 响应(保持 camelCase wire shape 与现有 `cloud_speech` 风格一致)。 +5. **App / UI (`src/apps/desktop` + `src/web-ui`)** — 桌面 host 注册语音服务实现并暴露 Tauri command;Web UI 新增麦克风采集适配(`voiceInputAudio.ts` 一类的薄封装)与输入区 UI 入口。注意:UI 组件不得直接调用 Tauri / 浏览器 API,必须走 adapter / infrastructure 层。 + +### 分层与依赖边界要点 + +- 产品逻辑平台无关:核心 `SpeechService` 与 DTO / port 保持平台无关,麦克风采集、Tauri command、Web UI 适配分别落在各自 owner 层; +- Services 不得依赖 assembly / core facade / app / UI; +- Assembly 只做 capability pack 事实与装配,不实现具体 ASR 推理; +- 新增 feature 必须 `default = []`,重运行时(ONNX、下载器)由调用方按需启用,避免污染默认编译。 + +## 设计草案 / 参考示例 + +- **本地 ASR 引擎候选**:sherpa-onnx(k2-fsa)—— 跨平台、支持 ONNX Runtime、已有中英日韩粤多语种预训练 int8 模型,授权宽松,适合打包进桌面安装包。 +- **候选模型**(均为 int8 量化,体积 / 精度折中): + - SenseVoice Small int8 —— 多语种(普通话 / 粤语 / 英 / 日 / 韩),体量小、首版默认; + - Qwen3-ASR-0.6B int8 —— 更高质量,作为可选升级档。 +- **模型分发**:首次使用时按 manifest 下载并安装到 `~/.bitfun/speech-models/`(与现有 MiniApp / 远端部署脚本的同构目录约定一致),支持取消与断点续传,附进度事件。 +- **交互参考**:OpenAI Whisper 桌面端、微软 Dictate、macOS 系统听写 —— 按住说话 + 点击录音双模式,转写完成后文本落入输入框并由用户决定是否发送(不自动提交)。 +- **隐私边界**:默认本地推理;如用户在 Settings 显式选择云端模型,则在 wire 上复用 `cloud_speech` 配置形态,但前端必须明确提示"音频将上传至第三方"。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 本提案严格遵循仓库"产品逻辑平台无关、再通过平台适配器暴露"的规则。 +- 远程工作场景需考虑:当用户从一台设备远程控制另一台桌面时,语音输入是否在受控端执行需要明确策略。首版可在 `src/apps/desktop/src/api/remote_workspace_policy.rs` 中声明为 local-only 并给出清晰的不支持态提示,而非静默失败。 +- 仓库已有的 `cloud_speech` 配置 wire 形态(`configId` / `modelName` camelCase)可作为云端选项的复用起点,避免新造协议。 +- HarmonyOS PC CLI/TUI 支持是未来平台目标,不属于当前桌面端集成范围;如后续要覆盖,按 [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) 单独立项。 diff --git a/docs/features/pr-review-capability.md b/docs/features/pr-review-capability.md new file mode 100644 index 0000000000..d318d37147 --- /dev/null +++ b/docs/features/pr-review-capability.md @@ -0,0 +1,81 @@ +# PR 审核(Pull Request Review)能力需求文档 + +> 状态:需求 / 提案 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/review-lifecycle.md`](../architecture/review-lifecycle.md)(Review 记录、版本、新鲜度、再审查、问题延续) +> - [`docs/architecture/deep-review.md`](../architecture/deep-review.md)(当前 Review 执行:目标证据、只读角色、受管分片、补充检查) +> - [`docs/sdlc-harness/features/pr-quality-gate.md`](../sdlc-harness/features/pr-quality-gate.md)(变更就绪度与可选 PR 门禁投影) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md)(分层与平台适配边界) + +### 功能类型 + +- [x] 新功能 +- [x] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [x] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun 已具备 `Review` / `DeepReview` 的只读审查执行能力,但目前一次 Review 运行仍主要由一个子会话表示,缺少面向 PR 的稳定产品身份。用户对某个 PR 的审查结果无法跨会话恢复、无法在 PR 面板看到“该 PR 最新审查”。 +- PR 更新后旧审查被当作过时结果丢弃,缺少**新鲜度**信号与“审查当前版本”的一键再审查入口;同一 PR 上多次审查的问题无法做 new / repeated / changed 追踪,只能人工对照。 +- 审查结论与门禁语义混淆风险:AI“未发现问题”可能被误读为“通过 / 可合并”,缺少“AI 结论仅为建议、非仓库门禁结果”的硬边界。 +- 与仓库“产品逻辑平台无关、再通过平台适配器暴露”的规则不符的现状:PR 审查的产品身份、新鲜度、问题延续缺少稳定契约,难以在桌面 / 远程工作区 / 受管策略下一致投影。 +- `review-lifecycle.md` 是已采纳的设计方向但尚未全部落地;本需求将其面向 PR 的产品能力显式化,作为可交付特性推进。 + +### 功能描述 + +- **审查入口**:支持从对话、已变更文件、Pull Request 三类入口发起审查;首次审查创建稳定的 **Review 记录**(审查谱系身份),后续再审查在**同一记录**内创建新版本(revision),不因文件列表或 PR 修订相似就启发式合并两次独立审查。 +- **只读隔离执行**:每个版本由一个隔离的只读 reviewer 子会话执行(复用现有 `CodeReview` / `DeepReview` 执行策略),审查期间不得修改被审查目标;修复仍走独立的、用户批准的修复路径。 +- **有界结果投影**:每个版本持久化“列表 / 卡片视图所需的最小结果投影”——结果可用性、完成时间、覆盖度(`complete` / `limited` / `failed` / `unknown`)、目标新鲜度(`current` / `stale` / `unknown`)、问题数量与风险等级、模型建议与简短评估;完整报告与 transcript 仅在用户打开详情时按需水合。 +- **PR 面板投影**:PR 面板按“已验证的 provider 身份 + base/head”展示该 PR 最新匹配记录;旧版本与过时结果历史作为次要详情。base/head 不匹配标记为 stale,提供“审查当前版本”入口。 +- **问题延续**:以归一化的 **group key**(路径 / 类别 / 标题)与 **occurrence fingerprint**(位置 / 严重度 / 确定性 / 描述 / 校验证据)双键追踪问题;提供系统观测(new / repeated / changed / not observed)与用户处置(open / resolved / dismissed)两个独立维度;模型沉默不得自动 resolve 问题。 +- **执行与加载解耦**:执行状态与 transcript 加载状态相互独立;打开或重载详情不发起模型调用、不创建子回合;应用重启不得静默复活或重复未完成回合;未加载内容的子会话呈现 preparing / loading / load-failed 而非空白面板。 +- **非门禁边界**:AI 结论永远以建议形式呈现,不得渲染为“通过 / approved / safe to merge / 仓库门禁结果”;门禁/强制审批仍由外部权威(CI、分支保护、CODEOWNERS、人类审查人)与可选的 [PR 门禁投影](../sdlc-harness/features/pr-quality-gate.md) 负责。 +- **后台与持久化**:发起审查默认留在父任务,立即给出可用卡片,应用重启后仍可用;Review 记录与版本元数据通过既有会话历史持久化服务存储与查询,不引入并行的 Review 数据库或 UI 自有索引。 + +### 期望效果 / 使用场景 + +1. 用户准备 PR 时一键发起审查,后台运行;结果以卡片形式留在父任务,不打断当前工作,应用重启后卡片仍可恢复。 +2. PR 面板展示该 PR 的最新审查记录(含覆盖度、新鲜度、问题摘要、下一步建议),跨会话可查询恢复;无需手动翻历史会话定位“这个 PR 审过没”。 +3. PR 在 review 后被推送新提交,旧审查自动标记为 stale,提供“审查当前版本”一键再审查;新结果归入同一记录的新版本,便于版本间对比。 +4. 多次审查的问题通过 new / repeated / changed 状态追踪,用户可显式 resolve / dismiss;问题在后续审查中未被观测到时变为 `not observed` 而非自动 `resolved`,避免模型静默关闭风险。 +5. 审查保持只读,修复走独立用户批准路径;AI“未发现问题”同时附带覆盖度与新鲜度,绝不被渲染为“通过 / 可合并”。 + +### 设计草案 / 参考示例 + +- **领域模型参考**:`review-lifecycle.md` 的 `ReviewRecord` / `ReviewRevision` / `TargetEvidence` / `ResultProjection` / `FindingObservation` / `FindingDisposition` 模型与 mermaid 状态机。 +- **状态语义参考**:`pr-quality-gate.md` 的 `ready / attention / blocked / degraded` 与投影方式 `off / summary / advisory / required / blocking`,PR 审查默认落在 `summary` / `advisory`。 +- **行业参照**: + - [GitHub Copilot 代码审查](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review):AI 审查以评论形式协助,强制审批由仓库规则配置(与“AI 仅建议、门禁由外部权威”一致)。 + - [CodeRabbit 审查强度](https://docs.coderabbit.ai/reference/configuration):审查强度可配置、默认减少噪音(对应 Review strength 由显式意图控制)。 +- **落地分层建议**(遵循仓库分层与边界): + 1. Contracts(`src/crates/contracts`):稳定 DTO / port——记录锚点、版本元数据、有界结果投影、问题 group key / occurrence fingerprint 契约,行为轻量、不向上依赖。 + 2. Execution(`src/crates/execution`):Review 执行 / 子会话 / 只读角色 / 受管分片 / 补充检查策略,复用既有 owner,不新增第二个 reviewer 执行器。 + 3. Services(`src/crates/services`):会话历史持久化服务作为 Review 记录与版本的**唯一**存储 / 查询 owner,不引入并行 Review 数据库。 + 4. Assembly(`src/crates/assembly`):声明 `ProductCapabilityId::PrReview`(或等价)与 capability pack 事实,按 delivery profile 选装;非桌面形态可裁剪。 + 5. Interfaces / App / UI(`src/apps` + `src/web-ui`):暴露 PR 审查 wire 契约与 PR 面板投影;UI 组件不得直接调用 host API,须走 adapter / infrastructure 层。 +- **前置依赖**:需要“无损 source contract”——当前单一 `evidence_status` 不足以同时表达覆盖度与新鲜度,必须先让结构化 Review 输出保留独立的 `coverage` 与 `freshness` 字段(或等价机读 reason code),否则有界投影不得上线。 + +### 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 本需求是 `review-lifecycle.md`(已采纳设计方向)面向 PR 的产品化推进;落地前必须确认无损 source contract(独立 `coverage` / `freshness`)就绪,否则有界投影与 stale 判定不可靠。 +- **非目标**(沿用 `review-lifecycle.md`):不在每次保存 / 推送 / PR 更新时自动审查;不做自动评论发布 / 批准 / 合并 / 门禁强制;不做模糊语义匹配关闭问题;不把本地审查结果复用到 PR 而无仓库 / 目标 / 内容 / 策略 / 上下文等价性证明;不假装所有 provider 支持任意 revision-delta 审查。 +- **远程工作场景**:PR 审查在远程工作区需保证 provider 身份与 base/head 可验证;若某能力无法在远程合理支持,应给出清晰的不支持态提示而非静默失败(参见仓库“远程兼容”全局规则)。 +- **HarmonyOS PC CLI/TUI** 是未来平台目标,不属当前范围;如后续覆盖,按 [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) 单独立项。 +- **治理边界**:不引入 Review 专属遥测管线;审查质量保护先由确定性验收证据保障,未来若 Quality Data Plane 具备生产生产者,仅发射已注册的生命周期与显式反馈事实。 diff --git a/docs/features/privacy-statement.md b/docs/features/privacy-statement.md new file mode 100644 index 0000000000..20661fcf76 --- /dev/null +++ b/docs/features/privacy-statement.md @@ -0,0 +1,77 @@ +# 用户隐私声明(Privacy Statement)能力需求文档 + +> 状态:需求 / 提案(假设尚未实现,从零立项) +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md)(分层与平台适配边界) +> - [`docs/architecture/i18n.md`](../architecture/i18n.md)(多语言与 locale 治理) +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md)(未来 HarmonyOS PC CLI/TUI 平台目标) + +### 功能类型 + +- [x] 新功能 +- [ ] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [x] 紧急(P0 - 核心需求,强烈期望实现) +- [ ] 高(P1 - 重要功能,期望尽快实现) +- [ ] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun 作为跨平台 AI Agent,会接触用户代码、对话内容、AI provider 凭据、远程工作区、可选云端语音转写等高度敏感数据,但目前缺少面向用户的统一隐私声明,用户无法清楚了解"我的数据去了哪里"。 +- 多 delivery profile(Desktop / CLI / Server / Web / MobileWeb / ACP)数据收集范围差异大,本地推理、云端 AI provider、远程 relay、云端 ASR、使用指标上报等可选项的数据流向缺少透明告知。 +- 合规红线:中国《个人信息保护法》(PIPL)、欧盟 GDPR、各应用商店上架政策均要求提供明确隐私声明并取得用户同意;缺少声明将直接阻断发布与上架。 +- 缺少版本化的声明管理:声明更新后无法区分"实质变更(需重新同意)"与"编辑性修订",无法证明用户接受的是哪个版本,合规审计无据可查。 +- 缺少"未同意时的降级模式":用户拒绝同意后,产品应能以受限模式继续运行(仅本地/离线功能)而非完全不可用,且不得静默收集任何数据。 +- 数据收集路径缺少统一门禁:各遥测/云端/上报路径若各自判断同意状态,易出现遗漏与静默上报。 + +### 功能描述 + +- **统一隐私声明文档**:提供一份面向用户的隐私声明,覆盖:收集的数据类型(本地代码 / 对话 / 凭据 / 设备信息 / 使用指标)、数据存储位置(本地 vs 云端)、数据流向(第三方 AI provider / relay / 云端 ASR)、数据保留与删除策略、用户权利(访问 / 更正 / 删除 / 导出 / 撤回同意)、第三方接收方与目的、安全措施摘要、联系方式。 +- **多语言**:声明按 locale 维护,跟随仓库 i18n 治理(locale id / 别名 / 回退由 `src/shared/i18n/contract/locales.json` 拥有),不硬编码 CJK;MobileWeb / Installer 不导入 Web UI locale catalog。 +- **版本化与变更分级**:每个声明版本带版本号、`updated_at`、`effective_at`、文档内容 SHA256;变更标记为 `material`(实质变更,需重新同意)或 `editorial`(编辑性修订,不触发重新同意)。 +- **同意生命周期**:首次启动或存在未读实质更新时展示声明,用户显式接受——记录所接受的版本、文档 SHA256、接受时间、locale、应用版本;未接受时进入受限模式。 +- **未读更新提示**:声明有实质更新时,状态标记存在未读更新,在合适入口提示用户查看并重新同意;编辑性修订不强制打断。 +- **降级模式**:用户拒绝同意时,产品以受限模式运行——本地推理 / 离线功能可用,云端 AI provider、远程 relay、云端 ASR、使用指标上报等被禁用,并给出清晰的不支持态提示而非静默失败。 +- **数据收集门禁**:提供单一的数据收集策略门禁,任何数据收集路径在执行前查询同意状态;未同意或处于受限模式时阻断收集(fail-closed),不静默上报。 +- **可访问入口**:在 Settings 内提供"查看隐私声明"入口,可随时查看当前版本与历史版本;提供"撤回同意"入口,撤回后进入受限模式。 +- **平台无关 + 平台适配**:声明内容与同意状态管理逻辑平台无关;各 delivery profile 通过平台适配器暴露(桌面 host command、Web UI 适配等);UI 组件不直接调用 host API,须走 adapter / infrastructure 层。 + +### 期望效果 / 使用场景 + +1. 用户首次安装 / 启动应用时,看到当前隐私声明,明确知道收集哪些数据、去向哪里、自己的权利;接受后才进入完整功能模式。 +2. 声明有实质更新时,应用提示"隐私声明已更新",用户查看并重新同意;编辑性修订不打断使用。 +3. 用户在 Settings 随时查看隐私声明当前版本与历史版本,并可撤回同意——撤回后应用进入受限模式,仅本地功能可用,云端能力被禁用并给出明确提示。 +4. 任何数据收集路径在用户未同意 / 受限模式下被 fail-closed 阻断,不发生静默上报;同意记录可作为合规证据被用户查看与导出。 +5. 多 delivery profile(桌面 / CLI / Web / MobileWeb)下声明内容与同意语义一致,仅暴露方式按平台适配。 + +### 设计草案 / 参考示例 + +- **行业参照**:GitHub Privacy Statement、OpenAI Privacy Policy、微软 Privacy Statement 的版本化与变更说明;中国 App 隐私政策模板(PIPL);GDPR 透明度与撤回同意要求。 +- **落地分层建议**(遵循仓库分层与边界,从零设计): + 1. Contracts(`src/crates/contracts/product-domains`):定义平台无关、行为轻量的稳定 DTO——声明视图(版本 / 变更类型 / 生效时间 / SHA256 / 内容)、同意记录(接受版本 / SHA256 / 时间 / locale / 应用版本)、生命周期状态(待选择 / 完整 / 未接受 / 资源错误)、有效模式(完整 / 未接受)、变更类型(实质 / 编辑)。 + 2. Services(`src/crates/services/services-integrations`):声明文档加载与校验、同意记录持久化、同意状态计算、单一数据收集策略门禁(提供"是否允许收集"查询与模式切换)。 + 3. Assembly(`src/crates/assembly`):声明文档作为不可变内置内容随版本发布,按 delivery profile 装配;声明更新随产品版本同步。 + 4. Interfaces / App / UI(`src/apps` + `src/web-ui`):桌面 host 注册隐私服务并暴露 command;Web UI 提供声明展示 / 同意 / 撤回 UI;UI 走 adapter / infrastructure 层,不直接调 host API。 +- **合规审计**:同意记录(版本、SHA256、时间、locale、应用版本)可被用户查看与导出,作为"用户接受了哪个版本"的合规证据。 +- **远程工作场景**:远程控制下隐私同意状态以受控端为准;若远程工作区无法满足同意要求,给出清晰不支持态提示而非静默失败。 + +### 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 隐私声明的存在与首次同意流程对应用上架与多法域合规是 release-gating 的,建议作为发布就绪的前置条件之一(`release_ready` 语义)。 +- **非目标**:不做行为广告、不出售用户数据、不做"暗模式"同意引导、不在未同意时静默收集。 +- 声明文本本身需法务 / 合规审阅;本需求只定义产品能力与契约,不替代法律文本撰写。 +- HarmonyOS PC CLI/TUI 是未来平台目标,不属当前范围;如后续覆盖,按 [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) 单独立项。 diff --git a/docs/features/skill-capability-support.md b/docs/features/skill-capability-support.md new file mode 100644 index 0000000000..bea3082736 --- /dev/null +++ b/docs/features/skill-capability-support.md @@ -0,0 +1,142 @@ +# Skill 能力支持(Skills 扩展层)需求文档 + +> 状态:能力规格 / 需求 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) +> - [`docs/architecture/agent-runtime-services-design.md`](../architecture/agent-runtime-services-design.md) +> - [`src/crates/execution/agent-runtime/AGENTS.md`](../../src/crates/execution/agent-runtime/AGENTS.md) +> - [`docs/features/gewu-market-integration.md`](./gewu-market-integration.md) + +## 背景与需求描述 + +BitFun 的扩展能力分四层(L1 自定义 Agent → **L2 MCP / Skills / Hooks** → L3 Mini Apps → L4 源码级改造)。其中 **Skills** 是 prompt / resource / instruction 形态的轻量扩展,作为 agent definition 或 harness input 的一部分注入运行时——与 MiniApp(自带界面与运行时)、MCP(外部工具协议)形成互补。 + +Skills 这条扩展路径需要满足的核心诉求: + +- **跨生态复用**:用户已有 Claude Code / Codex / Cursor / OpenCode / 通用 Agent Skills 目录里的 Skill 资产,BitFun 不能要求重新造一份,应能直接发现并按各自方言解析; +- **分层放置**:同一台机器上,项目级、用户家目录级、用户配置级的 Skill 应有清晰优先级与遮蔽规则,避免项目 Skill 被全局 Skill 静默覆盖; +- **按模式生效**:不同 Agent 模式(Agentic / Plan / Debug / DeepReview / DeepResearch 等)应能声明各自默认启用 / 隐藏的 Skill,用户可显式覆盖; +- **显式调用**:用户应能直接点名调用某个 Skill(而非只能被动随模式加载); +- **热加载**:编辑 / 新增 / 删除 Skill 后,运行时应能受控刷新发现结果,无需重启; +- **可分发**:精品 Skill 应能经由市场(如格物市场)安装与更新,而非只能手动拷贝; +- **远程可用**:远程工作区场景下,Skill 发现与刷新应明确归属哪一端执行,不能静默失败。 + +本需求文档定义 Skill 能力支持的目标范围、行为契约与分层归属。 + +## 期望行为 + +### 1. 多源发现 + +- 在以下生态目录下发现 Skill,并按各自方言(dialect)解析 markdown front-matter: + - BitFun 原生:`.bitfun/skills`; + - Claude Code:`.claude/skills`; + - Codex:`.codex/skills`; + - Cursor:`.cursor/skills`; + - OpenCode:`.opencode/skills`; + - 通用 Agent Skills:`.agents/skills`。 +- 每个发现源携带**生态标识**(source_id / source_label,如 `claude-code` / `Codex`),仅作展示用途,**绝不参与 Skill 优先级判定**,避免生态来源隐式影响执行。 +- 解析方言至少覆盖:Claude Code、Codex、通用 Agent Skills 三种 front-matter 形态。 + +### 2. 三级放置与优先级 + +- 支持三级 Skill 根目录: + - **项目级**:随项目仓库放置,团队共享; + - **用户家目录级**:跨项目共享,个人偏好; + - **用户配置级**:经用户 config 显式指定(如 OpenCode 的 `skills.paths` 配置)。 +- 同名 Skill 按项目级 > 用户级 的方向遮蔽,并产出清晰的遮蔽说明(被遮蔽的 Skill 仍可显式调用)。 +- Windows 下用户配置根目录需做平台特化解析(如 OpenCode 走 `~/.config/opencode/skills`)。 + +### 3. 内建目录与模式策略 + +- 提供内建 Skill 目录(builtin catalog),按 group 归类; +- 每个 Agent 模式声明:默认启用的内建 Skill、默认隐藏的内建 Skill; +- 用户可在模式级覆盖默认策略(启用 / 禁用 / 强制显式调用); +- 当用户显式点名一个默认隐藏的内建 Skill 时,应能解析为"本次显式生效"而非全局改动。 + +### 4. 选择与调用 + +- 按模式过滤候选 Skill(可隐式调用 / 仅显式调用 / 用户可调用); +- 对候选集排序、去重、标注遮蔽关系; +- 支持"可见 Skill 列表"在 assistant 上下文中渲染,使模型知道当前可调用哪些 Skill; +- Skill 列表变化时产出内部提醒(skill listing diff),帮助模型感知环境变化。 + +### 5. 热加载与刷新 + +- 通过文件监听服务(file_watch)管理 `bitfun-skills` 目录,编辑后受控触发 Agent 运行时重新发现; +- 提供运行时上下文刷新目标(reload target = Skills),供宿主在 Skill 变更后定向刷新,而非整会话重建; +- 嵌套 Skill 根的父目录注册应覆盖子目录变更。 + +### 6. 市场分发 + +- 与格物市场等市场链路打通:浏览 / 安装 / 版本更新 / 卸载精品 Skill(详见 `gewu-market-integration.md`); +- 市场安装的 Skill 落入既有 Skill 根目录约定,复用现有发现 / 解析链,不另造第二套发现机制。 + +### 7. 远程工作区 + +- 远程控制另一台桌面时,Skill 发现与刷新应在受控端执行;控制端只发起与展示; +- 在 `remote_workspace_policy` 中声明明确策略,不支持时给出清晰提示而非静默失败。 + +### 8. 助手可见性 + +- 已加载 Skill 应能渲染为 assistant 可读的 payload(来源 / 路径 / 模式生效态),便于模型引用; +- 转写 / 渲染保持平台无关,产物只在运行时层定义,宿主负责具体 IO。 + +## 非目标 / 范围外 + +- 不在本需求内做 Skill 运行时沙箱或权限收窄——Skill 作为 prompt / instruction 注入,安全模型与现有 Skills 一致; +- 不做 Skill 的图形化编辑器或可视化构建工具; +- 不替换 MCP / Hooks / 自定义 Agent / MiniApp 等其他扩展层; +- 不在本需求内定义格物市场私有协议(见 `gewu-market-integration.md`); +- 不覆盖 HarmonyOS PC CLI/TUI 形态(见 `platform-portability-design.md`,需单独立项); +- 不承诺跨 Skill 的依赖解析 / 组合编译——Skill 之间相互独立。 + +## 建议的落地路径(基于现有分层) + +依据仓库的分层与边界规则,Skill 能力的各部分应归属: + +1. **Execution / Agent Runtime (`src/crates/execution/agent-runtime`)** — Skill 的**可移植决策与事实**归属此 crate 的 `skills` 模块: + - DTO:`SkillData`、`SkillInfo`、`SkillLocation`、`ModeSkillInfo`、`SkillParseError` 等; + - 根目录事实:`SkillRootSpec`、`PROJECT_SKILL_ROOTS` / `USER_HOME_SKILL_ROOTS` / `USER_CONFIG_SKILL_ROOTS`、`BITFUN_SKILL_SOURCE_ID`; + - 内建目录:`BuiltinSkillSpec` / `BuiltinSkillGroup` / `builtin_skill_spec`; + - 模式策略与解析:`resolve_skill_state_for_mode`、`resolve_skill_default_enabled_for_mode`、`normalize_user_mode_skill_overrides`; + - 选择与遮蔽:`resolve_visible_skills`、`annotate_shadowed_skills`、`filter_candidates_for_mode`、`resolve_default_hidden_builtin_for_explicit_invocation`; + - 助手渲染:`render_loaded_skill_for_assistant`。 + - 边界:**纯事实与决策**,不得做具体文件系统 IO、配置 IO 或注册表扫描——这些归宿主 / 服务层。 +2. **Contracts (`src/crates/contracts`)** — 稳定的 Skill DTO / port 与上下文刷新目标(`AgentContextReloadTarget::Skills`)、Skill 列表 diff 事件形态等行为轻量契约。 +3. **Adapters (`src/crates/adapters`)** — 外部生态 Skill 源协议适配,如 `opencode-adapter` 的 `OpenCodeSkillRootProvider` / `OpenCodeConfiguredSkillRoot`、`claude-code-adapter` 与 `codex-adapter` 的 Skill 导入。仅做生态私有配置 / 目录方言翻译,不承载产品策略。 +4. **Assembly / Core (`src/crates/assembly/core`)** — Skill 注册表装配:`SkillRegistry`、`SkillRootEntry`、`RemoteSkillRootEntry`、`source_cache`,把外部源贡献(如 OpenCode 配置根)投影进运行时根集合;宿主在此层做具体发现扫描。 +5. **Services (`src/crates/services/services-integrations`)** — `file_watch` 管理 `bitfun-skills` 目录的热加载;市场安装(格物市场)落盘到 Skill 根目录后的清理 / 校验归 market 集成族。 +6. **App / UI (`src/apps/desktop` + `src/web-ui`)** — 桌面宿主装配 Skill 注册表、暴露 Skill 管理 UI(列表 / 启用禁用 / 模式覆盖 / 市场入口);UI 组件不得直接读文件系统或外部生态目录,必须走 adapter / service 层。 + +### 分层与依赖边界要点 + +- 产品逻辑平台无关:Skill 决策、目录事实、目录、方言解析、模式策略、选择遮蔽、助手渲染全部在 `agent-runtime` 的 `skills` 模块,平台无关; +- `agent-runtime` 不得依赖 `bitfun-core`、app、Tauri、具体 service crate——只能通过 port 与注入的注册表获取能力; +- 具体文件系统 / 配置 IO / 注册表扫描、生态私有协议翻译、市场安装落盘、热加载触发分别归各 owner 层; +- 生态标识(source_id)仅展示,绝不参与优先级——这是必须保持的不变量; +- 新增外部生态源应作为新 adapter 接入,而非在 `agent-runtime` 内堆砌生态特化分支。 + +## 设计草案 / 参考示例 + +- **目录方言**:Claude Code / Codex / 通用 Agent Skills 三种 front-matter 形态,由 `skill_source_dialect` 按来源 slot 分派;新增生态应通过新增方言 + adapter 接入,不在决策层加 `if` 分支。 +- **优先级模型**:项目级遮蔽用户级,遮蔽不删除被遮蔽 Skill(仍可显式调用);遮蔽关系作为展示元数据随 `SkillInfo` 一起渲染。 +- **模式策略参考**:DeepReview / DeepResearch / Plan / Debug 等模式各自声明默认启用与默认隐藏集;用户覆盖写入模式级 override,运行时按 `resolve_skill_state_for_mode` 解析最终态。 +- **热加载参考**:`file_watch` 服务对 `bitfun-skills` 目录的父目录注册覆盖子目录变更;嵌套根的父级注册需覆盖最深层变更。 +- **助手可见性参考**:`render_loaded_skill_for_assistant` 把已加载 Skill 渲染为模型可读 payload;Skill 列表变化经 `SkillListingDiff` 内部提醒通知模型。 +- **市场分发参考**:见 `gewu-market-integration.md`;市场安装复用既有根目录约定与发现链,不另造。 +- **跨生态兼容参考**:与 Codex hook 契约(`docs/features/agent-hooks.md`)保持一致——BitFun 实现既有生态契约而非另起炉灶,Skill 方言亦同。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 本需求严格遵循仓库"产品逻辑平台无关、再通过平台适配器暴露"与"优先事实与决策,具体 IO 下沉"的规则:Skill 的目录 / 目录 / 策略 / 选择 / 渲染是可移植决策,归 `agent-runtime`;具体发现扫描与生态协议翻译归 adapter / assembly / service。 +- 与 `gewu-market-integration.md` 的关系:本需求定义 Skill **能力本身**的支持范围,格物市场文档定义 Skill **分发通道**;两者互补,市场安装落盘后即进入本需求定义的发现 / 解析 / 选择链。 +- 与 `agent-hooks.md` 的关系:Skills 与 native Hooks 是 L2 扩展层的并列通道,互不替代;Skill 是 prompt / instruction 注入,Hook 是生命周期点副作用。 +- 远程工作区策略:Skill 发现 / 刷新归属受控端执行,控制端只发起与展示,在 `remote_workspace_policy` 中显式声明,不支持时清晰提示。 +- 相关分层入口:`src/crates/contracts/AGENTS.md`、`src/crates/adapters/AGENTS.md`、`src/crates/execution/agent-runtime/AGENTS.md`、`src/crates/assembly/core` 的 Skill 注册表实现、`src/crates/services/services-integrations/AGENTS.md`。 diff --git a/docs/features/tap-to-share-files.md b/docs/features/tap-to-share-files.md new file mode 100644 index 0000000000..db5cd88d3e --- /dev/null +++ b/docs/features/tap-to-share-files.md @@ -0,0 +1,98 @@ +# 碰一碰分享文件(Tap to Share Files)需求文档 + +> 状态:提案 / 未做 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/platform-portability-design.md`](../architecture/platform-portability-design.md) +> - [`docs/architecture/peer-device-mode.md`](../architecture/peer-device-mode.md) +> - [`harmonyos-pc-drag-drop.md`](./harmonyos-pc-drag-drop.md) +> - [`src/apps/ohos`](../../src/apps/ohos/) + +## 背景与需求描述 + +"碰一碰"是 HarmonyOS 提供的近场分享能力:两台设备轻触(经 NFC / 蓝牙 / Wi-Fi 近场感知)即触发文件 / 内容分享。BitFun 现有的跨设备通道是自托管 relay(零知识、AES-GCM)与 Remote Connect / Peer Device Mode,需要账号配对与网络;缺少**免配对、近场、即触即传**的轻量分享。 + +当前缺口与诉求: + +- 用户无法在两台 BitFun 实例(或 BitFun 与 HarmonyOS 设备)之间"一碰即传"文件,只能走 relay 配对 / 远程工作区 / 拖拽; +- 近场分享无需账号配对、无需联网到厂商云,与"自托管、零厂商云"定位一致; +- 接收侧须有确认与完整性校验,不静默接收未知来源; +- 鸿蒙 PC GUI 是独立产品专题(见 `platform-portability-design.md`),碰一碰是其下能力子项,不提前决定 GUI 整体选型。 + +本提案新增**碰一碰分享文件**能力:两台设备轻触即发起文件分享,接收侧确认后落盘到工作区,复用既有拖拽落点与文件校验。 + +## 期望行为 + +### 1. 发起与接收 + +- 发起侧:选中文件 / 内容,与另一台设备轻触,发起近场分享; +- 接收侧:弹出接收提示(来源、文件名、大小、类型),用户确认后接收; +- 不静默接收;用户可拒绝。 + +### 2. 落点与校验 + +- 接收文件落入当前工作区或用户指定目录(对齐拖拽落点:聊天输入 / 文件面板 / 工作区); +- 完整性校验(哈希,对齐 market 包校验策略),失败可回滚不残留半截文件; +- 大文件 / 批量有进度与取消。 + +### 3. 隐私与安全 + +- 近场分享不联网厂商云;凭据 / 配对信息最小化; +- 接收内容视为第三方来源,落盘前提示(对齐隐私协议第 8 条); +- 不自动执行接收文件,不自动打开可执行。 + +### 4. 平台与跨设备 + +- 优先 HarmonyOS 碰一碰 / 一碰传 / NFC 能力(华为官方 API 为准,本提案不臆测字段); +- 非 HarmonyOS 平台不支持时显式 unavailable,不静默回退到 relay; +- 与既有 relay / Remote Connect / Peer Device Mode 互补,不替换。 + +### 5. 远程与不可用态 + +- 碰一碰是本机近场交互,远程控制场景下声明本地执行; +- 目标鸿蒙版本 / 设备缺少近场能力时显式 unsupported,不借用桌面 / 移动端 / Remote 代执行。 + +## 非目标 / 范围外 + +- 不替换 relay / Remote Connect / Peer Device Mode; +- 不在本提案内做隔空传送(发现附近设备、无线传输,见 `harmonyos-pc-airdrop.md`); +- 不覆盖跨厂商 AirDrop 互操作(除非平台原生支持); +- 不预先决定鸿蒙 PC GUI 整体选型; +- 不做接收文件的自动解析 / 执行。 + +## 建议的落地路径(基于现有分层) + +1. **Contracts (`src/crates/contracts`)** — 碰一碰分享 DTO / port(来源、文件元数据、进度、确认),行为轻量,不耦合 HarmonyOS 私有 API。 +2. **OHOS App (`src/apps/ohos`)** — HarmonyOS 碰一碰 / NFC / 近场分享适配;鸿蒙私有协议不泄漏出适配层。 +3. **Services (`src/crates/services`)** — 接收文件落盘、哈希校验、临时文件清理(复用 market 包校验与 artifacts 约定)。 +4. **Web UI / ArkUI** — 接收提示 UI、落点选择(复用拖拽落点)。 +5. **远程策略** — 碰一碰命令远程策略声明本地执行,在 `remote_workspace_policy` 登记。 + +### 分层与依赖边界要点 + +- 严格遵守 `platform-portability-design.md`:鸿蒙 PC GUI 是独立专题,碰一碰是其下能力子项; +- 平台差异只在 app/adapter/service 边界,共享 Runtime 不按 target triple 分叉业务; +- 缺失能力显式 unsupported,不静默借用桌面 / 移动端 / Remote 代执行; +- 不建立巨型 `ohos` feature 或第二套分享协议; +- 复用拖拽落点与文件校验,不新造第二套接收链。 + +## 设计草案 / 参考示例 + +- **平台能力参考**:HarmonyOS 碰一碰 / 一碰传 / NFC(华为官方文档为准)。 +- **落点参考**:拖拽落点(聊天输入 / 文件面板 / 工作区导航),碰一碰接收复用同构落点。 +- **校验参考**:market 包哈希校验、原子落盘、失败回滚。 +- **隐私参考**:隐私协议第 8 条(第三方来源提示)。 +- **互补参考**:relay(零知识自托管)适合跨网络 / 持久配对;碰一碰适合近场 / 免配对 / 即触即传。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与 `harmonyos-pc-drag-drop.md` 的关系:两者都是鸿蒙 PC GUI 下的近场 / 本地交互能力子项,复用文件落点与校验。 +- 与 `harmonyos-pc-airdrop.md` 的关系:碰一碰是近场轻触触发,隔空传送是发现附近设备无线传输,互补不替换。 +- 与 relay 的关系:relay 适合跨网络持久配对,碰一碰适合近场免配对,二者互补。 +- 相关分层入口:`src/apps/ohos`、`docs/architecture/platform-portability-design.md`、`docs/architecture/peer-device-mode.md`。 diff --git a/docs/features/terminal-capability.md b/docs/features/terminal-capability.md new file mode 100644 index 0000000000..fd257ab78b --- /dev/null +++ b/docs/features/terminal-capability.md @@ -0,0 +1,102 @@ +# 终端能力(Terminal Capability)需求文档 + +> 状态:能力规格 / 需求 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/crates/services/terminal/AGENTS.md`](../../src/crates/services/terminal/AGENTS.md) +> - [`docs/architecture/agent-runtime-services-design.md`](../architecture/agent-runtime-services-design.md) +> - [`src/crates/assembly/core/AGENTS.md`](../../src/crates/assembly/core/AGENTS.md) + +## 背景与需求描述 + +BitFun Agent 要"进入真实环境"完成任务,必须能在用户工作区里驱动 shell:执行命令、读输出、发信号、取消进程。终端能力是 Agent 桌面执行层的基础设施之一,与文件系统、Git、浏览器操作并列。 + +本需求定义**终端能力**(区别于"内置终端面板 UI"——见 `builtin-terminal-panel.md`):即可被 Agent 工具与产品宿主复用的 PTY / 会话 / shell 集成服务,以及 Agent 直接调用的执行类工具。 + +当前缺口与诉求: + +- 终端能力应以**独立、平台无关的服务 crate** 形式存在,不耦合 `bitfun-core` / Tauri / 产品域 / AI / Git / MCP / transport; +- Agent 执行命令需稳定契约:创建会话、写 stdin、读输出、resize、信号、取消、关闭,跨 Windows / macOS / Linux 行为一致; +- 远程工作区场景下,终端会话应在受控端执行,控制端只发起与展示,不静默失败; +- 进程生命周期须受控回收(受管子进程清理),不残留孤儿进程; +- 转写(transcript)须可持久化与回放,并做路径 / 命令脱敏。 + +## 期望行为 + +### 1. PTY 与会话生命周期 + +- 创建 PTY 会话(`CreateSessionRequest`),分配 shell,产出会话 id; +- 写入(`WriteRequest` / `SendCommandRequest`)、读输出(事件流)、resize(`ResizeRequest`)、信号(`SignalRequest`)、关闭(`CloseSessionRequest`); +- 会话生命周期事件经 `TerminalEvent` / `TerminalEventEmitter` 投影到前端; +- 会话可持久化与回放(`session/replay`、`session/persistent`),冷启动后可恢复。 + +### 2. Shell 检测与集成 + +- 跨平台 shell 检测(Windows / macOS / Linux,`shell/detection`):探测、选择、缓存; +- shell 集成脚本注入(`shell/integration`、`shell/scripts_manager`、`shell/profiles`),支持命令补全提示、当前目录上报、退出码; +- 用户可配置 shell 偏好(`parse_configured_shell_preference`、`resolve_local_exec_shell`)。 + +### 3. Agent 执行工具 + +- `BashTool` / `ExecCommand` / `WriteStdin` / `ExecControl`(属 `core.basic` 工具组)供 Agent 调用; +- 执行支持后台化、stdin 写入、取消(`ExecControlAction`)、完成态(`ExecSessionCompletion`); +- 进程树受管清理(`services-core::process_tree`):Unix 进程组、Windows Job Object 兜底,明确这是生命周期收容而非 OS 沙箱。 + +### 4. 转写与脱敏 + +- 转写根目录可配置,`None` 禁用录制; +- 转写支持回放、截断保序、跨重启恢复; +- 转写与日志遵循脱敏:路径、命令、凭据按既有 redaction 规则。 + +### 5. 远程工作区 + +- 远程控制另一台桌面时,终端会话在受控端执行; +- 在 `remote_workspace_policy` 中声明终端相关命令的远程策略(远程路由 / 本地 / 不支持),不支持时清晰提示; +- 远程 SSH 终端属 `remote-ssh` owner,不在本需求。 + +### 6. 跨平台与鸿蒙 + +- 基础终端能力平台无关,Windows / macOS / Linux shell 兼容; +- 鸿蒙 PC CLI/TUI 的 PTY / 信号 / `/dev` 语义属未来专题(见 `platform-portability-design.md`),不在本需求承诺范围;鸿蒙不可用时显式 unsupported。 + +## 非目标 / 范围外 + +- 不在本需求内定义内置终端面板 UI(见 `builtin-terminal-panel.md`); +- 不覆盖 CLI/TUI 形态的终端(ratatui/crossterm,属 `src/apps/cli`); +- 不定义远程 SSH 终端协议(属 `remote-ssh` owner); +- 不在本需求内做终端外观 / 主题(属 appearance); +- 不替换 `BashTool` / `ExecCommand` 既有契约。 + +## 建议的落地路径(基于现有分层) + +1. **Contracts (`src/crates/contracts`)** — 终端 DTO / port:会话 id、请求 / 响应、事件形态、转写契约,行为轻量。 +2. **Services (`src/crates/services/terminal`,包名 `terminal-core`)** — PTY(`pty`)、会话(`session`)、shell(`shell`)、配置(`config`)、事件(`events`)、转写(`transcript`)、exec(`exec` / `exec_shell`)。边界:不依赖 core / Tauri / 产品域 / AI / Git / MCP / transport;平台差异在 terminal 抽象后。 +3. **Assembly / Core (`src/crates/assembly/core`)** — `BashTool` / `ExecCommand` / `WriteStdin` / `ExecControl` 工具实现与 product runtime 装配;远程路由。 +4. **App / UI** — 宿主注册终端服务、暴露 Tauri command;内置面板见 `builtin-terminal-panel.md`。 + +### 分层与依赖边界要点 + +- 终端能力平台无关:PTY / 会话 / shell / 转写决策在 `terminal-core`,平台无关;具体宿主命令与 UI 在上层; +- `terminal-core` 不依赖 `bitfun-core` / app / Tauri; +- 进程清理是生命周期收容,不是 OS 沙箱或资源限额,须在表面保持显式残余风险; +- 远程策略显式声明,不引入对远程工作区路径的隐式依赖。 + +## 设计草案 / 参考示例 + +- **模块布局参考**:`terminal-core` 的 `pty` / `session` / `shell` / `config` / `events` / `transcript` / `exec` 分层。 +- **shell 检测参考**:`shell/detection`(probe / selection / platform / path / cache)跨平台兼容。 +- **转写参考**:`transcript.rs` 的录制 / 回放 / 截断 / 跨重启恢复与脱敏。 +- **进程清理参考**:`services-core::process_tree` 的 Unix 进程组与 Windows Job Object 兜底。 +- **远程参考**:`remote_workspace_policy` 显式声明终端命令远程策略。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 与 `builtin-terminal-panel.md` 的关系:本需求定义终端**服务 / 能力**,后者定义**应用内面板 UI**;面板消费本服务。 +- 与远程工作区的关系:终端会话远程路由在 `remote_workspace_policy` 显式声明,不支持时清晰提示。 +- 相关分层入口:`src/crates/contracts/AGENTS.md`、`src/crates/services/terminal/AGENTS.md`、`src/crates/assembly/core/AGENTS.md`。 diff --git a/docs/features/user-feedback-ui-optimization.md b/docs/features/user-feedback-ui-optimization.md new file mode 100644 index 0000000000..d9066d9a80 --- /dev/null +++ b/docs/features/user-feedback-ui-optimization.md @@ -0,0 +1,135 @@ +# 功能建议:用户反馈界面(User Feedback UI) + +> 状态:提案 / 未做 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) +> - [`src/apps/desktop/AGENTS.md`](../../src/apps/desktop/AGENTS.md) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) +> - [`src/crates/services/services-integrations/src/privacy/assets/zh-CN.md`](../../src/crates/services/services-integrations/src/privacy/assets/zh-CN.md) + +## 背景与需求描述 + +BitFun 桌面端目前缺少一个完整、可用、体验连贯的**应用内用户反馈界面**。用户在使用过程中遇到的问题、建议、异常无法在应用内闭环提交,也无从知道官方是否回复,导致: + +- 问题只能去外部 Issue 跟踪系统(如 GitCode Issues)手动提交,与应用内上下文割裂,提交成本高; +- 反馈无法携带应用版本、运行环境等关联信息,定位困难; +- 官方回复无法回流到应用内,用户不知道自己的反馈被处理; +- 隐私同意未与反馈提交绑定,无法满足"提交反馈前需同意隐私协议"的合规要求; +- 不同平台(桌面 vs HarmonyOS)缺乏一致的反馈体验。 + +因此希望新增一个**应用内用户反馈界面**,让用户在应用内完成"提交反馈 → 收到官方回复 → 回复与确认已读"的完整闭环,作为外部 Issue 系统的补充(而非替代)。 + +## 期望行为 + +### 1. 入口与未读感知 + +- 在底部常驻操作区提供"反馈"入口; +- 当存在官方回复且用户尚未确认已读时,入口给出醒目的未读提示; +- 未读提示只对"可打开且有新回复"的会话计数,避免历史不可操作项误报; +- 反馈服务不可用时入口清晰灰显并给出原因,而非静默不可点。 + +### 2. 提交流程 + +- 提交表单包含:反馈分类、内容、是否附带关联信息(版本 / 运行环境)、隐私同意勾选; +- 草稿判定:分类 / 内容 / 关联信息 / 隐私勾选任一非空即视为有草稿; +- 有草稿时关闭、切换视图或切换会话需经丢弃确认; +- 提交中冻结关闭按钮、遮罩点击与临界退出(避免误关丢草稿); +- 内容超长时给用户明确截断反馈,不静默丢字; +- 提交成功后只展示单一完成动作,不并列冗余外链按钮。 + +### 3. 错误与配额态 + +- 配额超限时仅当服务端返回的正倒计时 > 0 时展示倒计时与重试按钮,避免"0 秒重试"无效态; +- 倒计时基于绝对截止时间,跨组件实例稳定; +- 隐私同意保存失败时给出可恢复文案并阻止继续提交; +- 网络 / 未知错误给出可重试入口,重试不丢失已填草稿。 + +### 4. 收件箱与会话 + +- 收件箱列表展示会话摘要、最近回复、未读标记; +- 未读关注只对"可打开且有新回复"的项计数; +- 回复发送态冻结关闭与遮罩,与提交态语义一致; +- 已读确认与打开会话分离,避免打开即静默确认; +- 切换会话时有未发送回复草稿时走丢弃确认 / 待定退出流程。 + +### 5. 布局与响应式 + +- 宽布局阈值(约 840px)基于容器宽度观察触发,宽态用双列布局(左侧列表 + 右侧会话); +- 对话框尺寸有上限(约 960×620)并随视口收窄,小屏切单列; +- 顶部留白始终避开宿主窗口控件区,无遮挡; +- 高 DPI / 极小尺寸下文案与按钮可读性保持,不截断不重叠。 + +### 6. 隐私与同意 + +- 未同意隐私协议时,反馈请求必须在用户完成"同意"后才发出; +- 内联同意区提供只读隐私声明入口,文案区分前缀 / 后缀; +- 同意态切换即时反馈到入口可用性; +- 用户可经帮助菜单撤回同意,撤回后反馈通道进入未同意态。 + +### 7. 可达性与国际化 + +- 完整键盘导航:Tab 顺序合理、焦点环可见、Esc 行为可预期(提交 / 回复发送态除外); +- `feedback.*` 文案完整,走命名空间懒加载,无硬编码; +- 表单控件带无障碍标签,错误态对屏幕阅读器可读。 + +### 8. 平台一致性 + +- HarmonyOS 走本地能力后端提交(凭据经安全资产存储),其他平台可外链外部 Issue 系统; +- 两条路径在未读关注、草稿、错误态上的体验对齐,差异仅在提交后端; +- 反馈相关 Tauri command 的远程工作区策略声明为与工作区位置无关,远程控制场景下反馈通道仍可用。 + +## 非目标 / 范围外 + +- 不替换外部 Issue 跟踪系统,应用内反馈是其补充; +- 不在本提案内设计反馈后端协议、配额策略或凭据存储模型; +- 不在本提案内撰写隐私协议正文(正文由隐私 owner 维护),仅做同意门交互; +- 不做反馈数据的可视化分析仪表盘; +- 不覆盖 CLI/TUI 形态的反馈呈现; +- 不做反馈内容的 AI 自动分类或摘要。 + +## 建议的落地路径(基于现有分层) + +依据仓库的分层与边界规则,用户反馈界面应落在: + +1. **Web UI 组件 (`src/web-ui/src/app/components/`)** — 反馈对话框、收件箱视图、会话视图、隐私声明链接、底部常驻入口的主要实现落点;复用既有 component-library 与状态管理,不新造前端原语。 +2. **Web UI 布局 (`src/web-ui/src/app/layout/`)** — 对话框挂载边界与临界退出确认。 +3. **Web UI 适配层 (`src/web-ui/src/infrastructure/api/`)** — 反馈 API adapter、错误类型、内容长度 / 截断工具;UI 组件不得绕过 adapter 直调 Tauri 或浏览器 API。 +4. **Web UI i18n (`src/web-ui/src/locales`)** — `feedback.*` 文案;shared terms 经 `src/shared/i18n/contract/locales.json` + `pnpm run i18n:generate`。 +5. **Desktop API (`src/apps/desktop/src/api/`)** — 反馈相关 Tauri command(提交、列表、回复、确认已读、访问态),远程策略声明为与工作区位置无关。 +6. **Services (`src/crates/services/services-integrations`)** — 反馈服务具体实现(HTTP 提交、列表、回复、配额),放在显式 feature 后,`default = []`。 +7. **OHOS 凭据 (`src/apps/ohos/`)** — HarmonyOS 反馈凭据与能力 token 的安全资产存取。 + +### 分层与依赖边界要点 + +- 产品逻辑平台无关:反馈服务核心实现与 DTO 保持平台无关,Tauri command、HarmonyOS 凭据、Web UI 适配分别落在各自 owner 层; +- UI 组件不得直调 Tauri / 浏览器 API,必须走 adapter / infrastructure 层; +- 复用既有 component-library 与状态管理,不新造前端原语; +- 主题 / 颜色 token 改动走颜色审计,失败时通过复用 token、合并冗余值或加最小 owner contract 修复,不抬 baseline; +- i18n 文案进 `src/web-ui/src/locales`,shared terms 进 `src/shared/i18n/resources/shared`; +- 日志英文、无 emoji、结构化; +- 反馈相关 command 远程策略声明为与工作区位置无关,不引入对远程工作区路径的隐式依赖。 + +## 设计草案 / 参考示例 + +- **未读提示**:未读关注判定为"可打开且有新回复",底部入口据此触发提示徽标。 +- **草稿与退出守卫**:草稿 = 分类 / 内容 / 关联信息 / 隐私勾选任一非空;提交 / 回复发送态早期拦截关闭,关闭按钮与遮罩点击跟随该态。 +- **配额倒计时**:基于绝对截止时间计算剩余秒数;仅当服务端正倒计时 > 0 时展示,避免 0 秒无效重试。 +- **隐私同意门**:提交顺序为"准备 → 同意 → 提交";隐私保存失败阻止继续提交;内联区提供只读隐私声明入口。 +- **布局**:容器宽度观察触发宽 / 窄双态;宽态双列、窄态单列;尺寸有上限并随视口收窄;顶部留白避开窗口控件。 +- **平台分流**:HarmonyOS 走本地能力后端提交;其他平台外链外部 Issue 系统;提交后完成态不与外链按钮并列。 +- **交互参考**:常见工单系统的"提交 → 列表 → 会话 → 已读"闭环;邮件客户端的未读徽标与草稿守卫。 + +## 是否愿意贡献 + +- [x] 我愿意参与开发 +- [ ] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +## 补充说明 + +- 本提案严格遵循仓库"产品逻辑平台无关、再通过平台适配器暴露""UI 组件不直调 Tauri、走 adapter 层""复用既有 store 与 component-library"的规则。 +- 与隐私协议的关系:仅做同意门交互与内联声明呈现,不改隐私协议正文;隐私协议重大变更走其自身的重新同意流程。 +- 与远程工作区的关系:反馈相关 command 远程策略声明为与工作区位置无关,远程控制场景下反馈通道仍可用;不引入对远程工作区路径的隐式依赖。 +- 与外部 Issue 系统的关系:应用内反馈是其补充,不替代;外链路径作为不支持应用内提交的平台兜底。 +- 相关分层入口:`src/web-ui/AGENTS.md`、`src/apps/desktop/AGENTS.md`、`src/crates/services/services-integrations/AGENTS.md`。 diff --git a/docs/features/user-theme-configuration-desktop-web-ui.md b/docs/features/user-theme-configuration-desktop-web-ui.md new file mode 100644 index 0000000000..0a6210bc47 --- /dev/null +++ b/docs/features/user-theme-configuration-desktop-web-ui.md @@ -0,0 +1,70 @@ +# 用户主题配置(Desktop / Web UI)功能提案 + +> 状态:提案 / 待评审 +> 仓库:BitFun-OHOS +> 相关架构入口: +> - [`docs/architecture/theme-token-optimization.md`](../architecture/theme-token-optimization.md) +> - [`docs/architecture/appearance-package-system.md`](../architecture/appearance-package-system.md) +> - [`src/web-ui/AGENTS.md`](../../src/web-ui/AGENTS.md) +> - [`docs/architecture/product-architecture.md`](../architecture/product-architecture.md) + +### 功能类型 + +- [x] 新功能 +- [ ] 现有功能增强 +- [ ] 用户体验优化 +- [ ] 性能优化 +- [ ] 接口/集成扩展 +- [ ] 其他 + +### 优先级 + +- [ ] 紧急(P0 - 核心需求,强烈期望实现) +- [ ] 高(P1 - 重要功能,期望尽快实现) +- [x] 中(P2 - 有价值的功能,计划实现) +- [ ] 低(P3 - 锦上添花,有时间再做) + +### 背景与动机 + +- BitFun GUI 主题目前只能在内置固定主题间切换,用户无法按个人偏好定制颜色:品牌色、护眼色、自定义深色变体、强调色偏好等都无法表达。用户对「我希望界面用自己的配色」这一基础诉求没有出口,只能被动接受预设。 +- 痛点:① 无法自定义 semantic 颜色(背景/文本/边框/交互/状态/accent),个性化需求无处满足;② 无法保存多个自定义主题并在其间切换;③ 自定义主题不能导入导出/分享,团队或设备间无法复用;④ 缺少可访问性提示,用户随手配色可能造成对比度不足、状态色混淆。 + +### 功能描述 + +- 在 Desktop/Web UI 新增「用户主题配置」能力,覆盖六个环节: + 1. **主题编辑器**:支持基于内置包派生或从空白创建自定义主题;按 Token 分层编辑 semantic 颜色(背景、文本、边框、交互、状态、accent),并在编辑时实时预览(消费运行时 CSS 变量,不在 SCSS 编译期复制颜色)。 + 2. **保存与持久化**:自定义主题可命名、复制、删除;持久化到 `appearance.selection`,支持保存多个自定义包并在其间切换;内置包只读,不可覆盖。 + 3. **导入 / 导出**:自定义主题包支持导入与导出(与既有包 schema 一致),导入时按包校验规则校验,失败给出可读错误而非静默丢弃。 + 4. **校验与可访问性**:保存时校验 Token 完整性(必需 semantic 角色齐全、无悬空引用);对关键文本/背景组合给出对比度与可访问性提示,但不强制阻断用户最终选择。 + 5. **应用与切换**:可将自定义主题设为当前主题,原子应用运行时 CSS 变量;首屏遵循既定规则——Rust 首屏使用系统默认启动色,JS 启动后原子应用完整包,避免闪烁。 + 6. **降级与可观测**:自定义包损坏或 Token 缺失时降级到内置默认主题,状态视图显式标注「当前为降级态 + 原因」,不静默回退。 +- 实现边界遵循主题治理规则:主题 owner 仍是 Web UI Appearance(`src/web-ui/src/infrastructure/appearance`),包 schema / 校验 / 唯一运行时不变;只持久化并解析 `appearance.selection`;普通组件优先消费运行时 CSS 变量,动态 CSS 变量族在 `scripts/theme-css-var-contract.mjs` 登记 owner、前缀与消费范围;iframe / MiniApp / 生成式 UI 仍只接收显式 allowlist 的主题 payload;主题 baseline 是 no-growth ratchet,用户自定义不得成为扩张普通应用色板或放宽审计基线的理由。 +- 非目标:不做跨 GUI/TUI 的通用主题 schema;不为 TUI 终端主题引入 GUI 自定义投影(TUI 主题独立);不引入在线主题市场(皮肤市场属独立能力,不在本提案内)。 + +### 期望效果 / 使用场景 + +1. 用户在 Appearance 设置打开「自定义主题」编辑器,基于内置深色包派生一份新主题,调整 accent 与背景色,实时预览后保存命名。 +2. 用户创建多个自定义主题(如「公司品牌色」「护眼绿」「深夜极暗」),在主题列表间一键切换,当前选择持久化并在重启后保持。 +3. 用户导出自定义主题为包文件分享给团队,同事导入后即用,导入失败时看到具体校验错误(如缺少必需 semantic 角色)。 +4. 用户配色导致文本对比度不足时,编辑器给出可访问性提示;用户坚持保存仍可生效,但状态视图标注潜在风险。 + +### 设计草案 / 参考示例 + +- Token 编辑分层:primitive(原料/alpha ramp)→ semantic(背景/文本/边框/交互/状态/accent)→ component(仅当 semantic 无法表达)→ exception domain(editor/terminal/syntax/diff 等,不在用户自定义范围内暴露)。 +- 持久化:扩展 `appearance.selection` 以承载自定义包列表与当前选择;内置包只读,用户包可增删改。 +- 应用路径:Appearance 运行时消费 CSS 变量,切换时原子应用;新增变量族登记到 `theme-css-var-contract.mjs`。 +- 校验:复用包校验规则(schema、必需角色、悬空引用),并叠加对比度提示(文本/背景组合)。 + +### 是否愿意贡献 + +- [ ] 我愿意参与开发 +- [x] 我愿意参与讨论和测试 +- [ ] 仅提出建议 + +### 补充说明 + +- 本提案聚焦 GUI 用户主题配置;TUI 终端主题、移动端 Web 主题、Installer 主题各自独立,不在本提案内合并 surface。 +- 边界约束:不得在 `core-types` / `runtime-ports` 内重定义主题包;Rust 不复制主题模型;主题 baseline 是 no-growth ratchet,用户自定义不得通过新增 owner、放宽 baseline 或绕过审计来制造色板扩张——新增颜色须按 Token 分层复用优先。 +- 安全提示:自定义主题包为本地用户数据,导入须按既有包校验规则校验,不接受任意可执行脚本或构建期资源。 +- 验证基线(建议):Web UI 侧 `pnpm run type-check:web`;主题/颜色变更须运行 `pnpm run theme:color-audit:all`、`pnpm run theme:color-audit:test`、`pnpm run theme:visual-contract`;i18n 文案经 `pnpm run i18n:audit`。 +- 若需扩展到「主题分享市场」或「跟随系统/时间」,可作为本提案的后续增强单独评审,不在本范围内。 diff --git a/src/apps/desktop/src/api/appearance_market_api.rs b/src/apps/desktop/src/api/appearance_market_api.rs index 1341a9f787..ce05507087 100644 --- a/src/apps/desktop/src/api/appearance_market_api.rs +++ b/src/apps/desktop/src/api/appearance_market_api.rs @@ -21,6 +21,8 @@ use bitfun_services_integrations::appearance_market::{ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::path::PathBuf; +#[cfg(target_env = "ohos")] +use std::sync::Arc; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] @@ -78,13 +80,25 @@ struct NormalizedManualSubmission { repository_url: Option, } +async fn appearance_market_client() -> Result { + #[cfg(target_env = "ohos")] + { + let store = + Arc::new(crate::api::ohos::market_credentials::OhosMarketCredentialStore::new()); + return AppearanceMarketClient::from_environment_with_credential_store(store) + .await + .map_err(market_error); + } + + #[cfg(not(target_env = "ohos"))] + AppearanceMarketClient::from_environment().await.map_err(market_error) +} + #[tauri::command] pub async fn appearance_market_browse( request: AppearanceMarketBrowseRequest, ) -> Result, String> { - let client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let client = appearance_market_client().await?; client.browse(&request).await.map_err(market_error) } @@ -93,9 +107,7 @@ pub async fn appearance_market_get_listing( request: AppearanceMarketSlugRequest, ) -> Result { validate_slug(&request.slug)?; - let client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let client = appearance_market_client().await?; client.listing(&request.slug).await.map_err(market_error) } @@ -104,9 +116,7 @@ pub async fn appearance_market_download_release( request: AppearanceMarketDownloadRequest, ) -> Result { validate_slug(&request.slug)?; - let client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let client = appearance_market_client().await?; let detail = client.listing(&request.slug).await.map_err(market_error)?; let release = find_release(&detail, request.release_number)?; if release.listing_id != detail.summary.listing_id @@ -142,9 +152,7 @@ pub async fn appearance_market_download_release( #[tauri::command] pub async fn appearance_market_list_submissions() -> Result, String> { - let mut client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let mut client = appearance_market_client().await?; client.list_submissions().await.map_err(market_error) } @@ -153,9 +161,7 @@ pub async fn appearance_market_submit_package( request: AppearanceMarketSubmitPackageRequest, ) -> Result { let normalized = normalize_manual_submission(request)?; - let mut client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let mut client = appearance_market_client().await?; let submissions = client.list_submissions().await.map_err(market_error)?; let (listing_id, release_number) = match resolve_appearance_release_target( &submissions, @@ -204,9 +210,7 @@ pub async fn appearance_market_submit_package( pub async fn appearance_market_withdraw_submission( request: AppearanceMarketSubmissionIdRequest, ) -> Result { - let mut client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let mut client = appearance_market_client().await?; client .withdraw_submission(&request.submission_id) .await @@ -216,9 +220,7 @@ pub async fn appearance_market_withdraw_submission( #[tauri::command] pub async fn appearance_market_list_review_submissions( ) -> Result, String> { - let mut client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let mut client = appearance_market_client().await?; client .list_admin_submissions(AppearanceMarketSubmissionStatus::Submitted) .await @@ -229,9 +231,7 @@ pub async fn appearance_market_list_review_submissions( pub async fn appearance_market_get_review_submission( request: AppearanceMarketSubmissionIdRequest, ) -> Result { - let mut client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let mut client = appearance_market_client().await?; client .admin_submission(&request.submission_id) .await @@ -242,9 +242,7 @@ pub async fn appearance_market_get_review_submission( pub async fn appearance_market_review_submission( request: AppearanceMarketReviewRequest, ) -> Result { - let mut client = AppearanceMarketClient::from_environment() - .await - .map_err(market_error)?; + let mut client = appearance_market_client().await?; client .review_submission( &request.submission_id, diff --git a/src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets b/src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets index 1118286e6d..5b8d4064a6 100644 --- a/src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets +++ b/src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets @@ -70,6 +70,14 @@ interface MonitorResult { width: number; height: number; scaleFactor: number; + avoidArea: MonitorAvoidArea; +} + +interface MonitorAvoidArea { + top: number; + bottom: number; + left: number; + right: number; } export default class EntryAbility extends RustAbility { @@ -317,6 +325,10 @@ export default class EntryAbility extends RustAbility { let dispWidth: number = 0; let dispHeight: number = 0; let scale: number = 1; + let avoidTop: number = 0; + let avoidBottom: number = 0; + let avoidLeft: number = 0; + let avoidRight: number = 0; try { const disp = display.getDefaultDisplaySync(); dispWidth = disp.width; @@ -326,7 +338,29 @@ export default class EntryAbility extends RustAbility { const be = e as BusinessError; hilog.warn(DOMAIN, TAG, `getDefaultDisplaySync failed: ${be.message}`); } - const result: MonitorResult = { width: dispWidth, height: dispHeight, scaleFactor: scale }; + try { + const avoidArea = windowStage.getMainWindowSync() + .getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); + avoidTop = avoidArea.topRect.height; + avoidBottom = avoidArea.bottomRect.height; + avoidLeft = avoidArea.leftRect.width; + avoidRight = avoidArea.rightRect.width; + } catch (e) { + const be = e as BusinessError; + hilog.warn(DOMAIN, TAG, `getWindowAvoidArea failed: ${be.message}`); + } + const avoid: MonitorAvoidArea = { + top: avoidTop, + bottom: avoidBottom, + left: avoidLeft, + right: avoidRight, + }; + const result: MonitorResult = { + width: dispWidth, + height: dispHeight, + scaleFactor: scale, + avoidArea: avoid, + }; return JSON.stringify(result); }); RustModule.registerArktsFunction('unmaximize_ohos', async (err: Error, arg: string): Promise => { diff --git a/src/crates/services/services-integrations/src/appearance_market/client.rs b/src/crates/services/services-integrations/src/appearance_market/client.rs index 7746e83a97..385bdedb15 100644 --- a/src/crates/services/services-integrations/src/appearance_market/client.rs +++ b/src/crates/services/services-integrations/src/appearance_market/client.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::miniapp_market::{ DesktopAuthPollRequest, DesktopAuthPollResponse, DesktopAuthStart, MarketClient, - MarketClientError, MarketMe, + MarketClientError, MarketCredentialStore, MarketMe, }; const DEFAULT_APPEARANCE_MARKET_API_URL: &str = "https://market.openbitfun.com/skin/api/v1"; @@ -43,6 +43,15 @@ impl AppearanceMarketClient { Self::with_identity(base_url, identity) } + pub async fn from_environment_with_credential_store( + credential_store: Arc, + ) -> Result { + let base_url = std::env::var("BITFUN_APPEARANCE_MARKET_API_URL") + .unwrap_or_else(|_| DEFAULT_APPEARANCE_MARKET_API_URL.to_string()); + let identity = MarketClient::from_environment_with_credential_store(credential_store).await?; + Self::with_identity(base_url, identity) + } + pub async fn new( base_url: impl Into, identity_base_url: impl Into, diff --git a/src/web-ui/src/app/components/FeedbackDialog/FeedbackDialog.tsx b/src/web-ui/src/app/components/FeedbackDialog/FeedbackDialog.tsx index dd04642e4b..c93e92830c 100644 --- a/src/web-ui/src/app/components/FeedbackDialog/FeedbackDialog.tsx +++ b/src/web-ui/src/app/components/FeedbackDialog/FeedbackDialog.tsx @@ -29,7 +29,7 @@ import { useFeedbackInboxStore } from './feedbackInboxStore'; import './FeedbackDialog.scss'; const log = createLogger('FeedbackDialog'); -const GITCODE_ISSUES_URL = 'https://gitcode.com/OpenHarmonyPCDeveloper/BitFun/issues'; +const GITCODE_ISSUES_URL = 'https://gitcode.com/OpenBitFun/bitfun_ade/issues'; let submissionRetryUntilMs = 0; function submissionRetrySecondsRemaining(): number { diff --git a/src/web-ui/src/app/components/FeedbackDialog/feedbackSubmissionContract.test.ts b/src/web-ui/src/app/components/FeedbackDialog/feedbackSubmissionContract.test.ts index b7105290e1..b2190facf1 100644 --- a/src/web-ui/src/app/components/FeedbackDialog/feedbackSubmissionContract.test.ts +++ b/src/web-ui/src/app/components/FeedbackDialog/feedbackSubmissionContract.test.ts @@ -11,7 +11,7 @@ describe('OpenHarmony feedback submission contract', () => { expect(footer).toContain("systemInfo.platform === 'openharmony'"); expect(footer).toContain('setShowFeedback(true)'); - expect(footer).toContain("systemAPI.openExternal('https://gitcode.com/OpenHarmonyPCDeveloper/BitFun/issues')"); + expect(footer).toContain("systemAPI.openExternal('https://gitcode.com/OpenBitFun/bitfun_ade/issues')"); }); it('shows unread attention only for conversations that can be opened and acknowledged', () => { diff --git a/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx b/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx index 11f99bb607..188f55b206 100644 --- a/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx +++ b/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx @@ -205,7 +205,7 @@ const PersistentFooterActions: React.FC = () => { } catch { // Web and older desktop hosts retain the external feedback behavior. } - await systemAPI.openExternal('https://gitcode.com/OpenHarmonyPCDeveloper/BitFun/issues'); + await systemAPI.openExternal('https://gitcode.com/OpenBitFun/bitfun_ade/issues'); }, [closeMenu, feedbackPlatformEnabled]); // const handleAccountLogin = () => { diff --git a/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.scss b/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.scss index c9bf157517..5c554f975c 100644 --- a/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.scss +++ b/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.scss @@ -119,6 +119,10 @@ $transition-timing: cubic-bezier(0.4, 0, 0.2, 1); pointer-events: auto; } +.bitfun-toolbar-mode--ohos .bitfun-toolbar-mode__header-overflow { + display: none; +} + .bitfun-toolbar-mode__header-collapsed-actions { display: flex; align-items: center; diff --git a/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.tsx b/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.tsx index d68f4b810e..0235473191 100644 --- a/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.tsx +++ b/src/web-ui/src/flow_chat/components/toolbar-mode/ToolbarMode.tsx @@ -62,6 +62,7 @@ export const ToolbarMode: React.FC = () => { }); const isMacOS = useMemo(() => isMacOSDesktopRuntime(), []); + const isOpenHarmony = useMemo(() => isOpenHarmonyRuntime(), []); const { workspacePath } = useCurrentWorkspace(); const { activeSession, sessionTitle } = useFlowChatSessions(); @@ -230,6 +231,7 @@ export const ToolbarMode: React.FC = () => { toolbarState.hasError && 'bitfun-toolbar-mode--error', toolbarState.hasPendingConfirmation && 'bitfun-toolbar-mode--confirm', isMacOS && 'bitfun-toolbar-mode--macos', + isOpenHarmony && 'bitfun-toolbar-mode--ohos', ].filter(Boolean).join(' '); return ( diff --git a/src/web-ui/src/flow_chat/components/toolbar-mode/toolbarModeWindowOps.ts b/src/web-ui/src/flow_chat/components/toolbar-mode/toolbarModeWindowOps.ts index 6e10e60604..d13229f1f4 100644 --- a/src/web-ui/src/flow_chat/components/toolbar-mode/toolbarModeWindowOps.ts +++ b/src/web-ui/src/flow_chat/components/toolbar-mode/toolbarModeWindowOps.ts @@ -197,10 +197,22 @@ const ohosOps = (): WindowOps => ({ }, async currentMonitor(): Promise { const m = await workspaceAPI.currentMonitorOhos(); + const avoid = m.avoidArea; + const hasAvoid = avoid && (avoid.top > 0 || avoid.bottom > 0 || avoid.left > 0 || avoid.right > 0); + const workArea = hasAvoid + ? { + position: { x: avoid.left, y: avoid.top }, + size: { + width: Math.max(0, m.width - avoid.left - avoid.right), + height: Math.max(0, m.height - avoid.top - avoid.bottom), + }, + } + : undefined; return { position: { x: 0, y: 0 }, size: { width: m.width, height: m.height }, scaleFactor: m.scaleFactor, + workArea, }; }, }); diff --git a/src/web-ui/src/infrastructure/api/service-api/WorkspaceAPI.ts b/src/web-ui/src/infrastructure/api/service-api/WorkspaceAPI.ts index c782955ff0..aae362e6ed 100644 --- a/src/web-ui/src/infrastructure/api/service-api/WorkspaceAPI.ts +++ b/src/web-ui/src/infrastructure/api/service-api/WorkspaceAPI.ts @@ -1199,10 +1199,10 @@ export class WorkspaceAPI { } } - async currentMonitorOhos(): Promise<{ width: number; height: number; scaleFactor: number }> { + async currentMonitorOhos(): Promise<{ width: number; height: number; scaleFactor: number; avoidArea: { top: number; bottom: number; left: number; right: number } }> { try { const raw = await api.invoke('current_monitor_ohos'); - return JSON.parse(raw) as { width: number; height: number; scaleFactor: number }; + return JSON.parse(raw) as { width: number; height: number; scaleFactor: number; avoidArea: { top: number; bottom: number; left: number; right: number } }; } catch (error) { throw createTauriCommandError('current_monitor_ohos', error); }