diff --git a/Cargo.toml b/Cargo.toml index ddcfcb6342..9c994bd780 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,7 +149,7 @@ toml = "0.9" git2 = { version = "0.21", default-features = false, features = ["https", "vendored-libgit2"] } # Terminal -portable-pty = "0.8" +portable-pty = "0.9.0" vte = "0.15.0" clap = { version = "4.6.1", features = ["derive"] } crossterm = "0.28" @@ -180,18 +180,18 @@ oxc-parse = { package = "oxc", version = "0.138.0", default-features = false } rquickjs = { version = "0.9", default-features = false, features = ["classes", "properties", "macro"] } # Tauri (desktop only) -tauri = { version = "2.11", features = ["unstable", "macos-private-api", "tray-icon"] } -tauri-plugin-opener = "2.5" -tauri-plugin-dialog = "2.7" -tauri-plugin-fs = "2.5" -tauri-plugin-log = "2.8" -tauri-plugin-autostart = "2.5" -tauri-plugin-notification = "2.3" -tauri-plugin-updater = "2.10" +tauri = { git = "https://github.com/richerfu/tauri", branch = "feat/open-harmony", features = [] } +tauri-plugin-dialog = "2" +tauri-plugin-opener = "2" +tauri-plugin-fs = "2" +tauri-plugin-log = "2" +tauri-plugin-autostart = "2" +tauri-plugin-notification = "2" +tauri-plugin-updater = "2" +tauri-build = { git = "https://github.com/richerfu/tauri", branch = "feat/open-harmony", features = [] } tauri-plugin-global-shortcut = "2.3" -tauri-plugin-single-instance = "2.4" -tauri-plugin-window-state = "2.4" -tauri-build = { version = "2.6", features = [] } +napi-ohos = { version = "1.1" } +napi-derive-ohos = { version = "1.1" } keepawake = "0.6.0" # Desktop support @@ -269,12 +269,14 @@ rustls = { version = "0.23", default-features = false, features = ["ring", "std" [patch.crates-io] # tao 0.35.3 can re-enter its Windows window callback while holding input locks. # Use the upstream fix until it is included in a crates.io release. -tao = { git = "https://github.com/tauri-apps/tao.git", rev = "c704261c519c58cfdd0bc2d58ba24e06a0b71c92" } -# Tauri 2.11 loses keyboard focus for child webviews after Windows reactivates -# an `unstable` multi-webview window. Use the upstream 2.12 fix until released. -tauri-runtime = { git = "https://github.com/tauri-apps/tauri.git", rev = "ce3860e84b79af0d5ee628b304399499a87328b1" } -tauri-runtime-wry = { git = "https://github.com/tauri-apps/tauri.git", rev = "ce3860e84b79af0d5ee628b304399499a87328b1" } -tauri-utils = { git = "https://github.com/tauri-apps/tauri.git", rev = "ce3860e84b79af0d5ee628b304399499a87328b1" } +wry = { git = "https://github.com/richerfu/wry"} +tao = { git = "https://github.com/richerfu/tao", branch = "feat-ohos-webview"} +openharmony-ability = {git = "https://github.com/harmony-contrib/openharmony-ability.git"} +openharmony-ability-derive = {git = "https://github.com/harmony-contrib/openharmony-ability.git"} +tauri = { git = "https://github.com/richerfu/tauri", branch = "feat/open-harmony"} +tauri-runtime = { git = "https://github.com/richerfu/tauri", branch = "feat/open-harmony"} +tauri-macros = { git = "https://github.com/richerfu/tauri", branch = "feat/open-harmony"} +tauri-runtime-wry = { git = "https://github.com/richerfu/tauri", branch = "feat/open-harmony"} [profile.dev] incremental = true diff --git a/MiniApp/Skills/miniapp-dev/SKILL.md b/MiniApp/Skills/miniapp-dev/SKILL.md deleted file mode 100644 index 385749305f..0000000000 --- a/MiniApp/Skills/miniapp-dev/SKILL.md +++ /dev/null @@ -1,419 +0,0 @@ ---- -name: miniapp-dev -description: Develops, maintains, and generates BitFun 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 / 写个 BitFun 小工具 / 创建 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/. ---- - -# BitFun MiniApp V2 指南 - -> **本 Skill 服务两类工作**: -> -> - **维护框架本身** → 阅读下方"代码架构 / Bridge / 权限模型 / window.app API"等章节。 -> - **生成一个新的 MiniApp** → **必读** [`design-playbook.md`](design-playbook.md),并遵循下方"生成新 MiniApp 必读(速查)"章节的硬约束。详细 API 见 [`api-reference.md`](api-reference.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(--bitfun-font-sans)` 优先) -- ❌ 12px 以下文字 / hit target < 32px -- ❌ 圆角混用 4/8/12/16(钉 1-2 档全应用统一) -- ❌ 用装饰性 stats / icon / sparkline 填空白(空白是排版问题,不是内容问题) - -### 颜色与字体 -- **首选** `var(--bitfun-*)` 系列 + 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 展示型 -绝大多数 BitFun 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 + `__BITFUN__` 替换为统一的 **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') - │ │ → bitfun_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 框架**只暴露下列能力**,没有任何"通用 BitFun 后端通道"。设计 / 生成新小应用前请先比对,能力不在表内的需求请走相应替代方案,**不要假设有 `app.bitfun.*` / `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 | -| 自定义后端 | `app.call('xxx', …)` + `worker.js` | 仅 `node.enabled = true` 时可用,自己实现业务逻辑 | -| 主题 / i18n | `app.theme` / `app.locale` / `app.onThemeChange` / `app.onLocaleChange` / `app.t(...)` | 见对应章节 | - -### 框架**不**直接暴露的 BitFun 后端能力(截至本文档) - -下面这些 BitFun 内部服务,目前**没有**给小应用开放调用通道: - -- WorkspaceService(结构化工作区索引、统一搜索) -- GitService(结构化 status / diff / blame,区别于裸 `git` 命令) -- TerminalService(创建/读写交互式终端) -- Session / AgenticSystem(启动 Agent 会话、消费工具调用与流式事件) -- LSP / Snapshot / Mermaid / Skills / Browser API / Computer Use / Config 等 - -需要这类能力时的合规姿势: - -1. **能用裸命令行解决的**(如 git)→ 在 `permissions.shell.allow` 里加命令名,用 `app.shell.exec` 包一层(参考 `builtin-coding-selfie/ui.js` 的 `scanGitWorkspace`); -2. **只是要读 BitFun 工作区内的文件**(如某些项目元数据) → 把 `{workspace}` 加到 `permissions.fs.read`,自己用 `app.fs.*` 读 + 在前端解析; -3. **必须真调用某个内部服务** → 暂不支持,先记录到需求池。**不要**自己起一个 worker 去模拟服务行为,会和真正的 service 行为漂移。 - -> 维护者:以后若新增 `app.bitfun.*` / `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 插件 | -| 生命周期 / 事件 | 见 bridge_builder 生成的适配器 | - -## 主题集成 - -MiniApp 在 iframe 中运行时自动与主应用主题同步,避免界面风格与主应用差距过大。 - -### 只读属性与事件 - -| 成员 | 说明 | -|------|------| -| `app.theme` | 当前主题类型字符串:`'dark'` 或 `'light'`(随主应用切换更新) | -| `app.onThemeChange(fn)` | 注册主题变更回调,参数为 payload:`{ type, id, vars }` | - -### data-theme-type 属性 - -编译后的 HTML 根元素 `` 带有 `data-theme-type="dark"` 或 `"light"`,便于用 CSS 按主题写样式,例如: - -```css -[data-theme-type="light"] .panel { background: #f5f5f5; } -[data-theme-type="dark"] .panel { background: #1a1a1a; } -``` - -### --bitfun-* CSS 变量 - -宿主会将主应用主题映射为以下 CSS 变量并注入 iframe 的 `:root`。在 MiniApp 的 CSS 中建议用 `var(--bitfun-*, )` 引用,以便在 BitFun 内与主应用一致,导出为独立应用时 fallback 生效。 - -**背景** - -- `--bitfun-bg` — 主背景 -- `--bitfun-bg-secondary` — 次级背景(如工具栏、面板) -- `--bitfun-bg-tertiary` — 第三级背景 -- `--bitfun-bg-elevated` — 浮层/卡片背景 - -**文字** - -- `--bitfun-text` — 主文字 -- `--bitfun-text-secondary` — 次要文字 -- `--bitfun-text-muted` — 弱化文字 - -**强调与语义** - -- `--bitfun-accent`、`--bitfun-accent-hover` — 强调色及悬停 -- `--bitfun-success`、`--bitfun-warning`、`--bitfun-error`、`--bitfun-info` — 语义色 - -**边框与元素** - -- `--bitfun-border`、`--bitfun-border-subtle` — 边框 -- `--bitfun-element-bg`、`--bitfun-element-hover` — 控件背景与悬停 - -**圆角与字体** - -- `--bitfun-radius`、`--bitfun-radius-lg` — 圆角 -- `--bitfun-font-sans`、`--bitfun-font-mono` — 无衬线与等宽字体 - -**滚动条** - -- `--bitfun-scrollbar-thumb`、`--bitfun-scrollbar-thumb-hover` — 滚动条滑块 - -示例(在 `style.css` 中): - -```css -:root { - --bg: var(--bitfun-bg, #121214); - --text: var(--bitfun-text, #e8e8e8); - --accent: var(--bitfun-accent, #60a5fa); -} -body { - font-family: var(--bitfun-font-sans, system-ui, sans-serif); - color: var(--text); - background: var(--bg); -} -``` - -### 同步时机 - -- iframe 加载后 bridge 会向宿主发送 `bitfun/request-theme`,宿主回推当前主题变量,iframe 内 `_applyThemeVars` 写入 `:root`。 -- 主应用切换主题时,宿主会向 iframe 发送 `themeChange` 事件,bridge 更新变量并触发 `onThemeChange` 回调。 - -## 国际化(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 -- [ ] 本地清掉 `~/.bitfun/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;用户脚本以 `