@microi.net/cli 5.0.0 → 5.0.2
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.
- package/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/assets/build-meta.json +4 -4
- package/package.json +1 -1
- package/scripts/mcp-server.js +85 -85
- package/scripts/microi-codex-router.js +9 -1
- package/scripts/microi-skills.meta.json +190 -190
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +33 -33
- package/skills/microi-client-frontend/SKILL.md +23 -4
- 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 +29 -6
- package/skills/microi-deployment/SKILL.md +14 -1
- package/skills/microi-deployment/references/deployment-matrix.md +7 -0
- package/skills/microi-docs-coverage/references/capability-map.md +1 -1
- package/skills/microi-microservice/SKILL.md +33 -2
- package/skills/microi-microservice/references/runtime-delivery.md +44 -1
- package/skills/playwright-e2e/SKILL.md +23 -5
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +51 -5
- package/skills/unity-integration/SKILL.md +2 -0
- package/skills/unity-integration/references/ai-app-delivery.md +2 -0
- package/skills/v8-file-upload/SKILL.md +16 -5
- package/skills/workspace-conventions/SKILL.md +17 -2
- 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-
|
|
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": "
|
|
173
|
-
"originalLines":
|
|
174
|
-
"prefixSha256": "
|
|
175
|
-
"prefixBytes":
|
|
176
|
-
"entryLines":
|
|
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": "
|
|
215
|
-
"lines":
|
|
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": "
|
|
271
|
-
"lines":
|
|
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": "
|
|
1348
|
-
"originalLines":
|
|
1349
|
-
"prefixSha256": "
|
|
1350
|
-
"prefixBytes":
|
|
1351
|
-
"entryLines":
|
|
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": "
|
|
1398
|
-
"lines":
|
|
1397
|
+
"sha256": "a66696c3263f060d0b7be309a527fca6a9bad95dd534eabbe84f1b6539770d8e",
|
|
1398
|
+
"lines": 24,
|
|
1399
1399
|
"heading": "本地测试账号自动发现"
|
|
1400
1400
|
},
|
|
1401
1401
|
{
|
|
@@ -1546,16 +1546,16 @@
|
|
|
1546
1546
|
"id": "playwright-e2e-024",
|
|
1547
1547
|
"ordinal": 24,
|
|
1548
1548
|
"destination": "playwright-e2e/references/progressive-04-ci-建议.md",
|
|
1549
|
-
"sha256": "
|
|
1550
|
-
"lines":
|
|
1549
|
+
"sha256": "b939c97eef28fab71caa54d134ea524d7ed7c8381deec09e38a7d694b15f53c0",
|
|
1550
|
+
"lines": 61,
|
|
1551
1551
|
"heading": "常见问题"
|
|
1552
1552
|
},
|
|
1553
1553
|
{
|
|
1554
1554
|
"id": "playwright-e2e-025",
|
|
1555
1555
|
"ordinal": 25,
|
|
1556
1556
|
"destination": "playwright-e2e/references/progressive-04-ci-建议.md",
|
|
1557
|
-
"sha256": "
|
|
1558
|
-
"lines":
|
|
1557
|
+
"sha256": "be071153d695081b7c20d34cb5e9563480e3f09d9cd0292f2ca4b0245438787b",
|
|
1558
|
+
"lines": 11,
|
|
1559
1559
|
"heading": "前端微服务 E2E 必测点"
|
|
1560
1560
|
},
|
|
1561
1561
|
{
|
|
@@ -2221,11 +2221,11 @@
|
|
|
2221
2221
|
]
|
|
2222
2222
|
},
|
|
2223
2223
|
"v8-file-upload": {
|
|
2224
|
-
"originalSha256": "
|
|
2225
|
-
"originalLines":
|
|
2224
|
+
"originalSha256": "a812df73c7f9e29bdfeeaa7f740a4b7b7490a6431e642d56ada31b2b9206923a",
|
|
2225
|
+
"originalLines": 529,
|
|
2226
2226
|
"prefixSha256": "2cb0db96cd348d7a50f36b6e4f43435188e374ace1962eb639a501b9c7490c7e",
|
|
2227
2227
|
"prefixBytes": 1074,
|
|
2228
|
-
"entryLines":
|
|
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": "
|
|
2251
|
-
"lines":
|
|
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": "
|
|
3200
|
-
"originalLines":
|
|
3199
|
+
"originalSha256": "58812f002d909c3fda3dc6f3b3ba04926da23c09b09fcd15c18f1e8fc401f9a6",
|
|
3200
|
+
"originalLines": 551,
|
|
3201
3201
|
"prefixSha256": "b58cd0a59d3643525695b94a5941278a5088c33cbe2ce81620359f37db69878e",
|
|
3202
3202
|
"prefixBytes": 252,
|
|
3203
|
-
"entryLines":
|
|
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": "
|
|
3282
|
-
"lines":
|
|
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": "
|
|
3410
|
-
"lines":
|
|
3409
|
+
"sha256": "07c3d729c8f1e9a2bf93ff00937e5d6eae4602d346e4f9254b03a33211ac4848",
|
|
3410
|
+
"lines": 31,
|
|
3411
3411
|
"heading": "多 AI 对话共享本地服务与发布互斥(强制)"
|
|
3412
3412
|
},
|
|
3413
3413
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: microi-client-frontend
|
|
3
|
-
description: Microi.Client 源码架构指南。用于修改 Microi.Client Vue
|
|
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=
|
|
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,13 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
> 按需读取;本文件由 SKILL.md 的原章节无损拆分。
|
|
4
4
|
|
|
5
|
-
<!-- microi-progressive:chunk id=microi-client-frontend-011 sha256=
|
|
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}`,否则地址过长且刷新或直接访问菜单路由容易加载空白页。
|
|
9
9
|
|
|
10
10
|
同一个编译后的微服务可以绑定多个后台菜单和内部页面。`MicroAppHost` 的 `<micro-app name>` 必须包含菜单 Id、路由路径或其它实例维度,避免多个菜单共享同一个 appKey 时触发 `app name conflict`。入口 URL 中的 `microRoute/routePath` 只用于解析,最终应通过 `data.microRoute` 传给子应用,入口文件 URL 保持稳定。
|
|
11
11
|
|
|
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
|
+
|
|
14
|
+
运行时缓存集中维护在 `utils/microAppRuntimeCache.js`:实例名必须由租户、AppKey、fullPath、版本和入口的安全指纹稳定生成,长度受限且不暴露 Token/查询原文。菜单 Id 可能在友好路由首屏之后才随动态菜单元数据补齐,只能进入权限上下文,禁止参与实例身份;否则首次返回同一路由会被误判为新实例。全局最多保留 5 个实例,只淘汰最久未使用的 hidden 实例。TagsView 的关闭当前/其它/全部和访问记录淘汰必须按 fullPath 精确销毁;退出登录、Token 重置、角色切换必须清空全部;同一路由版本/入口变化必须替换旧实例。销毁统一调用 `unmountApp(name,{destroy:true,clearData:true})`,不能只从本地 Map 删除。
|
|
15
|
+
|
|
16
|
+
宿主监听 `beforeshow/aftershow/afterhidden`:恢复时用 `forceSetData` 下发最新 Token、OsClient、权限、主题、路由和视口,并重新执行可见 DOM 健康检查;隐藏时停止宿主看门狗并把实例放入 LRU。`microAppData.cache` 与 `hostCapabilities.lifecycle` 要公开缓存模式、所有者、上限和 `appstate-change` 状态,错误诊断同时显示 cacheMode/cacheState/cacheInstance。可见 DOM 不健康时只自动销毁重建一次,禁止恢复阶段无限重试。
|
|
17
|
+
|
|
12
18
|
菜单型微服务的宿主操作集中维护在 `views/micro-app/host-bridge.js` 和 `host.vue`。
|
|
13
19
|
`microAppData.hostCapabilities` 必须下发 `microi.host.v1` 协议、`tab` 模式、请求/结果事件名和动作清单;
|
|
14
20
|
子应用只允许 dispatch `micro-app:host-action`,不能接收父页面函数或直接操作 TagsView/Router。
|
|
@@ -64,13 +70,30 @@ VS Code 插件执行前端微服务构建前必须先安全清理当前项目自
|
|
|
64
70
|
- `routes` 是页面源码、`microi.routes.json`、发布路由和菜单绑定的共同事实源;一条路由只生成一个页面文件,必须明确 `path/name/title/sourceFile/isHome`。不能为了提供默认首页额外生成一个未被需求或菜单使用的第三页面。
|
|
65
71
|
- 脚手架完成后依次执行:`npm install`、本地构建、`microi_create_microservice`、`microi_sync_microservice_source`、`microi_publish_application_directory_stream`。真实编译目录优先流式发布;只有当前服务器尚未部署流式端点且产物很小时,才允许临时使用兼容的 `microi_publish_microservice`,并在交付结论中如实注明。
|
|
66
72
|
- 发布回读取得 `sys_microiservice.Id` 与每条 `sys_microiservice_page.Id` 后,使用 `microi_create_module` 一次传入 `openType=MicroService`、`microServiceId`、`microServicePageId`、`microServiceRoutePath`、`microServiceKey`。菜单工具必须写后回读这些字段;不得长期依赖“先建普通 URL 菜单,再手工补字段”的两步绕路。
|
|
67
|
-
- 最终通过 `microi_get_application_context`、`microi_get_microservice`、`microi_get_module`
|
|
73
|
+
- 最终通过 `microi_get_application_context`、`microi_get_microservice`、`microi_get_module` 和真实登录后的友好菜单路由逐层验收;多个菜单至少往返切换 8 轮,检查标题与子路由不串页、缓存范围内输入/筛选/滚动保持、无 404/5xx/白屏/永久骨架屏/实例冲突。再打开第 6 个实例验证 LRU 冷启动,并关闭 Tab/退出登录验证精确销毁;保存 fullPage 截图后用 `view_image` 复核。
|
|
68
74
|
|
|
69
|
-
### 表单下拉 Data 动态对象选项
|
|
75
|
+
### 表单下拉 Data 动态对象选项
|
|
70
76
|
|
|
71
|
-
表单 V8 通过 `V8.FieldSet('字段名', 'Data', objectRows)` 动态写入下拉数据时,如果 `objectRows` 是对象数组,即使 `diy_field.Config.DataSource='Data'`,前端也必须按对象数据源处理,并使用 `SelectLabel/SelectSaveField` 或常见字段兜底生成 label/value。禁止把对象数组按普通字符串 Data 源过滤,否则会出现接口已有数据但下拉显示“无数据”的回归。
|
|
72
|
-
|
|
73
|
-
###
|
|
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 弹窗中空白
|
|
74
97
|
|
|
75
98
|
- 触发场景:同一租户的旧正式版打印正常,最新版列表点击打印只打开空白抽屉;数据库中的当前按钮已改成 `PrintEngineView`,但运行态菜单缓存仍可能返回历史 `ComponentName: 'OpenIframe'`。
|
|
76
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
|
|
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
|
|
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 产物确实包含这些规则。合并多个客户分支的同名组件前逐份比对功能,选择
|
|
@@ -159,6 +171,24 @@ AI 生成菜单微服务时,应优先封装一个 `callMicroiHost(action, data
|
|
|
159
171
|
放在右侧内容容器内,使微服务导航栏和顶部栏保持挂载;浏览器 `popstate/hashchange` 要能恢复
|
|
160
172
|
内部路由。只有确实要离开当前微服务、打开另一个吾码后台菜单或替换顶部 Tab 时才调用宿主路由动作。
|
|
161
173
|
|
|
174
|
+
### 菜单页签缓存与子应用生命周期(强制)
|
|
175
|
+
|
|
176
|
+
- 菜单微服务只有一个缓存所有者:Vue 路由宿主固定 `meta.keepAlive=false`,`<micro-app keep-alive>` 独占子应用状态。禁止把外层 Vue `KeepAlive` 打开,也禁止子应用通过随机实例名规避运行时缓存;双层缓存会产生旧宿主与当前路由竞争、无数据、永久骨架屏和白屏。
|
|
177
|
+
- 每个主框架 `fullPath` 使用稳定且不泄露查询参数/Token 的实例指纹。平台最多保留 5 个菜单运行时,超过后按 LRU 销毁最久未使用的隐藏实例;Tab 仍保留,再次进入允许冷启动。关闭当前/其它/全部 Tab、访问记录淘汰、退出登录、Token 重置、角色变化、同路由版本或入口变化时必须精确 `unmountApp(name,{destroy:true,clearData:true})`。
|
|
178
|
+
- 恢复隐藏实例时,宿主用 `forceSetData` 同步当前 Token、OsClient、权限、主题、路由和视口,再复核 `micro-app-body/#app` 的真实可见 DOM;失败只允许自动销毁重建一次。`hostCapabilities.lifecycle` 暴露 `cacheOwner=micro-app`、`cacheMode=runtime-keep-alive`、`maxCachedTabs=5` 和状态事件。
|
|
179
|
+
- AI 创建或修改菜单微服务时必须生成 `appstate-change` 适配:`afterhidden` 幂等暂停轮询、WebSocket、观察器和昂贵任务;`aftershow` 重新读取宿主数据、幂等恢复任务并在下一帧重算图表/虚拟列表。隐藏时保留表单输入、筛选、滚动与内部路由,禁止清空业务状态;弹窗和表单嵌入不套用菜单页签保活。
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
window.addEventListener('appstate-change', (event) => {
|
|
183
|
+
if (event.detail?.appState === 'afterhidden') pauseBackgroundWork();
|
|
184
|
+
if (event.detail?.appState === 'aftershow') {
|
|
185
|
+
configureMicroiV8(getMicroiContext());
|
|
186
|
+
resumeBackgroundWorkOnce();
|
|
187
|
+
requestAnimationFrame(resizeChartsAndVirtualLists);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
162
192
|
微服务所有主题变量、reset、通用元素规则必须限定在 AppKey 唯一根容器(推荐
|
|
163
193
|
`[data-mci-ui-root="{AppKey}"]`)下,不能只用宿主也会命中的裸 `[data-mci-ui-root]`;禁止用
|
|
164
194
|
`:root/html/body/#app`、裸 `*`、裸 `button/input` 污染宿主。
|
|
@@ -202,7 +232,8 @@ AI 生成菜单微服务时,应优先封装一个 `callMicroiHost(action, data
|
|
|
202
232
|
|
|
203
233
|
- 源码、构建文件、运行时、页面路由和菜单五层分别回读。
|
|
204
234
|
- 组合发布成功前,私有源码回读必须与本地源码在路径集合、文件数、字节数、逐文件 SHA-256 和规范化清单哈希上完全一致;任何缺失、多余或读取错误都要阻止运行版本切换。
|
|
205
|
-
-
|
|
235
|
+
- 直接刷新友好路由与多个菜单至少往返 8 轮不 404、白屏、永久骨架屏、串页或实例名冲突;缓存范围内输入/筛选/滚动/内部路由保持。
|
|
236
|
+
- 打开第 6 个菜单实例后确认 LRU 只淘汰最旧隐藏实例且重入可冷启动;关闭 Tab、关闭其它/全部与退出登录后确认对应运行时已销毁。
|
|
206
237
|
- Dialog/Drawer 成功、取消、错误和关闭协议正确。
|
|
207
238
|
- 表单 `DevComponentPath` 能匹配页面 `LegacyComponentPaths`,指定路由正常加载;Add/Edit/View/只读、字段值回写和自动高度均通过。
|
|
208
239
|
- 独立地址覆盖“已有 Token 自动进入”和“无 Token 显示帐号密码”;`EnableCaptcha` 开/关各验一次,验证码响应头和登录参数正确。
|
|
@@ -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
|
|
@@ -157,7 +175,7 @@ const host = window.microApp?.getData?.() || {};
|
|
|
157
175
|
|
|
158
176
|
常见字段:`apiBase`、`osClient`、`token`、`menuId`、`moduleEngineKey`、`diyTableId`、
|
|
159
177
|
`permissionContext`、`appKey`、`version`、`microRoute`、`dialog`、`dialogData`、
|
|
160
|
-
`componentMode`、`componentData`。只在内存中使用 Token。
|
|
178
|
+
`componentMode`、`componentData`、`cache`、`hostCapabilities.lifecycle`。只在内存中使用 Token。
|
|
161
179
|
|
|
162
180
|
独立访问时没有宿主 Token:先配置清单中的 `apiBase/osClient`,读取 `V8.GetSysConfig(true)`,
|
|
163
181
|
没有有效本地 Token 才显示吾码帐号密码登录;按 `EnableCaptcha` 动态请求验证码并向 `V8.Login`
|
|
@@ -175,6 +193,31 @@ const host = window.microApp?.getData?.() || {};
|
|
|
175
193
|
sticky/虚拟列表时,子应用以宿主可用高度约束自己的滚动容器并设置 `overflow-y:auto`,框架边界
|
|
176
194
|
因不再发生内容溢出而不显示滚动条。不要同时让宿主外层、微服务边界和自动高度根节点都承担滚动。
|
|
177
195
|
|
|
196
|
+
菜单页签还采用单一缓存所有者:主框架 Vue 宿主不进入 `KeepAlive`,由 `<micro-app keep-alive>`
|
|
197
|
+
保存子应用状态。宿主按租户、AppKey、主框架 `fullPath`、版本和入口生成稳定指纹,菜单 Id 只进入权限上下文、不参与实例名,避免首屏动态菜单元数据尚未补齐时产生第二个运行时;最多保留
|
|
198
|
+
5 个运行时;超过上限时只按 LRU 销毁隐藏实例。关闭当前/其它/全部 Tab、访问记录淘汰、退出登录、
|
|
199
|
+
Token 重置、角色变化、同一路由版本或入口变化时,使用 `destroy:true,clearData:true` 精确销毁。
|
|
200
|
+
弹窗和表单组件不承诺页签缓存,禁止套用菜单规则。
|
|
201
|
+
|
|
202
|
+
隐藏/恢复由子应用原生事件通知:
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
window.addEventListener('appstate-change', function (event) {
|
|
206
|
+
var state = event.detail && event.detail.appState;
|
|
207
|
+
if (state === 'afterhidden') pauseBackgroundWork();
|
|
208
|
+
if (state === 'aftershow') {
|
|
209
|
+
configureMicroiV8(getMicroiContext());
|
|
210
|
+
resumeBackgroundWorkOnce();
|
|
211
|
+
requestAnimationFrame(resizeChartsAndVirtualLists);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`pause/resume` 必须幂等,分别处理轮询、WebSocket、观察器、图表和虚拟列表;隐藏时不得清空用户
|
|
217
|
+
输入、筛选、滚动或内部路由。恢复时宿主会以 `host:resume` 强制同步当前 Token、OsClient、权限、
|
|
218
|
+
主题、路由和视口,然后复核真实可见 DOM;子应用也应重新读取宿主上下文。AI 生成菜单微服务时
|
|
219
|
+
必须包含此生命周期适配,不能只实现首次 `mount`。
|
|
220
|
+
|
|
178
221
|
子应用通过模板 SDK 调用接口,不自行发明认证协议。关闭/结果使用宿主约定的
|
|
179
222
|
success、cancel、error/close 事件;业务写入成功后再报告 success。
|
|
180
223
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: playwright-e2e
|
|
3
|
-
description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化、全面测试。用于测试 PC Vue、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=
|
|
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
|
-
|
|
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=
|
|
32
|
-
## 常见问题
|
|
31
|
+
<!-- microi-progressive:chunk id=playwright-e2e-024 sha256=b939c97eef28fab71caa54d134ea524d7ed7c8381deec09e38a7d694b15f53c0 -->
|
|
32
|
+
## 常见问题
|
|
33
33
|
|
|
34
34
|
| 现象 | 原因 | 处理 |
|
|
35
35
|
|---|---|---|
|
|
@@ -45,13 +45,59 @@ jobs:
|
|
|
45
45
|
| 用例偶发失败 | HMR 或网络请求未稳定 | CI 使用静态构建,断言明确等待关键元素 |
|
|
46
46
|
| 页面有横向滚动 | 组件撑出视口 | 对根容器和列表容器加 `max-width:100vw; overflow-x:hidden` |
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
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 -->
|
|
93
|
+
<!-- microi-progressive:chunk id=playwright-e2e-025 sha256=be071153d695081b7c20d34cb5e9563480e3f09d9cd0292f2ca4b0245438787b -->
|
|
50
94
|
## 前端微服务 E2E 必测点
|
|
51
95
|
|
|
52
96
|
测试 Vue3 MicroApp 微服务时,不能只验证 `/micro-app/{OsClient}/{appKey}/index.html` 或带 token 的临时 URL。必须先建立真实登录态,再访问用户实际使用的不带 token 菜单路由,例如 `/#/micro-app/{MsKey}/{RoutePath}`,并确认地址栏没有退回旧的 `micro-app-host` 长地址。
|
|
53
97
|
|
|
54
|
-
|
|
98
|
+
同一套微服务绑定多个菜单时,至少选择 3 个真实菜单往返切换 8 轮,逐轮断言主框架 route、当前菜单和子应用可见内容匹配,且没有 `element head is missing`、`Failed to fetch`、`ERR_TOO_MANY_REDIRECTS`、`app name conflict`、永久骨架屏或空白内容。不能只断言 `<micro-app>` 元素存在。
|
|
99
|
+
|
|
100
|
+
页签缓存验收必须覆盖单一所有者与清理边界:在一个缓存范围内修改表单输入、筛选、内部路由或滚动位置,切走再返回后状态应保持;连续打开 6 个菜单微服务实例,断言运行时最多保留 5 个,最久未使用的隐藏实例重入时正常冷启动;关闭当前/其它/全部 Tab 后对应实例消失,退出登录后全部实例清空。恢复页还要断言收到最新 Token/OsClient/权限/主题/视口上下文,且任一时刻只有一个可见活动微服务。若子应用有轮询或 WebSocket,记录 `appstate-change`,确认 `afterhidden` 暂停、`aftershow` 幂等恢复而没有重复连接。
|
|
55
101
|
|
|
56
102
|
如果页面内提供 Microi SDK 调用按钮,必须点击并断言返回 `Code=1`,同时确认没有 `登录身份已过期`、`1001`、`1002`。只看到标题文本不代表鉴权链路通过。
|
|
57
103
|
|
|
@@ -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
|
|