@microi.net/cli 5.0.1 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/assets/build-meta.json +4 -4
  7. package/package.json +1 -1
  8. package/scripts/mcp-server.js +63 -63
  9. package/scripts/microi-codex-router.js +9 -1
  10. package/scripts/microi-skills.meta.json +191 -191
  11. package/skills/.microi-skills-version.json +2 -2
  12. package/skills/.progressive-disclosure-manifest.json +31 -31
  13. package/skills/ai-engine/SKILL.md +1 -1
  14. package/skills/microi-client-frontend/SKILL.md +23 -4
  15. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +23 -6
  16. package/skills/microi-deployment/SKILL.md +14 -1
  17. package/skills/microi-deployment/references/deployment-matrix.md +7 -0
  18. package/skills/microi-docs-coverage/references/capability-map.md +1 -1
  19. package/skills/microi-microservice/SKILL.md +13 -1
  20. package/skills/microi-microservice/references/runtime-delivery.md +19 -1
  21. package/skills/playwright-e2e/SKILL.md +23 -5
  22. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +47 -3
  23. package/skills/unity-integration/SKILL.md +2 -0
  24. package/skills/unity-integration/references/ai-app-delivery.md +2 -0
  25. package/skills/v8-file-upload/SKILL.md +16 -5
  26. package/skills/workspace-conventions/SKILL.md +17 -2
  27. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +20 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "generatedAt": "2026-08-13T12:40:41.746Z",
3
+ "generatedAt": "2026-08-13T15:04:59.034Z",
4
4
  "policy": {
5
5
  "maxEntryLines": 285,
6
6
  "referenceBudgetLines": 245,
@@ -169,11 +169,11 @@
169
169
  ]
170
170
  },
171
171
  "microi-client-frontend": {
172
- "originalSha256": "508f4d7c021971433d72ff9ed3eb6e3bbe02f2634ba01cb53bc799bdadaedd6f",
173
- "originalLines": 602,
174
- "prefixSha256": "5decf25a3ed71a6eb78accc950df73a3e3addf0909921f38389d3c526efb8738",
175
- "prefixBytes": 720,
176
- "entryLines": 179,
172
+ "originalSha256": "0cd7f005debd9bc307e9a0c4beffcd9368a2b0ee1b2afa7869c749882267cd38",
173
+ "originalLines": 638,
174
+ "prefixSha256": "65cd4f270c1895c459014ab1ce7c376f69ec5469fe94ddf0f82827eb8616d579",
175
+ "prefixBytes": 781,
176
+ "entryLines": 198,
177
177
  "chunks": [
178
178
  {
179
179
  "id": "microi-client-frontend-000",
@@ -211,8 +211,8 @@
211
211
  "id": "microi-client-frontend-004",
212
212
  "ordinal": 7,
213
213
  "destination": "microi-client-frontend/SKILL.md",
214
- "sha256": "ec659a0b0836eb53a55ac85c6e9c3d7701c77b01881a073ee35fc2b205f8d912",
215
- "lines": 10,
214
+ "sha256": "5c5669acf2040f87491abe1f8c85f89e9707a128508ca00f82d8f6a73c3ba7bc",
215
+ "lines": 29,
216
216
  "heading": "7. 验证建议"
217
217
  },
218
218
  {
@@ -267,8 +267,8 @@
267
267
  "id": "microi-client-frontend-011",
268
268
  "ordinal": 11,
269
269
  "destination": "microi-client-frontend/references/progressive-03-vue3-前端微服务宿主规则.md",
270
- "sha256": "26acb7297e2d0e794ae447beaba3b19171f9f232255adafc26966187e445e95a",
271
- "lines": 82,
270
+ "sha256": "7f8680e6afd7cae492a0d938e1efc95d0d20b04d0a33b0b956f2d0edb26d25cb",
271
+ "lines": 99,
272
272
  "heading": "Vue3 前端微服务宿主规则"
273
273
  },
274
274
  {
@@ -1344,11 +1344,11 @@
1344
1344
  ]
1345
1345
  },
1346
1346
  "playwright-e2e": {
1347
- "originalSha256": "dfedb663bea48a7f16bf0c6ae8448ae6cef1249245cf2867fb9585414ceb9d89",
1348
- "originalLines": 748,
1349
- "prefixSha256": "8002a056799f289a3d76ae93418f5aaab4fde77a481b25d948ca70034714b30f",
1350
- "prefixBytes": 1696,
1351
- "entryLines": 180,
1347
+ "originalSha256": "ba0d85ed668e479a307f5e7dbd0f040bf8a8bdad2903fafdbabea3c7fea45662",
1348
+ "originalLines": 806,
1349
+ "prefixSha256": "4a1dca656797241fbd27b7b6c8022f01ff40229394928f3418ad0b8263da11f7",
1350
+ "prefixBytes": 1777,
1351
+ "entryLines": 198,
1352
1352
  "chunks": [
1353
1353
  {
1354
1354
  "id": "playwright-e2e-000",
@@ -1394,8 +1394,8 @@
1394
1394
  "id": "playwright-e2e-005",
1395
1395
  "ordinal": 5,
1396
1396
  "destination": "playwright-e2e/SKILL.md",
1397
- "sha256": "e348db509b586871f19b16b6b49da840c93aa438dd891d827af7107744513e00",
1398
- "lines": 10,
1397
+ "sha256": "a66696c3263f060d0b7be309a527fca6a9bad95dd534eabbe84f1b6539770d8e",
1398
+ "lines": 24,
1399
1399
  "heading": "本地测试账号自动发现"
1400
1400
  },
1401
1401
  {
@@ -1546,8 +1546,8 @@
1546
1546
  "id": "playwright-e2e-024",
1547
1547
  "ordinal": 24,
1548
1548
  "destination": "playwright-e2e/references/progressive-04-ci-建议.md",
1549
- "sha256": "01abd9079de1ec60a1de8a441b93e32beccd0666f7fedf359ccbec2e0d40f8e9",
1550
- "lines": 17,
1549
+ "sha256": "b939c97eef28fab71caa54d134ea524d7ed7c8381deec09e38a7d694b15f53c0",
1550
+ "lines": 61,
1551
1551
  "heading": "常见问题"
1552
1552
  },
1553
1553
  {
@@ -2221,11 +2221,11 @@
2221
2221
  ]
2222
2222
  },
2223
2223
  "v8-file-upload": {
2224
- "originalSha256": "60496ffb4c5476884f631801c0f2978362155620f5c3d0f7e94daf3a57b8b130",
2225
- "originalLines": 518,
2224
+ "originalSha256": "a812df73c7f9e29bdfeeaa7f740a4b7b7490a6431e642d56ada31b2b9206923a",
2225
+ "originalLines": 529,
2226
2226
  "prefixSha256": "2cb0db96cd348d7a50f36b6e4f43435188e374ace1962eb639a501b9c7490c7e",
2227
2227
  "prefixBytes": 1074,
2228
- "entryLines": 180,
2228
+ "entryLines": 191,
2229
2229
  "chunks": [
2230
2230
  {
2231
2231
  "id": "v8-file-upload-000",
@@ -2247,8 +2247,8 @@
2247
2247
  "id": "v8-file-upload-002",
2248
2248
  "ordinal": 2,
2249
2249
  "destination": "v8-file-upload/SKILL.md",
2250
- "sha256": "ab3fa9eda3090868f45651aaddfa6b5ecd390535123f4666c9b67fba6a6e34f7",
2251
- "lines": 90,
2250
+ "sha256": "01111b2fe994a2a5e424f45d405821f0b4f5c29235bc93757352d4c7e10d8d84",
2251
+ "lines": 101,
2252
2252
  "heading": "接收前端上传的文件"
2253
2253
  },
2254
2254
  {
@@ -3196,11 +3196,11 @@
3196
3196
  ]
3197
3197
  },
3198
3198
  "workspace-conventions": {
3199
- "originalSha256": "5e52e816cb38c5f9fee557e28c2bc82dfe851f6d648b934eba4735b218dcc143",
3200
- "originalLines": 518,
3199
+ "originalSha256": "58812f002d909c3fda3dc6f3b3ba04926da23c09b09fcd15c18f1e8fc401f9a6",
3200
+ "originalLines": 551,
3201
3201
  "prefixSha256": "b58cd0a59d3643525695b94a5941278a5088c33cbe2ce81620359f37db69878e",
3202
3202
  "prefixBytes": 252,
3203
- "entryLines": 186,
3203
+ "entryLines": 201,
3204
3204
  "chunks": [
3205
3205
  {
3206
3206
  "id": "workspace-conventions-000",
@@ -3278,8 +3278,8 @@
3278
3278
  "id": "workspace-conventions-009",
3279
3279
  "ordinal": 9,
3280
3280
  "destination": "workspace-conventions/SKILL.md",
3281
- "sha256": "3e9f3fbe30417e8b309ebc5b52544d70390db36b30cebe3e96f1fa5928a9b99a",
3282
- "lines": 13,
3281
+ "sha256": "dc7dbe2d2f60466a7170fff65a5df8769bc795b4ab23151a24b665380d7c6e37",
3282
+ "lines": 28,
3283
3283
  "heading": "多对话共享工作区变更归属保护(强制)"
3284
3284
  },
3285
3285
  {
@@ -3406,8 +3406,8 @@
3406
3406
  "id": "workspace-conventions-025",
3407
3407
  "ordinal": 25,
3408
3408
  "destination": "workspace-conventions/references/progressive-02-microi-net-api-本地启动约定.md",
3409
- "sha256": "4b9936ad45a2893f4b9c32f3acd7230e4f57cb4314fd67e16d13ce09f368c003",
3410
- "lines": 13,
3409
+ "sha256": "07c3d729c8f1e9a2bf93ff00937e5d6eae4602d346e4f9254b03a33211ac4848",
3410
+ "lines": 31,
3411
3411
  "heading": "多 AI 对话共享本地服务与发布互斥(强制)"
3412
3412
  },
3413
3413
  {
@@ -7,7 +7,7 @@ description: Microi AI 引擎、模型代理、NL2SQL/NL2V8 与知识库规范
7
7
 
8
8
  # Microi AI Engine
9
9
 
10
- 平台视频生成的受控 HTTP 入口为 `/api/Ai/CreateMiniMaxVideo`、`/api/Ai/GetMiniMaxVideoTask`、`/api/Ai/GetMiniMaxVideoFile`;AI 工作流入口统一位于 `/api/AIWorkFlow/*`。调用方只提交业务参数和模型选择,供应商密钥、租户配额、任务归属和文件读取权限由服务端判定。
10
+ 平台视频生成的受控 HTTP 入口为 `/api/Ai/CreateMiniMaxVideo`、`/api/Ai/GetMiniMaxVideoTask`、`/api/Ai/GetMiniMaxVideoFile`、`/api/Ai/PersistMiniMaxVideoFile`;AI 工作流入口统一位于 `/api/AIWorkFlow/*`。调用方只提交业务参数和模型选择,供应商密钥、租户配额、任务归属和文件读取权限由服务端判定。`PersistMiniMaxVideoFile` 只能将当前登录用户所属、且已成功完成的 MiniMax 视频任务文件持久化到当前租户 HDFS;禁止把该入口作为任意 URL 搬运器,任务归属、文件来源和租户边界必须由服务端重新校验。
11
11
 
12
12
  ## 能力
13
13
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: microi-client-frontend
3
- description: Microi.Client 源码架构指南。用于修改 Microi.Client Vue 前端代码,尤其是表单引擎、diy-table、diy-form-full、工作流面板、sys_menu 按钮、前端 V8 事件、路由、微服务宿主 keep-alive/TagsView 缓存/白屏恢复,以及页面、弹窗和抽屉行为。
3
+ description: Microi.Client 源码架构指南。用于修改 Microi.Client Vue 前端代码,尤其是本地 ApiBase/OsClient URL 切换、浏览器租户隔离、表单引擎、diy-table、diy-form-full、工作流面板、sys_menu 按钮、前端 V8 事件、路由、微服务宿主 keep-alive/TagsView 缓存/白屏恢复,以及页面、弹窗和抽屉行为。
4
4
  ---
5
5
 
6
6
  > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
@@ -157,9 +157,28 @@ description: Microi.Client 源码架构指南。用于修改 Microi.Client Vue
157
157
  ---
158
158
 
159
159
  <!-- /microi-progressive:chunk -->
160
- <!-- microi-progressive:chunk id=microi-client-frontend-004 sha256=ec659a0b0836eb53a55ac85c6e9c3d7701c77b01881a073ee35fc2b205f8d912 -->
161
- ## 7. 验证建议
162
-
160
+ <!-- microi-progressive:chunk id=microi-client-frontend-004 sha256=5c5669acf2040f87491abe1f8c85f89e9707a128508ca00f82d8f6a73c3ba7bc -->
161
+ ## 7. 验证建议
162
+
163
+ ### 本地 ApiBase 与 OsClient 解析(强制)
164
+
165
+ - `src/config.json.ApiBaseDev` 是本地默认 API;URL 中 `#` 之前的 `ApiBase`、`OsClient` 必须同时
166
+ 高于 `index.html`、config、Pinia 与 localStorage。解析统一走
167
+ `src/utils/runtime-endpoint-query.js`,禁止在新入口另写正则形成不同优先级。
168
+ - URL 只允许有效的 HTTP(S) ApiBase 和安全 OsClient。页面初始化后通过不含 Token 的
169
+ `window.__MICROI_RUNTIME_ENDPOINT__` 暴露实际值,便于 AI/自动化确认没有误连配置文件中的服务器。
170
+ - 同源浏览器窗口仍共享 Token、CurrentUser 等持久化状态。不同 `ApiBase + OsClient` 并行测试必须
171
+ 使用独立 browser context/profile;URL 最高优先级不等于登录态隔离。
172
+ - 修改该链路时运行 `node --test tests/runtime-endpoint-query.spec.mjs`,再使用两个独立
173
+ `browser.newContext()` 验证两组运行目标互不串号。
174
+
175
+ ### 菜单微服务缓存与恢复(强制)
176
+
177
+ - 动态菜单宿主的 Vue 路由保持 `keepAlive:false`,由 `<micro-app keep-alive>` 独占运行时状态;契约固定为 `runtime-keep-alive`,禁止 Vue `KeepAlive` 和 micro-app 双层缓存。
178
+ - 每个顶部 Tab 按完整路由生成稳定实例身份,最多保留 5 个隐藏实例并按 LRU 淘汰。关闭 Tab、退出登录、Token/角色变化以及版本或入口变化时必须精确销毁对应运行时。
179
+ - 恢复时强制同步宿主上下文并检查真实可见 DOM;子应用监听 `appstate-change`,在 `afterhidden` 幂等暂停轮询、WebSocket 和观察器,在 `aftershow` 幂等恢复并重新测量布局,同时保留用户输入、筛选、滚动和内部路由。
180
+ - 修改宿主、TagsView 或权限路由时,必须同时读取 [Vue3 前端微服务宿主规则](references/progressive-03-vue3-前端微服务宿主规则.md) 并运行微服务缓存契约测试。
181
+
163
182
  - 修改 Vue/JS 后先跑 VS Code Problems 或 `get_errors`。
164
183
  - 影响核心前端时跑 `Microi.Client` 的 `npm run build`。
165
184
  - 如果改了工作流、表单保存、按钮 V8,建议用实际 `sys_menu` 配置测试:
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
4
 
5
- <!-- microi-progressive:chunk id=microi-client-frontend-011 sha256=26acb7297e2d0e794ae447beaba3b19171f9f232255adafc26966187e445e95a -->
5
+ <!-- microi-progressive:chunk id=microi-client-frontend-011 sha256=7f8680e6afd7cae492a0d938e1efc95d0d20b04d0a33b0b956f2d0edb26d25cb -->
6
6
  ## Vue3 前端微服务宿主规则
7
7
 
8
8
  `sys_menu.OpenType=MicroService` 时,动态路由必须把 `MicroServiceId`、`MicroServicePageId`、`MicroServiceRoutePath` 和真实入口 `MicroAppUrl` 写入 route meta;浏览器侧菜单路由使用 `/#/micro-app/{MsKey}/{RoutePath}`,不要再生成 `/micro-app-host/{menuId}`,否则地址过长且刷新或直接访问菜单路由容易加载空白页。
@@ -11,7 +11,7 @@
11
11
 
12
12
  菜单微服务的缓存所有权固定为一层:动态菜单和友好路由都设置 `meta.keepAlive=false`、`meta.microAppHost=true`,`AppMain` 不缓存 Vue 宿主;`host.vue` 的 `<micro-app keep-alive>` 才保存子应用 DOM、路由和状态。`AppMain` 对菜单微服务使用 `$route.fullPath` 作为宿主 key,宿主创建时立即快照 path/fullPath/meta/query,之后不得监听全局 `$route` 去改写即将隐藏的旧宿主。普通 Vue 页面继续使用原有 `KeepAlive`,菜单微服务也不得占用或淘汰 `cachedViews` 槽位。
13
13
 
14
- 运行时缓存集中维护在 `utils/microAppRuntimeCache.js`:实例名必须由租户、AppKey、菜单、fullPath、版本和入口的安全指纹稳定生成,长度受限且不暴露 Token/查询原文;全局最多保留 5 个实例,只淘汰最久未使用的 hidden 实例。TagsView 的关闭当前/其它/全部和访问记录淘汰必须按 fullPath 精确销毁;退出登录、Token 重置、角色切换必须清空全部;同一路由版本/入口变化必须替换旧实例。销毁统一调用 `unmountApp(name,{destroy:true,clearData:true})`,不能只从本地 Map 删除。
14
+ 运行时缓存集中维护在 `utils/microAppRuntimeCache.js`:实例名必须由租户、AppKeyfullPath、版本和入口的安全指纹稳定生成,长度受限且不暴露 Token/查询原文。菜单 Id 可能在友好路由首屏之后才随动态菜单元数据补齐,只能进入权限上下文,禁止参与实例身份;否则首次返回同一路由会被误判为新实例。全局最多保留 5 个实例,只淘汰最久未使用的 hidden 实例。TagsView 的关闭当前/其它/全部和访问记录淘汰必须按 fullPath 精确销毁;退出登录、Token 重置、角色切换必须清空全部;同一路由版本/入口变化必须替换旧实例。销毁统一调用 `unmountApp(name,{destroy:true,clearData:true})`,不能只从本地 Map 删除。
15
15
 
16
16
  宿主监听 `beforeshow/aftershow/afterhidden`:恢复时用 `forceSetData` 下发最新 Token、OsClient、权限、主题、路由和视口,并重新执行可见 DOM 健康检查;隐藏时停止宿主看门狗并把实例放入 LRU。`microAppData.cache` 与 `hostCapabilities.lifecycle` 要公开缓存模式、所有者、上限和 `appstate-change` 状态,错误诊断同时显示 cacheMode/cacheState/cacheInstance。可见 DOM 不健康时只自动销毁重建一次,禁止恢复阶段无限重试。
17
17
 
@@ -72,11 +72,28 @@ VS Code 插件执行前端微服务构建前必须先安全清理当前项目自
72
72
  - 发布回读取得 `sys_microiservice.Id` 与每条 `sys_microiservice_page.Id` 后,使用 `microi_create_module` 一次传入 `openType=MicroService`、`microServiceId`、`microServicePageId`、`microServiceRoutePath`、`microServiceKey`。菜单工具必须写后回读这些字段;不得长期依赖“先建普通 URL 菜单,再手工补字段”的两步绕路。
73
73
  - 最终通过 `microi_get_application_context`、`microi_get_microservice`、`microi_get_module` 和真实登录后的友好菜单路由逐层验收;多个菜单至少往返切换 8 轮,检查标题与子路由不串页、缓存范围内输入/筛选/滚动保持、无 404/5xx/白屏/永久骨架屏/实例冲突。再打开第 6 个实例验证 LRU 冷启动,并关闭 Tab/退出登录验证精确销毁;保存 fullPage 截图后用 `view_image` 复核。
74
74
 
75
- ### 表单下拉 Data 动态对象选项
75
+ ### 表单下拉 Data 动态对象选项
76
76
 
77
- 表单 V8 通过 `V8.FieldSet('字段名', 'Data', objectRows)` 动态写入下拉数据时,如果 `objectRows` 是对象数组,即使 `diy_field.Config.DataSource='Data'`,前端也必须按对象数据源处理,并使用 `SelectLabel/SelectSaveField` 或常见字段兜底生成 label/value。禁止把对象数组按普通字符串 Data 源过滤,否则会出现接口已有数据但下拉显示“无数据”的回归。
78
-
79
- ### 复盘:历史 OpenIframe 打印入口在 Vue3 弹窗中空白
77
+ 表单 V8 通过 `V8.FieldSet('字段名', 'Data', objectRows)` 动态写入下拉数据时,如果 `objectRows` 是对象数组,即使 `diy_field.Config.DataSource='Data'`,前端也必须按对象数据源处理,并使用 `SelectLabel/SelectSaveField` 或常见字段兜底生成 label/value。禁止把对象数组按普通字符串 Data 源过滤,否则会出现接口已有数据但下拉显示“无数据”的回归。
78
+
79
+ ### 线上微服务到本地宿主的运行目标复现
80
+
81
+ AI 收到线上 `/micro-app/{MsKey}/{RoutePath}` 地址并需要用本地 `Microi.Client` 排查时:
82
+
83
+ 1. 在一次性隔离 browser context 打开线上地址并等待主框架初始化。
84
+ 2. 优先读取 `window.__MICROI_RUNTIME_ENDPOINT__`。旧版没有该对象时,读取 URL、
85
+ `window.ApiBase/window.OsClient`、`JSON.parse(localStorage.getItem('microi.net') || '{}')`;
86
+ OsClient 仍为空再通过域名解析接口或成功请求确认。
87
+ 3. 在新的独立 context 打开
88
+ `http://localhost:61500/?OsClient=<encoded>&ApiBase=<encoded>#/micro-app/{MsKey}/{RoutePath}`。
89
+ 4. 断言本地 `window.__MICROI_RUNTIME_ENDPOINT__` 与线上识别结果一致,再开始功能回归。若不一致,
90
+ 先停止测试,不能把 `config.json` 指向的其它服务器结果当成目标租户证据。
91
+
92
+ 同一个普通浏览器 Profile/Playwright context 不能并行承载不同租户;页面间会共享 Token、
93
+ CurrentUser、ApiBase 和 OsClient。无痕窗口是人工第二租户的最低要求,但多个无痕窗口可能共享临时
94
+ 会话;自动化必须一组运行目标一个 `browser.newContext()`。目标 API 还必须允许 localhost CORS。
95
+
96
+ ### 复盘:历史 OpenIframe 打印入口在 Vue3 弹窗中空白
80
97
 
81
98
  - 触发场景:同一租户的旧正式版打印正常,最新版列表点击打印只打开空白抽屉;数据库中的当前按钮已改成 `PrintEngineView`,但运行态菜单缓存仍可能返回历史 `ComponentName: 'OpenIframe'`。
82
99
  - 根因:Vue3 全局组件表移除了 Vue2 的 `OpenIframe` 注册,动态组件只能渲染成未知标签;同时历史 `DataApi` 可能带有 `https:/host` 这种单斜杠协议地址。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: microi-deployment
3
- description: Microi 安装、部署、升级和本地运行指南。用于 Docker Compose、离线安装、Windows IIS、源码运行、MySQL、Redis、MongoDB、MinIO、反向代理、滚动发布、健康检查、备份恢复和生产部署验收。
3
+ description: Microi 安装、部署、升级和本地运行指南。用于 Docker Compose、离线安装、Windows IIS、源码运行、本地 ApiBase/OsClient 切换与浏览器隔离、MySQL、Redis、MongoDB、MinIO、反向代理、滚动发布、健康检查、备份恢复和生产部署验收。
4
4
  ---
5
5
 
6
6
  > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
@@ -29,6 +29,19 @@ description: Microi 安装、部署、升级和本地运行指南。用于 Docke
29
29
  | Windows 传统环境 | IIS + .NET Hosting Bundle + 独立依赖 |
30
30
  | 开发/调试 | 后端源码 + 前端 Vite,本地依赖或隔离容器 |
31
31
 
32
+ 本地 `Microi.Client` 默认读取 `src/config.json` 的 `ApiBaseDev`,也允许在 `#` 前通过 URL 参数
33
+ 临时指定运行目标:
34
+
35
+ ```text
36
+ http://localhost:61500/?OsClient=iTdos&ApiBase=https%3A%2F%2Fapi.itdos.com
37
+ ```
38
+
39
+ URL 的 `ApiBase`、`OsClient` 优先级最高,但不会隔离同源 localStorage/Pinia/Token。多个 AI
40
+ 对话或自动化并行测试不同目标时,每个 `ApiBase + OsClient` 必须使用独立浏览器上下文/Profile;
41
+ Playwright 使用 `browser.newContext()`。人工第二组至少使用无痕窗口,多个 Chrome 无痕窗口不能
42
+ 视为多组强隔离。完整取值顺序、线上识别和验收见 `../microi-client-frontend/SKILL.md` 与
43
+ `../playwright-e2e/SKILL.md`。
44
+
32
45
  不得在未确认目标主机、目录、数据卷和备份的情况下执行官网“删除所有容器/编排”
33
46
  或任何递归删除命令。
34
47
 
@@ -79,6 +79,13 @@ IIS 进程启动不代表 API 可用,仍要检查 readiness 和真实登录路
79
79
 
80
80
  - 使用仓库规定的 Node/npm/pnpm 版本;
81
81
  - 复用已有 Vite 服务,不重复启动;
82
+ - `src/config.json` 的 `ApiBaseDev` 是默认值;本地 URL 可在 `#` 前用
83
+ `?OsClient=...&ApiBase=...` 以最高优先级覆盖 ApiBase 与租户;
84
+ - 多组 `ApiBase + OsClient` 并行时按组创建独立浏览器 Profile/进程或 Playwright context,不能在
85
+ 同一同源 context 的多个 Page 中混测;
86
+ - 人工第二组至少使用无痕窗口,但多个 Chrome 无痕窗口可能共享临时会话,不能承担多组强隔离;
87
+ - 从线上页面读取 `window.__MICROI_RUNTIME_ENDPOINT__`;旧版无该对象时按 URL、window 全局、
88
+ 同源状态、域名解析/成功请求逐级确认,禁止猜测;
82
89
  - 本地页面成功不替代宿主 Token、OsClient、菜单权限和生产构建验收。
83
90
 
84
91
  ## 最小上线验收
@@ -17,7 +17,7 @@ Markdown。第一列是相对 `microi.doc/docs/doc/` 的路径;第二列 Skill
17
17
  | `form-engine/form-field-info.md` | microi-form-engine, v8-table-event | 表单/字段属性与事件 |
18
18
  | `form-engine/model-engine.md` | v8-template-engine | 表格/表单模板 |
19
19
  | `getting-started/docker-run.md` | microi-deployment | Docker 部署与验收 |
20
- | `getting-started/local-run.md` | microi-deployment | 源码本地运行 |
20
+ | `getting-started/local-run.md` | microi-deployment, microi-client-frontend, playwright-e2e | 源码本地运行、URL 切换 ApiBase/OsClient 与并行浏览器隔离 |
21
21
  | `getting-started/source-code-architecture.md` | workspace-conventions, microi-system-delivery | 多仓源码边界、模块地图和修改路由 |
22
22
  | `getting-started/start-use.md` | microi-system-delivery, module-engine | 快速使用和首个模块 |
23
23
  | `getting-started/win-install-microi.md` | microi-deployment | Windows 部署 |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: microi-microservice
3
- description: Microi 前端微服务 MicroService 开发与交付指南。用于创建、读取、修改、构建、发布或修复 Vue3 微应用,维护 microi.routes.json,绑定 sys_menu,使用 V8.OpenAppDialog,处理菜单页签 keep-alive、appstate-change、状态保留、滚动条、骨架屏或白屏,或通过 MCP 管理 Web、UniApp、MicroService 应用源码和运行时。
3
+ description: Microi 前端微服务 MicroService 开发与交付指南。用于创建、读取、修改、构建、发布或修复 Vue3 微应用,识别线上 ApiBase/OsClient 并用本地 61500 隔离复现,维护 microi.routes.json,绑定 sys_menu,使用 V8.OpenAppDialog,处理菜单页签 keep-alive、appstate-change、状态保留、滚动条、骨架屏或白屏,或通过 MCP 管理 Web、UniApp、MicroService 应用源码和运行时。
4
4
  ---
5
5
 
6
6
  > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
@@ -72,6 +72,18 @@ AppKey 稳定且只含安全字符。`microi.routes.json` 是页面事实源,
72
72
  构建前遵守本地 OOM 保护;已有 dev server 可复用时不重复启动。新脚手架必须支持独立
73
73
  访问时的平台帐号登录,但独立 Vite 预览仍没有菜单/弹窗等完整宿主上下文,不能替代宿主验收。
74
74
 
75
+ ### 线上目标在本地 Microi.Client 复现(强制)
76
+
77
+ - 先在一次性隔离 browser context 打开线上友好路由并读取
78
+ `window.__MICROI_RUNTIME_ENDPOINT__`;旧版回退读取页面全局、同源缓存和域名解析,禁止猜
79
+ ApiBase/OsClient。
80
+ - 在新的独立 context 打开
81
+ `http://localhost:61500/?OsClient=<encoded>&ApiBase=<encoded>#/micro-app/{MsKey}/{RoutePath}`。
82
+ 两个 URL 参数是当前页面最高优先级;初始化后回读同一个运行时对象确认命中目标。
83
+ - 同源普通窗口共享 Token、CurrentUser、ApiBase、OsClient。并行不同目标必须一组目标一个
84
+ Playwright `browser.newContext()` 或独立浏览器 Profile;多个无痕窗口不保证彼此隔离。
85
+ - 本地复现、主框架宿主验收、远端运行产物和生产部署分别报告;本地通过不能替代发布后回读。
86
+
75
87
  迁移 Vue2 定制页到独立 Vite 微服务时,不得假设宿主会提供 Tailwind/UnoCSS 等原子类;
76
88
  页面依赖的宽高、颜色、间距、响应式和打印/下载样式必须由组件自身的语义 class 明确声明,
77
89
  并检查最终 CSS 产物确实包含这些规则。合并多个客户分支的同名组件前逐份比对功能,选择
@@ -30,6 +30,24 @@
30
30
 
31
31
  不要将本地项目的 AppKey 改成另一个已存在应用 Key。
32
32
 
33
+ ## 线上运行目标与本地宿主复现
34
+
35
+ 收到线上微服务 URL 时,先在一次性独立浏览器上下文等待主框架初始化,并读取
36
+ `window.__MICROI_RUNTIME_ENDPOINT__` 中的 `apiBase`、`osClient` 和 `webBase`。旧版主框架没有该
37
+ 对象时,依次检查 URL 参数、`window.ApiBase/window.OsClient`、同源 `microi.net` 持久化状态;
38
+ OsClient 仍为空时调用域名租户解析接口或从已经成功的请求确认,禁止按域名猜测。
39
+
40
+ 确认后用本地 `Microi.Client` 宿主复现,查询参数位于 `#` 之前并具有最高优先级:
41
+
42
+ ```text
43
+ http://localhost:61500/?OsClient=tenant-a&ApiBase=https%3A%2F%2Fapi.example.com#/micro-app/example-app/projects
44
+ ```
45
+
46
+ 同源页面会共享 Pinia/localStorage、Token、CurrentUser、ApiBase 和 OsClient。每组不同的
47
+ `ApiBase + OsClient` 必须使用独立浏览器 Profile/进程或 Playwright `browser.newContext()`;人工
48
+ 第二组至少使用无痕窗口,但多个 Chrome 无痕窗口仍可能共享同一临时会话,不能作为多组并发的
49
+ 强隔离。只切 URL 不等于隔离登录态,也不能绕过 CORS、菜单、角色或数据权限。
50
+
33
51
  `microi.routes.json`:
34
52
 
35
53
  ```json
@@ -176,7 +194,7 @@ sticky/虚拟列表时,子应用以宿主可用高度约束自己的滚动容
176
194
  因不再发生内容溢出而不显示滚动条。不要同时让宿主外层、微服务边界和自动高度根节点都承担滚动。
177
195
 
178
196
  菜单页签还采用单一缓存所有者:主框架 Vue 宿主不进入 `KeepAlive`,由 `<micro-app keep-alive>`
179
- 保存子应用状态。宿主按租户、AppKey、菜单、主框架 `fullPath`、版本和入口生成稳定指纹,最多保留
197
+ 保存子应用状态。宿主按租户、AppKey、主框架 `fullPath`、版本和入口生成稳定指纹,菜单 Id 只进入权限上下文、不参与实例名,避免首屏动态菜单元数据尚未补齐时产生第二个运行时;最多保留
180
198
  5 个运行时;超过上限时只按 LRU 销毁隐藏实例。关闭当前/其它/全部 Tab、访问记录淘汰、退出登录、
181
199
  Token 重置、角色变化、同一路由版本或入口变化时,使用 `destroy:true,clearData:true` 精确销毁。
182
200
  弹窗和表单组件不承诺页签缓存,禁止套用菜单规则。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: playwright-e2e
3
- description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化、全面测试。用于测试 PC Vue、前端微服务菜单切换与 keep-alive/LRU、uni-app H5、网站、界面引擎、移动商城、ApiEngine/FormEngine 契约、登录流程、写入闭环、网络防护、截图、报告和 Playwright Test for VSCode 集成。
3
+ description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化、全面测试。用于测试 PC Vue、本地多 ApiBase/OsClient 独立浏览器上下文、远端运行目标识别、前端微服务菜单切换与 keep-alive/LRU、uni-app H5、网站、界面引擎、移动商城、ApiEngine/FormEngine 契约、登录流程、写入闭环、网络防护、截图、报告和 Playwright Test for VSCode 集成。
4
4
  ---
5
5
 
6
6
  > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
@@ -101,7 +101,7 @@ PW_HOME_PATH=/#/pages/index/index
101
101
  ```
102
102
 
103
103
  <!-- /microi-progressive:chunk -->
104
- <!-- microi-progressive:chunk id=playwright-e2e-005 sha256=e348db509b586871f19b16b6b49da840c93aa438dd891d827af7107744513e00 -->
104
+ <!-- microi-progressive:chunk id=playwright-e2e-005 sha256=a66696c3263f060d0b7be309a527fca6a9bad95dd534eabbe84f1b6539770d8e -->
105
105
  ## 本地测试账号自动发现
106
106
 
107
107
  当没有显式传入 `PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD` / `MICROI_OSCLIENT` 时,AI 不要把账号密码写入后端配置来制造旁路:
@@ -111,7 +111,21 @@ PW_HOME_PATH=/#/pages/index/index
111
111
  3. 这些值只作为自动化进程的登录输入或接口请求参数使用。日志、最终回复、截图说明、报告和异常消息中必须写成 `<redacted>` 或“本地配置凭据”,不要展开真实账号密码、Token、连接串或 Redis 密码。
112
112
  4. 如果凭据不存在或登录失败,再报告具体阻塞点,例如“未提供受保护测试凭据”“本地后端未启动”“登录接口返回 Code=0”,不要泛泛说无法测试。
113
113
 
114
- <!-- /microi-progressive:chunk -->
114
+ ### 跨 ApiBase / OsClient 本地自动化(强制)
115
+
116
+ 1. 复用工作区唯一的 `61500` Vite 服务,但每组 `ApiBase + OsClient` 创建独立
117
+ `browser.newContext()`;禁止在同一个 context 的多个 Page 中混测不同租户。
118
+ 2. 本地入口固定把参数放在 `#` 前:
119
+ `http://localhost:61500/?OsClient=${encodeURIComponent(osClient)}&ApiBase=${encodeURIComponent(apiBase)}#/route`。
120
+ URL 参数应覆盖 `index.html`、`src/config.json`、Pinia 和 localStorage。
121
+ 3. 页面初始化后读取 `window.__MICROI_RUNTIME_ENDPOINT__`,断言实际 ApiBase/OsClient 与测试目标
122
+ 完全一致再登录或点击业务。该对象不得包含 Token。
123
+ 4. 从线上地址复现时,先在一次性独立 context 读取上述对象;旧版回退到页面全局值、
124
+ `localStorage['microi.net']` 和域名租户解析。不能根据标题猜租户,也不能复用线上 context 跑本地。
125
+ 5. 人工第二租户至少使用无痕窗口;多个无痕窗口可能共享同一临时会话,更多并行目标使用独立
126
+ Profile/`--user-data-dir`。自动化收尾只关闭自己创建的 context/browser。
127
+
128
+ <!-- /microi-progressive:chunk -->
115
129
  <!-- microi-progressive:chunk id=playwright-e2e-006 sha256=6aeefebda3a9e598564c53c2f8028a4ccefe2291c4c7c7ae4781ca15fb5d0697 -->
116
130
  ## 后端改动后的 E2E 前置动作
117
131
 
@@ -168,8 +182,12 @@ uni-app H5 或移动端前端按项目自身命令启动,例如 `npm run dev:h
168
182
  执行顺序:先检查端口/健康接口是否可达;不可达则用后台终端启动;等待服务输出监听地址;再重试接口同步、页面打开、Playwright 截图和断言。只有启动命令失败、缺少依赖、数据库连接失败、端口冲突无法自动换端口且无替代配置时,才算真正阻塞,并且要报告具体失败命令和错误。
169
183
 
170
184
  <!-- /microi-progressive:chunk -->
171
- ## 详细参考路由(渐进披露)
172
-
185
+ ## 详细参考路由(渐进披露)
186
+
187
+ ### 菜单微服务生命周期验收(强制)
188
+
189
+ 菜单型 MicroService 使用 `runtime-keep-alive` 单一缓存所有者。E2E 必须覆盖至少 3 条子路由连续切换 8 轮,确认返回后状态仍在、页面无永久骨架屏或空白;继续打开第 6 个实例,确认 LRU 只淘汰最久未使用的隐藏实例。还要观察 `appstate-change`:`afterhidden` 后后台任务应暂停,`aftershow` 后应幂等恢复;关闭 Tab、关闭其它/全部以及退出登录后,对应运行时必须被销毁。
190
+
173
191
  仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
174
192
 
175
193
  - [references/progressive-01-全自动登录-免验证码-但不免密码-必读.md](references/progressive-01-全自动登录-免验证码-但不免密码-必读.md):全自动登录(免验证码,但不免密码)——必读;表单引擎卡死/递归更新全自动化诊断;移动端视觉与资源验收;测试证据必须绑定需求编号;移动端/H5 回归纪律
@@ -28,8 +28,8 @@ jobs:
28
28
  ```
29
29
 
30
30
  <!-- /microi-progressive:chunk -->
31
- <!-- microi-progressive:chunk id=playwright-e2e-024 sha256=01abd9079de1ec60a1de8a441b93e32beccd0666f7fedf359ccbec2e0d40f8e9 -->
32
- ## 常见问题
31
+ <!-- microi-progressive:chunk id=playwright-e2e-024 sha256=b939c97eef28fab71caa54d134ea524d7ed7c8381deec09e38a7d694b15f53c0 -->
32
+ ## 常见问题
33
33
 
34
34
  | 现象 | 原因 | 处理 |
35
35
  |---|---|---|
@@ -45,7 +45,51 @@ jobs:
45
45
  | 用例偶发失败 | HMR 或网络请求未稳定 | CI 使用静态构建,断言明确等待关键元素 |
46
46
  | 页面有横向滚动 | 组件撑出视口 | 对根容器和列表容器加 `max-width:100vw; overflow-x:hidden` |
47
47
 
48
- <!-- /microi-progressive:chunk -->
48
+ ### 多服务器、多租户并行上下文模板
49
+
50
+ `incognito` 的本质是独立存储上下文。Playwright 的 `browser.newContext()` 每次都会创建隔离上下文,
51
+ 比在同一个浏览器 context 中开多个 Page 更可靠:
52
+
53
+ ```js
54
+ function buildLocalMicroiUrl({ apiBase, osClient, route = '/' }) {
55
+ return `http://localhost:61500/?OsClient=${encodeURIComponent(osClient)}`
56
+ + `&ApiBase=${encodeURIComponent(apiBase)}#${route}`;
57
+ }
58
+
59
+ const targetA = await browser.newContext();
60
+ const pageA = await targetA.newPage();
61
+ await pageA.goto(buildLocalMicroiUrl({ apiBase: apiA, osClient: tenantA, route: '/home' }));
62
+ await pageA.waitForFunction(() => Boolean(window.__MICROI_RUNTIME_ENDPOINT__));
63
+ await expect.poll(() => pageA.evaluate(() => window.__MICROI_RUNTIME_ENDPOINT__)).toMatchObject({
64
+ apiBase: apiA,
65
+ osClient: tenantA,
66
+ requiresIsolatedContextForParallelTenants: true
67
+ });
68
+
69
+ const targetB = await browser.newContext();
70
+ // targetB 重复同样流程;禁止复用 targetA.newPage() 测 tenantB。
71
+ ```
72
+
73
+ 若给定的是线上吾码页面,先在第三个一次性 context 中读取
74
+ `window.__MICROI_RUNTIME_ENDPOINT__`。旧版回退脚本只读取公开运行目标,不读取或输出 Token:
75
+
76
+ ```js
77
+ const endpoint = await page.evaluate(() => {
78
+ const current = window.__MICROI_RUNTIME_ENDPOINT__;
79
+ if (current?.apiBase && current?.osClient) return current;
80
+ const stored = JSON.parse(localStorage.getItem('microi.net') || '{}');
81
+ return {
82
+ apiBase: window.ApiBase || stored.ApiBase || location.origin,
83
+ osClient: new URLSearchParams(location.search).get('OsClient') || window.OsClient || stored.OsClient || ''
84
+ };
85
+ });
86
+ ```
87
+
88
+ OsClient 仍为空时调用目标站点域名租户解析接口或从成功请求确认。手工 Chrome 的第二个不同租户
89
+ 至少使用无痕窗口,但同一 Chrome 无痕会话的多个窗口可能继续共享存储;三个以上目标使用独立
90
+ Profile 或独立 `--user-data-dir`。
91
+
92
+ <!-- /microi-progressive:chunk -->
49
93
  <!-- microi-progressive:chunk id=playwright-e2e-025 sha256=be071153d695081b7c20d34cb5e9563480e3f09d9cd0292f2ca4b0245438787b -->
50
94
  ## 前端微服务 E2E 必测点
51
95
 
@@ -96,6 +96,7 @@ did: {DeviceId}
96
96
  - 页面必须 poster-first:未启动时不下载大体积 WASM/Data;提供加载、错误、重试、全屏、退出和低性能提示。
97
97
  - 多人界面要显示本地及远端昵称;同模型远端角色使用快照插值,失效租约及时销毁;公屏固定在不遮挡核心操作区的位置并支持键盘与表情选择。
98
98
  - 构建门禁必须拒绝缺失 Unity 产物的“空壳发布”,并校验 WASM、Data、体积、哈希、本机地址、source map 与疑似硬编码 Token。
99
+ - Unity `Data`、WASM 或 Windows 安装包大于 128 MiB 时,MCP/CLI 必须使用协议 v3 原始字节断点续传;禁止拆分文件、转 Base64 或通过提高普通表单上限发布。失败后读取同一不可变会话只续传缺片,并在“系统引擎 → 超大文件上传记录”回读进度、心跳、错误与恢复建议。
99
100
  - 先同步私有源码,再发布不可变 Web 产物,最后生成/发布商城包;三个动作分别回读。
100
101
 
101
102
  ### 6. 补齐官网与 Skill
@@ -136,6 +137,7 @@ did: {DeviceId}
136
137
  | 多人在线 | 至少两个独立会话互见唯一昵称、移动与动作;异常断线超过租约后双方快照均不再返回该角色 |
137
138
  | 实时公屏 | 两个独立会话互相收发文字与表情;非法表情、超长、超频和请求重放均被正确处理 |
138
139
  | 多节点 | 重复投递、节点切换、失败恢复时副作用仅一次 |
140
+ | 大型资产 | 断点后只补缺片、HDFS 整文件哈希一致、后台审计进度与终态可见 |
139
141
  | AI 应用 | 私有源码回读、运行版本哈希、列表/详情公开可见 |
140
142
  | 应用商城 | 包版本/策略回读,非官方租户安装与升级通过 |
141
143
 
@@ -50,6 +50,8 @@ tests/
50
50
  - Windows 默认交付 x64 安装包,至少包含当前用户安装、开始菜单入口和卸载信息;没有明确需求时不申请管理员权限。
51
51
  - 外壳应给出醒目的本地版下载入口,并同时显示版本、文件大小与 SHA-256;文件名包含语义版本,旧版本 URL 不覆盖。
52
52
  - 安装包属于公开运行资产,不属于私有源码。同步 `directory` 前必须排除 `public/downloads` 等生成目录,再把完整安装包随 `dist` 走流式资产发布;禁止拆分 Base64 或伪装成源码规避单文件上限。
53
+ - 单文件大于 128 MiB 时,MCP 与 `@microi.net/cli` 共用协议 v3:默认 16 MiB 原始字节分片、逐片 HDFS 回读、整文件 SHA-256 和确定性会话。重启后必须先查状态并只补缺片;5 GiB 文件应规划为 320 片,不得重新从 0 开始。
54
+ - v3 不设置 Microi 产品级文件/目录字节上限;对象存储、磁盘、代理与协议技术边界仍需容量预检。发布期间在“系统引擎 → 超大文件上传记录”回读字节进度、心跳、失败原因和恢复建议,终态记录保留用于审计。
53
55
  - 发布后从公网地址重新下载完整 EXE,比较字节数和 SHA-256;本地制包成功、MCP 返回文件 Id 或 HTTP HEAD 成功都不能替代完整回读。
54
56
  - 本地验收至少覆盖静默安装、主程序存在、可启动和卸载入口;签名状态、SmartScreen 信誉和硬件帧率必须单独如实说明。
55
57
 
@@ -38,7 +38,7 @@ description: Microi V8 与 MCP 文件上传下载指南。用于处理流式 AI
38
38
  可信后端 V8 可用 `V8.Http.GetResponse({ Url: url }).RawBytes` 下载,再用 `System.Convert.ToBase64String` 和 `V8.Method.Upload` 上传。该路径同样必须校验域名、大小、Content-Type、后缀和最终重定向目标。
39
39
 
40
40
  <!-- /microi-progressive:chunk -->
41
- <!-- microi-progressive:chunk id=v8-file-upload-002 sha256=ab3fa9eda3090868f45651aaddfa6b5ecd390535123f4666c9b67fba6a6e34f7 -->
41
+ <!-- microi-progressive:chunk id=v8-file-upload-002 sha256=01111b2fe994a2a5e424f45d405821f0b4f5c29235bc93757352d4c7e10d8d84 -->
42
42
  ## 接收前端上传的文件
43
43
 
44
44
  前端发起文件上传时,平台自动把文件以 base64 形式注入到 `V8.FilesByteBase64`:
@@ -69,9 +69,20 @@ var filePath = upResult.Data[0].Path; // 相对路径,存数据库
69
69
  var fullUrl = upResult.Data[0].FullPath; // 完整 URL(公有桶)
70
70
  ```
71
71
 
72
- ### 平台上传分层限制
72
+ ### AI 应用超大资产断点续传
73
73
 
74
- Token 不是无限上传授权。所有 HTTP、表单、V8 和移动端上传入口必须在解码 Base64、解析图片或调用对象存储前执行服务端校验。上传限制分为四层,不能把租户业务值误称为平台硬上限:
74
+ Unity `Data`、WASM、Windows 安装包、视频模型等发布资产不得进入 Base64、JSON 或 Jint。`microi_publish_application_directory_stream` 在协议 v3 下与 `@microi.net/cli` 共用同一套传输客户端:单文件大于 128 MiB 时自动切换为原始字节断点续传,小文件继续兼容旧版单请求链路。
75
+
76
+ - 默认分片 16 MiB;5 GiB 文件为 320 片。分片通过 `application/octet-stream` 发送,必须携带精确 `Content-Length` 与 SHA-256。
77
+ - 服务端逐片写入 HDFS 后重新流式回读校验;完成时按顺序合并、再次核对整文件 SHA-256,再生成不可变版本完整性标记。
78
+ - 会话 Id 由租户、应用、版本、路径和文件摘要确定。网络中断或进程重启后先读取远端状态,只续传缺失分片;已成功的相同摘要请求直接幂等返回。
79
+ - 吾码不为协议 v3 设置业务文件/目录字节上限,状态中的 `ApplicationAssetResumableProductSizeLimitBytes=0` 表示没有产品配置上限。每个对象仍受协议技术边界(最多 10000 片、单片最多 1 GiB)、JavaScript 安全整数、对象存储、磁盘、网关和网络条件约束。
80
+ - 该链路只允许通过能力鉴权的当前租户超级管理员,并继续受 `FileUploadEnabled` 总开关控制;它不是普通用户上传或任意 HDFS 路径写入接口。
81
+ - 每个会话都在 `mci_ai_app_file` 保留审计记录,`StorageScope=ApplicationAssetMultipartSession`。管理员在 **系统引擎 → 超大文件上传记录** 查看状态、阶段、已传字节/分片、进度、心跳、错误和恢复建议;成功、失败和取消记录都不静默删除。
82
+
83
+ ### 普通业务上传的分层限制
84
+
85
+ 以下限制适用于 HTTP、表单、V8、移动端和旧版应用资产单请求,不适用于上面的受信任 v3 断点续传。Token 不是无限上传授权;普通入口必须在解码 Base64、解析图片或调用对象存储前执行服务端校验:
75
86
 
76
87
  1. **租户业务配置**:有效正数/布尔值按 `sys_osclients` 当前租户 → 代码默认值解析。租户可以按业务需要提高或降低默认值,不要求安装者维护额外环境变量或修改 `appsettings`。
77
88
  2. **平台绝对上限**:最终业务值再与代码内固定灾难保护上限取较小值,租户和安装参数都不能放大。
@@ -91,7 +102,7 @@ Token 不是无限上传授权。所有 HTTP、表单、V8 和移动端上传入
91
102
 
92
103
  - `sys_osclients` 六个字段全部可空;空值、无效值或老数据库缺列时使用代码默认值,不会因升级自动停用上传。`FileUploadMaxRequestMB` 指一次上传所有文件的业务合计大小,不等于 Kestrel HTTP 请求正文上限。
93
104
  - 固定灾难保护和 HTTP/Multipart/Form 解析上限不属于安装配置;租户值即使更大也会被这些边界截断。最终单次总量还不能超过帐号或租户的有效日额度,单文件不能超过最终单次总量。
94
- - `FileUploadEnabled=0` 表示禁用当前租户的交互式上传,不表示绕过限制。平台内部受控任务仍受全局大小硬上限;租户配置刷新应走现有 SaaS 引擎重载和共享 Redis 发布订阅,不能依赖单节点内存。
105
+ - `FileUploadEnabled=0` 表示禁用当前租户上传,也会阻止 AI 应用资产断点续传;不能把内部发布协议当成绕过开关的后门。普通单请求继续受全局大小硬上限,v3 只移除产品级字节上限;租户配置刷新应走现有 SaaS 引擎重载和共享 Redis 发布订阅,不能依赖单节点内存。
95
106
  - 帐号与租户每日额度在共享 Redis 中用单次原子脚本预留,支持多节点;Redis 不可用时失败关闭,不能降级成无限上传。
96
107
  - 额度按 UTC 日期统计。为防并发重试绕过限制,后续对象存储失败也不退还已经预留的额度。
97
108
  - 每日额度只阻断短期滥用;对象存储必须另外配置租户/桶总容量、账单告警、生命周期与实际用量对账。Redis 计数不能作为长期容量事实源。
@@ -116,7 +127,7 @@ Token 不是无限上传授权。所有 HTTP、表单、V8 和移动端上传入
116
127
  4. 保存后逐条远程回读;FormEngine 会排队重载 SaaS 运行配置,再用真实小文件上传做生效冒烟。只看到 MCP 返回“更新成功”不算验收。
117
128
  5. 提高每日配额保留当天已用计数,剩余额度为新上限减已用量。计数按 UTC 日期,失败上传不退款;除非用户明确授权事故处置,不得删除 Redis 配额 Key。
118
129
 
119
- 租户 MCP 只能调整业务层配置;平台固定灾难保护、HTTP/Multipart/Form 解析上限和反向代理上限不能通过 `sys_osclients` 绕过。写入 `sys_osclients` 属于控制面操作,只允许当前租户的 `Level >= 9999` 管理身份,并且必须保留 MCP 审计与写后回读。
130
+ 租户 MCP 只能调整普通业务上传配置;平台固定灾难保护、HTTP/Multipart/Form 解析上限和反向代理上限不能通过 `sys_osclients` 绕过。协议 v3 的原始分片不读取普通单请求大小字段,但仍要求能力鉴权、总开关、版本快照、逐片/整文件哈希和审计。写入 `sys_osclients` 属于控制面操作,只允许当前租户的 `Level >= 9999` 管理身份,并且必须保留 MCP 审计与写后回读。
120
131
 
121
132
  ### UniApp / H5 客户端直传路径规则
122
133
 
@@ -161,7 +161,7 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
161
161
  - 文档改动后执行 `npm run docs:build`;验收时检查本次没有无理由新增 `.md` 页面或导航路由。
162
162
 
163
163
  <!-- /microi-progressive:chunk -->
164
- <!-- microi-progressive:chunk id=workspace-conventions-009 sha256=3e9f3fbe30417e8b309ebc5b52544d70390db36b30cebe3e96f1fa5928a9b99a -->
164
+ <!-- microi-progressive:chunk id=workspace-conventions-009 sha256=dc7dbe2d2f60466a7170fff65a5df8769bc795b4ab23151a24b665380d7c6e37 -->
165
165
  ## 多对话共享工作区变更归属保护(强制)
166
166
 
167
167
  同一工作区可能同时被用户、其它 Codex 对话、IDE、自动化任务或外部 Git 操作修改。任务启动前已经存在、或无法用本对话证据严格证明归属的差异,一律视为他人资产并保留;“工作区是脏的”不是清理授权。
@@ -174,7 +174,22 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
174
174
  - 修复误撤回时,只恢复被本对话删除的原始字节/行,随后断言目标 hunk 已恢复、其它既有差异保持不变,并在最终说明中明确列出仍存在但未触碰的并行改动。
175
175
  - 对 `microi.doc/docs/doc/about/update-log.md` 尤其严格:已经发布的条目即使日期是当天、位于最新提交或内容覆盖当前任务,也必须默认属于既有发布成果。除非用户明确要求修改,或本对话持有精确新增证据,否则不得删除、重写或降级该条目。
176
176
 
177
- <!-- /microi-progressive:chunk -->
177
+ ## 本地多租户浏览器隔离(强制)
178
+
179
+ - 本地 `Microi.Client` 使用 `src/config.json.ApiBaseDev` 作为默认 API;URL 中位于 `#` 之前的
180
+ `ApiBase` 与 `OsClient` 是当前页面最高优先级,标准形式为
181
+ `http://localhost:61500/?OsClient=<tenant>&ApiBase=<encodeURIComponent(apiBase)>#/route`。
182
+ - 同一个浏览器 Profile/Context 下的 localhost 页面共享 localStorage、Pinia、Token、CurrentUser、
183
+ ApiBase 和 OsClient。并行测试不同目标时,一组 `ApiBase + OsClient` 必须对应一个独立浏览器
184
+ Context/Profile;Playwright/Codex 使用 `browser.newContext()`,不得只在同一 context 中新开 Page。
185
+ - 人工测试的第二个不同租户至少使用无痕窗口;多个无痕窗口可能共享同一临时会话,三个以上并行
186
+ 目标必须使用独立 Profile、独立 `--user-data-dir` 或自动化独立 context。
187
+ - AI 收到线上吾码地址时,先在一次性独立 context 读取
188
+ `window.__MICROI_RUNTIME_ENDPOINT__`;旧版再回退到页面全局值、同源缓存和域名解析。确认实际
189
+ ApiBase/OsClient 后,才在新的独立 context 打开本地 URL。详细流程读取 `microi-client-frontend`、
190
+ `playwright-e2e` 与 `microi-deployment`。
191
+
192
+ <!-- /microi-progressive:chunk -->
178
193
  ## 详细参考路由(渐进披露)
179
194
 
180
195
  仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。