From 85c9c4e9e9f432bd60c4a5af9420559a9112040a Mon Sep 17 00:00:00 2001
From: GCWing
Date: Sat, 24 Oct 2026 16:16:49 +0800
Subject: [PATCH] feat(web): refine project and subscription flows and add
MiniApp demos
---
MiniApp/Demo/background-remover/AGENTS.md | 14 +
MiniApp/Demo/background-remover/README.md | 79 ++
MiniApp/Demo/background-remover/meta.json | 31 +
MiniApp/Demo/background-remover/package.json | 8 +
.../Demo/background-remover/source/build.mjs | 25 +
.../source/esm_dependencies.json | 1 +
.../Demo/background-remover/source/index.html | 91 ++
.../Demo/background-remover/source/package.py | 40 +
.../Demo/background-remover/source/style.css | 110 ++
MiniApp/Demo/background-remover/source/ui.js | 519 ++++++++++
.../Demo/background-remover/source/ui/core.js | 131 +++
.../Demo/background-remover/source/ui/i18n.js | 61 ++
.../Demo/background-remover/source/ui/main.js | 321 ++++++
.../Demo/background-remover/source/worker.js | 1 +
.../background-remover/tests/core.test.mjs | 116 +++
.../tests/delivery.test.mjs | 28 +
MiniApp/Demo/icon-studio-v2/AGENTS.md | 15 +
MiniApp/Demo/icon-studio-v2/README.md | 95 ++
MiniApp/Demo/icon-studio-v2/meta.json | 21 +
MiniApp/Demo/icon-studio-v2/package.json | 6 +
MiniApp/Demo/icon-studio-v2/source/build.mjs | 25 +
.../source/esm_dependencies.json | 1 +
MiniApp/Demo/icon-studio-v2/source/index.html | 75 ++
MiniApp/Demo/icon-studio-v2/source/package.py | 40 +
MiniApp/Demo/icon-studio-v2/source/style.css | 106 ++
MiniApp/Demo/icon-studio-v2/source/ui.js | 959 ++++++++++++++++++
MiniApp/Demo/icon-studio-v2/source/ui/boot.js | 29 +
.../Demo/icon-studio-v2/source/ui/geometry.js | 180 ++++
MiniApp/Demo/icon-studio-v2/source/ui/i18n.js | 68 ++
.../icon-studio-v2/source/ui/interactions.js | 214 ++++
MiniApp/Demo/icon-studio-v2/source/ui/io.js | 156 +++
.../Demo/icon-studio-v2/source/ui/render.js | 111 ++
.../Demo/icon-studio-v2/source/ui/state.js | 78 ++
.../Demo/icon-studio-v2/source/ui/trace.js | 107 ++
MiniApp/Demo/icon-studio-v2/source/worker.js | 1 +
.../icon-studio-v2/tests/delivery.test.mjs | 22 +
.../icon-studio-v2/tests/geometry.test.mjs | 124 +++
.../icon-studio-v2/tests/persistence.test.mjs | 73 ++
scripts/frontend-color-surface-registry.json | 35 +
.../NavPanel/MainNav.projectCreation.test.tsx | 11 +
.../src/app/components/NavPanel/MainNav.tsx | 36 +-
.../NewProjectDialog.test.tsx | 53 +-
.../NewProjectDialog/NewProjectDialog.tsx | 49 +-
...temCompatibilityScene.presentation.test.ts | 24 +
.../EcosystemCompatibilityScene.scss | 43 +-
.../ecosystem-compatibility/EcosystemPets.tsx | 7 +-
.../ExternalAgentContent.tsx | 8 +-
.../ai/ModelSettingsPage.loading.test.tsx | 73 ++
.../ai/ModelSettingsPage.presentation.test.ts | 32 +
.../settings/pages/ai/ModelSettingsPage.scss | 56 +-
.../settings/pages/ai/ModelSettingsPage.tsx | 216 ++--
.../ai/SubscriptionQuotaPanel.module.scss | 65 +-
.../pages/ai/SubscriptionQuotaPanel.test.tsx | 54 +-
.../pages/ai/SubscriptionQuotaPanel.tsx | 39 +-
.../ai/SubscriptionServiceGroup.test.tsx | 4 +
.../pages/ai/SubscriptionServiceGroup.tsx | 22 +-
.../src/app/services/createProject.test.ts | 10 +
src/web-ui/src/app/services/createProject.ts | 5 +-
src/web-ui/src/app/utils/projectDraft.ts | 7 +
.../ssh-remote/WorkspaceSourceSelector.tsx | 5 +-
src/web-ui/src/locales/en-US/common.json | 1 +
src/web-ui/src/locales/zh-CN/common.json | 1 +
src/web-ui/src/locales/zh-TW/common.json | 1 +
63 files changed, 4756 insertions(+), 183 deletions(-)
create mode 100644 MiniApp/Demo/background-remover/AGENTS.md
create mode 100644 MiniApp/Demo/background-remover/README.md
create mode 100644 MiniApp/Demo/background-remover/meta.json
create mode 100644 MiniApp/Demo/background-remover/package.json
create mode 100644 MiniApp/Demo/background-remover/source/build.mjs
create mode 100644 MiniApp/Demo/background-remover/source/esm_dependencies.json
create mode 100644 MiniApp/Demo/background-remover/source/index.html
create mode 100644 MiniApp/Demo/background-remover/source/package.py
create mode 100644 MiniApp/Demo/background-remover/source/style.css
create mode 100644 MiniApp/Demo/background-remover/source/ui.js
create mode 100644 MiniApp/Demo/background-remover/source/ui/core.js
create mode 100644 MiniApp/Demo/background-remover/source/ui/i18n.js
create mode 100644 MiniApp/Demo/background-remover/source/ui/main.js
create mode 100644 MiniApp/Demo/background-remover/source/worker.js
create mode 100644 MiniApp/Demo/background-remover/tests/core.test.mjs
create mode 100644 MiniApp/Demo/background-remover/tests/delivery.test.mjs
create mode 100644 MiniApp/Demo/icon-studio-v2/AGENTS.md
create mode 100644 MiniApp/Demo/icon-studio-v2/README.md
create mode 100644 MiniApp/Demo/icon-studio-v2/meta.json
create mode 100644 MiniApp/Demo/icon-studio-v2/package.json
create mode 100644 MiniApp/Demo/icon-studio-v2/source/build.mjs
create mode 100644 MiniApp/Demo/icon-studio-v2/source/esm_dependencies.json
create mode 100644 MiniApp/Demo/icon-studio-v2/source/index.html
create mode 100644 MiniApp/Demo/icon-studio-v2/source/package.py
create mode 100644 MiniApp/Demo/icon-studio-v2/source/style.css
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/boot.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/geometry.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/i18n.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/interactions.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/io.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/render.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/state.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/ui/trace.js
create mode 100644 MiniApp/Demo/icon-studio-v2/source/worker.js
create mode 100644 MiniApp/Demo/icon-studio-v2/tests/delivery.test.mjs
create mode 100644 MiniApp/Demo/icon-studio-v2/tests/geometry.test.mjs
create mode 100644 MiniApp/Demo/icon-studio-v2/tests/persistence.test.mjs
diff --git a/MiniApp/Demo/background-remover/AGENTS.md b/MiniApp/Demo/background-remover/AGENTS.md
new file mode 100644
index 0000000000..087491611c
--- /dev/null
+++ b/MiniApp/Demo/background-remover/AGENTS.md
@@ -0,0 +1,14 @@
+# Background Remover MiniApp
+
+Run the focused checks from the repository root:
+
+```sh
+node MiniApp/Demo/background-remover/source/build.mjs
+python3 MiniApp/Demo/background-remover/source/package.py
+node --test MiniApp/Demo/background-remover/tests/*.test.mjs
+```
+
+After UI or color changes, also run `pnpm run theme:color-audit:all`.
+Edit `source/ui/*.js`, then rebuild the generated `source/ui.js` bundle.
+The standalone HTML is generated under repository-level ignored `output/miniapps/`, separate from host-owned `compiled.html`.
+Do not use Computer Use or browser control for verification unless the user asks.
diff --git a/MiniApp/Demo/background-remover/README.md b/MiniApp/Demo/background-remover/README.md
new file mode 100644
index 0000000000..2240b54fde
--- /dev/null
+++ b/MiniApp/Demo/background-remover/README.md
@@ -0,0 +1,79 @@
+# 轻抠 / Background Remover
+
+给图标、Logo 去掉纯色或近似纯色背景,下载真正带 Alpha 通道的透明 PNG。
+所有像素处理都在当前打开页面的设备上完成;不上传图片,不加载模型,不需要网络、账号或 Node Worker。
+
+## 使用
+
+在仓库根目录运行:
+
+```sh
+node MiniApp/Demo/background-remover/source/build.mjs
+```
+
+打开仓库根目录下生成的 `output/miniapps/background-remover.html` 即可离线使用,无需启动服务器。
+
+1. 点击上传、拖入或粘贴一张 PNG、JPG、WebP 图片。
+2. 自动读取图片边缘的主要背景颜色,并显示抠图结果。棋盘格代表真实透明。
+3. 背景未去干净时,在原图上点击背景取色,或调整颜色容差和边缘柔化。
+4. 点击「下载透明 PNG」,保留原图像素尺寸。对比底色只改变预览。
+
+默认只移除与图片四边连通的背景,保留主体内部同色区域。
+需要去掉字母、镂空区域内的背景时,取消勾选该选项;这也可能移除主体内部的同色内容。
+对已有透明边缘的图片,自动模式先保留原图,手动取色后可继续处理。
+
+最大输入为 30 MiB、1600 万像素,单边不超过 8192 像素;超限会明确提示,不会自动缩图。
+适合简单背景;复杂照片、已经烘焙进图片的棋盘格、与背景相连的同色主体无法可靠分离。
+容差过大可能清空图片,此时禁用导出并提示调整设置。
+
+## OpenBitFun MiniApp
+
+**源码文件夹和独立 HTML 不会自动出现在应用列表里,需要先导入。**
+
+在 OpenBitFun 中打开 Mini Apps,点击「导入小应用」→「从文件夹导入」,
+选择本目录 `MiniApp/Demo/background-remover`(含 `meta.json` 的目录,不是 `source` 子目录)。
+客户端会完成安装、编译并更新应用列表;无需把它改成内置应用,也无需重新构建客户端。
+
+也可以在构建后生成安装包:
+
+```sh
+python3 MiniApp/Demo/background-remover/source/package.py
+```
+
+然后在「导入小应用」菜单中导入 `output/miniapps/background-remover.bfminiapp`,
+查看权限并确认。安装包不会发布到市场。
+
+本目录同时包含标准 `meta.json`、`source/index.html`、`source/style.css`、`source/ui.js`、
+`source/worker.js` 和空的 `source/esm_dependencies.json`。
+宿主应通过标准 MiniApp 创建/导入流程读取这些源码并编译;不要把独立 HTML 复制为 `compiled.html`。
+本次交付未调用宿主 `InitMiniApp` / `FinalizeMiniApp`,未安装到用户的 Mini App 列表。
+
+仅申请 `{user-selected}` 写权限,用于 `app.dialog.save` 选择位置后保存 PNG。
+图片输入来自页面文件选择器、拖拽或粘贴,不读取工作区、宿主路径或任意目录。
+在 OpenBitFun 中保存使用 `app.fs.writeFile`;独立 HTML 使用页面下载。
+不支持文件保存的宿主会显示明确提示。
+随宿主切换明暗主题和中英文;独立版也提供语言和主题切换。
+
+## 开发与验证
+
+```sh
+node MiniApp/Demo/background-remover/source/build.mjs
+node --test MiniApp/Demo/background-remover/tests/*.test.mjs
+pnpm run theme:color-audit:all
+```
+
+编辑 `source/ui/*.js` 后重新构建,`source/ui.js` 为生成入口。
+算法测试覆盖背景识别、边缘连通、封闭区域、既有透明度、柔化和去色边、取消处理。
+未使用浏览器控制或 Computer Use 验证界面。
+
+远程场景:本应用不调用工作区、Agent Runtime 或命令执行接口,像素处理不依赖宿主文件系统。
+远程工作区、远程控制、Peer Device Mode 和 Detached Dispatch 均未做端到端验证;
+不据本地算法测试宣称这些宿主支持图片上传、保存或独立运行界面。
+
+## English
+
+Build using the command above, then open `output/miniapps/background-remover.html` from the repository root locally.
+Upload, drop, or paste an icon, pick its background color if necessary, adjust tolerance and edge softness,
+and download a transparent PNG at the original resolution. Processing stays on the viewing device.
+Edge-connected removal preserves enclosed foreground regions; disable it to remove matching colors inside holes.
+This tool targets solid or near-solid backgrounds rather than complex photographic segmentation.
diff --git a/MiniApp/Demo/background-remover/meta.json b/MiniApp/Demo/background-remover/meta.json
new file mode 100644
index 0000000000..c2e15800ac
--- /dev/null
+++ b/MiniApp/Demo/background-remover/meta.json
@@ -0,0 +1,31 @@
+{
+ "id": "background-remover",
+ "name": "轻抠",
+ "description": "为图标和 Logo 去除纯色或近似纯色背景。图片仅在当前设备处理,支持背景取色、容差调整和透明 PNG 导出。",
+ "icon": "Scissors",
+ "category": "creative",
+ "tags": ["image", "background", "transparent", "icon"],
+ "version": 1,
+ "created_at": 0,
+ "updated_at": 0,
+ "permissions": {
+ "fs": { "read": [], "write": ["{user-selected}"] },
+ "shell": { "allow": [] },
+ "net": { "allow": [] },
+ "node": { "enabled": false }
+ },
+ "i18n": {
+ "locales": {
+ "zh-CN": {
+ "name": "轻抠",
+ "description": "图标、Logo 简单背景抠图,自动识别背景、手动取色,本地导出透明 PNG。",
+ "tags": ["图片", "抠图", "透明背景", "图标"]
+ },
+ "en-US": {
+ "name": "Background Remover",
+ "description": "Remove simple backgrounds from icons and logos, pick a background color, and export transparent PNGs locally.",
+ "tags": ["image", "background removal", "transparent", "icon"]
+ }
+ }
+ }
+}
diff --git a/MiniApp/Demo/background-remover/package.json b/MiniApp/Demo/background-remover/package.json
new file mode 100644
index 0000000000..a21bcb5ffd
--- /dev/null
+++ b/MiniApp/Demo/background-remover/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "miniapp-background-remover",
+ "private": true,
+ "scripts": {
+ "build": "node source/build.mjs",
+ "test": "node --test tests/*.test.mjs"
+ }
+}
diff --git a/MiniApp/Demo/background-remover/source/build.mjs b/MiniApp/Demo/background-remover/source/build.mjs
new file mode 100644
index 0000000000..e9a0ece649
--- /dev/null
+++ b/MiniApp/Demo/background-remover/source/build.mjs
@@ -0,0 +1,25 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const sourceRoot = path.dirname(fileURLToPath(import.meta.url));
+const appRoot = path.dirname(sourceRoot);
+const repoRoot = path.resolve(appRoot, '../../..');
+const inputs = ['ui/core.js', 'ui/i18n.js', 'ui/main.js'];
+const bundle = inputs.map(file => `/* ${file} */\n${fs.readFileSync(path.join(sourceRoot, file), 'utf8')}\n`).join('');
+fs.writeFileSync(path.join(sourceRoot, 'ui.js'), bundle);
+
+// This is an offline user deliverable, not the host-managed compiled.html.
+// Reuse the canonical first-paint projection instead of creating another palette.
+const appearance = fs.readFileSync(path.join(repoRoot,
+ 'src/crates/contracts/product-domains/src/miniapp/generated/default_appearance_style.html'), 'utf8');
+const css = fs.readFileSync(path.join(sourceRoot, 'style.css'), 'utf8');
+const html = fs.readFileSync(path.join(sourceRoot, 'index.html'), 'utf8');
+const escapeScript = script => script.replace(/<\/script/gi, '<\\/script');
+const standalone = html
+ .replace('', `${appearance}\n\n`)
+ .replace('
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PNG
+
+
+
+
+
+
+
+
+
+
+
+', `\n`);
+const outputDir = path.join(repoRoot, 'output', 'miniapps');
+fs.mkdirSync(outputDir, { recursive: true });
+fs.writeFileSync(path.join(outputDir, 'background-remover.html'), standalone);
+console.log('Built MiniApp source/ui.js and standalone output/miniapps/background-remover.html');
diff --git a/MiniApp/Demo/background-remover/source/esm_dependencies.json b/MiniApp/Demo/background-remover/source/esm_dependencies.json
new file mode 100644
index 0000000000..fe51488c70
--- /dev/null
+++ b/MiniApp/Demo/background-remover/source/esm_dependencies.json
@@ -0,0 +1 @@
+[]
diff --git a/MiniApp/Demo/background-remover/source/index.html b/MiniApp/Demo/background-remover/source/index.html
new file mode 100644
index 0000000000..4bc4624026
--- /dev/null
+++ b/MiniApp/Demo/background-remover/source/index.html
@@ -0,0 +1,91 @@
+
+
+