miniapp-dev

star 1.0k

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/.

GCWing By GCWing schedule Updated 6/5/2026

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,并遵循下方"生成新 MiniApp 必读(速查)"章节的硬约束。详细 API 见 api-reference.md

生成新 MiniApp 必读(速查)

完整指南见 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.rsregister_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)

// 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.rsresolve_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.jsscanGitWorkspace);
  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 根元素 <html> 带有 data-theme-type="dark""light",便于用 CSS 按主题写样式,例如:

[data-theme-type="light"] .panel { background: #f5f5f5; }
[data-theme-type="dark"] .panel { background: #1a1a1a; }

--bitfun-* CSS 变量

宿主会将主应用主题映射为以下 CSS 变量并注入 iframe 的 :root。在 MiniApp 的 CSS 中建议用 var(--bitfun-*, <fallback>) 引用,以便在 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 中):

: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.localewindow.app.onLocaleChange(fn)window.app.t(table, fallback) 实现。

meta.json 多语言示例

{
  "id": "your-app",
  "name": "默认名(兜底)",
  "description": "默认描述",
  "tags": ["默认标签"],
  "i18n": {
    "locales": {
      "zh-CN": { "name": "中文名", "description": "中文描述", "tags": ["中文"] },
      "en-US": { "name": "English Name", "description": "English desc", "tags": ["en"] }
    }
  }
}

回退顺序:currenten-USzh-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 内部统一约定:

  • <span data-i18n="key">默认</span> —— 切换语言时 applyStaticI18n() 读取 data-i18n 并替换 textContent
  • <div data-i18n="ariaKey" data-i18n-attr="aria-label">...</div> —— 设置某个属性而非文本

参考 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/<app_id>/,并在该目录下写入 .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/<app>/ 下任何文件(index.html / style.css / ui.js / worker.js / meta.json),都必须同步在 builtin.rsBUILTIN_APPS 中把对应条目的 version: NN + 1

// 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/<app>/* 任何文件
  • builtin.rs 中对应 BuiltinApp.version 已 +1
  • 本地清掉 ~/.bitfun/miniapps/<app_id>/.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.tsMiniAppToolDisplay.tsx 增加对应卡片

修改编译器

compiler.rs:注入 Import Map(build_import_map)、Runtime Adapter(build_bridge_script)、CSP;用户脚本以 <script type="module"> 注入 ui_js

前端事件

后端 miniapp-created / miniapp-updated / miniapp-deleted / miniapp-worker-*,前端 useMiniAppCatalogSync 统一监听并刷新 store。

场景注册检查清单

同前:SceneBar/types.tsscenes/registry.tsSceneViewport.tsxNavPanel/config.tsapp/types/index.ts、locales。

参考

  • 重构计划: .cursor/plans/miniapp_v2_full_refactor_*.plan.md
  • 架构说明见 plan 内「MiniApp V2 一步到位重构计划」
Install via CLI
npx skills add https://github.com/GCWing/BitFun --skill miniapp-dev
Repository Details
star Stars 1,012
call_split Forks 111
navigation Branch main
article Path SKILL.md
More from Creator