diff --git a/.agents/skills/mpx2skyline-workspace/benchmark.md b/.agents/skills/mpx2skyline-workspace/benchmark.md new file mode 100644 index 0000000000..8387d64cd0 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/benchmark.md @@ -0,0 +1,7 @@ +# Mpx2Skyline 测试集 + +当前有效定义:v4,4个case、37条断言,尚未执行。 + +[设计](test-design.md) · [定义](iteration-4/evals.json) · [评分标准](iteration-4/grading-standard.md) + +[iteration-3历史结果](iteration-3/benchmark.md)属于旧任务上下文,分数不迁移至v4。 diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/README.md b/.agents/skills/mpx2skyline-workspace/iteration-4/README.md new file mode 100644 index 0000000000..3234f626b8 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/README.md @@ -0,0 +1,11 @@ +# 当前测试集 v4 + +4个case/37条断言,未执行。原case 4合并到1并统一为orders.mpx页面输入,原case 3合并到2并统一为user-list.mpx组件输入(保留外部row.wxml和logo.svg);新case 3为仅提供需求的任务看板页面创建。 + +原始产物与评分保留在iteration-3。新版外层input只保留一份,不复制Skill,不预建执行目录。定义详见evals.json,迁移关系见assertion-migration.json。 + +从Mpx仓库根目录执行定义校验: + +```sh +node node_modules/jest/bin/jest.js --config '{"rootDir":"./.agents/skills/mpx2skyline-workspace/iteration-4","testMatch":["**/validate-suite.test.cjs"],"testEnvironment":"node","transform":{}}' --runInBand --watchman=false +``` diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/assertion-migration.json b/.agents/skills/mpx2skyline-workspace/iteration-4/assertion-migration.json new file mode 100644 index 0000000000..3ee4c9b5e2 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/assertion-migration.json @@ -0,0 +1,315 @@ +{ + "from_suite": 3, + "to_suite": 4, + "old_total": 31, + "preserved": 21, + "added": 6, + "new_total": 37, + "items": [ + { + "assertion_id": "s0_00", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。", + "previous_verification": "检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。" + }, + { + "assertion_id": "s0_01", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。", + "previous_verification": "检查父子布局关系及 flex basis/width,计算两列可用宽度。" + }, + { + "assertion_id": "s0_02", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。", + "previous_verification": "追踪实际活动节点 class 与颜色声明的匹配关系。" + }, + { + "assertion_id": "s0_03", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。", + "previous_verification": "分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。" + }, + { + "assertion_id": "s0_04", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。", + "previous_verification": "检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。" + }, + { + "assertion_id": "s0_05", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。", + "previous_verification": "计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。" + }, + { + "assertion_id": "s0_06", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。", + "previous_verification": "追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。" + }, + { + "assertion_id": "s0_07", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。", + "previous_verification": "检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。" + }, + { + "assertion_id": "s0_08", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。", + "previous_verification": "结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。" + }, + { + "assertion_id": "s0_09", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。", + "previous_verification": "核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。" + }, + { + "assertion_id": "s0_10", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。", + "previous_verification": "追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。" + }, + { + "assertion_id": "s0_11", + "from_case": 0, + "to_case": 0, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。", + "previous_verification": "结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。" + }, + { + "assertion_id": "s1_00", + "from_case": 1, + "to_case": 1, + "disposition": "adapted-to-unified-page", + "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。", + "previous_text": "Skyline 页面主体使用具有明确可滚动高度的 scroll-view,显式选择type=list,订单项作为列表的直接子节点。", + "previous_verification": "检查列表直接子节点与高度约束链;使用超出容器高度的订单数据核对滚动结构。" + }, + { + "assertion_id": "s1_01", + "from_case": 1, + "to_case": 1, + "disposition": "adapted-to-unified-page", + "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。", + "previous_text": "Skyline 通过 bindrefresherrefresh 启动刷新,refresher-triggered 关联刷新状态,并在请求成功和失败后结束容器刷新态。", + "previous_verification": "触发容器刷新事件,分别模拟请求resolve/reject,检查触发态最终为false。" + }, + { + "assertion_id": "s1_02", + "from_case": 1, + "to_case": 1, + "disposition": "adapted-to-unified-page", + "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。", + "previous_text": "Skyline 通过 scroll-view 的 bindscrolltolower 连接原分页加载方法,容器触底后显示追加的订单。", + "previous_verification": "从实际模板事件绑定调用分页方法,核对下一页结果进入同一滚动列表。" + }, + { + "assertion_id": "s1_03", + "from_case": 1, + "to_case": 1, + "disposition": "adapted-to-unified-page", + "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。", + "previous_text": "Skyline 通过 scroll-view 的 bindscroll 读取 event.detail.scrollTop 并更新滚动位置展示。", + "previous_verification": "向实际滚动处理器传入detail.scrollTop,核对展示状态对应更新。" + }, + { + "assertion_id": "s1_04", + "from_case": 1, + "to_case": 1, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。", + "previous_verification": "解析页面JSON并检查真实导航节点和主体布局关系。" + }, + { + "assertion_id": "s1_05", + "from_case": 1, + "to_case": 1, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。", + "previous_verification": "解析 app.json 并检查顶层属性值。" + }, + { + "assertion_id": "s1_06", + "from_case": 1, + "to_case": 1, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。", + "previous_verification": "逐项解析五个字段的层级、类型和值。" + }, + { + "assertion_id": "s1_07", + "from_case": 4, + "to_case": 1, + "disposition": "adapted-to-unified-page", + "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。", + "previous_text": "Skyline 外层纵向滚动采用type=nested,内层滚动显式选择list/custom,并通过associative-container=nested-scroll-view建立关联。", + "previous_verification": "沿模板父子关系检查nested祖先、内层类型和关联值。", + "source_assertion_id": "s4_00" + }, + { + "assertion_id": "s1_08", + "from_case": 4, + "to_case": 1, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。", + "previous_verification": "检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。", + "source_assertion_id": "s4_01" + }, + { + "assertion_id": "s1_09", + "from_case": 4, + "to_case": 1, + "disposition": "adapted-to-unified-page", + "note": "适配同一订单页面的嵌套主区域;list类型/直接子项能力继续由s1_08横向列表及n3_01新建页面覆盖。", + "previous_text": "Skyline 分支使用sticky-section/sticky-header实现组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应的CSS sticky实现。", + "previous_verification": "分别选择renderer分支,检查sticky节点关系、背景与WebView样式;真机吸顶另记验证状态。", + "source_assertion_id": "s4_02" + }, + { + "assertion_id": "s1_10", + "from_case": 4, + "to_case": 1, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。", + "previous_verification": "追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。", + "source_assertion_id": "s4_03" + }, + { + "assertion_id": "s2_00", + "from_case": 2, + "to_case": 2, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。", + "previous_verification": "检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。" + }, + { + "assertion_id": "s2_01", + "from_case": 2, + "to_case": 2, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。", + "previous_verification": "关联模板id、组件查询作用域和select字符串,核对查询目标一致。" + }, + { + "assertion_id": "s2_02", + "from_case": 2, + "to_case": 2, + "disposition": "adapted-to-unified-component", + "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。", + "previous_text": "Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。", + "previous_verification": "从查询目标追踪其enhanced属性及node().exec后的scrollTo({top:0})调用。" + }, + { + "assertion_id": "s2_03", + "from_case": 2, + "to_case": 2, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。", + "previous_verification": "检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。" + }, + { + "assertion_id": "s2_04", + "from_case": 2, + "to_case": 2, + "disposition": "preserved", + "note": "断言ID、正文及验证方法保留;规则来源标题跟随当前Skill更新。", + "previous_text": "Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。", + "previous_verification": "检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。" + }, + { + "assertion_id": "s2_05", + "from_case": 3, + "to_case": 2, + "disposition": "adapted-to-unified-component", + "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。", + "previous_text": "Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。", + "previous_verification": "检查微信输出实际 span 容器的省略属性、图片 display、renderer 分支及父级宽度和收缩约束;使用超长标题核对图标与文字共同截断的实现路径。普通 text 的省略属性不能替代此混排容器检查。", + "source_assertion_id": "s3_00" + }, + { + "assertion_id": "s2_06", + "from_case": 3, + "to_case": 2, + "disposition": "adapted-to-unified-component", + "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。", + "previous_text": "Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。", + "previous_verification": "追踪真实圆点节点的关键帧、fill-mode与周期,确认尺寸颜色及opacity变化对应原效果。", + "source_assertion_id": "s3_01" + }, + { + "assertion_id": "s2_07", + "from_case": 3, + "to_case": 2, + "disposition": "adapted-to-unified-component", + "note": "评分正文与能力保持,验证目标统一到user-list标题、提示圆点及同一个回顶按钮。", + "previous_text": "Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。", + "previous_verification": "追踪按下/松开/取消绑定到Skyline状态及CSS,核对scale(.96)、opacity(.7)与恢复值。", + "source_assertion_id": "s3_02" + } + ], + "new_assertions": [ + "n3_00", + "n3_01", + "n3_02", + "n3_03", + "n3_04", + "n3_05" + ], + "adapted": 10, + "retained_ids": 31, + "id_renames": { + "s3_00": "s2_05", + "s3_01": "s2_06", + "s3_02": "s2_07", + "s4_00": "s1_07", + "s4_01": "s1_08", + "s4_02": "s1_09", + "s4_03": "s1_10" + } +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/eval_metadata.json new file mode 100644 index 0000000000..05c821996b --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/eval_metadata.json @@ -0,0 +1,190 @@ +{ + "eval_id": 0, + "eval_name": "style-layout", + "title": "样式与布局", + "description": "适配组件样式、间距、视觉效果及字体兼容。", + "task_type": "adaptation", + "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。", + "files": [ + "input/style-card.mpx", + "input/task.md" + ], + "assertions": [ + { + "id": "s0_00", + "text": "Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。", + "rule_id": "skyline.text-ellipsis", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "文本溢出省略适配" + }, + "verification": "检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。", + "source_assertions": [ + "e0_01", + "e0_02", + "e6_06", + "e7_08", + "e8_05" + ] + }, + { + "id": "s0_01", + "text": "Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。", + "rule_id": "skyline.equal-columns", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "布局、盒模型与层叠差异" + }, + "verification": "检查父子布局关系及 flex basis/width,计算两列可用宽度。", + "source_assertions": [ + "e0_03", + "e6_07" + ] + }, + { + "id": "s0_02", + "text": "Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。", + "rule_id": "skyline.class-selector", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "选择器支持" + }, + "verification": "追踪实际活动节点 class 与颜色声明的匹配关系。", + "source_assertions": [ + "e0_04" + ] + }, + { + "id": "s0_03", + "text": "Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。", + "rule_id": "skyline.responsive-padding", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "@media screen 替换方案" + }, + "verification": "分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。", + "source_assertions": [ + "e0_06", + "e0_07", + "e0_08" + ] + }, + { + "id": "s0_04", + "text": "Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。", + "rule_id": "skyline.parent-spacing", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "垂直 margin 折叠处理" + }, + "verification": "检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。", + "source_assertions": [ + "e5_00" + ] + }, + { + "id": "s0_05", + "text": "Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。", + "rule_id": "skyline.sibling-spacing", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "垂直 margin 折叠处理" + }, + "verification": "计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。", + "source_assertions": [ + "e5_02" + ] + }, + { + "id": "s0_06", + "text": "Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。", + "rule_id": "skyline.layered-shadows", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "背景、边框与遮罩差异" + }, + "verification": "追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。", + "source_assertions": [ + "e5_04" + ] + }, + { + "id": "s0_07", + "text": "Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。", + "rule_id": "skyline.layered-filters", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "滤镜差异" + }, + "verification": "检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。", + "source_assertions": [ + "e5_05" + ] + }, + { + "id": "s0_08", + "text": "Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。", + "rule_id": "skyline.font-resolution", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "字体 PostScript name 兼容" + }, + "verification": "结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。", + "source_assertions": [ + "e5_06", + "e5_07" + ] + }, + { + "id": "s0_09", + "text": "Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。", + "rule_id": "skyline.single-shadow", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "背景、边框与遮罩差异" + }, + "verification": "核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。", + "source_assertions": [ + "e5_03" + ] + }, + { + "id": "s0_10", + "text": "Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。", + "rule_id": "skyline.single-filter", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "滤镜差异" + }, + "verification": "追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。", + "source_assertions": [ + "e5_05" + ] + }, + { + "id": "s0_11", + "text": "Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。", + "rule_id": "skyline.content-box-width", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "非标准默认值" + }, + "verification": "结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。", + "source_assertions": [ + "e5_01" + ] + } + ] +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/style-card.mpx b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/style-card.mpx new file mode 100644 index 0000000000..11b3ff67b0 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/style-card.mpx @@ -0,0 +1,37 @@ + + + + diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/task.md new file mode 100644 index 0000000000..95108f3023 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-0-style-layout/input/task.md @@ -0,0 +1,5 @@ +# 样式与布局 + +适配 style-card.mpx。保持长标题单行省略、两列等宽标签和红色活动文案。两种renderer在屏宽≤320px时卡片padding为12rpx,否则24rpx,按当前屏宽即可。child盒子的顶部距outer上外沿20px,这段距离由outer的padding-top实现;child保持四周10px padding,因此其内容顶部距outer上外沿30px。child内容宽100px、含padding外宽120px,两块垂直间距16px;呈现原有单个rgba阴影、双阴影、独立blur滤镜、复合滤镜及品牌字体效果。宿主已配置defaultDisplayBlock/defaultContentBox。字体二进制由宿主提供,City-Semibold有当前独立字体族,Trip-Medium来自宿主;字体核验信息和机型风险写入report.md,视觉调整需沿用已确认设计。 + +交付所有输入业务文件的完整适配版本与report.md。多个组件分别保持自身接口与业务语义,无需为合并测试额外构造父子调用关系。评分目标为微信Skyline/glass-easel;WebView保持需求中的体验,其他目标分支可采用各自合法实现。验证证据放配置run-1/。 diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/eval_metadata.json new file mode 100644 index 0000000000..9771dac58a --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/eval_metadata.json @@ -0,0 +1,186 @@ +{ + "eval_id": 1, + "eval_name": "page-scroll-sticky-layer-config", + "title": "页面滚动、吸顶与层级配置", + "description": "适配单个分组订单页面,统一嵌套纵向主区域的刷新、分页、滚动监听,组内横向列表、吸顶及弹层层级。", + "task_type": "adaptation", + "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。", + "files": [ + "input/app.json", + "input/orders.mpx", + "input/service.js", + "input/task.md" + ], + "assertions": [ + { + "id": "s1_00", + "text": "Skyline 订单页面的外层与主订单纵向scroll-view均具有明确可滚动高度,概览与分组主体按嵌套层次布局,分组实际参与主滚动区域。", + "rule_id": "skyline.list-scroll", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "检查导航下方的外层高度、概览占位和主订单容器高度链,以多组数据核对主区域可滚动;具体类型及吸顶结构分别按s1_07/s1_09验证。", + "source_assertions": [ + "e1_01", + "e2_08", + "e8_04" + ] + }, + { + "id": "s1_01", + "text": "Skyline 主订单纵向scroll-view通过bindrefresherrefresh启动刷新,refresher-triggered绑定刷新状态,请求成功和失败均结束该容器刷新态。", + "rule_id": "skyline.container-refresh", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "定位承载sections的主纵向容器及刷新绑定,分别注入fetchOrders(1)成功和失败,核对刷新态复位;外层或横向容器的绑定不能替代主区域链路。", + "source_assertions": [ + "e1_02", + "e1_05", + "e8_03" + ] + }, + { + "id": "s1_02", + "text": "Skyline 主订单纵向scroll-view通过bindscrolltolower连接分页加载,触底后下一页分组追加到同一sections列表并继续展示。", + "rule_id": "skyline.container-bottom", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "从主订单容器实际触底绑定连续调用两次,核对页号推进、新分组追加和原分组保留;确认横向触底不触发纵向分页。", + "source_assertions": [ + "e1_03", + "e8_03" + ] + }, + { + "id": "s1_03", + "text": "Skyline 主订单纵向scroll-view通过bindscroll读取event.detail.scrollTop并更新概览中的滚动位置。", + "rule_id": "skyline.container-scroll", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "给主区域滚动处理器传入detail.scrollTop并核对展示;检查外层及横向滚动事件不会被误当作主订单区域位置。", + "source_assertions": [ + "e1_04" + ] + }, + { + "id": "s1_04", + "text": "Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。", + "rule_id": "skyline.page-renderer-navigation", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "适配参考" + }, + "verification": "解析页面JSON并检查真实导航节点和主体布局关系。", + "source_assertions": [ + "e1_06", + "e1_07", + "e8_06", + "e8_07" + ] + }, + { + "id": "s1_05", + "text": "Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。", + "rule_id": "skyline.lazy-components", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "app.json 顶层配置" + }, + "verification": "解析 app.json 并检查顶层属性值。", + "source_assertions": [ + "e1_08", + "e8_08" + ] + }, + { + "id": "s1_06", + "text": "Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。", + "rule_id": "skyline.renderer-baseline", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "rendererOptions.skyline 配置项" + }, + "verification": "逐项解析五个字段的层级、类型和值。", + "source_assertions": [ + "e1_09", + "e8_08" + ] + }, + { + "id": "s1_07", + "text": "Skyline 外层纵向scroll-view采用type=nested,主订单纵向容器显式选择type=custom,内层横向容器显式选择list/custom,并通过associative-container=nested-scroll-view建立嵌套关联。", + "rule_id": "skyline.nested-association", + "scope": "skyline", + "source": { + "file": "references/skyline-component-reference.md", + "section": "Skyline 必填属性与结构约束" + }, + "verification": "沿外层、主区域及横向列表的父子关系核对类型和关联;主区域的custom用于承载吸顶分组,横向列表承担订单排列。", + "source_assertions": [ + "e4_00", + "e4_01" + ] + }, + { + "id": "s1_08", + "text": "Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。", + "rule_id": "skyline.horizontal-list", + "scope": "skyline", + "source": { + "file": "references/skyline-component-reference.md", + "section": "Skyline 相对 WebView 的高频差异补充" + }, + "verification": "检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。", + "source_assertions": [ + "e4_02", + "e7_06", + "e7_07" + ] + }, + { + "id": "s1_09", + "text": "Skyline 主订单custom容器内使用sticky-section/sticky-header实现分组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应CSS sticky实现。", + "rule_id": "skyline.sticky-structure", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "sticky 吸顶替代方案" + }, + "verification": "核对主区域type=custom、每组sticky节点关系、标题背景和renderer分支;真实吸顶与嵌套手势另外记录真机验证状态。", + "source_assertions": [ + "e4_03", + "e4_04", + "e4_05" + ] + }, + { + "id": "s1_10", + "text": "Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。", + "rule_id": "skyline.fixed-layer", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "z-index 与层叠适配" + }, + "verification": "追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。", + "source_assertions": [ + "e4_06", + "e4_07" + ] + } + ] +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/app.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/app.json new file mode 100644 index 0000000000..c61fe53e69 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/app.json @@ -0,0 +1 @@ +{"pages":["pages/home","pages/orders"],"window":{"navigationBarTitleText":"演示"},"rendererOptions":{"webview":{}}} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/orders.mpx b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/orders.mpx new file mode 100644 index 0000000000..b2da500718 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/orders.mpx @@ -0,0 +1,56 @@ + + + + diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/service.js b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/service.js new file mode 100644 index 0000000000..7ca6b6bb77 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/service.js @@ -0,0 +1,11 @@ +export function fetchOrders (page, shouldFail = false) { + if (shouldFail) return Promise.reject(new Error('订单加载失败')) + return Promise.resolve(Array.from({ length: 4 }, (_, groupIndex) => ({ + id: `group-${page}-${groupIndex}`, + title: `订单分组 ${page}-${groupIndex}`, + items: Array.from({ length: 8 }, (_, index) => ({ + id: `order-${page}-${groupIndex}-${index}`, + name: `订单 ${page}-${groupIndex}-${index}` + })) + }))) +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md new file mode 100644 index 0000000000..6d469b4456 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md @@ -0,0 +1,24 @@ +# 页面滚动、吸顶与层级配置 + +将给定orders.mpx适配为完整的分组订单页面,更新app.json,保留service.js提供的数据接口。当前输入中的滚动事件仍走页面生命周期,需要将实际交互与目标滚动区域接通。所有业务在同一个页面内,范围已确认。 + +## 同一页面的布局与滚动 + +- 页面标题为“订单”,实际显示自定义导航;概览区高120px,展示主订单区域的滚动位置。 +- 导航下方为有界外层纵向滚动区域,概览可随外层滚动离开视口;内层为可独立纵向滚动的分组订单主体,内外层需要嵌套滚动关联。适配后依据页面可用高度安排滚动区,输入中的400px仅为原布局尺寸。 +- sections为[{id,title,items:[{id,name}]}]。每组标题在主订单区域内吸顶;组内横向展示订单,单项宽120px且可横向滚动。WebView和Skyline均提供对应体验。 +- 主订单纵向区域统一承接下拉刷新、触底分页和滚动位置展示。外层只承接概览与主体之间的嵌套滚动,横向区域只负责浏览该组订单。 + +## 数据与交互 + +- 初次进入调用fetchOrders(1),渲染4个分组,每组8条订单;分组和订单有稳定唯一id。 +- 主订单区域下拉刷新重新请求第1页并替换sections;刷新成功和失败都结束刷新反馈。fetchOrders(page,true)可注入失败;刷新失败保留原列表,继续操作。 +- 同一主订单区域触底时请求下一页,将新分组追加到sections;原分组与组内订单保留,页号成功后推进。 +- 主订单区域滚动时,通过概览显示该区域scrollTop;内外纵向及横向滚动的事件归属应清晰。 +- “订单说明”悬浮按钮打开全屏弹层,弹层覆盖该按钮;点击弹层关闭。 + +## 交付与验证 + +交付orders.mpx、app.json、service.js及report.md;原首页、window与WebView配置继续使用。输入中的页面滚动生命周期、CSS sticky及层级写法是待适配内容。采用适合嵌套与吸顶的滚动结构,保持上述业务语义。 + +评分目标为微信Skyline/glass-easel,WebView保留对应体验,其他平台分支可采用自身合法实现。验证刷新成功/失败、连续两次分页及主滚动位置更新,并记录真实证据到run-1/。真机嵌套滚动、吸顶与手势未验证时标记not_run。 diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/eval_metadata.json new file mode 100644 index 0000000000..1b8fd1ccad --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/eval_metadata.json @@ -0,0 +1,138 @@ +{ + "eval_id": 2, + "eval_name": "template-runtime-inline-animation", + "title": "模板运行时、图文混排与动画", + "description": "适配单个用户列表组件,将标题图文截断、提示圆点动画和回顶按钮反馈与列表数据、查询及外部模板组合为完整交互。", + "task_type": "adaptation", + "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。", + "files": [ + "input/logo.svg", + "input/row.wxml", + "input/task.md", + "input/user-list.mpx" + ], + "assertions": [ + { + "id": "s2_00", + "text": "Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。", + "rule_id": "skyline.loop-data", + "scope": "skyline", + "source": { + "file": "references/skyline-runtime-practice.md", + "section": "[必须] 确保 wx:for 数据始终为 Array 或 Object" + }, + "verification": "检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。", + "source_assertions": [ + "e2_03", + "e2_04" + ] + }, + { + "id": "s2_01", + "text": "Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。", + "rule_id": "skyline.scoped-selector", + "scope": "skyline", + "source": { + "file": "references/skyline-runtime-practice.md", + "section": "[推荐] 用 this.createSelectorQuery 替代 wx.createSelectorQuery" + }, + "verification": "关联模板id、组件查询作用域和select字符串,核对查询目标一致。", + "source_assertions": [ + "e2_05", + "e2_07" + ] + }, + { + "id": "s2_02", + "text": "Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。", + "rule_id": "skyline.scroll-context", + "scope": "skyline", + "source": { + "file": "references/skyline-runtime-practice.md", + "section": "[必须] ScrollViewContext:开启 enhanced 属性" + }, + "verification": "从user-list.mpx实际回顶按钮的点击绑定追踪查询目标、enhanced属性及node().exec后的scrollTo({top:0})调用,确认不是other容器。", + "source_assertions": [ + "e2_06" + ] + }, + { + "id": "s2_03", + "text": "Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。", + "rule_id": "skyline.loop-template", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "[必须] wx:for 内嵌 <include> 时改为 <template>" + }, + "verification": "检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。", + "source_assertions": [ + "e2_09" + ] + }, + { + "id": "s2_04", + "text": "Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。", + "rule_id": "skyline.navigator-children", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "navigator 嵌套限制" + }, + "verification": "检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。", + "source_assertions": [ + "e5_08", + "e5_09" + ] + }, + { + "id": "s2_05", + "text": "Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。", + "rule_id": "skyline.inline-flow", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "图文混排" + }, + "verification": "检查user-list.mpx标题中logo与label共同承载的实际span、省略属性、图片display及renderer路径和宽度约束;使用长label核对两者共同截断。", + "source_assertions": [ + "e3_00", + "e3_01", + "e3_02", + "e3_03" + ] + }, + { + "id": "s2_06", + "text": "Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。", + "rule_id": "skyline.node-animation", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "动画与过渡差异" + }, + "verification": "追踪user-list.mpx提示圆点的真实节点、关键帧、fill-mode与1秒周期,核对8px、#f50及opacity .3到1。", + "source_assertions": [ + "e3_04", + "e3_05" + ] + }, + { + "id": "s2_07", + "text": "Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。", + "rule_id": "skyline.state-transition", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "animation API 不支持 → 使用 CSS transition" + }, + "verification": "追踪user-list.mpx同一个回顶按钮的按下/松开/取消绑定到状态类和CSS,核对150ms、scale(.96)/opacity(.7)及恢复值;点击回顶链路另由s2_02验证。", + "source_assertions": [ + "e3_06", + "e3_07", + "e3_08", + "e6_08" + ] + } + ] +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/logo.svg b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/logo.svg new file mode 100644 index 0000000000..6ba82ab4ea --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/logo.svg @@ -0,0 +1 @@ + diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/row.wxml b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/row.wxml new file mode 100644 index 0000000000..2b7eb9185e --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/row.wxml @@ -0,0 +1 @@ +{{index}}:{{item.name}} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/task.md new file mode 100644 index 0000000000..b37a139245 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/task.md @@ -0,0 +1,18 @@ +# 模板运行时、图文混排与动画 + +将给定user-list.mpx适配为完整的用户列表组件,同时处理标题图文、提示圆点及回到顶部按钮的交互反馈。row.wxml是循环内使用的外部行片段,logo.svg是标题图标;两者继续作为组件资源交付。宿主页已接入Skyline/glass-easel,范围已确认。 + +## 一个组件内的完整交互 + +- 组件标题为label,允许长文案;图标和label在同一行展示,并在可用宽度不足时作为同段图文共同单行截断。 +- 标题旁的提示圆点保持8px、#f50,按原1秒周期在透明度0.3与1之间循环变化。 +- setRows接收{items:Array|null};初次渲染、数据返回前及null时显示空列表,正常数据仅展示visible用户。每行通过外部row.wxml展示过滤后行号与姓名。 +- “回到顶部”是同一个可按压按钮:按下缩放0.96且透明度0.7,松开或取消恢复1,过渡150ms;点击后操作实际用户列表滚回顶部。旁边other滚动容器用于区分查询目标。 +- 两个详情入口均到/pages/detail:一个是简单文本入口,一个是卡片内容入口,均保持可用。 +- 保留label/payload接口及config.default数据。现有数字开头id、include循环片段、未保护的循环数据、伪元素动画和动画API是待适配内容。 + +## 交付与验证 + +交付user-list.mpx、row.wxml、logo.svg及report.md。所有模板、运行时查询、图文与动画适配都在这一个组件及其外部片段中完成。 + +评分目标为微信Skyline/glass-easel;WebView保持对应体验,其他平台分支可采用自身合法实现。验证初始化/null/数组更新、过滤行数据、实际查询目标及回顶调用、两个详情跳转、长label共同截断、按下/松开/取消状态。测试和审计证据放run-1/;真机渲染与实际滚动未验证时标记not_run。 diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/user-list.mpx b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/user-list.mpx new file mode 100644 index 0000000000..2df19142c6 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-2-template-runtime-inline-animation/input/user-list.mpx @@ -0,0 +1,57 @@ + + + + diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/eval_metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/eval_metadata.json new file mode 100644 index 0000000000..544dfb8807 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/eval_metadata.json @@ -0,0 +1,106 @@ +{ + "eval_id": 3, + "eval_name": "new-task-board-page", + "title": "从零创建任务看板页面", + "description": "仅给定产品需求和宿主配置,验证从零选择Skyline页面、滚动、文本及状态动画方案。通用语法和业务功能单独验证。", + "task_type": "creation", + "prompt": "请读取input/task.md,根据产品需求从零创建Mpx任务看板页面并更新宿主配置,兼容微信Skyline与WebView。范围已确认,交付完整文件和验证报告。", + "files": [ + "input/app.json", + "input/task.md" + ], + "assertions": [ + { + "id": "n3_00", + "text": "Skyline 新页面配置renderer=skyline、componentFramework=glass-easel、navigationStyle=custom和disableScroll=true,实际呈现任务看板导航;app顶层lazyCodeLoading及rendererOptions.skyline五项推荐配置完整。", + "rule_id": "skyline.creation-page-config", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "适配参考" + }, + "verification": "解析页面与app配置,逐项核对requiredComponents及defaultDisplayBlock/defaultContentBox/enableScrollViewAutoSize=true、tagNameStyleIsolation/keyframeStyleIsolation=legacy,检查实际导航节点。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_04", + "s1_05", + "s1_06" + ] + }, + { + "id": "n3_01", + "text": "Skyline 新页面通过有明确高度约束的type=list纵向scroll-view承载任务,任务项为直接子节点,标题及筛选区位于滚动主体之外。", + "rule_id": "skyline.creation-scroll-layout", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "检查父子高度与Flex收缩链、scroll-y及列表直接子节点;以超出一屏的任务验证有界滚动布局。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_00" + ] + }, + { + "id": "n3_02", + "text": "Skyline 新页面将下拉刷新接到scroll-view的bindrefresherrefresh,refresher-triggered绑定状态,成功及失败路径均结束容器刷新态。", + "rule_id": "skyline.creation-refresh", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "沿实际事件绑定触发刷新,注入resolve/reject,核对刷新态最终false且容器可继续操作。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_01" + ] + }, + { + "id": "n3_03", + "text": "Skyline 新页面将scroll-view的bindscrolltolower接入分页追加,每次容器触底后新任务进入同一滚动列表。", + "rule_id": "skyline.creation-pagination", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "从实际模板触底绑定调用处理器两次,核对每次新增2条且原列表保留;分类和唯一键另作业务验证。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_02" + ] + }, + { + "id": "n3_04", + "text": "Skyline 新页面长任务标题在实际text承载节点设置max-lines=1、overflow=ellipsis,并在有界可收缩宽度内与WebView单行省略路径共同生效。", + "rule_id": "skyline.creation-title-ellipsis", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "文本溢出省略适配" + }, + "verification": "检查text属性、父级宽度/收缩约束和WebView样式;代入长标题审查两种renderer的实际截断路径。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s0_00" + ] + }, + { + "id": "n3_05", + "text": "Skyline 新页面分类按钮通过状态类驱动transform/opacity的150ms CSS transition,按下达到scale(.96)/opacity(.7),松开和取消均恢复1。", + "rule_id": "skyline.creation-press-feedback", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "animation API 不支持 → 使用 CSS transition" + }, + "verification": "追踪真实触摸绑定到响应状态和CSS,分别模拟按下/松开/取消,核对数值、持续时间和恢复。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s2_07" + ] + } + ] +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/app.json b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/app.json new file mode 100644 index 0000000000..4494c3e852 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/app.json @@ -0,0 +1,11 @@ +{ + "pages": [ + "pages/home" + ], + "window": { + "navigationBarTitleText": "演示" + }, + "rendererOptions": { + "webview": {} + } +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/task.md b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/task.md new file mode 100644 index 0000000000..4112f37b6d --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/eval-3-new-task-board-page/input/task.md @@ -0,0 +1,19 @@ +# 从零创建任务看板页面 + +没有现成页面代码。请根据以下产品需求从零创建 pages/task-board.mpx,并交付更新后的 app.json。页面面向微信 Skyline/glass-easel,同时保持微信 WebView 的对应体验。范围已确认,宿主首页继续保留。 + +## 数据与交互 + +- 初始任务为[{taskKey:'t1',title:'整理本周跨团队协作事项与上线验收清单',category:'工作',completed:false},{taskKey:'t2',title:'购买周末出行用品',category:'生活',completed:false},{taskKey:'t3',title:'完成每日阅读',category:'生活',completed:true}]。 +- 顶部显示“任务看板”和当前筛选结果数量,提供“全部/工作/生活”分类,当前分类有选中态。通过页面category参数选择初始分类,非法值回到全部。 +- 点击任务切换完成状态;无匹配任务时显示“暂无任务”。标题无论多长都显示一行,超出部分省略。 +- 页面主体数据增多时可纵向滚动,顶部标题和筛选区域保持可见;窄屏仍有明确的滚动区域。 +- 下拉刷新恢复初始任务。模拟异步请求,并提供可注入失败的测试入口;请求结束后刷新反馈结束,失败时原列表仍可继续使用。 +- 滚动到底部追加2条当前分类的未完成任务,使用唯一taskKey;全部分类时追加工作任务。每次触底后列表继续显示已存在任务。 +- 分类按钮按下时缩放到0.96、透明度0.7,松开或取消恢复1;过渡150ms。 + +## 实现与交付 + +使用Mpx组合式API及script setup,样式使用组件内语义class。宿主未提供原子CSS工具链。通过所给app.json接入页面,保留首页和现有window/WebView设置;页面配置与导航由你完成,确保可用于Skyline和WebView。 + +交付pages/task-board.mpx、app.json及report.md。记录真实验证及未执行项;测试与证据放配置run-1/。验证内容包括参数初始化、筛选、完成状态、空列表、刷新成功/失败、连续分页及触摸取消。当前专项评分只评价Skyline适配要求,通用Mpx语法与业务行为单独验证。其他目标平台可采用自身合法分支。 diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/evals.json b/.agents/skills/mpx2skyline-workspace/iteration-4/evals.json new file mode 100644 index 0000000000..977c47d8e1 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/evals.json @@ -0,0 +1,675 @@ +{ + "skill_name": "mpx2skyline", + "suite_version": 4, + "iteration": 4, + "status": "cases-ready-not-run", + "description": "4个case:三个存量适配综合场景和一个从零创建页面场景,共37条Skyline正向断言。", + "scoring_scope": "仅评价微信Skyline/glass-easel实际生效实现,WebView仅用于对应兼容要求;RN分支按自身规则实现。", + "comparison": { + "purpose": "独立Skill与合并Skill在同一新版测试集上的不劣化比较", + "groups": [ + { + "id": "mpx2skyline", + "skill": ".agents/skills/mpx2skyline/SKILL.md", + "status": "not_run" + }, + { + "id": "no_skill", + "skill": null, + "status": "not_run" + }, + { + "id": "merged_skill", + "skill": null, + "status": "path-to-be-specified-before-execution" + } + ] + }, + "runner": { + "prompt_templates": "prompt_templates.json", + "grading_standard": "grading-standard.md", + "subagent_config": { + "model": "must_match_parent", + "reasoning_effort": "must_match_parent", + "fork_turns": "none" + } + }, + "evals": [ + { + "id": 0, + "name": "style-layout", + "title": "样式与布局", + "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。", + "files": [ + "input/style-card.mpx", + "input/task.md" + ], + "assertions": [ + { + "id": "s0_00", + "text": "Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。", + "rule_id": "skyline.text-ellipsis", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "文本溢出省略适配" + }, + "verification": "检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。", + "source_assertions": [ + "e0_01", + "e0_02", + "e6_06", + "e7_08", + "e8_05" + ] + }, + { + "id": "s0_01", + "text": "Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。", + "rule_id": "skyline.equal-columns", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "布局、盒模型与层叠差异" + }, + "verification": "检查父子布局关系及 flex basis/width,计算两列可用宽度。", + "source_assertions": [ + "e0_03", + "e6_07" + ] + }, + { + "id": "s0_02", + "text": "Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。", + "rule_id": "skyline.class-selector", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "选择器支持" + }, + "verification": "追踪实际活动节点 class 与颜色声明的匹配关系。", + "source_assertions": [ + "e0_04" + ] + }, + { + "id": "s0_03", + "text": "Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。", + "rule_id": "skyline.responsive-padding", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "@media screen 替换方案" + }, + "verification": "分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。", + "source_assertions": [ + "e0_06", + "e0_07", + "e0_08" + ] + }, + { + "id": "s0_04", + "text": "Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。", + "rule_id": "skyline.parent-spacing", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "垂直 margin 折叠处理" + }, + "verification": "检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。", + "source_assertions": [ + "e5_00" + ] + }, + { + "id": "s0_05", + "text": "Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。", + "rule_id": "skyline.sibling-spacing", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "垂直 margin 折叠处理" + }, + "verification": "计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。", + "source_assertions": [ + "e5_02" + ] + }, + { + "id": "s0_06", + "text": "Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。", + "rule_id": "skyline.layered-shadows", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "背景、边框与遮罩差异" + }, + "verification": "追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。", + "source_assertions": [ + "e5_04" + ] + }, + { + "id": "s0_07", + "text": "Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。", + "rule_id": "skyline.layered-filters", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "滤镜差异" + }, + "verification": "检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。", + "source_assertions": [ + "e5_05" + ] + }, + { + "id": "s0_08", + "text": "Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。", + "rule_id": "skyline.font-resolution", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "字体 PostScript name 兼容" + }, + "verification": "结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。", + "source_assertions": [ + "e5_06", + "e5_07" + ] + }, + { + "id": "s0_09", + "text": "Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。", + "rule_id": "skyline.single-shadow", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "背景、边框与遮罩差异" + }, + "verification": "核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。", + "source_assertions": [ + "e5_03" + ] + }, + { + "id": "s0_10", + "text": "Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。", + "rule_id": "skyline.single-filter", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "滤镜差异" + }, + "verification": "追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。", + "source_assertions": [ + "e5_05" + ] + }, + { + "id": "s0_11", + "text": "Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。", + "rule_id": "skyline.content-box-width", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "非标准默认值" + }, + "verification": "结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。", + "source_assertions": [ + "e5_01" + ] + } + ], + "description": "适配组件样式、间距、视觉效果及字体兼容。", + "task_type": "adaptation", + "source_cases": [ + 0 + ] + }, + { + "id": 1, + "name": "page-scroll-sticky-layer-config", + "title": "页面滚动、吸顶与层级配置", + "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。", + "files": [ + "input/app.json", + "input/orders.mpx", + "input/service.js", + "input/task.md" + ], + "assertions": [ + { + "id": "s1_00", + "text": "Skyline 订单页面的外层与主订单纵向scroll-view均具有明确可滚动高度,概览与分组主体按嵌套层次布局,分组实际参与主滚动区域。", + "rule_id": "skyline.list-scroll", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "检查导航下方的外层高度、概览占位和主订单容器高度链,以多组数据核对主区域可滚动;具体类型及吸顶结构分别按s1_07/s1_09验证。", + "source_assertions": [ + "e1_01", + "e2_08", + "e8_04" + ] + }, + { + "id": "s1_01", + "text": "Skyline 主订单纵向scroll-view通过bindrefresherrefresh启动刷新,refresher-triggered绑定刷新状态,请求成功和失败均结束该容器刷新态。", + "rule_id": "skyline.container-refresh", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "定位承载sections的主纵向容器及刷新绑定,分别注入fetchOrders(1)成功和失败,核对刷新态复位;外层或横向容器的绑定不能替代主区域链路。", + "source_assertions": [ + "e1_02", + "e1_05", + "e8_03" + ] + }, + { + "id": "s1_02", + "text": "Skyline 主订单纵向scroll-view通过bindscrolltolower连接分页加载,触底后下一页分组追加到同一sections列表并继续展示。", + "rule_id": "skyline.container-bottom", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "从主订单容器实际触底绑定连续调用两次,核对页号推进、新分组追加和原分组保留;确认横向触底不触发纵向分页。", + "source_assertions": [ + "e1_03", + "e8_03" + ] + }, + { + "id": "s1_03", + "text": "Skyline 主订单纵向scroll-view通过bindscroll读取event.detail.scrollTop并更新概览中的滚动位置。", + "rule_id": "skyline.container-scroll", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "给主区域滚动处理器传入detail.scrollTop并核对展示;检查外层及横向滚动事件不会被误当作主订单区域位置。", + "source_assertions": [ + "e1_04" + ] + }, + { + "id": "s1_04", + "text": "Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。", + "rule_id": "skyline.page-renderer-navigation", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "适配参考" + }, + "verification": "解析页面JSON并检查真实导航节点和主体布局关系。", + "source_assertions": [ + "e1_06", + "e1_07", + "e8_06", + "e8_07" + ] + }, + { + "id": "s1_05", + "text": "Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。", + "rule_id": "skyline.lazy-components", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "app.json 顶层配置" + }, + "verification": "解析 app.json 并检查顶层属性值。", + "source_assertions": [ + "e1_08", + "e8_08" + ] + }, + { + "id": "s1_06", + "text": "Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。", + "rule_id": "skyline.renderer-baseline", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "rendererOptions.skyline 配置项" + }, + "verification": "逐项解析五个字段的层级、类型和值。", + "source_assertions": [ + "e1_09", + "e8_08" + ] + }, + { + "id": "s1_07", + "text": "Skyline 外层纵向scroll-view采用type=nested,主订单纵向容器显式选择type=custom,内层横向容器显式选择list/custom,并通过associative-container=nested-scroll-view建立嵌套关联。", + "rule_id": "skyline.nested-association", + "scope": "skyline", + "source": { + "file": "references/skyline-component-reference.md", + "section": "Skyline 必填属性与结构约束" + }, + "verification": "沿外层、主区域及横向列表的父子关系核对类型和关联;主区域的custom用于承载吸顶分组,横向列表承担订单排列。", + "source_assertions": [ + "e4_00", + "e4_01" + ] + }, + { + "id": "s1_08", + "text": "Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。", + "rule_id": "skyline.horizontal-list", + "scope": "skyline", + "source": { + "file": "references/skyline-component-reference.md", + "section": "Skyline 相对 WebView 的高频差异补充" + }, + "verification": "检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。", + "source_assertions": [ + "e4_02", + "e7_06", + "e7_07" + ] + }, + { + "id": "s1_09", + "text": "Skyline 主订单custom容器内使用sticky-section/sticky-header实现分组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应CSS sticky实现。", + "rule_id": "skyline.sticky-structure", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "sticky 吸顶替代方案" + }, + "verification": "核对主区域type=custom、每组sticky节点关系、标题背景和renderer分支;真实吸顶与嵌套手势另外记录真机验证状态。", + "source_assertions": [ + "e4_03", + "e4_04", + "e4_05" + ] + }, + { + "id": "s1_10", + "text": "Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。", + "rule_id": "skyline.fixed-layer", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "z-index 与层叠适配" + }, + "verification": "追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。", + "source_assertions": [ + "e4_06", + "e4_07" + ] + } + ], + "description": "适配单个分组订单页面,统一嵌套纵向主区域的刷新、分页、滚动监听,组内横向列表、吸顶及弹层层级。", + "task_type": "adaptation", + "source_cases": [ + 1, + 4 + ] + }, + { + "id": 2, + "name": "template-runtime-inline-animation", + "title": "模板运行时、图文混排与动画", + "prompt": "请按input/task.md将给定Mpx文件适配到微信Skyline,保持要求中的WebView体验,输出完整文件和验证报告。范围和交互已确认。", + "files": [ + "input/logo.svg", + "input/row.wxml", + "input/task.md", + "input/user-list.mpx" + ], + "assertions": [ + { + "id": "s2_00", + "text": "Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。", + "rule_id": "skyline.loop-data", + "scope": "skyline", + "source": { + "file": "references/skyline-runtime-practice.md", + "section": "[必须] 确保 wx:for 数据始终为 Array 或 Object" + }, + "verification": "检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。", + "source_assertions": [ + "e2_03", + "e2_04" + ] + }, + { + "id": "s2_01", + "text": "Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。", + "rule_id": "skyline.scoped-selector", + "scope": "skyline", + "source": { + "file": "references/skyline-runtime-practice.md", + "section": "[推荐] 用 this.createSelectorQuery 替代 wx.createSelectorQuery" + }, + "verification": "关联模板id、组件查询作用域和select字符串,核对查询目标一致。", + "source_assertions": [ + "e2_05", + "e2_07" + ] + }, + { + "id": "s2_02", + "text": "Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。", + "rule_id": "skyline.scroll-context", + "scope": "skyline", + "source": { + "file": "references/skyline-runtime-practice.md", + "section": "[必须] ScrollViewContext:开启 enhanced 属性" + }, + "verification": "从user-list.mpx实际回顶按钮的点击绑定追踪查询目标、enhanced属性及node().exec后的scrollTo({top:0})调用,确认不是other容器。", + "source_assertions": [ + "e2_06" + ] + }, + { + "id": "s2_03", + "text": "Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。", + "rule_id": "skyline.loop-template", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "[必须] wx:for 内嵌 <include> 时改为 <template>" + }, + "verification": "检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。", + "source_assertions": [ + "e2_09" + ] + }, + { + "id": "s2_04", + "text": "Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。", + "rule_id": "skyline.navigator-children", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "navigator 嵌套限制" + }, + "verification": "检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。", + "source_assertions": [ + "e5_08", + "e5_09" + ] + }, + { + "id": "s2_05", + "text": "Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。", + "rule_id": "skyline.inline-flow", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "图文混排" + }, + "verification": "检查user-list.mpx标题中logo与label共同承载的实际span、省略属性、图片display及renderer路径和宽度约束;使用长label核对两者共同截断。", + "source_assertions": [ + "e3_00", + "e3_01", + "e3_02", + "e3_03" + ] + }, + { + "id": "s2_06", + "text": "Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。", + "rule_id": "skyline.node-animation", + "scope": "skyline", + "source": { + "file": "references/skyline-style-reference.md", + "section": "动画与过渡差异" + }, + "verification": "追踪user-list.mpx提示圆点的真实节点、关键帧、fill-mode与1秒周期,核对8px、#f50及opacity .3到1。", + "source_assertions": [ + "e3_04", + "e3_05" + ] + }, + { + "id": "s2_07", + "text": "Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。", + "rule_id": "skyline.state-transition", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "animation API 不支持 → 使用 CSS transition" + }, + "verification": "追踪user-list.mpx同一个回顶按钮的按下/松开/取消绑定到状态类和CSS,核对150ms、scale(.96)/opacity(.7)及恢复值;点击回顶链路另由s2_02验证。", + "source_assertions": [ + "e3_06", + "e3_07", + "e3_08", + "e6_08" + ] + } + ], + "description": "适配单个用户列表组件,将标题图文截断、提示圆点动画和回顶按钮反馈与列表数据、查询及外部模板组合为完整交互。", + "task_type": "adaptation", + "source_cases": [ + 2, + 3 + ] + }, + { + "id": 3, + "name": "new-task-board-page", + "title": "从零创建任务看板页面", + "description": "仅给定产品需求和宿主配置,验证从零选择Skyline页面、滚动、文本及状态动画方案。通用语法和业务功能单独验证。", + "task_type": "creation", + "prompt": "请读取input/task.md,根据产品需求从零创建Mpx任务看板页面并更新宿主配置,兼容微信Skyline与WebView。范围已确认,交付完整文件和验证报告。", + "files": [ + "input/app.json", + "input/task.md" + ], + "assertions": [ + { + "id": "n3_00", + "text": "Skyline 新页面配置renderer=skyline、componentFramework=glass-easel、navigationStyle=custom和disableScroll=true,实际呈现任务看板导航;app顶层lazyCodeLoading及rendererOptions.skyline五项推荐配置完整。", + "rule_id": "skyline.creation-page-config", + "scope": "skyline", + "source": { + "file": "references/skyline-configuration.md", + "section": "适配参考" + }, + "verification": "解析页面与app配置,逐项核对requiredComponents及defaultDisplayBlock/defaultContentBox/enableScrollViewAutoSize=true、tagNameStyleIsolation/keyframeStyleIsolation=legacy,检查实际导航节点。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_04", + "s1_05", + "s1_06" + ] + }, + { + "id": "n3_01", + "text": "Skyline 新页面通过有明确高度约束的type=list纵向scroll-view承载任务,任务项为直接子节点,标题及筛选区位于滚动主体之外。", + "rule_id": "skyline.creation-scroll-layout", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "检查父子高度与Flex收缩链、scroll-y及列表直接子节点;以超出一屏的任务验证有界滚动布局。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_00" + ] + }, + { + "id": "n3_02", + "text": "Skyline 新页面将下拉刷新接到scroll-view的bindrefresherrefresh,refresher-triggered绑定状态,成功及失败路径均结束容器刷新态。", + "rule_id": "skyline.creation-refresh", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "沿实际事件绑定触发刷新,注入resolve/reject,核对刷新态最终false且容器可继续操作。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_01" + ] + }, + { + "id": "n3_03", + "text": "Skyline 新页面将scroll-view的bindscrolltolower接入分页追加,每次容器触底后新任务进入同一滚动列表。", + "rule_id": "skyline.creation-pagination", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "页面滚动替代方案" + }, + "verification": "从实际模板触底绑定调用处理器两次,核对每次新增2条且原列表保留;分类和唯一键另作业务验证。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s1_02" + ] + }, + { + "id": "n3_04", + "text": "Skyline 新页面长任务标题在实际text承载节点设置max-lines=1、overflow=ellipsis,并在有界可收缩宽度内与WebView单行省略路径共同生效。", + "rule_id": "skyline.creation-title-ellipsis", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "文本溢出省略适配" + }, + "verification": "检查text属性、父级宽度/收缩约束和WebView样式;代入长标题审查两种renderer的实际截断路径。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s0_00" + ] + }, + { + "id": "n3_05", + "text": "Skyline 新页面分类按钮通过状态类驱动transform/opacity的150ms CSS transition,按下达到scale(.96)/opacity(.7),松开和取消均恢复1。", + "rule_id": "skyline.creation-press-feedback", + "scope": "skyline", + "source": { + "file": "references/skyline-layout-practice.md", + "section": "animation API 不支持 → 使用 CSS transition" + }, + "verification": "追踪真实触摸绑定到响应状态和CSS,分别模拟按下/松开/取消,核对数值、持续时间和恢复。", + "source_assertions": [], + "related_adaptation_assertions": [ + "s2_07" + ] + } + ], + "design_references": [ + "mpx2rn-workspace/iteration-17/eval-6-new-rating-component", + "mpx2rn-workspace/iteration-17/eval-7-new-segmented-control", + "mpx2rn-workspace/iteration-17/eval-8-new-task-board-page" + ] + } + ] +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/fixture-provenance.json b/.agents/skills/mpx2skyline-workspace/iteration-4/fixture-provenance.json new file mode 100644 index 0000000000..c156b8b171 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/fixture-provenance.json @@ -0,0 +1,8 @@ +{ + "note": "保留未改造业务输入的原始哈希;case 1页面及case 2组件已按合并需求重组,由语义测试验证。", + "files": { + "eval-0-style-layout/input/style-card.mpx": "02971adbcf26eea73fdb3b249f04307a3cd9dc86e35d0db4a3890fc700c50370", + "eval-2-template-runtime-inline-animation/input/logo.svg": "c71a85400c9d1bc64393103364611c9370076caec60d65bc20fdcfdd97f6d29d", + "eval-2-template-runtime-inline-animation/input/row.wxml": "80f43cf55dbaf032920128f167d8b324b588e4dc01cbaa66e5f4063c394c876d" + } +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/grading-standard.md b/.agents/skills/mpx2skyline-workspace/iteration-4/grading-standard.md new file mode 100644 index 0000000000..d53884509c --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/grading-standard.md @@ -0,0 +1,21 @@ +# Skyline 专项评分标准 v4 + +4个case,共37条正向断言,分母依次为12、11、8、6。evals.json是唯一评分定义,各eval_metadata.json保持一致。 + +仅评价实际微信Skyline/glass-easel路径;WebView按明确的兼容要求检查,RN分支可采用自身合法实现。每条满足全部条件得1分,证据不足得0分。允许规则支持的语义等价实现;按verification追踪真实节点与执行链路。 + +原31条适配断言保留覆盖目标;case 1的6条滚动断言按统一页面修订,case 2的4条验证方法明确指向统一组件中的实际节点,迁移表保留前版内容。新增6条创建断言用于验证“需求到方案”的独立入口,与迁移case共享能力规则但不同任务触发;related_adaptation_assertions显式标记对应能力,不能宣称37条是37种互不重叠的能力。每个case内部按不同适配结果计分。case 1的主订单区域使用custom承载吸顶,外层nested负责嵌套,横向list/custom负责组内订单;刷新、分页和位置监听都验证主区域的真实绑定。另列迁移31条和创建6条分数,避免综合分掩盖任一入口劣化。 + +交付完整性、props/API/script setup/defineExpose语法、页面注册、参数筛选、普通状态与事件、稳定key及资源完整性记录于validation.json,不单独占Skyline分数。真实编译错误使目标实现不可执行时,对应断言仍失败。 + +新建case实际执行参数初始化、空分类、完成切换、刷新成功/失败、两次分页与触摸取消的业务验证;事件与Skyline容器/动画的衔接按专项断言评分。静态或mock通过不等于真机通过。应用构建、微信模板编译、真机渲染分别记录,未执行为not_run。 + +产物位于eval-*//outputs/;评分、验证、执行、耗时和Token证据位于run-1/。输入统一读取eval-*/input/,Skill读取中央路径,记录执行前后输入和Skill版本/哈希,缺失Token/精确耗时用unavailable。 + +独立Skill、no_skill及未来合并Skill采用相同输入、模型参数和验证方式,只有Skill读取权限不同。比较逐条通过转失败及分入口分数;本版尚未执行,不复用iteration-3分数。 + +case 2的外部row.wxml与logo.svg继续保留,以验证外部模板作用域与真实图文混排;回顶按钮的查询结果和CSS反馈分别计分,所有证据应来自同一个user-list组件。 + +Case 2断言统一编号为s2_00–s2_07;原s3_00/s3_01/s3_02依次迁移为s2_05/s2_06/s2_07,旧ID保存在迁移表source_assertion_id中。断言正文及验证方法不变。 + +Case 1断言统一编号为s1_00–s1_10;原s4_00/s4_01/s4_02/s4_03依次迁移为s1_07/s1_08/s1_09/s1_10,旧ID保存在迁移表source_assertion_id中。评分要求不变。 diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/prompt_templates.json b/.agents/skills/mpx2skyline-workspace/iteration-4/prompt_templates.json new file mode 100644 index 0000000000..f1a7da4fba --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/prompt_templates.json @@ -0,0 +1,16 @@ +{ + "variables": { + "TASK_PROMPT": "eval.prompt", + "INPUT_PATHS": "当前eval外层input文件绝对路径;共享读取", + "OUTPUT_DIR": "eval-*//outputs绝对路径", + "WORKDIR": "eval-*//run-1绝对路径", + "SKILL_PATH": "当前配置中央Skill路径;执行前指定" + }, + "template": "任务:{{TASK_PROMPT}}\n输入:{{INPUT_PATHS}},先读task.md。\n先完整读取{{SKILL_PATH}},按需阅读关联参考。当前目标是微信Skyline/glass-easel,其他平台分支可采用各自合法实现。\n工作目录:{{WORKDIR}};业务产物与report.md写入{{OUTPUT_DIR}},测试和审计证据放工作目录。输入和Skill共享只读,不复制到run目录。\n仅读取任务输入及当前配置允许的Skill,保持评分文件和历史产物隔离。范围已确认,直接实施。记录真实验证与未验证项,单测失败最多尝试3次修复。", + "archive_rules": [ + "执行前后记录输入、Skill逐文件哈希和模型参数。", + "产物完整性、语法编译、业务回归另记validation.json;Skyline得分仅来自evals.json。", + "独立Skill与合并Skill采用同一模板、输入、模型参数和验证方法。" + ], + "no_skill_template": "任务:{{TASK_PROMPT}}\n输入:{{INPUT_PATHS}},先读task.md。\n本组不读取任何Skill或Skill参考资料,仅依据输入和已有知识完成。当前目标是微信Skyline/glass-easel,其他平台分支可采用各自合法实现。\n工作目录:{{WORKDIR}};业务产物与report.md写入{{OUTPUT_DIR}},测试和审计证据放工作目录。输入和Skill共享只读,不复制到run目录。\n仅读取任务输入及当前配置允许的Skill,保持评分文件和历史产物隔离。范围已确认,直接实施。记录真实验证与未验证项,单测失败最多尝试3次修复。" +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/run-metadata.json b/.agents/skills/mpx2skyline-workspace/iteration-4/run-metadata.json new file mode 100644 index 0000000000..d83027fd64 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/run-metadata.json @@ -0,0 +1,8 @@ +{ + "status": "not_run", + "suite_version": 4, + "cases": 4, + "assertions": 37, + "historical_baseline": "../iteration-3", + "baseline_reuse": "合并任务改变上下文,新建任务增加创建入口;新版需重新执行两组,旧评分不迁移。" +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/source-snapshot.json b/.agents/skills/mpx2skyline-workspace/iteration-4/source-snapshot.json new file mode 100644 index 0000000000..61c2d14567 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/source-snapshot.json @@ -0,0 +1,30 @@ +{ + "status": "definition-only", + "files": { + "run-metadata.json": "af00d55a3dcfc624e1936da6d8d2b4e8a1099b25c7de3ac2c9c270085b0eef41", + "fixture-provenance.json": "765bc5058b6e0703b68094c00a1dd00b508b899b1d4c32f75b36d381091adf32", + "grading-standard.md": "7f451565d85d3f1f0a1a4f8133a46ba6defd99f81ede9d08bd341ed47312b952", + "evals.json": "69cd93daf51ff3e3da3a7d5c02e0e7063f89319921e849abd9e8c01b200dcecb", + "prompt_templates.json": "34504f40ce661883354785a1091cba0c7dc3e793898d1c8a99f36bf1f631051a", + "README.md": "e5dad33a70648d452b99221e64e152373f28f934622522eccb12efb13b5f100b", + "assertion-migration.json": "6fc54abc5f97a583ed48f5fdf62e79dd5cae65f031e50faf155d068993a57f77", + "validate-suite.test.cjs": "5dff42924895d258a1d7e7028cc6d1a75b238d2511507f9500914e11e84f5c8c", + "eval-3-new-task-board-page/eval_metadata.json": "092dc91a23645b36e05913857ff54cb1f45985b3a36e67f2693c832b307ed85f", + "eval-1-page-scroll-sticky-layer-config/eval_metadata.json": "1615c69f86f8f983af32b8d733fd02dd39dd6beec977385398cca36ef05f452a", + "eval-0-style-layout/eval_metadata.json": "d83839636bcc95b3c81cc0c4cfbeb64608e3802b6da945bd9024841927655962", + "eval-2-template-runtime-inline-animation/eval_metadata.json": "970d2b8dfd396cb274b0dfd8034fb8e28c2c10a2699851ab196e80f90d13a0cb", + "eval-2-template-runtime-inline-animation/input/row.wxml": "80f43cf55dbaf032920128f167d8b324b588e4dc01cbaa66e5f4063c394c876d", + "eval-2-template-runtime-inline-animation/input/user-list.mpx": "508fe0ecaa078cb526de50a5d8a0be13209401ee36feed974fea1c450f422e11", + "eval-2-template-runtime-inline-animation/input/task.md": "820cd9daddb3bdb88cb7ef386f42ab63385953ac528be86b15e768875bf17c38", + "eval-2-template-runtime-inline-animation/input/logo.svg": "c71a85400c9d1bc64393103364611c9370076caec60d65bc20fdcfdd97f6d29d", + "eval-0-style-layout/input/style-card.mpx": "02971adbcf26eea73fdb3b249f04307a3cd9dc86e35d0db4a3890fc700c50370", + "eval-0-style-layout/input/task.md": "2d3e10c639fd4715bdcd80fe4a221519a80f4cd9c5d7ed49a709ee335c01ca5f", + "eval-1-page-scroll-sticky-layer-config/input/orders.mpx": "6e0df185e713f033af82368b5acf069c43812259509b2a381d3ce946de0b60ad", + "eval-1-page-scroll-sticky-layer-config/input/app.json": "08b6c0c8a67d9602540f6eba281fd3649e75b8aee175ce2640a7dd3a714cf1ac", + "eval-1-page-scroll-sticky-layer-config/input/service.js": "977d51816125ab91147f6e3b4bf9b764046fefc7ad958495285cd4489e3bf164", + "eval-1-page-scroll-sticky-layer-config/input/task.md": "f91ca5b0a218c2c50ce008a605568a762f4a62ab96bb1f08c37309d0de6aba34", + "eval-3-new-task-board-page/input/app.json": "29beeb70b987df710a8381437d21a137ff68b9cab73eddace62ca26c1fa54dca", + "eval-3-new-task-board-page/input/task.md": "97a423449478347cb8068eb755544a9fcf1cb12d06a0459ac8725120e7899286" + }, + "note": "记录新版定义和输入;执行时另记录实际Skill版本/哈希。" +} diff --git a/.agents/skills/mpx2skyline-workspace/iteration-4/validate-suite.test.cjs b/.agents/skills/mpx2skyline-workspace/iteration-4/validate-suite.test.cjs new file mode 100644 index 0000000000..0352de60c0 --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/iteration-4/validate-suite.test.cjs @@ -0,0 +1,151 @@ +const fs = require('fs') +const path = require('path') +const repo = process.cwd() +const read = file => JSON.parse(fs.readFileSync(file, 'utf8')) +const manifest = read(path.join(__dirname, 'evals.json')) +const assertions = manifest.evals.flatMap(item => item.assertions) + +test('four cases preserve all 31 adaptation assertions and add six creation assertions', () => { + expect(manifest.evals.map(item => item.assertions.length)).toEqual([12, 11, 8, 6]) + expect(assertions).toHaveLength(37) + expect(new Set(assertions.map(item => item.id)).size).toBe(37) + const migration = read(path.join(__dirname, 'assertion-migration.json')) + expect(migration.items).toHaveLength(31) + expect(new Set(migration.items.map(item => item.assertion_id)).size).toBe(31) + migration.items.forEach(move => { + const current = assertions.find(value => value.id === move.assertion_id) + expect(current).toBeDefined() + expect(manifest.evals[move.to_case].assertions).toContain(current) + if (move.disposition !== 'preserved') { + expect(move.previous_text.length).toBeGreaterThan(0) + expect(move.previous_verification.length).toBeGreaterThan(0) + expect([1, 2]).toContain(move.to_case) + } else { + expect(current.text).toBe(move.previous_text) + expect(current.verification).toBe(move.previous_verification) + } + }) +}) + +test('metadata, shared inputs and rule references resolve', () => { + const parse = require(path.join(repo, 'packages/webpack-plugin/lib/parser')) + const babel = require(path.join(repo, 'node_modules/@babel/core')) + manifest.evals.forEach(item => { + const dir = path.join(__dirname, `eval-${item.id}-${item.name}`) + const metadata = read(path.join(dir, 'eval_metadata.json')) + expect(metadata.assertions).toEqual(item.assertions) + expect(metadata.files).toEqual(item.files) + item.files.forEach(file => { + const target = path.join(dir, file) + expect(fs.existsSync(target)).toBe(true) + if (file.endsWith('.mpx')) { + const sfc = parse(fs.readFileSync(target, 'utf8'), { filePath: target, mode: 'wx' }) + expect(sfc.template.content.length).toBeGreaterThan(0) + expect(() => babel.parseSync(sfc.script.content, { configFile: false, babelrc: false, sourceType: 'module' })).not.toThrow() + expect(() => JSON.parse(sfc.json.content)).not.toThrow() + } + if (file.endsWith('.json')) expect(() => read(target)).not.toThrow() + }) + item.assertions.forEach(assertion => { + expect(assertion.scope).toBe('skyline') + expect(assertion.text).toContain('Skyline') + expect(assertion.text).not.toMatch(/不得|禁止|不能|不依赖|不要|无Worklet|不引入/) + const reference = fs.readFileSync(path.join(repo, '.agents/skills/mpx2skyline', assertion.source.file), 'utf8') + expect(reference).toContain(assertion.source.section) + }) + }) +}) + +test('merged fixtures are intact and creation starts from requirements', () => { + const crypto = require('crypto') + const provenance = read(path.join(__dirname, 'fixture-provenance.json')) + Object.entries(provenance.files).forEach(([file, digest]) => { + expect(crypto.createHash('sha256').update(fs.readFileSync(path.join(__dirname, file))).digest('hex')).toBe(digest) + }) + const creation = manifest.evals[3] + expect(creation.task_type).toBe('creation') + expect(creation.files).toEqual(['input/app.json', 'input/task.md']) + creation.assertions.forEach(item => item.related_adaptation_assertions.forEach(id => { + expect(assertions.some(assertion => assertion.id === id)).toBe(true) + })) + expect(manifest.status).toBe('cases-ready-not-run') + expect(read(path.join(__dirname, 'run-metadata.json')).status).toBe('not_run') + expect(fs.existsSync(path.join(__dirname, 'benchmark.json'))).toBe(false) +}) + + +test('unified orders fixture appends grouped pages and retains data on refresh failure', async () => { + const vm = require('vm') + const dir = path.join(__dirname, 'eval-1-page-scroll-sticky-layer-config/input') + expect(fs.readdirSync(dir).sort()).toEqual(['app.json', 'orders.mpx', 'service.js', 'task.md']) + const service = fs.readFileSync(path.join(dir, 'service.js'), 'utf8') + const fetchOrders = vm.runInNewContext(service.replace('export function', 'function') + '; fetchOrders') + const parse = require(path.join(repo, 'packages/webpack-plugin/lib/parser')) + const file = path.join(dir, 'orders.mpx') + const sfc = parse(fs.readFileSync(file, 'utf8'), { filePath: file, mode: 'wx' }) + let options + const stop = jest.fn() + vm.runInNewContext(sfc.script.content.replace(/^import .*$/gm, ''), { + createPage: value => { options = value }, + fetchOrders, + wx: { stopPullDownRefresh: stop } + }) + const state = Object.assign({}, options.data, options.methods) + await state.reload() + expect(state.sections).toHaveLength(4) + expect(state.sections.every(section => section.items.length === 8)).toBe(true) + await state.loadMore() + await state.loadMore() + expect(state.sections).toHaveLength(12) + expect(state.pageNo).toBe(3) + expect(new Set(state.sections.map(section => section.id)).size).toBe(12) + const orders = state.sections.flatMap(section => section.items) + expect(new Set(orders.map(order => order.id)).size).toBe(96) + const previous = state.sections + await expect(state.reload(true)).rejects.toThrow('订单加载失败') + expect(state.sections).toBe(previous) + expect(stop).toHaveBeenCalledTimes(2) + state.open() + expect(state.opened).toBe(true) + state.close() + expect(state.opened).toBe(false) + const byId = Object.fromEntries(manifest.evals[1].assertions.map(item => [item.id, item])) + expect(byId.s1_07.text).toContain('type=custom') + expect(byId.s1_00.text).not.toContain('type=list') + ;['s1_01', 's1_02', 's1_03'].forEach(id => expect(byId[id].text).toContain('主订单纵向scroll-view')) +}) + + +test('unified user-list connects heading, external rows and feedback to the same component', () => { + const vm = require('vm') + const dir = path.join(__dirname, 'eval-2-template-runtime-inline-animation/input') + expect(fs.readdirSync(dir).sort()).toEqual(['logo.svg', 'row.wxml', 'task.md', 'user-list.mpx']) + const file = path.join(dir, 'user-list.mpx') + const parse = require(path.join(repo, 'packages/webpack-plugin/lib/parser')) + const sfc = parse(fs.readFileSync(file, 'utf8'), { filePath: file, mode: 'wx' }) + let options + let selected + const scrollTo = jest.fn() + const query = { in () { return this }, select (id) { selected = id; return this }, node () { return this }, exec (cb) { cb([{ node: { scrollTo } }]) } } + const createAnimation = config => { + const result = { duration: config.duration } + return { scale (value) { result.scale = value; return this }, opacity (value) { result.opacity = value; return this }, step () { return this }, export () { return result } } + } + vm.runInNewContext(sfc.script.content.replace(/^import .*$/gm, ''), { + createComponent: value => { options = value }, + wx: { createSelectorQuery: () => query, createAnimation } + }) + const state = Object.assign({}, options.data, options.methods) + state.setRows({ items: [{ id: 'a', name: '甲', visible: true }, { id: 'b', name: '乙', visible: false }] }) + expect(options.computed.visibleItems.call(state).map(item => item.id)).toEqual(['a']) + state.scrollTop() + expect(selected).toBe('#1users') + expect(scrollTo).toHaveBeenCalledWith({ top: 0 }) + state.press() + expect(state.animationData).toEqual({ duration: 150, scale: 0.96, opacity: 0.7 }) + state.release() + expect(state.animationData).toEqual({ duration: 150, scale: 1, opacity: 1 }) + expect(sfc.template.content).toMatch(/]*logo.svg[^>]*\/>{{label}}<\/text>/) + expect(sfc.template.content).toContain('') + expect(sfc.template.content).toMatch(/]*bindtap="scrollTop"[^>]*bindtouchstart="press"[^>]*bindtouchend="release"[^>]*bindtouchcancel="release"/) +}) diff --git a/.agents/skills/mpx2skyline-workspace/test-design.md b/.agents/skills/mpx2skyline-workspace/test-design.md new file mode 100644 index 0000000000..9a66893c6b --- /dev/null +++ b/.agents/skills/mpx2skyline-workspace/test-design.md @@ -0,0 +1,99 @@ +# Skyline 适配测试集设计 v4 + +当前为4个case、37条Skyline正向断言,尚未执行。旧[iteration-3结果](iteration-3/benchmark.md)保持历史归属。 + +| Case | 名称 | 断言数 | 来源 | +| --- | --- | ---: | --- | +| 0 | 样式与布局 | 12 | 原case 0 | +| 1 | 页面滚动、吸顶与层级配置 | 11 | 原case 1,4 | +| 2 | 模板运行时、图文混排与动画 | 8 | | +| 3 | 从零创建任务看板页面 | 6 | 新建需求场景 | + +## 合并与计分边界 + +case 1将订单与分类面板合并为单个orders.mpx输入,数据接口统一返回分组订单;case 2将推广卡片的图文与动画并入user-list组件,保留row.wxml及logo.svg作为必要外部资源。旧31条断言保留能力覆盖,其中case 1的6条按统一主滚动区域修订,case 2的4条验证方法指向同一组件;前版正文与验证方法记录在迁移表。来源章节名称与当前Skill对齐。 + +新增case通过仅提供需求而不提供待修复页面,验证从零实现Skyline适配。业务与通用Mpx语法单独验证,不纳入专项断言。创建入口与迁移入口有意复用核心能力,分开报告31条迁移分数和6条创建分数。 + +## Case 0:样式与布局 + +适配组件样式、间距、视觉效果及字体兼容。 + +[需求](iteration-4/eval-0-style-layout/input/task.md) + +| 断言 | Skyline适配要求 | 验证方法 | +| --- | --- | --- | +| `s0_00` | Skyline 标题的实际 text 承载节点设置 max-lines=1、overflow=ellipsis,并与 WebView 单行省略样式共同实现长标题截断。 | 检查标题节点属性和有界宽度;分别审查两种 renderer 的单行省略路径。 | +| `s0_01` | Skyline 两列标签使用显式横向 Flex 和等分子项布局,实现两列等宽。 | 检查父子布局关系及 flex basis/width,计算两列可用宽度。 | +| `s0_02` | Skyline 活动状态通过受支持的 class 选择器映射到红色活动文案。 | 追踪实际活动节点 class 与颜色声明的匹配关系。 | +| `s0_03` | Skyline 通过 renderer 与屏宽状态选择容器 padding,宽度≤320px 为12rpx、>320px 为24rpx;Skyline 默认覆盖位于媒体查询之后,WebView 继续使用原媒体查询。 | 分别代入 renderer 两值和320/321px,按选择器优先级与源码顺序计算最终 padding。 | +| `s0_04` | Skyline 内容与父容器上外沿的20px距离由父 padding 表达,子节点从父内容区起始位置布局。 | 检查 .outer/.child 的盒模型,计算父外沿到首个子盒的20px距离。 | +| `s0_05` | Skyline 相邻块的垂直间距集中由一侧的16px margin承担,最终相邻盒间距为16px。 | 计算第一块下边界到第二块上边界的间距,核对两侧 margin 的实际贡献。 | +| `s0_06` | Skyline 将双阴影分配到同尺寸的嵌套节点或等效分层结构,呈现原有两层阴影的参数和前后关系。 | 追踪0 2px 4px #000与0 4px 8px #333分别作用的节点、尺寸和绘制层次。 | +| `s0_07` | Skyline 将复合滤镜分层为内层blur(2px)和外层brightness(.8),组合呈现原有两种效果。 | 检查滤镜节点嵌套与作用顺序,逐层核对单函数参数。 | +| `s0_08` | Skyline 字体处理识别 City-Semibold 的同名独立字体族,明确 Trip-Medium 的宿主字体与 PostScript 映射核验点,并记录500/600字重的机型验证要求。 | 结合 @font-face 与报告核对两个字体来源;宿主二进制缺失时,记录待核验信息及保持现有视觉的集成方案。 | +| `s0_09` | Skyline 单阴影节点以单个 box-shadow 呈现原有 0 2px 4px rgba(0,0,0,.2) 效果,颜色函数作为完整颜色值解析。 | 核对 .single-shadow 的实际阴影层数为1,偏移、模糊半径和颜色透明度均与输入一致。 | +| `s0_10` | Skyline 单滤镜节点采用受支持的 blur(2px),呈现原有独立模糊效果。 | 追踪 .single-filter 的实际滤镜节点和参数,确认独立内容仍具有2px模糊效果。 | +| `s0_11` | Skyline 在宿主 defaultContentBox=true 条件下,child 保持100px内容宽度及左右各10px padding,实际外宽为120px。 | 结合宿主默认盒模型和实际节点 box-sizing、width、padding、border 计算内容宽与外宽,分别核对100px和120px。 | + +## Case 1:页面滚动、吸顶与层级配置 + +适配单个分组订单页面,统一嵌套纵向主区域的刷新、分页、滚动监听,组内横向列表、吸顶及弹层层级。 + +[需求](iteration-4/eval-1-page-scroll-sticky-layer-config/input/task.md) + +| 断言 | Skyline适配要求 | 验证方法 | +| --- | --- | --- | +| `s1_00` | Skyline 订单页面的外层与主订单纵向scroll-view均具有明确可滚动高度,概览与分组主体按嵌套层次布局,分组实际参与主滚动区域。 | 检查导航下方的外层高度、概览占位和主订单容器高度链,以多组数据核对主区域可滚动;具体类型及吸顶结构分别按s1_07/s1_09验证。 | +| `s1_01` | Skyline 主订单纵向scroll-view通过bindrefresherrefresh启动刷新,refresher-triggered绑定刷新状态,请求成功和失败均结束该容器刷新态。 | 定位承载sections的主纵向容器及刷新绑定,分别注入fetchOrders(1)成功和失败,核对刷新态复位;外层或横向容器的绑定不能替代主区域链路。 | +| `s1_02` | Skyline 主订单纵向scroll-view通过bindscrolltolower连接分页加载,触底后下一页分组追加到同一sections列表并继续展示。 | 从主订单容器实际触底绑定连续调用两次,核对页号推进、新分组追加和原分组保留;确认横向触底不触发纵向分页。 | +| `s1_03` | Skyline 主订单纵向scroll-view通过bindscroll读取event.detail.scrollTop并更新概览中的滚动位置。 | 给主区域滚动处理器传入detail.scrollTop并核对展示;检查外层及横向滚动事件不会被误当作主订单区域位置。 | +| `s1_04` | Skyline 页面配置 renderer=skyline、componentFramework=glass-easel、navigationStyle=custom、disableScroll=true,并在模板实现订单自定义导航。 | 解析页面JSON并检查真实导航节点和主体布局关系。 | +| `s1_05` | Skyline 接入所需的 lazyCodeLoading=requiredComponents 配置于 app.json 顶层。 | 解析 app.json 并检查顶层属性值。 | +| `s1_06` | Skyline 在 app.rendererOptions.skyline 中配置 defaultDisplayBlock=true、defaultContentBox=true、tagNameStyleIsolation=legacy、enableScrollViewAutoSize=true、keyframeStyleIsolation=legacy。 | 逐项解析五个字段的层级、类型和值。 | +| `s1_07` | Skyline 外层纵向scroll-view采用type=nested,主订单纵向容器显式选择type=custom,内层横向容器显式选择list/custom,并通过associative-container=nested-scroll-view建立嵌套关联。 | 沿外层、主区域及横向列表的父子关系核对类型和关联;主区域的custom用于承载吸顶分组,横向列表承担订单排列。 | +| `s1_08` | Skyline 横向列表显式选择type=list/custom,开启enable-flex并设置横向Flex布局;采用list时条目为直接子节点,项目保持120px宽度和相应的收缩约束。 | 检查横向容器的type、scroll-x、enable-flex、flex-direction及条目宽度/收缩;采用list时检查直接子节点,多项目排列后形成横向内容。 | +| `s1_09` | Skyline 主订单custom容器内使用sticky-section/sticky-header实现分组标题吸顶,header为section首子节点且具有背景;WebView分支采用对应CSS sticky实现。 | 核对主区域type=custom、每组sticky节点关系、标题背景和renderer分支;真实吸顶与嵌套手势另外记录真机验证状态。 | +| `s1_10` | Skyline 弹层与悬浮按钮组织为可比较的fixed层,通过层级值使弹层覆盖按钮。 | 追踪实际fixed兄弟或等效可比较层级,比较最终覆盖关系及z-index。 | + +## Case 2:模板运行时、图文混排与动画 + +适配单个用户列表组件,将标题图文截断、提示圆点动画和回顶按钮反馈与列表数据、查询及外部模板组合为完整交互。 + +[需求](iteration-4/eval-2-template-runtime-inline-animation/input/task.md) + +| 断言 | Skyline适配要求 | 验证方法 | +| --- | --- | --- | +| `s2_00` | Skyline/glass-easel 的 wx:for 在初始化、数据返回前、null返回及正常数组更新阶段均接收 Array/Object 类型的数据。 | 检查初始渲染数据及computed所有消费路径,分别模拟undefined/null/空数组/有效数组。 | +| `s2_01` | Skyline/glass-easel 的用户容器使用合法的非数字开头id,组件内通过 this.createSelectorQuery 定位同一容器。 | 关联模板id、组件查询作用域和select字符串,核对查询目标一致。 | +| `s2_02` | Skyline 的实际用户滚动目标开启 enhanced,节点查询返回的 ScrollViewContext 用于执行回到顶部操作。 | 从user-list.mpx实际回顶按钮的点击绑定追踪查询目标、enhanced属性及node().exec后的scrollTo({top:0})调用,确认不是other容器。 | +| `s2_03` | Skyline/glass-easel 循环中的外部片段采用 import 加具名 template 调用,并显式传递当前 item/index。 | 检查导入路径、模板名称和循环数据参数,代入两行不同数据确认作用域。 | +| `s2_04` | Skyline 的简单 navigator 使用 text 或纯文本子节点;卡片导航采用符合该子节点结构的内容,或由外层点击事件实现同一详情跳转。 | 检查两个导航入口的实际子节点和/pages/detail目标;复杂外层事件方案核对绑定与跳转调用。 | +| `s2_05` | Skyline 图标与标题置于同一个可收缩的 span 内联容器,容器设置 max-lines=1、overflow=ellipsis,图片采用 inline-block,使同段图文在有限宽度内共同单行截断;WebView 对应分支保留同段图文单行截断。 | 检查user-list.mpx标题中logo与label共同承载的实际span、省略属性、图片display及renderer路径和宽度约束;使用长label核对两者共同截断。 | +| `s2_06` | Skyline 闪烁圆点由真实节点承载 CSS animation,采用支持的fill-mode(如both或forwards),实现原有1秒循环和透明度变化。 | 追踪user-list.mpx提示圆点的真实节点、关键帧、fill-mode与1秒周期,核对8px、#f50及opacity .3到1。 | +| `s2_07` | Skyline 按钮通过状态类驱动 transform/opacity 的150ms CSS transition,完成按下及恢复的视觉过渡;其他渲染目标可使用各自适配实现。 | 追踪user-list.mpx同一个回顶按钮的按下/松开/取消绑定到状态类和CSS,核对150ms、scale(.96)/opacity(.7)及恢复值;点击回顶链路另由s2_02验证。 | + +## Case 3:从零创建任务看板页面 + +仅给定产品需求和宿主配置,验证从零选择Skyline页面、滚动、文本及状态动画方案。通用语法和业务功能单独验证。 + +[需求](iteration-4/eval-3-new-task-board-page/input/task.md) + +| 断言 | Skyline适配要求 | 验证方法 | +| --- | --- | --- | +| `n3_00` | Skyline 新页面配置renderer=skyline、componentFramework=glass-easel、navigationStyle=custom和disableScroll=true,实际呈现任务看板导航;app顶层lazyCodeLoading及rendererOptions.skyline五项推荐配置完整。 | 解析页面与app配置,逐项核对requiredComponents及defaultDisplayBlock/defaultContentBox/enableScrollViewAutoSize=true、tagNameStyleIsolation/keyframeStyleIsolation=legacy,检查实际导航节点。 | +| `n3_01` | Skyline 新页面通过有明确高度约束的type=list纵向scroll-view承载任务,任务项为直接子节点,标题及筛选区位于滚动主体之外。 | 检查父子高度与Flex收缩链、scroll-y及列表直接子节点;以超出一屏的任务验证有界滚动布局。 | +| `n3_02` | Skyline 新页面将下拉刷新接到scroll-view的bindrefresherrefresh,refresher-triggered绑定状态,成功及失败路径均结束容器刷新态。 | 沿实际事件绑定触发刷新,注入resolve/reject,核对刷新态最终false且容器可继续操作。 | +| `n3_03` | Skyline 新页面将scroll-view的bindscrolltolower接入分页追加,每次容器触底后新任务进入同一滚动列表。 | 从实际模板触底绑定调用处理器两次,核对每次新增2条且原列表保留;分类和唯一键另作业务验证。 | +| `n3_04` | Skyline 新页面长任务标题在实际text承载节点设置max-lines=1、overflow=ellipsis,并在有界可收缩宽度内与WebView单行省略路径共同生效。 | 检查text属性、父级宽度/收缩约束和WebView样式;代入长标题审查两种renderer的实际截断路径。 | +| `n3_05` | Skyline 新页面分类按钮通过状态类驱动transform/opacity的150ms CSS transition,按下达到scale(.96)/opacity(.7),松开和取消均恢复1。 | 追踪真实触摸绑定到响应状态和CSS,分别模拟按下/松开/取消,核对数值、持续时间和恢复。 | + +## 后续执行 + +使用同一模型/参数先建立独立Skill与no_skill基线,再比较合并Skill。保存输入、Skill哈希和实际执行证据。本次只更新测试定义,未执行模型评测。 + +[完整定义](iteration-4/evals.json) · [评分标准](iteration-4/grading-standard.md) · [迁移表](iteration-4/assertion-migration.json) + +Case 2断言统一编号为s2_00–s2_07;原s3_00/s3_01/s3_02依次迁移为s2_05/s2_06/s2_07,旧ID保存在迁移表source_assertion_id中。断言正文及验证方法不变。 + +Case 1断言统一编号为s1_00–s1_10;原s4_00/s4_01/s4_02/s4_03依次迁移为s1_07/s1_08/s1_09/s1_10,旧ID保存在迁移表source_assertion_id中。评分要求不变。 diff --git a/.agents/skills/mpx2skyline/SKILL.md b/.agents/skills/mpx2skyline/SKILL.md new file mode 100644 index 0000000000..cd4f1d5692 --- /dev/null +++ b/.agents/skills/mpx2skyline/SKILL.md @@ -0,0 +1,225 @@ +--- +name: mpx2skyline +description: | + 基于 Mpx 开发实现的微信小程序 WebView 适配 Skyline 渲染引擎指南,覆盖布局、样式、组件、配置四大维度。 + 当用户要求对已有微信小程序页面或组件进行 Skyline 适配、创建符合 Skyline 兼容规范的页面或组件、 + 排查 Skyline 下样式不生效/组件不渲染/布局异常/层级错乱等问题、或查询某项能力在 + Skyline 下的支持情况时强制调用。当用户问题不涉及 Skyline 适配时不应调用,如 + Mpx 输出 RN 问题、支付宝小程序问题、纯微信原生小程序、纯 WebView 小程序开发问题等。 +metadata: + version: "1.0.1" +--- + +# Mpx 输出 Skyline 渲染引擎的开发&适配指南 + +## 背景介绍 + +Mpx 是一个以微信小程序语法为基础、进行了类 Vue 语法拓展支持的跨端开发框架,支持将同一套代码输出到小程序(微信、支付宝、百度等)、Web 和 React Native 平台。 + +Skyline 是微信小程序新一代渲染引擎,旨在替代 WebView 渲染以获得更接近原生的性能和体验。与 WebView 模式相比,Skyline 在布局模型、层叠机制、样式能力、组件支持、页面行为上存在系统性差异。 + +### 适用场景 + +本 SKILL 是 Mpx WebView 适配 Skyline 渲染引擎的统一指南,覆盖布局、样式、组件、配置四大维度。涉及 Mpx Skyline 适配的任务均应在动笔前阅读本 SKILL 的[通用约束与适配原则](#通用约束与适配原则),包括但不限于: + +- **技术方案设计**:评估需求在 Skyline 下的可行性、跨渲染模式(WebView 与 Skyline)兼容方案选型、是否需要通过 `this.renderer === 'skyline'` 进行运行时模式隔离等; +- **WebView 页面 Skyline 适配改造**:对已基于 WebView 模式编写、未适配 Skyline 的存量页面进行兼容性补齐(参见下文[任务一](#任务一对已有-webview-页面或组件进行-skyline-适配改造)); +- **页面 / 组件开发迭代**:从零编写或迭代符合 WebView 与 Skyline 双模式兼容规范的 `.mpx` 页面与组件(参见下文[任务二](#任务二创建符合-skyline-兼容规范的页面或组件)); +- **运行时报错与异常排查**:定位 Skyline 下样式不生效(如不支持选择器/属性静默失效)、组件不渲染(如 `scroll-view` 缺失 `type`)、布局异常(如默认 `display: flex` / `border-box` 引发的差异)、层级错乱(z-index 无层叠上下文)、模板转义、SelectorQuery 数字开头等问题; +- **能力查询**:查询基础组件、属性、样式、API、滚动 API 在 Skyline 下的支持情况、版本要求与 WebView 差异;涉及 Worklet 动画、手势系统、自定义路由、共享元素时,本 SKILL 仅判断 Mpx 双模式接入边界,具体能力回源[微信官方 Skyline Skills](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills); +- **Code Review**:以本 SKILL 的[通用约束与适配原则](#通用约束与适配原则)为标准对照检查 Skyline 兼容性与跨渲染模式兼容性。 + +### 不适用场景 + +以下场景与 Mpx Skyline 适配无关,**不应调用**本 SKILL: + +- 仅面向微信小程序 WebView 的开发和适配问题(不涉及 Skyline 适配,无需 Skyline 兼容性约束); +- 支付宝、百度、抖音等其他小程序平台的开发问题(Skyline 是微信小程序专属渲染引擎,不适用于其他厂商); +- Skyline only 项目的开发问题(本 SKILL 强调 Mpx 框架下 WebView 与 Skyline 双模式兼容,纯 Skyline 项目应直接参考 [微信官方 Skyline Skills](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills)); +- Mpx 跨端输出 RN(Mpx2RN / Mpx2DRN)相关问题; +- Mpx 跨端输出 Web(Mpx2Web)相关问题; +- 不经 Mpx 框架编译的纯微信原生小程序开发问题。 + +## 知识库索引 + +| 知识库 | 说明 | +| --- |----------------------------------------------------------------------------------------| +| [Skyline 组件不支持与差异参考](./references/skyline-component-reference.md) | 查询 WebView 迁移 Skyline 时的组件差异,覆盖不支持组件、WebView-only 属性/取值、必填属性、结构约束与高频行为差异;不是完整组件手册,未收录能力需回源确认 | +| [Skyline 样式支持程度与兼容方案](./references/skyline-style-reference.md) | 查询 Skyline 样式与 Web/W3C CSS 标准不一致的部分,覆盖默认值、选择器、值类型、布局层叠、文本、背景遮罩、滤镜、动画等差异 | +| [Skyline 布局与样式适配实践](./references/skyline-layout-practice.md) | 进行视图层适配改造时读取,覆盖布局/层叠、页面滚动、图文混排、sticky、文本省略、flex、媒体查询与 SVG 展示限制等改造方案 | +| [Skyline 运行时适配实践](./references/skyline-runtime-practice.md) | 进行运行时常见问题或者性能相关问题时读取,覆盖渲染模式判断、SelectorQuery、组件实例方法、Scroll API、常见报错与性能优化等 | +| [Skyline 配置项与接入规范参考](./references/skyline-configuration.md) | 接入项目级与页面级配置时读取;按需点查 app.json 顶层配置、rendererOptions.skyline、页面配置示例与 Worklet Babel 插件配置 | +| [Skyline 适配检查矩阵](./references/skyline-audit-matrix.md) | 适配完成前强制执行的审计矩阵,覆盖扫描 pattern、判定、修复、例外与验证要求 | + +### Skyline 高级能力 + +Worklet 动画、手势系统、自定义路由、共享元素均属于 Skyline 高级能力。本 SKILL **只负责方案路由与 Mpx 接入边界**,具体 API、事件参数、版本要求、线程模型或完整实现规则参考以下官方 SKILL: + +| 能力 | 官方来源 | 本 SKILL 负责 | +| --- | --- | --- | +| Worklet 动画 | [skyline-worklet](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills/skyline-worklet) | 判断是否确需 UI 线程驱动;补充 Mpx Babel 构建配置、`renderer === 'skyline'` 隔离与 WebView 降级方案 | +| 手势系统 | [gesture-system](https://github.com/wechat-miniprogram/skyline-skills/blob/master/skills/skyline-components/references/gesture/gesture-system.md) / [gesture-negotiation](https://github.com/wechat-miniprogram/skyline-skills/blob/master/skills/skyline-components/references/gesture/gesture-negotiation.md) | 判断是否需要 Skyline 手势能力;处理 Mpx 模板与脚本接入、跨渲染模式隔离 | +| 自定义路由 | [skyline-route](https://github.com/wechat-miniprogram/skyline-skills/tree/master/skills/skyline-route) | 判断转场需求与 Mpx 页面配置、生命周期及 WebView 降级边界 | +| 共享元素 | [share-element](https://github.com/wechat-miniprogram/skyline-skills/blob/master/skills/skyline-components/references/special/share-element.md) | 判断是否采用共享元素方案;处理 Mpx 页面结构、双模式隔离与降级边界 | + +处理上述能力时,先读取对应官方 Skill 确认能力约束与实现方案,再应用本 SKILL 的 Mpx 编译接入和 WebView 与 Skyline 兼容约束。官方 Skill 未明确支持的能力不得依据本地经验推断;两者冲突时,Skyline 能力事实以官方 Skill 为准,Mpx 接入方式以本 SKILL 为准。 + +### 知识库使用建议 + +参考文档体量较大,**不要一次性预读全部参考**,按需取用即可: + +1. **入口只读本 SKILL.md**:完整读完本文档(含下方通用约束与任务流程)足以覆盖 80% 常见场景的判断;不要在动笔前预读 references 目录。 +2. **触发式读取**:只在任务流程或通用约束中**明确指向**某份参考时读取,且仅读取与当前问题相关的小节(参考文档均含目录与章节锚点,使用 `rg` / 锚点跳读,不要整文件 Read)。 +3. **典型任务的最小阅读集**: + - 已有 WebView 页面 Skyline 适配改造:识别问题维度后再读对应能力参考的相关小节,通常 1–2 份足够(如样式能力差异查 `skyline-style-reference.md`,布局或模板结构改造查 `skyline-layout-practice.md`,组件差异查 `skyline-component-reference.md`,运行时问题查 `skyline-runtime-practice.md`)。未收录的组件或能力不要反推结论,需回源确认。 + - 新建 WebView / Skyline 双模式兼容页面或组件:先按本 SKILL.md 的通用约束起手,遇到能力存疑(某属性是否支持、某 API 是否存在)时再点查对应参考。 + - 项目级配置接入:app.json 顶层项查 [`app.json 顶层配置`](./references/skyline-configuration.md#appjson-顶层配置),`rendererOptions.skyline` 查 [`rendererOptions.skyline 配置项`](./references/skyline-configuration.md#rendereroptionsskyline-配置项),页面配置示例查 [`适配参考`](./references/skyline-configuration.md#适配参考),Worklet 构建配置查 [`Worklet Babel 插件`](./references/skyline-configuration.md#worklet-babel-插件)。 + - Worklet 动画、手势系统、自定义路由或共享元素:按[高级能力](#skyline-高级能力)读取对应官方 Skill,不预读无关高级能力参考。 +4. **何时读取 `skyline-audit-matrix.md`**:仅在适配完成前检查或 Code Review 时读取,并按要求执行完整矩阵;不要在方案设计或编码前预读。 + +### 内容职责与同步规则 + +- **本 SKILL.md**:维护任务流程、决策优先级、高频跨维度约束、知识路由与人工验收,确保只读入口即可完成常见判断;不复制扫描 pattern、规则 ID 或完整能力枚举。 +- **`references/`**:维护能力事实、适用条件、实现细节与示例。能力支持情况或实现方案变化时,先更新对应 reference。 +- **审计矩阵**:维护可扫描规则的 ID、level、候选 pattern、判定、修复与例外。reference 中的变化可被源码扫描或结构复核发现时,再同步更新矩阵。 +- 仅当变化影响通用决策、知识路由或人工验收时才同步本 SKILL.md;任务流程引用通用约束或 reference,不重复具体规则。内容冲突时,能力事实以 reference 为准,扫描与分级以审计矩阵为准,执行顺序与确认门禁以本 SKILL.md 为准。 + +## 通用约束与适配原则 + +适配改造、新建页面或组件、重构与 Code Review 均须遵循本节约束。应用本 Skill 的具体规则时,按以下优先级处理: + +- 规则明确指向知识库或外部文档时,先读取与当前问题相关的小节,再实施改动; +- 规则已给出明确实现(属性值、CSS 片段、组件属性写法等)时,默认直接采用,不自行扩展替代方案; +- Skill 未给出替代方案、规则含义不明确或文档存在歧义时,不推断实现,先说明不确定点并请求确认; +- Skill 方案与更简写法、邻近代码风格或其他实现冲突时,先验证语义是否等价,以及 Skill 方案是否覆盖了未显式声明的上下文;验证后仍需偏离 Skill 方案的,说明差异并确认后再改。 + +### 跨渲染模式兼容约束 + +产物代码须在 WebView 与 Skyline 下均正常运行,按以下顺序选择方案: + +- **优先采用通用方案**:新方案若同时兼容 WebView、Skyline 与 RN,直接统一为新方案,无需按渲染模式分支; +- **隔离 Skyline-only 方案**:仅 Skyline 可用的新逻辑默认通过 `this.renderer === 'skyline'` 运行时隔离。仅当细则明确要求该逻辑在 WebView 下保留,或已确认其在 WebView 下无副作用时,才可不作隔离; +- **保留在 Skyline 下静默失效的 WebView 方案**:既有 WebView 方案若在 Skyline 下静默失效,确认其在 Skyline 下无副作用后可保留原逻辑,仅新增 Skyline 兼容实现。静默失效不等于无副作用;无法确认时,仍须按渲染模式隔离; +- **不处理 Skyline 低版本兼容**:通过 Skyline 开量开关控制最低基础库版本,未达到要求的版本降级为 WebView 渲染。 + +运行时隔离方式见 [判断当前渲染模式](./references/skyline-runtime-practice.md#判断当前渲染模式)。上述原则贯穿模板 / 脚本 / 样式 / JSON 四个维度。 + +### 布局(layout)约束 + +1. **先对齐默认布局基线**:在 `rendererOptions.skyline` 中开启 `defaultDisplayBlock` 与 `defaultContentBox`,分别对齐 WebView 的 `display: block` 和 `box-sizing: content-box`;需要静态定位时仍须显式声明 `position: static`。配置位置见 [rendererOptions.skyline 配置项](./references/skyline-configuration.md#rendereroptionsskyline-配置项),其余默认值差异见 [非标准默认值](./references/skyline-style-reference.md#非标准默认值)。 +2. **不依赖 BFC 与 margin 合并**:Skyline 没有 BFC 和 margin 合并机制,`overflow: hidden` 仅用于裁剪。容器外沿空间用父容器 `padding` 表达,兄弟间距只由一侧承担;复杂存量布局按 [不要依赖 BFC 和 margin 合并](./references/skyline-layout-practice.md#不要依赖-bfc-和-margin-合并) 改造。 +3. **页面滚动统一迁移到 scroll-view**:Skyline 不支持页面滚动,`onPullDownRefresh` / `onReachBottom` / `onPageScroll` 不会触发。页面声明 `disableScroll: true`,使用 `scroll-view` 承载滚动,并根据直接子节点结构选择 `list` / `custom` / `nested`,常见为列表模式 `type="list"`。原生命周期同步迁移到 `bindrefresherrefresh` / `bindscrolltolower` / `bindscroll`,WebView 对齐同一事件链路;详见 [页面滚动替代方案](./references/skyline-layout-practice.md#页面滚动替代方案)。 +4. **按 normal-context / fixed-context 设计层级**:Skyline 没有 WebView 层叠上下文,非 fixed 节点最终比较共同父级下的兄弟分支;fixed 节点会全局提升并按自身 `z-index` 排序,整体高于非 fixed 内容。`transform` / `opacity` 不会抬升层级,`scroll-view` 直接子节点的 `z-index` 不生效。需要比较层级的节点应调整为可比较的兄弟结构,避免依赖负 `z-index`;详见 [z-index 与层叠适配](./references/skyline-layout-practice.md#z-index-与层叠适配)。 +5. **吸顶逻辑双分支保留**:Skyline 不支持 `position: sticky`,Skyline 分支使用 `sticky-section` / `sticky-header`,WebView 分支保留 CSS sticky。`sticky-header` 必须是 section 的第一个子节点且显式设置背景色,完整结构见 [sticky 吸顶替代方案](./references/skyline-layout-practice.md#sticky-吸顶替代方案)。 +6. **使用自定义导航**:Skyline 页面声明 `navigationStyle: 'custom'` 并实现自定义导航栏,不依赖默认导航;页面配置见 [适配参考](./references/skyline-configuration.md#适配参考)。 + +### 样式(style)约束 + +1. **只使用受支持的选择器**:不使用通配选择器和属性选择器;伪元素只使用 `::before` / `::after`,其他伪类按 [选择器支持](./references/skyline-style-reference.md#选择器支持) 核对版本与替代方案,不能用时改为模板动态类或真实节点。 +2. **值类型按稳定范围使用**:长度优先使用 `rpx` / `px` / `rem`;百分比仅用于 [百分比支持情况](./references/skyline-style-reference.md#百分比支持情况) 明确记录的属性,Flex 子节点不能依赖百分比 `min-width` 撑开或等分。`calc()` 只用于非嵌套的长度计算,不用于角度等类型;详见 [长度、函数与单位](./references/skyline-style-reference.md#长度函数与单位)。 +3. **滚动与特殊布局改用组件或显式布局**:不使用 `overflow: auto` / `scroll`、`overflow-x` / `overflow-y`、`display: grid` / `flow-root` 或 `position: sticky`;分别改用 `scroll-view`、Flex / `grid-view`、sticky 组件。其他布局差异按 [布局、盒模型与层叠差异](./references/skyline-style-reference.md#布局盒模型与层叠差异) 处理。 +4. **文本省略同时保留两端实现**:保留 WebView 的 `text-overflow` / `-webkit-line-clamp` 等样式,并在承载文本的组件上新增 `max-lines` 与 `overflow` 供 Skyline 使用;新增或替换为 `text` 时将插值紧贴标签,避免字面空白影响截断。完整规则见 [文本溢出省略适配](./references/skyline-layout-practice.md#文本溢出省略适配)。 +5. **字体与文本能力先核对再替换**:`font-weight: 500/600` 在部分机型不生效,命中时先检查字体资源与 PostScript name,再确认是否改为 `bold` / `700`,未确认时保留并说明风险。`white-space`、`word-break`、`text-decoration` 等能力按 [文本与字体差异](./references/skyline-style-reference.md#文本与字体差异) 处理;`text-decoration-line` 多值按 [多值适配](./references/skyline-layout-practice.md#text-decoration-line-多值适配) 拆分节点。 +6. **背景、边框、遮罩与滤镜遵循层数和值域限制**:圆角非 0 时四边边框颜色和样式保持一致;多层背景、遮罩或阴影超出支持范围时拆节点;`mask-image` 不使用渐变;`filter` / `backdrop-filter` 不使用 `url()`、`drop-shadow()` 或多函数组合。具体值域见 [背景、边框与遮罩差异](./references/skyline-style-reference.md#背景边框与遮罩差异) 与 [滤镜差异](./references/skyline-style-reference.md#滤镜差异)。 +7. **媒体查询保留 WebView、补 Skyline 动态类**:Skyline 会忽略 `@media screen` 条件但可能保留内部规则,不能直接删除或全局覆盖。WebView 继续使用原媒体查询,Skyline 通过运行时状态类表达条件,并在媒体查询后补 Skyline 默认类兜底;详见 [@media screen 替换方案](./references/skyline-layout-practice.md#media-screen-替换方案)。 +8. **未支持属性按跨渲染原则处理**:命中未支持或静默失效的 CSS 时,先在 [Skyline 不支持能力及兼容方案](./references/skyline-style-reference.md#skyline-不支持能力及兼容方案) 查询替代方案;确认原 WebView 样式在 Skyline 下无副作用后可保留,仅新增 Skyline 实现。没有等效方案或副作用不明确时,说明风险并请求确认。 + +### 组件(component)约束 + +组件参考只记录 WebView 迁移 Skyline 的差异,不是完整组件手册;未收录的组件、属性或事件不得反推为支持,需回源确认。 + +1. **scroll-view 必须显式选型**:每个 `scroll-view` 都声明 `type`。`type="list"` 仅用于列表项是直接子节点的场景,单一外层 wrapper 会使按需渲染退化;嵌套滚动时外层使用 `type="nested"`,内层显式使用 `list` / `custom` 并设置 `associative-container="nested-scroll-view"`。选型与结构约束见 [Skyline 必填属性与结构约束](./references/skyline-component-reference.md#skyline-必填属性与结构约束)。 +2. **scroll-view 行为按需补齐**:横向滚动同时开启 `enable-flex` 并设置横向布局;自定义下拉刷新节点声明 `slot="refresher"`;需要内容撑高时开启 `enableScrollViewAutoSize`。通过 `NodesRef.node()` 获取 `ScrollViewContext` 时,目标滚动容器必须开启 `enhanced`;详见 [组件高频差异](./references/skyline-component-reference.md#skyline-相对-webview-的高频差异补充) 与 [ScrollViewContext](./references/skyline-runtime-practice.md#必须-scrollviewcontext开启-enhanced-属性)。 +3. **不支持组件采用替代或降级**:命中 `web-view`、富文本编辑、可移动视图等不支持能力时,按 [不支持或不建议使用的组件](./references/skyline-component-reference.md#skyline-不支持或不建议使用的组件) 选择替代组件、独立 WebView 页面或 renderer 降级;复杂交互无明确等效方案时说明风险并请求确认。 +4. **WebView-only 属性与取值不得作为 Skyline 方案**:例如 `image` 的 WebView-only 裁剪模式、`text` 的 `space` / `decode`、输入组件的 `placeholder-class` 等,确认在 Skyline 下无副作用后可保留给 WebView,并补充 Skyline 实现;存在副作用时替换为双端支持写法或按 renderer 隔离,不明确时说明风险并请求确认。完整范围见 [WebView-only 属性、取值与行为](./references/skyline-component-reference.md#webview-only-属性取值与行为)。 +5. **遵守组件子节点结构**:`navigator` 只能嵌套 `text` 或纯文本,`text` 只能嵌套 `text`;复杂卡片改为外层点击事件。图标、图片与文本处于同一行时使用 `span` 方案,并补齐 Skyline 的内联布局与截断属性;详见 [图文混排](./references/skyline-layout-practice.md#图文混排)。 +6. **模板结构按 glass-easel 规则改造**:数据绑定外的引号使用 XML 实体,数据绑定内不使用反斜杠转义;`wx:for` 子树中的 `` 改为 `` + `