diff --git a/.gitignore b/.gitignore index c96f08e95c..3164478251 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,12 @@ lerna-debug.log* node_modules **/node_modules +# These packages share pnpm-lock.yaml. Standalone npm packages keep their own lockfile. +/package-lock.json +/OpenBitFun-Installer/package-lock.json +/src/mobile-web/package-lock.json +/tests/e2e/package-lock.json + # Build outputs - Frontend dist dist-ssr @@ -125,3 +131,6 @@ src/apps/mobile/android/.kotlin/ # Local generated workspace output. /output/ + +# Retired implementation-process notes stay local; durable docs live with their owner. +/docs/superpowers/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 33cdf42d7f..f42792cd53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,12 @@ The check detects: pnpm install ``` +The pnpm workspace uses the root `pnpm-lock.yaml` as its dependency lockfile; +do not commit `package-lock.json` files for workspace packages. The standalone +`packages/dsh-acp` npm package and `src/apps/extension-host` Bun host retain their +own lockfiles and preparation commands. Keep generated Tauri `gen/` directories +and local implementation-process notes out of Git. + ### Common commands ```bash @@ -115,11 +121,11 @@ We welcome contributions beyond standard feature or bug-fix PRs. Examples includ | Contribution area | Location / files | Example | | --- | --- | --- | -| Prompts | `src/crates/assembly/core/src/agentic/agents/prompts/` | Add or refine prompts, and update related logic as needed | +| Prompts | `src/crates/assembly/agent-content/prompts/agents/` | Add or refine built-in prompts; keep selection and runtime policy in their existing owners | | Tools | `src/crates/assembly/core/src/agentic/tools/implementations/`, `src/crates/assembly/core/src/agentic/tools/registry.rs` | Add tool implementations and register them in the tool registry | -| Subagents | `src/crates/assembly/core/src/agentic/agents/custom_subagents/`, `src/crates/assembly/core/src/agentic/agents/registry.rs` | Add subagent implementations and register them in the subagent registry | -| Mode contributions | `src/crates/assembly/core/src/agentic/agents/*_mode.rs`, `src/crates/assembly/core/src/agentic/agents/prompts/*_mode.md`, `src/web-ui/src/locales/*/settings/modes.json` | Add/improve Agentic or custom modes and keep prompts + UI copy in sync | -| Scenario guides for Code Agent and AIIde | `website/src/docs/` | Add workflows, playbooks, and real-world scenario docs (or link them from `README.md`) | +| Subagents | `src/crates/assembly/core/src/agentic/agents/definitions/`, `src/crates/assembly/core/src/agentic/agents/registry/` | Add subagent definitions and register them with the owning registry | +| Mode contributions | `src/crates/assembly/core/src/agentic/agents/definitions/`, `src/crates/assembly/agent-content/prompts/agents/`, `src/web-ui/src/locales/` | Keep mode policy, built-in prompts, and owning UI copy in sync | +| Playbook and scenario guides | `src/shared/interactive-capabilities/catalog.json`, owning app README | Maintain the source catalog and run `pnpm run capabilities:generate`; `website/` consumes the generated catalog | ### Before you start @@ -175,7 +181,7 @@ Common local checks: | Repository metadata or GitHub config | `pnpm run check:repo-hygiene && pnpm run check:github-config && git diff --check` | | Frontend runtime or UI | `pnpm run check:web`, plus the nearest focused test when behavior changed | | Mobile web | `pnpm --dir src/mobile-web run type-check` | -| Rust shared runtime or services | `cargo check --workspace`, plus a focused `cargo test` when behavior changed | +| Rust shared runtime or services | Follow the nearest module `AGENTS.md`: one package/test target and the minimum required features | | Desktop/Tauri integration | `cargo check -p openbitfun-desktop` | | i18n resources or contract | use the matching i18n row in `AGENTS.md` | diff --git a/CONTRIBUTING_CN.md b/CONTRIBUTING_CN.md index d51a4a9ffa..32731211af 100644 --- a/CONTRIBUTING_CN.md +++ b/CONTRIBUTING_CN.md @@ -50,6 +50,11 @@ pnpm run check:build-prereqs -- --fix # 尝试自动修复缺失的前置依赖 pnpm install ``` +pnpm 工作区统一使用根目录的 `pnpm-lock.yaml`,不要为工作区包提交 +`package-lock.json`。独立的 `packages/dsh-acp` npm 包与 +`src/apps/extension-host` Bun 宿主保留各自的锁文件和准备命令。 +Tauri 生成的 `gen/` 目录以及本地实施过程记录不进入 Git。 + ### 常用命令 ```bash @@ -105,11 +110,11 @@ DevTools;`Cmd/Ctrl + Shift + I` 切换 OpenBitFun 元素检查器,`Cmd/Ctrl | 贡献方向 | 位置/文件 | 示例说明 | | --- | --- | --- | -| Prompts | `src/crates/assembly/core/src/agentic/agents/prompts/` | 新增或优化提示词,并按需更新相关逻辑 | +| Prompts | `src/crates/assembly/agent-content/prompts/agents/` | 新增或优化内置提示词;选择逻辑与运行时策略仍由现有模块负责 | | Tools | `src/crates/assembly/core/src/agentic/tools/implementations/`、`src/crates/assembly/core/src/agentic/tools/registry.rs` | 新增工具实现,并在工具注册表中注册 | -| Subagents | `src/crates/assembly/core/src/agentic/agents/custom_subagents/`、`src/crates/assembly/core/src/agentic/agents/registry.rs` | 新增子代理实现,并在子代理注册表中注册 | -| 模式贡献 | `src/crates/assembly/core/src/agentic/agents/*_mode.rs`、`src/crates/assembly/core/src/agentic/agents/prompts/*_mode.md`、`src/web-ui/src/locales/*/settings/modes.json` | 新增/优化 Agentic 或自定义 Agent 模式的逻辑与提示词,并同步前端模式文案 | -| Code Agent 与 AIIde 场景指南 | `website/src/docs/` | 补充流程、playbook 与真实场景说明(或从 `README.md` 链接) | +| Subagents | `src/crates/assembly/core/src/agentic/agents/definitions/`、`src/crates/assembly/core/src/agentic/agents/registry/` | 新增子代理定义,并在所属注册表中注册 | +| 模式贡献 | `src/crates/assembly/core/src/agentic/agents/definitions/`、`src/crates/assembly/agent-content/prompts/agents/`、`src/web-ui/src/locales/` | 同步模式策略、内置提示词及所属界面文案 | +| Playbook 与场景指南 | `src/shared/interactive-capabilities/catalog.json`、所属应用 README | 维护源目录并运行 `pnpm run capabilities:generate`;`website/` 消费生成的目录 | ### 开始前 @@ -161,7 +166,7 @@ Repository Object Sizes 检查会拒绝超过 5 MiB 的 Git 文件对象,包 | 仓库元信息或 GitHub 配置 | `pnpm run check:repo-hygiene && pnpm run check:github-config && git diff --check` | | 前端运行时或 UI | `pnpm run check:web`;行为变化时再加最近的 focused test | | Mobile web | `pnpm --dir src/mobile-web run type-check` | -| Rust 共享 runtime 或 services | `cargo check --workspace`;行为变化时再加 focused `cargo test` | +| Rust 共享 runtime 或 services | 遵循最近模块的 `AGENTS.md`,选择单个包/测试目标和最小所需 feature | | Desktop/Tauri 集成 | `cargo check -p openbitfun-desktop` | | i18n 资源或契约 | 使用 `AGENTS.md` 中匹配的 i18n 验证行 | diff --git a/MiniApp/Skills/miniapp-dev/SKILL.md b/MiniApp/Skills/miniapp-dev/SKILL.md index db6b79d124..c5c9e4b726 100644 --- a/MiniApp/Skills/miniapp-dev/SKILL.md +++ b/MiniApp/Skills/miniapp-dev/SKILL.md @@ -1,444 +1,21 @@ --- name: miniapp-dev -description: Develops, maintains, and generates OpenBitFun MiniApps (Zero-Dialect Runtime). Use when (1) working on miniapp framework code under src/crates/assembly/core/src/miniapp/ or src/web-ui/src/app/scenes/miniapps/; or (2) generating / creating / designing a NEW MiniApp for the user — including any request like "做一个小应用 / 生成 MiniApp / 写个 OpenBitFun 小工具 / 创建 mini app". Also triggers on MiniApp, miniapps, bridge, zero-dialect, InitMiniApp, app.fs / app.shell / app.storage, or any work under MiniApp/Demo/ and MiniApp/Skills/. +description: Maintain MiniApp framework code in this repository, or find the canonical built-in MiniApp authoring guide and examples. --- -# OpenBitFun MiniApp V2 指南 +# MiniApp 开发入口 -> **本 Skill 服务两类工作**: -> -> - **维护框架本身** → 阅读下方"代码架构 / Bridge / 权限模型 / window.app API"等章节。 -> - **生成一个新的 MiniApp** → **必读** [`design-playbook.md`](design-playbook.md),并遵循下方"生成新 MiniApp 必读(速查)"章节的硬约束。详细 API 见 [`api-reference.md`](api-reference.md)。 +本目录保留仓库维护入口。产品分发的生成流程、API 和设计约定统一维护在 +[内置 miniapp-dev skill](../../../src/crates/assembly/core/builtin_skills/miniapp-dev/SKILL.md), +避免仓库指南与产品内置说明分别演进。 ---- - -## 生成新 MiniApp 必读(速查) - -> 完整指南见 [`design-playbook.md`](design-playbook.md)。这里是**不可妥协**的硬约束,AI 在用 `InitMiniApp` 工具创建骨架后**必须**遵守。 - -### 流程 -1. **先问,再做**:用户的目标 / 受众 / 是否需要 node mode / 权限边界 / 是否需要 Tweaks 变体 / 是否多语言 / 是否有视觉参考——任何一项含糊就用 `AskUserQuestion` 问。**不要替用户决定**。 -2. **找设计上下文**:先读 `MiniApp/Demo/` 与 `src/crates/contracts/product-domains/src/miniapp/builtin/assets/` 中**最贴近形态**的内置应用,复刻它的视觉语言(间距 / 圆角 / 卡片密度 / motif)。**从零 mock 是最后选择**。 -3. **声明设计系统**:`style.css` 顶部用注释钉住 palette / typography / radius / motif(参见 playbook §1.3 模板),后续全应用复用。 -4. **占位先行 → 早预览**:第一版用占位文本 / 占位图框 / fixture 数据,先在 Toolbox 里跑给用户看,再迭代。 -5. **验证**:light/dark × zh/en 共 4 套截图都过;过 playbook §8 的 QA Checklist。 - -### 反 AI 味(默认禁用,除非用户明确要求) -- ❌ 蓝紫渐变 / "Aurora" 风背景 -- ❌ Emoji 当主图标(用描边 SVG 或字母圆形容器) -- ❌ 左侧色条 + 圆角卡片组合 -- ❌ 标题下加 1-2px 装饰横线 -- ❌ 硬画复杂插画 SVG(用占位框,标注 "Image TBD") -- ❌ Inter / Roboto 兜底就完事(用 `var(--openbitfun-font-sans)` 优先) -- ❌ 12px 以下文字 / hit target < 32px -- ❌ 圆角混用 4/8/12/16(钉 1-2 档全应用统一) -- ❌ 用装饰性 stats / icon / sparkline 填空白(空白是排版问题,不是内容问题) - -### 颜色与字体 -- **首选** `var(--openbitfun-*)` 系列 + fallback,与宿主主题协同(见下文"主题集成"章节的完整变量清单)。 -- 一个颜色占视觉权重 60-70%(dominant),1-2 个 supporting,1 个 accent——**禁止给所有色块同等权重**。 -- 字号:标题 18-22px / Section 14-15px / 正文 13-14px / Caption 11-12px。 - -### Tweaks 变体(推荐做法) -对外观/密度/字号/布局的多种合理选择,做成运行时可切换、写入 `app.storage('tweaks')`、右下角浮动小面板"Tweaks"——一份代码服务多种偏好是 MiniApp 的天然优势。详细约定见 playbook §4。 - -### 占位优于劣质实现 -没图标 / 没数据 / 没素材时,用明确的占位(标注尺寸或 "TBD"),并在 README 里登记待补清单——**不要硬画一个糟糕的真实物**。 - -### 工具型 vs 展示型 -绝大多数 OpenBitFun MiniApp 是**工具型**——信息密集、操作短、配色冷静,仿照 `regex-playground` / `coding-selfie` / `git-graph` 的克制感。只有用户明确要"对外展示 / 灵感型 / 作品集"时才放飞视觉。 - -### 内容守则 -- 不为填空白而加内容——空白说明结构应被简化。 -- 每个元素都要能回答"为什么在这里",回答不了就删掉。 -- 加新 section / page / 功能前**先问用户**——你不比用户更懂他的目标。 - ---- - -## 核心哲学:Zero-Dialect Runtime - -MiniApp 使用 **标准 Web API + window.app**:UI 侧为 ESM 模块(`ui.js`),后端逻辑在独立 JS Worker 进程(Bun 优先 / Node 回退)中执行。Rust 负责进程管理、权限策略和 Tauri 独占 API;Bridge 从旧的 `require()` shim + `__OPENBITFUN__` 替换为统一的 **window.app** Runtime Adapter。 - -## 代码架构 - -### Rust 后端 - -``` -src/crates/assembly/core/src/miniapp/ -├── types.rs # MiniAppSource (ui_js/worker_js/esm_dependencies/npm_dependencies), NodePermissions -├── manager.rs # CRUD + recompile() + resolve_policy_for_app() -├── storage.rs # ui.js, worker.js, package.json, esm_dependencies.json -├── compiler.rs # Import Map + Runtime Adapter 注入 + ESM -├── bridge_builder.rs # window.app 生成 + build_import_map() -├── permission_policy.rs # resolve_policy() → JSON 策略供 Worker 启动 / host_dispatch 复用 -├── host_dispatch.rs # 宿主直连分发 fs/shell/os/net(无需 Bun/Node Worker) -├── runtime_detect.rs # detect_runtime() Bun/Node -├── js_worker.rs # 单进程 stdin/stderr JSON-RPC -├── js_worker_pool.rs # 池管理 + install_deps -├── exporter.rs # 导出骨架 -└── mod.rs -``` - -### Tauri Commands - -``` -src/apps/desktop/src/api/miniapp_api.rs -``` - -- 应用管理: `list_miniapps`, `get_miniapp`, `create_miniapp`, `update_miniapp`, `delete_miniapp` -- 存储/授权: `get/set_miniapp_storage`, `grant_miniapp_workspace`, `grant_miniapp_path` -- 版本: `get_miniapp_versions`, `rollback_miniapp` -- Worker/Runtime: `miniapp_runtime_status`, `miniapp_worker_call`, `miniapp_host_call`, `miniapp_worker_stop`, `miniapp_install_deps`, `miniapp_recompile` -- 对话框由前端 Bridge 用 Tauri dialog 插件处理,无单独后端命令 - -### Agent 工具 - -``` -src/crates/assembly/core/src/agentic/tools/implementations/ -└── miniapp_init_tool.rs # InitMiniApp — 唯一工具,创建骨架目录供 AI 用通用文件工具编辑 -``` - -注册在 `registry.rs` 的 `register_all_tools()` 中。AI 后续用 Read/Edit/Write 等通用文件工具编辑 MiniApp 文件。 - -### 前端 - -``` -src/web-ui/src/app/scenes/miniapps/ -├── MiniAppGalleryScene.tsx / .scss -├── MiniAppScene.tsx / .scss -├── miniAppStore.ts -├── views/ MiniAppGalleryView -├── components/ MiniAppCard, MiniAppRunner (iframe 带 data-app-id) -├── hooks/ -│ ├── useMiniAppBridge.ts # worker.call → workerCall() + dialog.open/save/message -│ └── useMiniAppCatalogSync.ts # 列表与运行态同步 -└── utils/ miniAppIcons.tsx, buildMiniAppThemeVars.ts - -src/web-ui/src/infrastructure/api/service-api/MiniAppAPI.ts # runtimeStatus, workerCall, workerStop, installDeps, recompile -src/web-ui/src/flow_chat/tool-cards/MiniAppToolDisplay.tsx # InitMiniAppDisplay -``` - -### Worker 宿主 - -``` -src/apps/desktop/resources/worker_host.js -``` - -Node/Bun 标准脚本:从 argv 读策略 JSON,stdin 收 RPC、stderr 回响应,内置 fs/shell/net/os/storage dispatch + 加载用户 `source/worker.js` 自定义方法。 - -## MiniApp 数据模型 (V2) - -```rust -// types.rs -MiniAppSource { - html, css, - ui_js, // 浏览器侧 ESM - esm_dependencies, - worker_js, // Worker 侧逻辑 - npm_dependencies, -} -MiniAppPermissions { fs?, shell?, net?, node? } // node 替代 env/compute -``` - -## 权限模型 - -- **permission_policy.rs**:`resolve_policy(perms, app_id, app_data_dir, workspace_dir, granted_paths)` 生成 JSON 策略,传给 Worker 启动参数;Worker 内部按策略拦截越权。 -- 路径变量同前:`{appdata}`, `{workspace}`, `{user-selected}`, `{home}` 等。 - -## Bridge 通信流程 (V2) - -``` -iframe 内 window.app.call(method, params) - → postMessage({ method: 'worker.call', params: { method, params } }) - → useMiniAppBridge 监听 - ├─ 框架原语 (fs.* / shell.* / os.* / net.*): - │ ├─ node.enabled = false → miniAppAPI.hostCall → Tauri invoke('miniapp_host_call') - │ │ → openbitfun_core::miniapp::host_dispatch(纯 Rust,无需 Bun/Node) - │ └─ node.enabled = true → miniAppAPI.workerCall → Tauri invoke('miniapp_worker_call') - │ → JsWorkerPool(保留旧路径,允许 worker.js 覆写 fs/shell 等) - ├─ 自定义方法:始终走 worker.call → JsWorkerPool(要求 node.enabled = true 且 worker.js 导出) - └─ storage.* (node.enabled = false 时):直接走 get/set_miniapp_storage 命令 - -dialog.open / dialog.save / dialog.message - → postMessage → useMiniAppBridge 直接调 @tauri-apps/plugin-dialog -``` - -### 何时使用「无 Node 模式」(推荐) - -只要小应用的后端能力可以用 `fs.*` / `shell.*` / `os.*` / `net.*` 完成(例如调用 `git` 拉数据、读写工作区文件、抓取 HTTP API),就把 `permissions.node.enabled` 设为 `false`: - -- 不依赖 Bun/Node 安装环境,bundle 后即点即用,避免 "JS Worker pool not initialized" 类问题; -- 安全与性能与 Worker 路径完全等价(同一份 `permission_policy`,Rust 直接执行); -- 仍然可以使用 `app.shell.exec / fs.* / net.fetch / os.info / storage.get|set` 全部框架原语。 - -什么时候需要 `node.enabled = true`: - -- 需要写 `worker.js` 自定义方法(CPU 密集 / 长流程 / 复杂解析等); -- 需要 `npm_dependencies` 安装第三方 npm 包; -- 需要在 worker 内长期持有连接、缓存、状态。 - -> 走「无 Node 模式」时,**禁止** 调用 `app.call('myCustomMethod', …)`,宿主会显式报错;只能调用框架原语和 `app.storage.*`。 - -## 能力边界(重要) - -MiniApp 框架**只暴露下列能力**,没有任何"通用 OpenBitFun 后端通道"。设计 / 生成新小应用前请先比对,能力不在表内的需求请走相应替代方案,**不要假设有 `app.openbitfun.*` / `app.workspace.*` / `app.git.*` / `app.session.*` 之类的接口存在。** - -| 能力 | 入口 | 说明 | -|---|---|---| -| 文件系统 | `app.fs.*` | 受 `permissions.fs.read/write` 路径白名单限制 | -| 子进程 / 命令行 | `app.shell.exec` | 受 `permissions.shell.allow` 命令名白名单限制 | -| HTTP | `app.net.fetch` | 受 `permissions.net.allow` 域名白名单限制 | -| 系统信息 | `app.os.info` | 仅 platform / cpus / homedir / tmpdir 等只读字段 | -| KV 存储 | `app.storage.get/set` | 每个小应用独立的 `storage.json`,跨会话保留 | -| AI | `app.ai.complete / chat / cancel / getModels` | 复用宿主 AIClient,受 `permissions.ai`(含 `allowed_models` / 速率限制) | -| 对话框 | `app.dialog.open/save/message` | Tauri dialog 插件 | -| 剪贴板 | `app.clipboard.readText/writeText` | 宿主 navigator.clipboard | -| Agent 会话 | `app.agent.run / cancel / turnText / cancelStaleRuns / onEvent` | 受 `permissions.agent.enabled` 限制;启动小应用自己的隐藏 agent 回合,事件只回流到发起的小应用。工具集按运行时档位收敛:市场小应用(`runtime_profile = market_strict`)保留 `WebSearch` / `WebFetch`,并可通过 `options.contextFiles` 注入有大小上限的只读上下文;宿主在 Agent Runtime 内为每次运行发布独立、不可变的 `.miniapp-context/` 虚拟快照、向 prompt 注入精确路径和“不可信数据”提示,并仅在本次请求有上下文时开放限定到该快照的 `Read` / `Grep`。虚拟路径不会落盘或回退到同名物理文件,Agent 仍碰不到其他文件、命令行和宿主控制面。内置 / `compatibility` 档位保留完整的 headless 工具集 | -| 悬浮会话气泡 | `app.chat.claimComposer / releaseComposer / focusSession / setComposerDraft / onUserMessage` | 受 `permissions.agent.enabled` 限制;把内容和提交路由注册进右下角的标准悬浮聊天窗(输入器、附件、模型、权限、停止等仍由宿主共享组件拥有),并展示小应用自己的 Agent 过程。用户从该气泡启动实时语音时,未显式指定其他工作区的任务也经同一个 `onUserMessage` 路由进入小应用会话(Agentic MiniApp 模式,样板间:`builtin-ppt-live`) | -| 幻灯片栅格化 | `app.deck.renderPage` | 在隐藏宿主 WebView 中渲染单页 HTML,返回 base64 PNG/PDF(导出用) | -| 自定义后端 | `app.call('xxx', …)` + `worker.js` | 仅 `node.enabled = true` 时可用,自己实现业务逻辑 | -| 主题 / i18n | `app.appearanceMode` / `app.locale` / `app.onAppearanceChange` / `app.onLocaleChange` / `app.t(...)` | 见对应章节 | - -### 框架**不**直接暴露的 OpenBitFun 后端能力(截至本文档) - -下面这些 OpenBitFun 内部服务,目前**没有**给小应用开放调用通道: - -- WorkspaceService(结构化工作区索引、统一搜索) -- GitService(结构化 status / diff / blame,区别于裸 `git` 命令) -- TerminalService(创建/读写交互式终端) -- Session / AgenticSystem 的**通用**会话管理(任意会话的创建、接管、读写)——小应用只能通过 `app.agent.*` 启动**自己的**隐藏会话并消费其事件,再通过 `app.chat.*` 借用悬浮会话气泡做输入与过程展示;不能访问其他会话 -- Snapshot / Mermaid / Skills / Browser API / Computer Use / Config 等 - -需要这类能力时的合规姿势: - -1. **能用裸命令行解决的**(如 git)→ 在 `permissions.shell.allow` 里加命令名,用 `app.shell.exec` 包一层(参考 `builtin-coding-selfie/ui.js` 的 `scanGitWorkspace`); -2. **只是要读 OpenBitFun 工作区内的文件**(如某些项目元数据) → 把 `{workspace}` 加到 `permissions.fs.read`,自己用 `app.fs.*` 读 + 在前端解析; -3. **必须真调用某个内部服务** → 暂不支持,先记录到需求池。**不要**自己起一个 worker 去模拟服务行为,会和真正的 service 行为漂移。 - -> 维护者:以后若新增 `app.openbitfun.*` / `app.workspace.*` 这类宿主直通通道,请同步更新本节,避免"文档说没有、代码偷偷加了"的不一致。 - -## window.app 运行时 API - -MiniApp UI 内通过 **window.app** 访问: - -| API | 说明 | -|-----|------| -| `app.call(method, params)` | 调用 Worker 方法(含 fs/shell/net/os/storage 及用户 worker.js 导出) | -| `app.fs.*` | 封装为 worker.call('fs.*', …) | -| `app.shell.*` | 同上 | -| `app.net.*` | 同上 | -| `app.os.*` | 同上 | -| `app.storage.*` | 同上 | -| `app.dialog.open/save/message` | 由 Bridge 转 Tauri dialog 插件 | -| `app.agent.*` | 隐藏 agent 回合(`permissions.agent.enabled`),事件经 `app.agent.onEvent` 回流 | -| `app.chat.*` | 标准悬浮聊天窗集成:`claimComposer({ title, composer: { placeholder }, welcome })` 注册有界内容与提交路由(不能替换/缩放输入器;当前 tab 为本小应用时,共享 ChatInput 和从该气泡启动的实时语音任务均经 `onUserMessage` 送达)、`focusSession(sessionId)` 让气泡展示本小应用的 agent 会话、`setComposerDraft(text)` 展开气泡并预填共享输入器(不发送,供示例 prompt 使用)。`onUserMessage` payload 含唯一 `requestId` 及 `source: 'composer' | 'realtime_voice'`;处理器应返回覆盖 Agent 回合及小应用后处理的 Promise,供语音模式等待最终结果 | -| 生命周期 / 事件 | 见 bridge_builder 生成的适配器 | - -## 主题集成 - -MiniApp 在 iframe 中运行时自动与主应用主题同步,避免界面风格与主应用差距过大。 - -### 只读属性与事件 - -| 成员 | 说明 | -|------|------| -| `app.appearanceMode` | 当前主题类型字符串:`'dark'` 或 `'light'`(随主应用切换更新) | -| `app.onAppearanceChange(fn)` | 注册主题变更回调,参数为 payload:`{ mode, id, vars }` | - -### data-openbitfun-appearance-mode 属性 - -编译后的 HTML 根元素 `` 带有 `data-openbitfun-appearance-mode="dark"` 或 `"light"`,便于用 CSS 按主题写样式,例如: - -```css -[data-openbitfun-appearance-mode="light"] .panel { background: #f5f5f5; } -[data-openbitfun-appearance-mode="dark"] .panel { background: #1a1a1a; } -``` - -### --openbitfun-* CSS 变量 - -宿主会将主应用主题映射为以下 CSS 变量并注入 iframe 的 `:root`。在 MiniApp 的 CSS 中建议用 `var(--openbitfun-*, )` 引用,以便在 OpenBitFun 内与主应用一致,导出为独立应用时 fallback 生效。 - -**背景** - -- `--openbitfun-bg` — 主背景 -- `--openbitfun-bg-secondary` — 次级背景(如工具栏、面板) -- `--openbitfun-bg-tertiary` — 第三级背景 -- `--openbitfun-bg-elevated` — 浮层/卡片背景 - -**文字** - -- `--openbitfun-text` — 主文字 -- `--openbitfun-text-secondary` — 次要文字 -- `--openbitfun-text-muted` — 弱化文字 - -**强调与语义** - -- `--openbitfun-accent`、`--openbitfun-accent-hover` — 强调色及悬停 -- `--openbitfun-success`、`--openbitfun-warning`、`--openbitfun-error`、`--openbitfun-info` — 语义色 - -**边框与元素** - -- `--openbitfun-border`、`--openbitfun-border-subtle` — 边框 -- `--openbitfun-element-bg`、`--openbitfun-element-hover` — 控件背景与悬停 - -**圆角与字体** - -- `--openbitfun-radius`、`--openbitfun-radius-lg` — 圆角 -- `--openbitfun-font-sans`、`--openbitfun-font-mono` — 无衬线与等宽字体 - -**滚动条** - -- `--openbitfun-scrollbar-thumb`、`--openbitfun-scrollbar-thumb-hover` — 滚动条滑块 - -示例(在 `style.css` 中): - -```css -:root { - --bg: var(--openbitfun-bg, #121214); - --text: var(--openbitfun-text, #e8e8e8); - --accent: var(--openbitfun-accent, #60a5fa); -} -body { - font-family: var(--openbitfun-font-sans, system-ui, sans-serif); - color: var(--text); - background: var(--bg); -} -``` - -### 同步时机 - -- iframe 加载后 bridge 会向宿主发送 `openbitfun/request-appearance`,宿主回推当前主题变量,iframe 内 `_applyAppearanceVars` 写入 `:root`。 -- 主应用切换主题时,宿主会向 iframe 发送 `appearanceChange` 事件,bridge 更新变量并触发 `onAppearanceChange` 回调。 - -## 国际化(i18n) - -MiniApp 框架在 V2 之后内置 i18n 支持,开发者**必须**为多语言用户考虑两类文案: - -1. **Gallery 元数据**(`name` / `description` / `tags`)—— 在 `meta.json` 顶层加 `i18n.locales` 块,宿主 Gallery / Card / Scene 标题自动按当前语言挑选。 -2. **应用内文案**(HTML / JS 中的所有可见字符串)—— 通过 `window.app.locale`、`window.app.onLocaleChange(fn)` 与 `window.app.t(table, fallback)` 实现。 - -### `meta.json` 多语言示例 - -```json -{ - "id": "your-app", - "name": "默认名(兜底)", - "description": "默认描述", - "tags": ["默认标签"], - "i18n": { - "locales": { - "zh-CN": { "name": "中文名", "description": "中文描述", "tags": ["中文"] }, - "en-US": { "name": "English Name", "description": "English desc", "tags": ["en"] } - } - } -} -``` - -回退顺序:`current` → `en-US` → `zh-CN` → 顶层默认值。 - -### `window.app` i18n 运行时 API - -| 成员 | 说明 | -|------|------| -| `app.locale` | 当前语言 ID(如 `'zh-CN'` / `'en-US'`),随宿主切换更新 | -| `app.onLocaleChange(fn)` | 注册语言切换回调,参数为新 locale 字符串 | -| `app.t(table, fallback)` | 从 `{ 'zh-CN': '...', 'en-US': '...' }` 表挑选字符串;解析顺序:current → en-US → zh-CN → 表的第一项 → fallback | - -### HTML 静态文案:`data-i18n` 约定 - -宿主不强制要求该写法,但推荐 MiniApp 内部统一约定: - -- `默认` —— 切换语言时 `applyStaticI18n()` 读取 `data-i18n` 并替换 `textContent` -- `
...
` —— 设置某个属性而非文本 - -参考 `builtin/assets/gomoku/ui.js` 等内置应用的 `I18N` 表 + `applyStaticI18n()` + `app.onLocaleChange` 三件套即可复用。 - -### 编写自检清单 - -- [ ] `meta.json` 已加 `i18n.locales`(至少 `zh-CN` / `en-US`) -- [ ] HTML 中静态文案均带 `data-i18n` 属性 -- [ ] JS 内动态拼接的字符串使用 `app.t()` 或自有 `I18N` 表 -- [ ] 注册了 `app.onLocaleChange`,切换语言时重新渲染(包括动态列表、aria-label、title) -- [ ] 持久化数据(`app.storage`)保存语言无关的索引/键,而非已翻译的字符串 - -## 内置小应用(builtin/assets/*)维护规范 - -内置小应用通过 `src/crates/contracts/product-domains/src/miniapp/builtin.rs` 中的 `BUILTIN_APPS` 数组以 `include_str!` 方式打包进 Rust 二进制;首次启动 / 升级时由 `seed_builtin_miniapps()` 把资源写入用户的 `miniapps_dir//`,并在该目录下写入 `.builtin-manifest.json` 主标记文件,同时兼容写入 `.builtin-version` legacy 标记。 - -**只有当 bundled `version` / asset hash 与 on-disk `.builtin-manifest.json` 不一致时才会重新 seed**,否则启动时会跳过、用户看到的还是旧版本。 - -### 修改流程(强制) - -凡是修改了 `src/crates/contracts/product-domains/src/miniapp/builtin/assets//` 下任何文件(`index.html` / `style.css` / `ui.js` / `worker.js` / `meta.json`),**都必须**同步在 `builtin.rs` 的 `BUILTIN_APPS` 中把对应条目的 `version: N` → `N + 1`。 - -```rust -// src/crates/contracts/product-domains/src/miniapp/builtin.rs -BuiltinApp { - id: "builtin-daily-divination", - version: 14, // ← 改完资源就把这里 +1 - ... -} -``` - -未 bump 的后果: -- asset hash 变化仍会触发 reseed,但 bundle version 和 `.builtin-version` legacy 标记无法体现升级批次 -- QA / Release 难以用版本号关联资源变更,容易误判资源是否已随包更新 - -### 自检清单 - -- [ ] 改完 `assets//*` 任何文件 -- [ ] `builtin.rs` 中对应 `BuiltinApp.version` 已 +1 -- [ ] 本地清掉 `~/.openbitfun/miniapps//.builtin-manifest.json` 或直接整目录删,再启动验证 reseed 生效 -- [ ] meta.json 中的 `version` 字段(用户可见的元数据版本)按需同步(与 reseed 无关,但展示用) - -### 提示 - -- `meta.json` 里的 `version`(默认 1)是给用户看的版本号,**不**驱动 reseed -- 真正驱动 reseed 的是 `builtin.rs` 中的 `BuiltinApp.version` 字段(u32)和 bundled asset hash -- 二者最好语义一致:资源有重大更新时同步 bump,便于排查 - -## 开发约定 - -### 新增 Agent 工具 - -当前仅 **InitMiniApp**。若扩展: -1. `implementations/miniapp_xxx_tool.rs` 实现 `Tool` -2. `mod.rs` + `registry.rs` 注册 -3. `flow_chat/tool-cards/index.ts` 与 `MiniAppToolDisplay.tsx` 增加对应卡片 - -### 修改编译器 - -`compiler.rs`:注入 Import Map(`build_import_map`)、Runtime Adapter(`build_bridge_script`)、CSP;用户脚本以 `