| name | liveapp-dev |
| description | Develops, maintains, and generates Sparo OS Live Apps. Use for Live App framework code, LiveAppStudio, InitLiveApp, window.app APIs, app.fs/app.shell/app.storage/app.net/app.ai/app.agentic, runtime debugging, or work under live_app/Demo/ and live_app/Skills/. |
Sparo OS Live App V2 开发指南
本 Skill 服务两类工作:
- 维护框架本身 → 阅读下方"代码架构 / Bridge / 权限模型 / window.app API"等章节。
- 生成一个新的 Live App → 先遵循 Studio prompt 的默认策略;本文件只提供 API、权限、视觉硬约束。需要深入视觉 polish 时再读
[design-playbook.md](design-playbook.md)。详细 API 见 [api-reference.md](api-reference.md)。
调用方与加载顺序
本 Skill 同时服务两类入口:
- 任意 Agent 用
Skill('liveapp-dev') 加载(手动调用,框架维护或生成新 Live App)。
- LiveAppStudio Mode 自动调用:每个 Studio 会话首轮强制加载本
SKILL.md。Studio 的工作循环(Intake / Anchor / Scaffold / Skeleton / Loop / Polish / Review)已写入它的 prompt,本文档不重复。本文档只提供 Anchor 阶段的视觉锚定上下文与 Polish 阶段的 QA Checklist。
| 场景 | 必读 | 按需 Read |
|---|
| Studio 生成新 Live App | SKILL.md | design-playbook.md(深度视觉 polish 时)、api-reference.md(写 worker.js / 自定义权限时) |
| 维护框架本身 | SKILL.md + architecture.md | api-reference.md |
| 改 builtin 应用 | SKILL.md(reseed 规则) | design-playbook.md(视觉变更时) |
Studio prompt 已硬规定:同一会话内不重复加载本 Skill 任何文件。
视觉锚白名单(Anchor 阶段)
按"工具型 → 展示型 → 设计系统型"递进选择最贴近的形态后 Read 其 style.css 顶部 Design System 注释。以下路径只保证在开发仓库中存在;二进制发布版应优先依赖内置 liveapp-dev Skill 的 compact baseline 和已安装 Live App,不要假设 Demo 目录存在。
- 内置(克制工具型):
bundles/live-apps/
gomoku/ — 交互 + 主题切换 + 持久化
divination/ — 仪式感配色与卡片
- Demo(更激进 / 复杂模块化):
live_app/Demo/
git-graph/ — 复杂 UI 拆模块(components / panels / services)
icon-design-system/ — 设计系统型应用范例
background-remover/ — 单页工具 + 文件交互范例
仅当用户明确要求"对外展示 / 灵感型 / 作品集"风格时才优先取 Demo;默认优先取内置 assets 的克制感。
生成新 Live App 必读(速查)
完整指南见 [design-playbook.md](design-playbook.md)。这里是不可妥协的硬约束,AI 在用 InitLiveApp 工具创建骨架后必须遵守。
流程
- 少问,默认决策:最多问 3 个用户能回答的问题:目的/受众、数据来源、隐私或外部访问、视觉参考。不要问 node mode、权限实现、i18n、Tweaks、框架或文件结构;由 Studio 用最小权限、no node、zh-CN + en-US、必要时 Tweaks 的默认策略决定。
- 找设计上下文:开发仓库中可先读
live_app/Demo/ 与 bundles/live-apps/ 中最贴近形态的应用,复刻它的视觉语言(间距 / 圆角 / 卡片密度 / motif)。如果这些路径不存在(例如二进制发布版),不要搜索用户工作区凑参考,直接使用 packaged liveapp-dev 的设计 baseline。
- 声明设计系统:
style.css 顶部用注释钉住 palette / typography / radius / motif(参见 playbook §1.3 模板),后续全应用复用。
- 占位先行 → 早预览:第一版用占位文本 / 占位图框 / fixture 数据,先在 Toolbox 里跑给用户看,再迭代。
- 验证:light/dark × zh/en 共 4 套截图都过;过 playbook §8 的 QA Checklist,尤其检查 CSS 是否引用了无效或臆造的主题变量。
反 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,与宿主主题协同(见下文"主题集成"章节的完整变量清单)。只把该清单里的变量当作宿主主题变量;--bitfun-surface、--bitfun-card、--theme-bg、--color-primary 等未定义名字必须改成已定义变量,或在 :root 中作为应用自己的 alias 明确定义。
- 优先使用运行态 UI Kit:常规 Button / Card / Input / Badge / Alert / Empty / Stack / Toolbar 优先使用
app.ui,它随 Live App 编译产物注入,不需要 import,也不依赖主应用开发态别名。
- 一个颜色占视觉权重 60-70%(dominant),1-2 个 supporting,1 个 accent — — 禁止给所有色块同等权重。
- 字号:标题 18-22px / Section 14-15px / 正文 13-14px / Caption 11-12px。
Tweaks 变体(推荐做法)
对外观/密度/字号/布局的多种合理选择,做成运行时可切换、写入 app.storage('tweaks')、右下角浮动小面板"Tweaks" — — 一份代码服务多种偏好是 Live App 的天然优势。详细约定见 playbook §4。
占位优于劣质实现
没图标 / 没数据 / 没素材时,用明确的占位(标注尺寸或 "TBD"),并在 meta.json.description 末尾登记待补清单;复杂交付才新增 README — — 不要硬画一个糟糕的真实物。
工具型 vs 展示型
绝大多数 Sparo OS Live App 是工具型 — — 信息密集、操作短、配色冷静,仿照 gomoku / divination / git-graph 的克制感。只有用户明确要"对外展示 / 灵感型 / 作品集"时才放飞视觉。
内容守则
- 不为填空白而加内容 — — 空白说明结构应被简化。
- 每个元素都要能回答"为什么在这里",回答不了就删掉。
- 加新 section / page / 功能前先问用户 — — 你不比用户更懂他的目标。
核心哲学:Zero-Dialect Runtime
Live App(灵动应用)使用 标准 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/core/src/live_app/
├── types.rs # LiveAppSource (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/live_app_api.rs
- 应用管理:
list_live_apps, get_live_app, create_live_app, update_live_app, delete_live_app
- 存储/授权:
get/set_live_app_storage, grant_live_app_workspace, grant_live_app_path
- 版本:
get_live_app_versions, rollback_live_app
- Worker/Runtime:
live_app_runtime_status, live_app_worker_call, live_app_host_call, live_app_worker_stop, live_app_install_deps, live_app_recompile
- 对话框由前端 Bridge 用 Tauri dialog 插件处理,部分封装为
live_app_dialog_* 等
Agent 工具
src/crates/core/src/agentic/tools/implementations/
└── live_app_init_tool.rs # InitLiveApp — 创建骨架目录供 AI 用通用文件工具编辑
注册在 registry.rs 的 register_all_tools() 中。AI 后续用 Read/Edit/Write 等通用文件工具编辑 Live App 源文件。
前端
src/web-ui/src/app/scenes/apps/live-app/
├── liveAppStore.ts
├── components/ LiveAppCard, LiveAppRunner (iframe 带 data-app-id)
├── hooks/
│ ├── useLiveAppBridge.ts # worker.call → workerCall() + dialog.open/save/message
│ └── useLiveAppCatalogSync.ts # 列表与运行态同步
└── liveAppIcons.tsx 等
src/web-ui/src/app/scenes/apps/LiveAppScene.tsx / LiveAppScene.scss
src/web-ui/src/infrastructure/api/service-api/LiveAppAPI.ts
src/web-ui/src/flow_chat/tool-cards/InitLiveAppToolDisplay.tsx # InitLiveAppDisplay,工具名 InitLiveApp
Worker 宿主
src/apps/desktop/resources/worker_host.js
Node/Bun 标准脚本:从 argv 读策略 JSON,stdin 收 RPC、stderr 回响应,内置 fs/shell/net/os/storage dispatch + 加载用户 source/worker.js 自定义方法。
Live App 数据模型 (V2)
LiveAppSource {
html, css,
ui_js,
esm_dependencies,
worker_js,
npm_dependencies,
}
LiveAppPermissions { fs?, shell?, net?, node?, ai?, agentic? }
权限模型
- 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) → useLiveAppBridge 监听
├─ 框架原语 (fs.* / shell.* / os.* / net.*):
│ ├─ node.enabled = false → liveAppAPI.hostCall → Tauri invoke('live_app_host_call')
│ │ → bitfun_core::live_app::host_dispatch(纯 Rust,无需 Bun/Node)
│ └─ node.enabled = true → liveAppAPI.workerCall → Tauri invoke('live_app_worker_call')
│ → JsWorkerPool(保留旧路径,允许 worker.js 覆写 fs/shell 等)
├─ 自定义方法:始终走 worker.call → JsWorkerPool(要求 node.enabled = true 且 worker.js 导出)
├─ storage.* (node.enabled = false 时):直接走 get/set_live_app_storage 命令
├─ ai.*:走 live_app_ai_* 命令,复用宿主 AIClient
└─ agentic.*:走 live_app_agentic_* 命令,创建/驱动宿主管理的 Sparo OS Agentic 会话
dialog.open / dialog.save / dialog.message → postMessage → useLiveAppBridge 直接调 @tauri-apps/plugin-dialog
何时使用「无 Node 模式」(推荐)
只要小应用的后端能力可以用 fs.* / shell.* / os.* / net.* / storage.* / ai.* / agentic.* 完成(例如调用 git 拉数据、读写工作区文件、抓取 HTTP API、直连宿主模型、或驱动 Sparo OS Agentic 会话),就把 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 / ai.* / agentic.* 等宿主桥接能力。
什么时候需要 node.enabled = true:
- 需要写
worker.js 自定义方法(CPU 密集 / 长流程 / 复杂解析等);
- 需要
npm_dependencies 安装第三方 npm 包;
- 需要在 worker 内长期持有连接、缓存、状态。
走「无 Node 模式」时,禁止 调用 app.call('myCustomMethod', …),宿主会显式报错;只能调用框架原语和 app.storage.*。
能力边界(重要)
Live App 运行时只暴露下列能力,没有任何任意调用内部服务的"通用 Sparo OS 后端通道"。设计 / 生成新小应用前请先比对,能力不在表内的需求请走相应替代方案。Agentic 会话只能通过表内的 app.agentic.* 管理,不要假设有 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 / 速率限制) |
| Agentic | app.agentic.createSession / sendMessage / cancelTurn / listSessions / restoreSession / deleteSession / confirmTool / rejectTool / openSession / onEvent | 创建并驱动真实 Sparo OS Agentic 会话,受 permissions.agentic 限制;需要 Sparo OS 工具链、会话持久化、原生 Flow Chat 查看时使用 |
| 对话框 | 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(...) | 见对应章节 |
Runtime UI Kit(运行态组件子集)
每个编译后的 Live App 都会注入一个小型运行态 UI Kit:window.app.ui。它不是主应用 React 组件库的开发态直连,而是为 sandbox iframe 准备的白名单子集:用原生 DOM helper + 与组件库对齐的 class contract,避免 Live App 依赖 Vite alias、React context 或开发服务器。
当前白名单:
app.ui.Button({ text, variant, size, onClick })
app.ui.Card({ children, variant, padding })
app.ui.CardHeader({ title, subtitle, extra })
app.ui.CardBody({ children })
app.ui.CardFooter({ children, align })
app.ui.Input({ label, placeholder, value, onInput })
app.ui.Badge({ text, variant })
app.ui.Alert({ type, title, message, description })
app.ui.Empty({ title, description })
app.ui.Stack({ children, direction, gap })
app.ui.Toolbar({ children })
app.ui.mount(target, child) / app.ui.createElement(tag, attrs, ...children)
生成常规工具型 Live App 时,优先用 app.ui 搭骨架,再写业务样式。若必须手写 HTML,也优先复用这些运行态 class:btn、v-card、bitfun-input-wrapper、badge、alert、bfui-stack。
示例:
const ui = app.ui;
const panel = ui.Card({
children: [
ui.CardHeader({ title: app.t({ 'zh-CN': '待办清单', 'en-US': 'Tasks' }) }),
ui.CardBody({
children: ui.Stack({
children: [
ui.Input({ label: app.t({ 'zh-CN': '新任务', 'en-US': 'New task' }) }),
ui.Button({ text: app.t({ 'zh-CN': '添加', 'en-US': 'Add' }) }),
],
}),
}),
],
});
ui.mount('#app', panel);
框架不直接暴露的 Sparo OS 后端能力(截至本文档)
下面这些 Sparo OS 内部服务,目前没有给小应用开放直接调用通道(表内已有的 app.agentic.* 是唯一受控 Agentic 会话入口):
- WorkspaceService(结构化工作区索引、统一搜索)
- GitService(结构化 status / diff / blame,区别于裸
git 命令)
- TerminalService(创建/读写交互式终端)
- Session / AgenticSystem 的任意内部 API(只能用
app.agentic.* 创建/恢复 Live App 自己拥有的会话、发送 prompt、接收事件、确认/拒绝工具、跳转查看)
- LSP / Snapshot / Mermaid / Skills / Browser API / Computer Use / Config 等
需要这类能力时的合规姿势:
- 能用裸命令行解决的(如 git) → 在
permissions.shell.allow 里加命令名,用 app.shell.exec 包一层;
- 只是要读 Sparo OS 工作区内的文件(如某些项目元数据) → 把
{workspace} 加到 permissions.fs.read,自己用 app.fs.* 读 + 在前端解析;
- 必须启动/驱动 Agentic 会话 → 用
app.agentic.*,不要用 app.ai.chat 模拟;
- 必须真调用其他内部服务 → 暂不支持,先记录到需求池。不要自己起一个 worker 去模拟服务行为,会和真正的 service 行为漂移。
维护者:以后若新增 app.bitfun.* / app.workspace.* 这类宿主直通通道,请同步更新本节,避免"文档说没有、代码偷偷加了"的不一致。
window.app 运行时 API
Live App UI 内通过 window.app 访问:
| API | 说明 |
|---|
app.call(method, params) | 调用自定义 Worker 方法;仅 node.enabled = true 且 worker.js 导出时可用 |
app.fs.* | 文件系统原语;node 关闭时由 Rust host_dispatch 处理,node 开启时可走 Worker |
app.shell.* | Shell 原语;受命令白名单限制 |
app.net.* | HTTP 原语;受域名白名单限制 |
app.os.* | 只读系统信息 |
app.storage.* | 每应用 KV 存储;无 Node 模式下由 manager 命令直接处理 |
app.ai.* | 宿主模型调用;受 permissions.ai 限制 |
app.agentic.* | 宿主管理的 Sparo OS Agentic 会话;受 permissions.agentic 限制 |
app.dialog.open/save/message | 由 Bridge 转 Tauri dialog 插件 |
app.clipboard.* | 由 Bridge 转宿主剪贴板 |
| 生命周期 / 事件 / i18n | onActivate / onDeactivate / onThemeChange / onLocaleChange / app.on/off / app.t |
主题集成
Live App 在 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。在 Live App 的 CSS 中建议用 var(--bitfun-*, <fallback>) 引用,以便在 Sparo OS 内与主应用一致,导出为独立应用时 fallback 生效。
审阅时必须把下列清单当作唯一有效的宿主主题变量白名单。任何不在清单内的 --bitfun-* 引用都是无效变量;任何 --theme-* / --color-* / --surface-* 之类主题名只有在 Live App 自己的 :root 明确定义后才能使用。
背景
--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)
Live App 运行在 V2 之后内置 i18n 支持,开发者必须为多语言用户考虑两类文案:
- Gallery 元数据(
name / description / tags) — — 在 meta.json 顶层加 i18n.locales 块,宿主 Gallery / Card / Scene 标题自动按当前语言挑选。
- 应用内文案(HTML / JS 中的所有可见字符串) — — 通过
window.app.locale、window.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"] }
}
}
}
回退顺序: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 约定
宿主不强制要求该写法,但推荐 Live App 内部统一约定:
<span data-i18n="key">默认</span> — — 切换语言时 applyStaticI18n() 读取 data-i18n 并替换 textContent
<div data-i18n="ariaKey" data-i18n-attr="aria-label">...</div> — — 设置某个属性而非文本
参考 bundles/live-apps/spark-board/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)保存语言无关的索引/键,而非已翻译的字符串
内置小应用(bundles/live-apps/*)维护规范
内置小应用放在 bundles/live-apps/<app>/,每个包用 bundle.json 声明稳定 id 和 reseed version。src/crates/core/src/live_app/builtin/mod.rs 会以 include_dir! 打包整个 bundles/live-apps 目录;首次启动 / 升级时由 seed_builtin_live_apps() 把资源写入用户的 liveapps/<app_id>/,并在该目录下写入 .builtin-version 标记文件。
只有当 bundled version > on-disk 标记时才会重新 seed,否则启动时会跳过,用户看到的还是旧版本。
修改流程(强制)
凡是修改了 bundles/live-apps/<app>/ 下任何文件(index.html / style.css / ui.js / worker.js / meta.json),都必须同步把该包 bundle.json 的 version: N 改为 N + 1。
{
"schemaVersion": 1,
"id": "builtin-daily-divination",
"version": 14
}
未 bump 的后果:
- 已经体验过该小应用的用户(本地有
.builtin-version 标记)不会收到新版本,无法验证设计 / 修复
- QA / Release 看到的还是旧文件,会误判“代码已合但效果没出来”
自检清单
- 改完
bundles/live-apps/<app>/ 任何文件
bundle.json 中对应 version 已 +1
- 本地清掉用户数据目录中
liveapps/<app_id>/.builtin-version 或直接删整目录,再启动验证 reseed 生效
meta.json 中的 version 字段(用户可见的元数据版本)按需同步(与 reseed 无关,但用于展示)
提示
meta.json 里的 version 是给用户看的版本号,不驱动 reseed
- 真正驱动 reseed 的是
bundle.json 中的 version 字段(u32)
- 二者最好语义一致:资源有重大更新时同步 bump,便于排查
开发约定
新增 Agent 工具
当前仅 InitLiveApp。若扩展:
implementations/live_app_xxx_tool.rs(或他名)实现 Tool
mod.rs + registry.rs 注册
flow_chat/tool-cards/index.ts 增加对应卡片组件
修改编译器
compiler.rs:注入 Import Map(build_import_map)、Runtime Adapter(build_bridge_script)、CSP;用户脚本以 <script type="module"> 注入 ui_js。
前端事件
后端 liveapp-created / liveapp-updated / liveapp-deleted / liveapp-worker-*,前端 useLiveAppCatalogSync 统一监听并刷新 store。
场景注册检查清单
同前:SceneBar/types.ts、scenes/registry.ts、SceneViewport.tsx、NavPanel/config.ts、app/types/index.ts、locales。
参考
- 历史重构计划(文件名可能仍含 miniapp):
.cursor/plans/miniapp_v2_full_refactor_*.plan.md
- 架构摘要: 同目录
architecture.md