@microi.net/cli 5.9.0 → 5.9.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.
Files changed (22) 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 +3 -3
  7. package/cordis.patch.yml +1 -1
  8. package/package.json +1 -1
  9. package/scripts/microi-skills.meta.json +210 -207
  10. package/skills/.microi-skills-version.json +2 -2
  11. package/skills/.progressive-disclosure-manifest.json +95 -77
  12. package/skills/README.md +2 -2
  13. package/skills/microi-docs-coverage/references/capability-map.md +1 -1
  14. package/skills/microi-mobile-app-quality/SKILL.md +27 -9
  15. package/skills/microi-mobile-app-quality/references/mobile-first-delivery.md +75 -0
  16. package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +31 -17
  17. package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +8 -7
  18. package/skills/microi-uniapp-frontend/SKILL.md +28 -17
  19. package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +103 -67
  20. package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +12 -12
  21. package/skills/workspace-conventions/SKILL.md +4 -2
  22. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +9 -1
@@ -2,13 +2,13 @@
2
2
 
3
3
  > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
4
 
5
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-010 sha256=2820c6dbc7641b03cb2d3af98f80ca654162fdac7995993be5cb7e25b8e5bdea -->
5
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-010 sha256=81d5dbf6cae493337a5289d66ef39bb6d6a64a3e3f64c98e228dc77853810986 -->
6
6
  ## 移动端分类/双栏列表独立滚动
7
7
 
8
8
  商品分类、知识库分类、通讯录分组、资产分类等“左侧分类 + 右侧列表”的移动端页面,根节点必须固定在一个视口内,不能让整页和内部列表同时滚动。
9
9
 
10
- - 根页面使用 `height:100vh; overflow:hidden; display:flex; flex-direction:column;`。
11
- - 分类主体使用 `flex:1; min-height:0; display:flex;`,并给底部 tabBar 预留 `padding-bottom: calc(tabBarHeight + env(safe-area-inset-bottom));`。
10
+ - 根页面使用有界视口高度、`overflow:hidden; display:flex; flex-direction:column;`;H5 使用 `100dvh` 或共享可见高度变量,保留 `100vh` 旧端兜底。
11
+ - 分类主体使用 `flex:1; min-height:0; display:flex;`。导航在根 flex 流内时不再加 tabBar 占位;导航覆盖正文时,才由共享壳预留一次实测总高度(已经包含安全区)。
12
12
  - 左侧分类和右侧列表分别用 `scroll-view scroll-y`,高度来自父级 `height:100%` / `flex:1; min-height:0`,不要用整页滚动承载右侧商品列表。
13
13
  - 右侧分页必须绑定 `@scrolltolower`,设置合理 `lower-threshold`,并维护 `pageIndex/pageSize/loading/finished`,第一页重置列表,后续页追加列表。
14
14
  - 切换左侧分类或顶部专区时,必须重置分页状态并重新加载第一页;不能沿用旧分类的 `finished` 或 `pageIndex`。
@@ -27,14 +27,16 @@
27
27
  ```
28
28
 
29
29
  ```scss
30
- .page-category { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
31
- .cat-body { flex: 1; min-height: 0; display: flex; padding-bottom: calc(104rpx + env(safe-area-inset-bottom)); }
30
+ .page-category { height: 100vh; height: var(--mci-visible-height, 100dvh); overflow: hidden; display: flex; flex-direction: column; }
31
+ .cat-body { flex: 1; min-height: 0; display: flex; }
32
32
  .cat-side { width: 176rpx; height: 100%; }
33
33
  .cat-content { flex: 1; min-width: 0; height: 100%; }
34
+ // 本示例采用流内导航,导航自己占高度并消费安全区;覆盖式导航另由共享壳预留实测高度。
35
+ .category-nav { flex-shrink: 0; padding-bottom: var(--mci-safe-bottom, env(safe-area-inset-bottom)); }
34
36
  ```
35
37
 
36
38
  <!-- /microi-progressive:chunk -->
37
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-011 sha256=a28fba298274b738ef9039c6bd6a1707468687e2ae9644a819736374586749e9 -->
39
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-011 sha256=fcf60104a95a27645f4b519b19bde6aab55d41f38388c442179533dd4ed8a35a -->
38
40
  ## 数据页必须使用骨架屏 Loading
39
41
 
40
42
  任何依赖接口/数据库返回数据的移动端页面,都必须区分 `loading`、`data`、`empty`,并且首屏加载态必须使用骨架屏(Skeleton Screen)。接口请求结束前不能提前显示“暂无数据/暂无明细/空空如也”,也不能只用“图标 + 数据加载中...”或单独 spinner 作为页面级 loading。
@@ -72,27 +74,28 @@ async function load() {
72
74
  ```
73
75
 
74
76
  <!-- /microi-progressive:chunk -->
75
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-012 sha256=5554c817702cc491937fb2b32f5ba2ce76554a35ef0a2189979ff1d60789ab30 -->
77
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-012 sha256=affb88f7856aa410c7d8dd4efa9a5b804be4721efda013e2319203e490d58f54 -->
76
78
  ## 移动端安全区必须兼容 iOS 与 Android
77
79
 
78
80
  任何 UniApp/H5 移动端页面都必须同时适配 iPhone 刘海屏/Dynamic Island/Home Indicator、Android 状态栏/虚拟导航栏/手势条、微信/浏览器/WebView 容器差异。不要用固定 `20px/44px/64px` 直接硬编码顶部或底部间距。
79
81
 
80
82
  - `manifest.json` / H5 模板必须确保 viewport 含 `viewport-fit=cover`,否则 iOS 的 `env(safe-area-inset-*)` 不会完整生效。
81
- - 页面根节点使用 `min-height:100vh` 或固定视口布局时,顶部内容、底部固定栏和内部滚动容器必须一起考虑安全区,不能只给根节点加 padding。
83
+ - 页面根节点使用最小高度或固定视口布局时,顶部内容、底部固定栏和内部滚动容器必须一起考虑安全区,不能只给根节点加 padding;有界 H5 壳优先动态可见高度,不能用 `min-height:100vh` 代替高度上限。
82
84
  - 顶部自定义导航栏应结合 `uni.getSystemInfoSync().statusBarHeight` 和 CSS `env(safe-area-inset-top)`:状态栏占位负责不同系统高度,导航按钮和标题整体下移,返回按钮触摸区不能压到刘海/状态栏。
83
85
  - 不能只依赖 `env(safe-area-inset-*)`。微信小程序、部分 Android WebView 或开发者工具中该值可能为 `0`;项目必须通过 `uni.getWindowInfo()`(旧端回退 `uni.getSystemInfoSync()`)读取 `statusBarHeight`、`safeArea` / `safeAreaInsets`,注入统一的 `--mci-safe-top`、`--mci-safe-bottom` 等页面壳变量。
84
86
  - 微信小程序使用 `navigationStyle: custom` 时,必须读取 `uni.getMenuButtonBoundingClientRect()`(必要时回退 `wx.getMenuButtonBoundingClientRect()`),给顶部栏右侧预留 `windowWidth - capsule.left + gap`。登录、分享、状态角标、更多操作等任何按钮都不能进入右上角胶囊区域。
85
87
  - 全屏弹层/工作台如果包含历史、新建、关闭等多个头部操作,必须先计算整组宽度;胶囊左侧不足时将整组放到胶囊底边以下,不得通过缩小触摸区、覆盖胶囊或截断标题硬塞。自动化测试应读取元素与胶囊 `boundingClientRect` 并断言不相交。
86
88
  - 安全区实现必须集中在 `MciPage`、页面壳 composable/runtime 或全局布局中;禁止每页各自猜测 `20px/44px`。`pages.json` 中每个 `navigationStyle: custom` 页面都必须接入同一个页面壳,新增路由时同步纳入检查。
87
- - 底部 `tabBar`、购买栏、提交栏、批量操作栏等 fixed 元素必须使用 `padding-bottom: env(safe-area-inset-bottom)`,主体内容必须额外预留底部高度,避免最后一条数据被按钮或 tabBar 遮挡。
89
+ - 底部 `tabBar`、购买栏、提交栏、批量操作栏应在栏内消费统一的真实安全区。流内栏已经占据布局高度,正文不得再加整条栏占位;覆盖式 fixed 栏才预留一次栏的实测总高度,确保最后一条数据可见。
88
90
  - 底部 fixed 元素应优先使用运行时 `--mci-safe-bottom`,以 CSS `env(safe-area-inset-bottom)` 作为 H5 兜底;底部导航、提交栏、弹出层和滚动容器必须引用同一变量,不能各算一套。
89
- - 双栏分类页、聊天页、详情页带底部按钮时,内部 `scroll-view` 要用 `flex:1; min-height:0` 承载滚动,并在滚动容器底部预留 `calc(fixedBarHeight + env(safe-area-inset-bottom))`。
91
+ - 双栏分类页、聊天页、详情页带底部按钮时,内部 `scroll-view` 要用 `flex:1; min-height:0` 承载滚动。`fixedBarHeight` 若已经包含安全区,不再加一份 `env`;禁止根 padding、原生占位、正文 padding 和栏 padding 共同重复预留。
90
92
  - H5 在 PC 手机壳模式下,fixed 顶栏/底栏仍要限制在手机壳宽度内;不能铺满整个桌面浏览器。
93
+ - 桌面预览没有真实手机手势区时底部安全区为 `0`;不能为了模仿手机外观硬塞 `34px/80rpx` 等假安全区。边框、阴影、装饰 Home Indicator 与系统安全区要分别处理。
91
94
  - 验收必须至少覆盖一个 iPhone 刘海/灵动岛尺寸、一个 Android 高状态栏或虚拟导航栏尺寸、一个微信开发者工具真机模拟尺寸、一个 PC H5 手机壳尺寸;逐项截图检查顶部不被状态栏/胶囊遮挡、底部按钮不贴边、列表最后一项可见。不能只截图首页,必须按 `pages.json` 路由清单覆盖登录、Tab 页、详情、表单、弹层和管理页。
92
95
  - 独占屏幕且需要支持手机侧滑返回的功能应使用独立页面路由。`onBackPress`/页面返回先消费当前页内部的键盘、对话框和抽屉状态;内部状态清空后才弹出当前页,不能让一次返回直接退出小程序或越过底层业务页。
93
96
 
94
97
  <!-- /microi-progressive:chunk -->
95
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-013 sha256=591a8e5a3e33cfcdb102abf56ebc6eeb5c5896d621442c30e734f455d625842c -->
98
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-013 sha256=b6074ef264327e9cc630a9c4136989d6355ed33ba4902098e8ae025661a207ed -->
96
99
  ## 微信自定义组件的点击与拖动事件必须真机链路验收
97
100
 
98
101
  - UniApp 可拖动浮动入口等自定义组件,不要给 `touchstart/touchmove/touchend/tap` 整组无差别添加 `.stop/.prevent`。这些修饰符会生成微信 `catchtouch* / catchtap`,部分 UniApp 自定义组件中可能吞掉事件桥,出现节点可见但点击和触摸方法完全不执行。
@@ -121,7 +124,7 @@ async function load() {
121
124
  ```
122
125
 
123
126
  <!-- /microi-progressive:chunk -->
124
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-014 sha256=62f20b920f2365d9f2f5062218b10b17aa181ccb3ae5d2260f795e086355f678 -->
127
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-014 sha256=201c7dd1b1e923a62319f1402088fa696bb96aa8ca58a8c7f9817a6ecce36e12 -->
125
128
  ## 列表型资料页必须提供完整管理动作
126
129
 
127
130
  地址、联系人、收款方式、发票抬头、车辆、设备、证照、银行卡等用户维护型资料页,不能只展示简略列表。除非业务明确只读,移动端必须提供:
@@ -135,7 +138,7 @@ async function load() {
135
138
  - 空态行动:没有数据时给出新增入口,但仍要遵守上面的加载态规则。
136
139
 
137
140
  <!-- /microi-progressive:chunk -->
138
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-015 sha256=d8e9280b5127d7dafd4dcb83b22bdb379fef39eac1e2e1b2e37f1c064cfe7fc6 -->
141
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-015 sha256=287d085d3651e0eb20b97fadf0ba616e9f4aea9447efda6824612b64309efd27 -->
139
142
  ## 移动端资产/奖励流水展示
140
143
 
141
144
  收益明细、积分明细、奖励明细、充值记录、订单流水等页面要面向用户展示“发生了什么”和“是否到账”,不要直接暴露后台调试字段。
@@ -147,79 +150,112 @@ async function load() {
147
150
  - 后端接口应先把 `TypeLabel`、`SettleStatusLabel`、`DisplayTime`、`ContributorName`、`CardNo` 等字段整理好,前端只做轻展示,避免多个页面各自拼接导致重复或口径不一致。
148
151
 
149
152
  <!-- /microi-progressive:chunk -->
150
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-016 sha256=610b00696fd8a1548842974b5551e0e55bc276a3605459947251f508b4ef2ad3 -->
153
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-016 sha256=f1c583f99234a5a82a7c1557658c3ba036020b39d5524466eca0e2b1cdb85988 -->
151
154
  ## H5 在 PC 浏览器必须自动模拟移动端
152
155
 
153
156
  移动端 UniApp H5 被 PC 浏览器访问时,不能按桌面宽屏铺满。必须在全局样式里用媒体查询生成手机预览壳。
154
157
 
155
158
  基础要求:
156
159
 
157
- - `@media screen and (min-width: 768px)` 下把 `uni-app` 居中并限制到常见手机宽度,例如 `430px`。
160
+ - 桌面预览把内屏居中并限制到常见手机宽度,例如 `430px`;预览条件综合宽度、输入能力或项目运行时设备标记,不能仅按 `min-width:768px` 把手机横屏当桌面。下面媒体查询是精细指针桌面示例,项目还需验证移动设备仿真和真实设备判断。
158
161
  - `html, body` 使用克制的桌面背景,`uni-app` 内保持移动端页面本身背景。
159
162
  - 如果项目或主题给 `body.theme-light`、`body.theme-dark` 写了背景色,PC 媒体查询必须显式覆盖,避免手机壳外侧仍显示暗色或项目内装饰背景。
160
- - 同步约束 `uni-page`、`uni-page-wrapper`、`uni-page-body` 的宽度。
161
- - `uni-page-body` 给底部菜单和安全区预留 padding,避免内容或底部操作栏压住 tabBar。
162
- - 所有 `position: fixed` 底部操作栏按同一手机壳宽度居中。
163
- - 原生 `uni-tabbar` 和 `.uni-tabbar` 必须显式设置 `position: fixed`、`bottom: 0`、同宽居中和足够的 `z-index`,否则主体像手机壳但底部菜单可能丢失或铺满 PC 宽屏。
163
+ - 同步约束页面壳及 `uni-page / uni-page-wrapper / uni-page-body` 中实际参与布局的包装层:`min-height:0; min-width:0`。头部和导航不收缩,剩余高度留给正文;不能把 `uni-page-body` 写成整屏高后再追加导航。
164
+ - 先确定导航是流内还是覆盖式。流内栏使用 `flex-shrink:0`,正文不加整栏占位;覆盖式栏的宽、高、底边和唯一占位由共享壳负责。原生 `uni-tabbar` 的平台占位存在时不能再叠自定义占位。
165
+ - 有桌面外边距或矮屏壳时,栏必须贴壳内屏底边,不是外窗 `bottom:0`。为覆盖式栏建立属于内屏的定位包含块,或根据其真实矩形定位;不要同时给原生 tabBar 外层和内层重复 `fixed`。
166
+ - `rpx` 按设备宽度计算,不自动跟随 CSS 手机壳宽度。`pages.json.globalStyle` 的最大换算宽度和基准宽度应与预览策略一致,例如 767/430;检查 768、960 和 4K 外窗的实际换算结果。全宽使用 `100%` 或 flex,不能用 `750rpx`。参见 [DCloud 宽屏适配](https://uniapp.dcloud.io/tutorial/adapt.html)。
164
167
  - 页面内 `position: fixed` 的装饰背景(如 aurora、粒子、全屏渐变)在 PC 壳模式下必须收回到 `uni-app/uni-page-body` 内,不能覆盖整块桌面背景。
165
168
 
166
- 参考样式:
169
+ 自定义流内导航参考结构(选择该模式后,不再并列渲染原生导航):
167
170
 
168
- ```scss
169
- @media screen and (min-width: 768px) {
170
- html,
171
- body {
172
- min-height: 100%;
173
- background:
174
- linear-gradient(135deg, rgba(255,255,255,.78), rgba(244,246,250,.92) 44%, rgba(236,239,245,.98)),
175
- radial-gradient(circle at 18% 16%, rgba(181,18,32,.07), transparent 32%),
176
- radial-gradient(circle at 84% 10%, rgba(216,162,58,.08), transparent 28%),
177
- #F3F5F9;
178
- }
171
+ ```html
172
+ <main class="mci-h5-viewport" data-app-viewport>
173
+ <header class="mci-preview-header">移动端预览</header>
174
+ <section class="mci-page-scroll" data-page-scroll>页面内容</section>
175
+ <nav class="mci-bottom-nav" data-bottom-nav>图标与菜单触摸区</nav>
176
+ </main>
177
+ ```
179
178
 
180
- body { margin: 0; }
179
+ 参考样式:
181
180
 
182
- uni-app {
183
- position: relative;
184
- display: block;
185
- width: min(430px, 100vw);
186
- min-height: 100vh;
187
- margin: 0 auto;
188
- overflow-x: hidden;
189
- background: var(--app-bg-base, #F7F8FB);
181
+ ```scss
182
+ html, body { margin: 0; height: 100%; overflow: hidden; }
183
+ .mci-h5-viewport {
184
+ box-sizing: border-box;
185
+ width: 100%; height: 100vh;
186
+ height: var(--mci-visible-height, 100dvh);
187
+ min-height: 0;
188
+ display: flex; flex-direction: column; overflow: hidden;
189
+ background: var(--app-bg-base, #F7F8FB);
190
+ }
191
+ .mci-preview-header { display: none; flex-shrink: 0; }
192
+ .mci-page-scroll { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; }
193
+ .mci-bottom-nav {
194
+ flex-shrink: 0; box-sizing: border-box;
195
+ padding-bottom: var(--mci-safe-bottom, env(safe-area-inset-bottom, 0px));
196
+ }
197
+ @media screen and (min-width: 768px) and (hover: hover) and (pointer: fine) {
198
+ body { display: grid; place-items: center; background: #F3F5F9; }
199
+ .mci-h5-viewport {
200
+ --mci-safe-bottom: 0px; // 桌面预览没有手机系统手势区,不伪造安全区。
201
+ width: 430px;
202
+ height: calc(100vh - 32px); height: calc(100dvh - 32px);
203
+ max-height: 900px;
204
+ border-radius: 24px;
190
205
  box-shadow: 0 18px 54px rgba(28, 36, 52, .16);
191
206
  }
207
+ .mci-preview-header { display: block; }
208
+ }
209
+ ```
192
210
 
193
- uni-page,
194
- uni-page-wrapper,
195
- uni-page-body {
196
- width: 100% !important;
197
- max-width: 430px;
198
- margin: 0 auto;
199
- }
211
+ 真实 UniApp 页面还应检查框架包装层高度和原生 tabBar 占位。这个结构示例不授权业务页覆盖所有 `uni-*` 标签,也不适用于必须使用文档滚动的页面;文档滚动模式必须另行证明根滚动是唯一 owner、导航跟随可见视口且尾部占位仅一份。
200
212
 
201
- uni-page-body {
202
- padding-bottom: calc(64px + env(safe-area-inset-bottom));
203
- }
213
+ ### 导航贴底与剩余空间的真实断言
204
214
 
205
- .bottom-bar {
206
- left: 50% !important;
207
- right: auto !important;
208
- width: calc(min(430px, 100vw) - 24px);
209
- transform: translateX(-50%);
210
- }
215
+ H5 安全区必须来自 CSS `env(safe-area-inset-bottom)` 等浏览器权威来源。`screenHeight - windowHeight` 与 `screen.height - innerHeight` 包含外窗、工具栏和缩放差异,禁止转换为安全区 padding。App/小程序的权威 inset 可以为 `0`,只能在值缺失时按明确平台契约处理,不能用 `inset || guessedFallback` 将零替换。桌面非最大化窗口和缩放必须纳入验收,物理屏幕与视口不同也应保持导航内栏高度有界。
211
216
 
212
- uni-tabbar,
213
- uni-tabbar .uni-tabbar {
214
- position: fixed !important;
215
- left: 50% !important;
216
- right: auto !important;
217
- bottom: 0 !important;
218
- width: min(430px, 100vw) !important;
219
- transform: translateX(-50%);
220
- z-index: 99 !important;
221
- }
222
- }
217
+ 下列例子测量自定义流内导航;选择器按项目真实结构替换,目标边界必须是**内屏**而不是带边框的装饰壳。设计值在测试开始前固定,不能根据异常画面扩大阈值:
218
+
219
+ ```js
220
+ const geometry = await page.evaluate(() => {
221
+ const rect = node => {
222
+ const r = node.getBoundingClientRect();
223
+ return { top: r.top, bottom: r.bottom, left: r.left, right: r.right, height: r.height };
224
+ };
225
+ const screen = document.querySelector('[data-app-viewport]');
226
+ const nav = document.querySelector('[data-bottom-nav]');
227
+ const scroll = document.querySelector('[data-page-scroll]');
228
+ if (!screen || !nav || !scroll) throw new Error('页面结构缺失');
229
+ const items = [...nav.querySelectorAll('[data-nav-item]')];
230
+ if (!items.length) throw new Error('导航菜单缺失');
231
+ return {
232
+ screen: rect(screen), nav: rect(nav), scroll: rect(scroll), items: items.map(rect),
233
+ safeBottom: parseFloat(getComputedStyle(nav).paddingBottom) || 0,
234
+ rootOverflow: document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight
235
+ };
236
+ });
237
+ expect(Math.abs(geometry.nav.bottom - geometry.screen.bottom)).toBeLessThanOrEqual(2);
238
+ expect(geometry.nav.left).toBeGreaterThanOrEqual(geometry.screen.left - 2);
239
+ expect(geometry.nav.right).toBeLessThanOrEqual(geometry.screen.right + 2);
240
+ expect(geometry.scroll.bottom).toBeLessThanOrEqual(geometry.nav.top + 2);
241
+ expect(geometry.rootOverflow).toBeLessThanOrEqual(2);
242
+ expect(geometry.nav.height).toBeLessThanOrEqual(designNavContentHeight + geometry.safeBottom + 2);
243
+ const lastItemBottom = Math.max(...geometry.items.map(item => item.bottom));
244
+ expect(geometry.nav.bottom - lastItemBottom)
245
+ .toBeLessThanOrEqual(geometry.safeBottom + designNavInnerBottomGap + 2);
246
+ await page.screenshot({ path: screenshotPath, fullPage: false });
223
247
  ```
224
248
 
249
+ `safeBottom` 在此示例是 CSS 计算结果,不代表系统安全区来源已经可信。测试仍须核对运行时安全值、同一个值的唯一消费位置和桌面为零;不能用一个错误的巨大 padding 放宽几何门禁。短内容允许正文留白,禁止的是**导航下方**无业务依据的大块剩余区域。
250
+
251
+ | 场景 | 必须断言 |
252
+ |---|---|
253
+ | 三个主 Tab、短内容/空态 | 导航底边贴内屏,内栏高度有界,图标文字可见且触摸区可点 |
254
+ | 长内容滚动中/到底、切回 Tab | 导航位置不漂移,最后一项可达且未遮挡,壳外根滚动不变化 |
255
+ | 桌面 1024×600 / 1366×768 / 1920×1080 / 4K | 内屏在视口内,导航贴壳底;rpx 不随外窗放大,正文只有一个 owner |
256
+ | 手机 375×812 / 430×932、767/768 断点、横屏与旋转 | 移动模式去壳,内屏铺满可见区域;旋转后重测安全区和底边 |
257
+ | 键盘打开/关闭、浏览器栏展开/收起 | 焦点与操作可见,关闭后恢复底边,无残留占位或第二条滚动条 |
258
+
259
+ H5 键盘可能改变 visual viewport 而不改变 layout viewport;`100dvh` 不是所有键盘模式的保证。共享壳按目标浏览器处理 `visualViewport` 尺寸/偏移与 resize/恢复,原生端按配置的键盘模式测量;真机 iOS/Android 另验。缩小 Playwright 视口只证明 resize 分支,不等于软键盘实测。参考 [W3C Viewport 交互部件规则](https://www.w3.org/TR/css-viewport-1/#interactive-widget-section)。
260
+
225
261
  <!-- /microi-progressive:chunk -->
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
4
 
5
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-017 sha256=f4c3bd827f3349b65dd40c894a51299d32ba7d75ba58a3a81d04aaba6b1733f2 -->
5
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-017 sha256=9ef6eaa852b4b29ee01b51a4353685ee97ee219ff5d6da881f3de6371654861f -->
6
6
  ## 关键业务资产不得默认选中
7
7
 
8
8
  凡是会扣减、消耗、转移、提交审批或触发财务后果的业务资产,都不能默认选中第一条。例如资产卡、余额账户、积分账户、优惠券、库存批次、付款账户、审批对象、设备工单等。
@@ -15,14 +15,14 @@
15
15
  - 规则同时写在 UI 状态和提交前校验中。
16
16
 
17
17
  <!-- /microi-progressive:chunk -->
18
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-018 sha256=35f9826cc82000f9cedd3ccaffd8e7718b0efbec75cf12665145f1de4f8a6d23 -->
18
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-018 sha256=df78e011402f4e4b8901d6f8a99392bf1ee51d3085fccc69c49fe39f425903a2 -->
19
19
  ## 账号角色与会话状态
20
20
 
21
21
  - Microi 企业移动端默认要从 `sys_user.RoleIds`、`_Roles`、`Roles`、`RoleName`、`Level` 解析内部账号角色,不要只用“是否登录”控制界面。
22
22
  - 角色能力必须集中在 Pinia/session store 中计算,例如 `isTechnician`、`isServiceAgent`、`isCustomerAccount`、`canAcceptOrders`、`canManageCustomers`、`canViewReports`。多角色账号取能力并集;只有服务端已确认的 `Level>=9999` 才属于平台超级管理员。前端“超级管理员”角色名只用于展示,不能授予接口权限。
23
23
  - 客户账号判断要精确,只把“客户”“客户账号”“客户用户”或明确包含“客户账号”的角色当作客户侧账号;不要把“客户管理”等后台角色误判为客户。
24
24
  - 所有页面、底部导航、按钮、未登录提示、头像姓名和角色文本都必须读同一个 session store。页面不能直接读取旧 storage 展示用户名。
25
- - 客户小程序手机号登录得到的是业务 `CustomerToken`,与员工 `sys_user` token 是两条会话;客户数据必须通过绑定关系过滤,不要把客户账号塞进员工接口绕过权限。
25
+ - 新建手机号登录、自动注册和多角色移动端统一签发平台 DiyToken,数据按真实用户及绑定关系过滤,不能并行创建第二套长期用户/权限 Token。存量已审核的 `CustomerToken` 协议只按原接口兼容并维护隔离,不把它当新项目默认身份体系,也不混用员工接口绕过权限。
26
26
  - 登出、登录失败、token 缺失、用户 `Id` 缺失时要统一清理 `Token`、`staffUser/customerUser`、绑定信息和本地 session。
27
27
  - 接口引擎登录失败时要把 `Msg` 原样传到统一错误展示层,禁止在 store 或业务 API 包装中覆盖成固定文案;网络错误优先读取 `errMsg/message`,HTTP 错误同时保留状态码。
28
28
  - 员工账号登录必须传准确 `_ClientType`;H5、App、微信/支付宝/飞书/抖音小程序均属于移动长效终端,默认读取 SaaS 引擎 `AccessTokenLifetime`(单位天,默认 30 天)。完整 Token 协议以 `microi-frontend-sdk/SKILL.md` 为准。
@@ -31,7 +31,7 @@
31
31
  - 收到 `Code=1001/1002` 时用可完整阅读的模态框展示后端 `Msg`,包括过期分钟/小时/天或租户不匹配信息,确认后再跳登录;不能先覆盖成固定 Toast。
32
32
 
33
33
  <!-- /microi-progressive:chunk -->
34
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-019 sha256=72621b385229c3308cbe98dbfa0fb29de95e88d675dad31d9fbe4543b441fdbb -->
34
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-019 sha256=7a258af0c36dd3e82d7f9444043d3b0b9d3bc99f329ff85a167b91594b1a54b1 -->
35
35
  ## 数字、主题、上传与消息
36
36
 
37
37
  - 资产金额、积分、余额、库存值、累计充值、收益等数字要按空间自适应格式化。金额很大时显示为 `1.23万`、`123万`、`1.2亿` 等,不能撑破卡片。
@@ -46,7 +46,7 @@
46
46
  - 私有图片、身份证照片、支付凭证等禁止匿名访问的文件,前端必须先换取临时 URL;不能直接把私有路径给 `<image>`。
47
47
 
48
48
  <!-- /microi-progressive:chunk -->
49
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-020 sha256=6f5c05a725b3325feb889fbb4c97621e247ca9d6eb89970bf9f8602a81177524 -->
49
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-020 sha256=2ae732a49279cc7604169a302987d5428ab3b9e8a108ec442813bbd0aea735a0 -->
50
50
  ## 图片上传必须支持替换与预览
51
51
 
52
52
  头像、支付凭证、实名认证、收款码、证照、商品图、富文本图片等移动端图片上传场景,选择图片后不能把入口锁死。所有上传入口必须统一做到:
@@ -60,7 +60,7 @@
60
60
  - 自动化或手工验收至少覆盖支付凭证、头像/实名认证/收款码中一个私有图场景,确认可替换、可预览、不会丢表单字段。
61
61
 
62
62
  <!-- /microi-progressive:chunk -->
63
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-021 sha256=ad8b543f8e0cd7a20464adb88d456bc21e0451e3f216b1419fa572631543cd49 -->
63
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-021 sha256=68367fcd8e3fae5c2e7da8a956fd803b712ea7bdddbc5a595b16c35b4f7c9fd8 -->
64
64
  ## 组件复用与页面去重
65
65
 
66
66
  同一类 UniApp/H5 UI 在两个及以上页面出现时,必须抽成 `Mci*` 或项目级 `mci-*` 组件,不要复制模板和 scoped 样式到多个业务页面。常见必须复用的结构包括:未登录/授权提示、空态、错误态、骨架屏、列表卡片、商品卡、消息卡、筛选栏、Tab、底部操作栏、按钮组、头像/角标。
@@ -73,7 +73,7 @@
73
73
  - 对复用组件补充自动化检查:静态检查至少确认业务页使用同一个组件;视觉检查至少覆盖两个不同业务页实例。
74
74
 
75
75
  <!-- /microi-progressive:chunk -->
76
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-022 sha256=79b92cb4a1e0b37d786b148a98848fbae3f4424b4d07febc96adbf62ef389431 -->
76
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-022 sha256=bf2b295c18b0e848bffb9dd16a3c8fa2c1d022e7f9a344dd100a2305c5e14de1 -->
77
77
  ## 验收要求
78
78
 
79
79
  每次改动 UniApp/H5 前端后,至少做以下验证:
@@ -90,7 +90,7 @@
90
90
  - 未登录/未授权态必须额外截图确认:提示卡片位于 header 与 tabBar/底栏之间的可用区域中心,不能只横向居中但纵向贴顶。
91
91
 
92
92
  <!-- /microi-progressive:chunk -->
93
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-023 sha256=bdd657712c4a6a12698c619d22c58b43648c3a3ab32ded54f09c3dc7331ad8ab -->
93
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-023 sha256=07c9a59b5b1c165d75648a618039d9627560398a4849da78ea6d1cfa71c4c0de -->
94
94
  ## Microi 前端 SDK 必须接入
95
95
 
96
96
  任何 Microi UniApp/H5 Vue3 项目都必须优先使用 `microi.skills/microi.v8.js` 作为统一前端 SDK,并参考 `microi.skills/microi-frontend-sdk/SKILL.md`。新项目不得再手写分散的 `uni.request`、Token 存储、上传、私有文件 URL、头像解析、`ApiEngine` 或 `FormEngine` 包装。
@@ -103,7 +103,7 @@
103
103
  - SDK 不绑定任何 UI 库;页面 UI 仍遵守本 Skill 的骨架屏、安全区、移动端富文本和资源展示规范。
104
104
 
105
105
  <!-- /microi-progressive:chunk -->
106
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-024 sha256=b2b9b1ea707ab4bd114db5838eda185b7b7e375435cdca21effd7be24f996a27 -->
106
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-024 sha256=c206d390961681ac6dec722beb96c598efa97a97112744c9fabc6f7eee79e43c -->
107
107
  ## MCI-UI Mobile 必须优先使用
108
108
 
109
109
  新的 Microi UniApp/H5 Vue3 项目必须默认基于 `Microi.UI/src/uniapp` 建立页面基础组件,至少包括页面壳、导航栏、按钮、卡片、分段标签、指标卡、底部安全区操作栏、头像、商品卡、骨架屏、数据状态、富文本。用户未主动指定 UI 风格时,AI 必须自动采用 Microi吾码UI。项目可以使用 `uni-ui`、`uView`、`FirstUI` 等第三方组件,但应封装在 MCI-UI 或项目级 `mci-*` 组件后面,不要让业务页面直接散落多套视觉风格。
@@ -117,10 +117,10 @@
117
117
  5. 商品详情、公告、协议等富文本使用 `MciRichText` 或遵循同等结构。
118
118
 
119
119
  <!-- /microi-progressive:chunk -->
120
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-025 sha256=c472359f2f16b287398c0781cb66cbfb98fea99accddbfa078e9f1e9356aa30d -->
120
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-025 sha256=aae9073d117844c10351d533df89c546661e63b15e82319df9e818b9dee004f9 -->
121
121
  ## 登录、图标与主题补充规范
122
122
 
123
- - 登录页不要同时铺开两套完整登录系统。H5/App 默认只做一个“账号/手机号 + 密码”表单;微信小程序默认展示 `<button open-type="getPhoneNumber">` 手机号授权登录,账号密码只能作为次级折叠/备用入口。
123
+ - 登录页不同时铺开两套完整登录系统。H5/App 默认手机号、图形验证码、短信验证码统一登录/自动注册,遵守当前租户开放注册策略;密码作为次级备用入口。微信小程序正式能力可用时优先展示 `<button open-type="getPhoneNumber">` 手机号授权登录,仍共用平台 DiyToken。完整流程以入口“默认快捷登录、自动注册与长效会话”为准。
124
124
  - 微信小程序手机号授权登录必须使用 `@getphonenumber` 的 `detail.code`,并重新调用 `uni.login({ provider:'weixin' })` 获取新的 `LoginCode`;不要假设前端能拿到手机号明文。
125
125
  - 账号密码兜底入口必须跟随 `Sys_Config.EnableCaptcha`:开启时显示验证码图片和输入框,提交 `_CaptchaId/_CaptchaValue`;关闭时完全隐藏且不提交空字段。
126
126
  - 登录页、我的页、设置页不要向终端用户展示“当前租户 / OsClient / 移动端版本 / API 地址 / 调试版本”等内部实现块。
@@ -136,7 +136,7 @@
136
136
  - 列表进入详情必须保持身份路径:员工列表点报告详情走员工 token/FormEngine 权限,客户列表点报告详情走 CustomerToken,分享链接走 ShareToken;禁止员工点击可见报告后因为传空 CustomerToken 被跳回登录。
137
137
 
138
138
  <!-- /microi-progressive:chunk -->
139
- <!-- microi-progressive:chunk id=microi-uniapp-frontend-026 sha256=67c8816c77d24e6aef77f1706a72330c7a103b58c623178c056a71203e2b43d3 -->
139
+ <!-- microi-progressive:chunk id=microi-uniapp-frontend-026 sha256=12cab2ca3839d0eee4bebc69648f63b172a793ddeade2c6b0a1108fcad0adc4a -->
140
140
  ## UniApp 上传路径与 Header 规则
141
141
 
142
142
  任何移动端图片、头像、身份认证、付款凭证、富文本图片、收款码上传,都必须走项目统一的 `uploadFile` 包装,并最终委托 `microi.v8.js` 的 `V8.uploadFile`。页面里不得直接调用 `/api/HDFS/UniappUpload`,不得临时手写 `uni.uploadFile`。
@@ -234,7 +234,7 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
234
234
  - `Microi.net.Api/Controllers` 除五个兼容内核 Controller 与统一旧客户端兼容 Controller 外,只能保留已证明接口引擎无法承担的薄协议 Controller;每个保留项必须同步登记 `api-ownership-catalog.json` 并由结构测试锁定。已完整迁入接口引擎的旧 Controller 必须继续物理删除。
235
235
  - `Program.cs` 只保留有说明的插件注册和最薄宿主入口;ASP.NET 组合代码可留在同项目 `Hosting`,可复用业务/运行时逻辑进入 `Microi.Core`、`Microi.net`、`Microi.Upgrade` 或对应插件,禁止通过新建“中转层”掩盖归属问题。
236
236
 
237
- <!-- microi-progressive:chunk id=workspace-conventions-009 sha256=cb0a9b2286d51e41dfd3c4249f28d4ac57b6736112be3c1f57f8eb405d0631b1 -->
237
+ <!-- microi-progressive:chunk id=workspace-conventions-009 sha256=0343192b5c71d39f9f31a21bccb5046715f1b47d4876ba962b2d5f188c021271 -->
238
238
  ## 多对话共享工作区变更归属保护(强制)
239
239
 
240
240
  ### 功能验收后的源码提交与推送(强制)
@@ -245,6 +245,8 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
245
245
  - 正式发布前,候选必须包含此前已交付功能的提交,并完成本任务提交、推送及远端提交号回读,再从该冻结候选构建与发布。仅更新某个说明页面时也要核对整个站点的候选;隔离工作树不能因为没有未提交变更就被当成最新线上功能。发布锁只防并发,不能代替源码完整性检查。
246
246
  - 收尾逐仓记录本地提交号、远端分支和回读结果,并区分源码推送、构建发布与真实线上验收。网络、权限、冲突或门禁阻止推送时,保留本地提交、准确报告未推送项并继续完成可独立推进的工作;不得宣称完整交付,也不得为赶进度先发布未交付源码。
247
247
 
248
+ - **Git 大文件推送确认(强制)**:每次 Git 推送前检查全部待推送提交中新引入的 Blob;单个达到 10 MiB 或合计达到 50 MiB 时,必须提供路径、实际大小、SHA-256 和目标仓库/分支,取得用户对具体清单的确认后才推送。一般提交推送授权不能代替大文件确认;完整检查、CDN 引用、历史瘦身与失败回执规则见[Git 大文件推送确认](references/progressive-03-cli-与-ide-插件错版共存约定.md#git-大文件推送确认强制)。
249
+
248
250
  同一工作区可能同时被用户、其它 Codex 对话、IDE、自动化任务或外部 Git 操作修改。任务启动前已经存在、或无法用本对话证据严格证明归属的差异,一律视为他人资产并保留;“工作区是脏的”不是清理授权。
249
251
 
250
252
  - 开始修改前先保存只读基线,至少包括 `git status --short`、目标文件的 `git diff -- <file>`,必要时记录文件 SHA-256。VS Code 重启、上下文压缩或接续中断任务后,必须重新建立基线,不能沿用对差异归属的猜测。
@@ -277,5 +279,5 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
277
279
 
278
280
  - [references/progressive-01-版本更新日志保护规则-强制.md](references/progressive-01-版本更新日志保护规则-强制.md):版本更新日志保护规则(强制);配置文件说明中文优先规则;后端 API 配置白名单与 SaaS 单一事实源(强制);身份、可逆业务秘密与敏感操作统一规范(强制);多语言优先约定;后台菜单层级默认规则;后台任务与安全防护约定;业务逻辑优先接口引擎约定;应用商城优先于 Microi.Upgrade(强制);在线 AI 应用上下文默认发现规则(强制);VS Code 插件空目录生成规则;Microi 版本号规则;C# dynamic 强类型落地规则;根目录保留文件说明
279
281
  - [references/progressive-02-microi-net-api-本地启动约定.md](references/progressive-02-microi-net-api-本地启动约定.md):Microi.net.Api 本地启动约定;多 AI 对话共享本地服务与发布互斥(强制);本地租户与测试凭据读取约定;自动化登录约定;V8 远端/本地同步收尾约定;V8 缓存刷新约定;MCP 元数据更新验收约定;MCP 可用性排查约定;MCP 写入超时与降级约定;Codex MCP 单入口约定;.venv Python 环境说明;后端代码改动后的重启验收;MCP 可调用性诊断补充;Windows MCP 控制台闪窗复盘
280
- - [references/progressive-03-cli-与-ide-插件错版共存约定.md](references/progressive-03-cli-与-ide-插件错版共存约定.md):CLI 与 IDE 插件错版共存约定
282
+ - [references/progressive-03-cli-与-ide-插件错版共存约定.md](references/progressive-03-cli-与-ide-插件错版共存约定.md):CLI 与 IDE 插件错版共存约定;Git 大文件推送确认
281
283
  <!-- microi-progressive:end -->
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
4
 
5
- <!-- microi-progressive:chunk id=workspace-conventions-038 sha256=57098466d31d0636bf330fde545daff8cb8e4116ac6ea2efff8abc729fdcef77 -->
5
+ <!-- microi-progressive:chunk id=workspace-conventions-038 sha256=97d43d23dc7e50e2806b9ef41c0d5afce73a3dde0ee0b2c6f3fdb468278ee248 -->
6
6
  ## CLI 与 IDE 插件错版共存约定
7
7
 
8
8
  - CLI 与 IDE 插件共用配置、Token、MCP、Skills 或生成文件时,所有持久化协议必须按“新字段可选、旧字段保留、未知字段不删除”设计。不得将 JSON 解析到旧类型后只序列化已知字段。
@@ -24,4 +24,12 @@
24
24
  - 根因:新 scope/新版本在 npm 网站、写入节点和公共 registry 读取节点之间存在短暂传播窗口;固定少量、短间隔轮询不足以区分“尚未发布”和“已经接收但尚未公开传播”。
25
25
  - 通用规则:发布命令成功和公共回读确认必须作为两个阶段记录。npm 新版本回读使用 `--prefer-online` 和分钟级有限重试;重试结束仍为 E404 时标记 `pending-propagation`,禁止自动重发同一不可变版本,并提供独立只读验证命令稍后确认。只有发布命令本身失败且公共 registry 也始终不存在时,才进入补发流程。
26
26
  - 自动化检查:模拟 `npm publish` 成功后前几次 `npm view` 返回 E404、随后返回期望版本,断言不会重复发布;再模拟重试窗口结束仍为 E404,断言输出待传播状态和只读验证命令,而不是提示重新上传同一版本。
27
+ ## Git 大文件推送确认(强制)
28
+
29
+ - 每次 Git 推送前检查暂存内容及全部待推送提交中新引入的 Blob,不能只看工作树、最新提交或首尾文件差异;中间提交加入后又删除的大文件仍会进入历史。以刚核验的远端引用为基线,结合 `git rev-list --objects` 与 `git cat-file --batch-check` 检查真实对象大小;基线或对象不完整时先补齐并复核,不能绕过检查。
30
+ - 默认将单个新增 Blob 达到 **10 MiB**,或本次新增 Blob 合计达到 **50 MiB** 视为需要确认的大文件推送。列出具体路径、实际字节数、SHA-256、目标仓库/分支及合计体积,向用户明确询问是否推送,收到答复前暂停受影响的 Git 推送。一般“提交并推送”授权不能代替这份具体大文件清单的确认;用户已明确确认同一清单和内容时可继续,路径、哈希、数量或体积变化后须重新确认。不要因远端已有且本次未增加的历史大文件反复索要授权。
31
+ - PDF、PPT/PPTX、视频、压缩资源、导出报告等交付附件默认通过当前授权租户的 MCP 上传到 CDN,核验实际下载字节数和 SHA-256 后使用 FileServer/CDN 地址引用。源码仓库保留必要源码、引用及可重复生成的说明;不能静默提交导出产物。运行必需的字体、模板和第三方二进制按用途判断,达到上述阈值仍须列入确认,不得擅自删除或转移。
32
+ - 历史瘦身另行确认改写范围,保留同事提交、有效分支、标签和可恢复证据;仅删除当前文件不能释放仍被历史引用的大对象。用户授权瘦身后使用明确引用清单及旧值保护,禁止未经盘点直接执行 `push -f --all` 或 `--mirror`,禁止为解除配额清空、删除或重建仓库。服务端 PR 引用、reflog、恢复记录和配额阻挡应通过管理界面或技术支持处理。
33
+ - 推送失败时保存原生 Git 的完整命令、退出码和 stdout/stderr,隐藏凭据但不删减错误正文,回读远端引用确认实际状态;区分本地 Hook、网络、权限与服务端容量拒绝。同一错误不盲目重跑,向技术支持提供与该次候选绑定的实际压缩体积、引用范围和完整日志,不能把本地精简成功当作远端已瘦身。
34
+
27
35
  <!-- /microi-progressive:chunk -->