cardbuddy 0.25.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,8 +8,8 @@
8
8
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16-Cg6Nrosk.png" />
9
9
  <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32-B_1744sp.png" />
10
10
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon-BQcES9QK.png" />
11
- <script type="module" crossorigin src="/assets/index-B6NhNlBx.js"></script>
12
- <link rel="stylesheet" crossorigin href="/assets/index-MWKPP9nd.css">
11
+ <script type="module" crossorigin src="/assets/index-Bn5gP68-.js"></script>
12
+ <link rel="stylesheet" crossorigin href="/assets/index-CeoWrec1.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="app"></div>
@@ -25,6 +25,7 @@ dsl-card 项目的 AI 技能层。它是**编排层**:把卡片编辑任务拆
25
25
  6. **改坏可回滚**:`card_write` 每次写卡前自动把当前版本存为历史快照(与编辑器改卡同语义);编辑失误时用 `card_rollback`(默认回滚到最新快照)撤销,用 `card_history` 挑选更早的回滚目标。
26
26
  7. **dev server 前置**:`card_render_status` / `card_node_models` / `card_import_meta` 必须 dev server 已启动,未起时返回 `dev-server-required`;`card_sync` / `card_save` / `card_slice_upload` 除 dev server 外还需已登录远端。(本仓库 `npm run dev` 默认 5180,由 Vite 把 `/__*` 代理到 8787;`cardbuddy init` 出来的工程 `npm run dev` 直接是 8787。)`card_list` / `card_read` / `card_write` / `card_validate` / `card_history` / `card_rollback` 会自动降级为直接读盘/写盘/跑 Python(render_status 标 skipped);`card_screenshot` 降级到包内独立离线渲染器(`source:'standalone'`)。
27
27
  8. **建卡先判输入形态**(Workflow D):收到设计稿输入先调 `card_route_input({path})`,按返回的 `kind` 分流,**不要凭感觉决定要不要跑上游**。判为 `meaxure-export`(Sketch MeaXure 标注导出)时必须先经 `sketch-spec-to-card` 前处理产出 `UI/<稿名>/` 要素包,**禁止直接读 `preview/` 整图建卡**;`preprocess.needed=false` 表示已前处理过,直接复用存量产物。`card_route_input` 纯离线,不需要 dev server。
28
+ 9. **编辑前先适配**(Workflow A/B 第 0 步):`node skills/dsl-card-generator/scripts/adapt_schema.mjs --id <id>`(可加 `--write`)。存量卡、刚同步进来的卡、复制过子树的卡必须先把旧形态清掉再改——未声明变量、越界 `$_index`、style 里写死的 display、空条件 v-show 会让 `bindingErrors` 混进与本次任务无关的历史噪音。规则与事故来源见 `dsl-card-generator/references/schema_adaptation.md`。
28
29
 
29
30
  ## 前置:`card_*` 工具从哪来(agent 里看不到工具先看这里)
30
31
 
@@ -141,6 +142,10 @@ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
141
142
 
142
143
  目标:把一张卡的 `bindingErrors` 清零。
143
144
 
145
+ 0. **适配(先做)**:`node skills/dsl-card-generator/scripts/adapt_schema.mjs --id <id> [--write]`。
146
+ 确定性可修项(style 里写死的 display、空条件 v-show)直接 `--write` 落盘;未声明变量(AD-01)、
147
+ 越界 `$_index`(AD-02)按报告人工判定后再进下一步。不做这步会把历史遗留错误当成本次要修的
148
+ 绑定问题,白跑几轮。
144
149
  1. `card_render_status(id)` → 读 `bindingErrors`(每项有 `path` / `expr` / `message`)。
145
150
  2. **区分「真坏绑定」与「级联误报」**(实测关键,见下):
146
151
  - **真坏绑定** = 表达式**自身语法错误**,message 形如 `Unexpected token '}'` / `Unexpected end of input`。这类是编辑手滑(括号/引号没闭合),必须修。
@@ -159,10 +164,11 @@ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
159
164
 
160
165
  1. `card_list` → 选目标卡集合(id 白名单 / `className` 特征 / 全量)。
161
166
  2. 对每张卡:
162
- a. `card_node_models(id)` 定位要改的字段,确认跨卡字段形状一致(同一 `className` 的字段通常同构)。
163
- b. `card_read(id)` 拿完整 schema + data。
164
- c. 改 schema(**整体替换**,保留未涉及节点/字段与孤儿字段)。
165
- d. `card_write(id, { schema })` 收口校验。
167
+ a. **适配**(同 Workflow A 第 0 步):`adapt_schema.mjs --id <id> [--write]`,先把历史遗留形态清掉再进编辑。
168
+ b. `card_node_models(id)` 定位要改的字段,确认跨卡字段形状一致(同一 `className` 的字段通常同构)。
169
+ c. `card_read(id)` 拿完整 schema + data。
170
+ d. 改 schema(**整体替换**,保留未涉及节点/字段与孤儿字段)。
171
+ e. `card_write(id, { schema })` 收口校验。
166
172
  3. 汇总:哪些卡改了、哪些卡校验失败(失败的不写或回滚,报告用户)。
167
173
  4. **纪律**:批量改是整卡为单元,不要逐字段 patch 漏掉兄弟字段;跨卡编辑前先 `card_node_models` 验证形状一致,避免把 A 卡的字段名错用到 B 卡。
168
174
 
@@ -29,6 +29,7 @@ description: 生成、编辑远端/YNet 低代码卡片 schema.json + data.json
29
29
  14. **数字语义变量提取** — 含运行期数字(金额/笔数/利率/期限/日期)抽 inputParams + 表达式拼接;禁整串写死/绑 string/正则见数字就拆(R61,rules.md §十四)
30
30
  15. **图表绘制层序(R62)** — 底→顶:参考线/网格/轨道最底 → 数据标记 → 文字标签最顶;禁先填充后画网格(rules.md §十五)。机械兜底在 v3 生成器 `chartPaintLayers`(`lib/v3_shared.mjs`)+ 回归测试 `tools/tests/chart-layer-order.test.mjs`;**lint 不拦这一条**(无法可靠解析 Canvas 表达式的调用顺序),AI 手写时靠渲染后目视。
31
31
  16. **宽度自适应(占满禁写死 px,R66)** — 顶层 `view.width` = 卡面宽(非画板宽);纵向流父级里占满父内容盒的容器**禁写 px 宽**,用 `100%` 或不写(meta 默认即 100%),px 只给真固定元素(ir-format.md §2f,lint `r66-fullwidth-px`)。写死 px 的卡在非设计宽度的宿主容器里锁死不自适应。
32
+ 17. **编辑前先适配(AD-*)** — 存量卡 / 刚同步进来的卡 / 从别卡复制过子树的卡,动手前先跑 `adapt_schema.mjs` 归一到当前契约:未声明变量、越界 `$_index`、style 里写死的 display、空条件 v-show 一次清掉;布局容器条件显隐(发布产物 `display:'block'` 风险)按报告确认宿主已装兜底补丁(`references/schema_adaptation.md`)。
32
33
 
33
34
  ## 0.5 速查优先
34
35
 
@@ -222,6 +223,11 @@ node scripts/diff_bands.mjs --id <卡id> --design <card-1.png> --tol 2 # 量
222
223
 
223
224
  ### Workflow B — 编辑已有卡片
224
225
 
226
+ 0. **适配(必跑)**:`node scripts/adapt_schema.mjs --id <id>`。有 `auto` 可修项就加 `--write` 落盘
227
+ (只改「改法唯一」的:style 里写死的 display、空条件 v-show 降级);AD-01/AD-02 按报告人工判定
228
+ (未声明变量是否复制残留、越界 `$_index` 节点该删还是该显)。存量卡、刚同步进来的卡、复制过子树
229
+ 的卡**必须**先做这步——否则在错基线上改,改完仍报同一个错。规则与事故来源见
230
+ `references/schema_adaptation.md`。
225
231
  1. 读卡:`card_read(id)` 或直接读 `src/cards/<id>/schema.json`(及 data.json)。
226
232
  2. 改结构:`add_component.mjs --id <id> --parent <cid> --className <X> [--text "…"] [--click]` 或 MCP `card_add_component`(自带离线硬校验);`card_node_models(id)` 定位字段。保留未涉及节点与孤儿字段。
227
233
  3. 同步数据:增删改 inputParams[] 时 data.json 同步(autofix 或 derive)。
@@ -248,6 +254,7 @@ node scripts/expand_ir.mjs --ir <IR.json> --out src/cards/<卡id>/ # IR→s
248
254
  node scripts/iterate.mjs --ir <IR> --out <dir> --design <png> [--set 'p=v'] # 一条龙视觉闭环
249
255
  node scripts/spec_tree.mjs --spec <spec.json> [--card 1] [--compact] # 层级树
250
256
  node scripts/lint_card.mjs --id <卡id> | --all [--json] # 行为规则体检(条数以实跑为准)
257
+ node scripts/adapt_schema.mjs --id <卡id> | --all [--write] [--json] # 适配环节:旧形态/错误属性归一(编辑前必跑)
251
258
  node scripts/diff_card.mjs --id <卡id> [--baseline <path>] # 变更对比(整体替换后必跑)
252
259
  node scripts/check_fidelity.mjs --spec <spec.json> --schema <schema.json> # 保真门禁(npm run check:fidelity)
253
260
  node scripts/render_card.mjs --id <卡id> [--keep-alive] # 离线截图
@@ -260,7 +267,7 @@ node scripts/v3_regression.mjs [--update-baseline] [--cases <path>] # v3 回
260
267
 
261
268
  **P0 生成必读**:`quickref.md`(一页纸速查)+ `ui_fidelity_rules.md`(还原度规则)+ `component_rules.md`(组件硬约束)。
262
269
 
263
- **P1 按场景**:`rules.md`(铁律全集)|`dsl_structure.md`(结构/itemId 全表)|`component_specs.md`(组件骨架)|`expression_engine.md`($ 引擎)|`amount_formatting.md`(金额)|`event_patterns.md` + `platform_jsapi.md`(事件/JSAPI)|`field_naming.md`(命名)|`recipes.md` + `recipe_snippets/`(范式)|`previewer_contract.md`(预览器契约)|`spec_to_schema_patterns.md`(v3 范式 + §20 决策层)|`iteration_protocol.md`(迭代协议)|`semantic_adjudication.md`(语义裁决细则)|`scripts_reference.md`(脚本全集)|`slices_convention.md`(切图)|`image_to_card.md`(图片管线)|`message-center-pattern.md`(消息中心)|`image_diff.md`(视觉清单)|`card_to_summary.md`(反向描述)|`card_index.json`/`card_templates.json`(路由索引)。
270
+ **P1 按场景**:`rules.md`(铁律全集)|`schema_adaptation.md`(适配规则库:旧形态/错误属性判定与修法)|`dsl_structure.md`(结构/itemId 全表)|`component_specs.md`(组件骨架)|`expression_engine.md`($ 引擎)|`amount_formatting.md`(金额)|`event_patterns.md` + `platform_jsapi.md`(事件/JSAPI)|`field_naming.md`(命名)|`recipes.md` + `recipe_snippets/`(范式)|`previewer_contract.md`(预览器契约)|`spec_to_schema_patterns.md`(v3 范式 + §20 决策层)|`iteration_protocol.md`(迭代协议)|`semantic_adjudication.md`(语义裁决细则)|`scripts_reference.md`(脚本全集)|`slices_convention.md`(切图)|`image_to_card.md`(图片管线)|`message-center-pattern.md`(消息中心)|`image_diff.md`(视觉清单)|`card_to_summary.md`(反向描述)|`card_index.json`/`card_templates.json`(路由索引)。
264
271
 
265
272
  **P2 改脚本/排查**:`generation_pitfalls.md`(132KB 事故档案,**训练侧编号体系**,与 lint 的 code 不是一套——查 lint 规则用 `scripts/lib/rules/registry.mjs`;已固化进 lint/expand_ir/autofix 的条目机械拦截,生成时无需预读)。
266
273
 
@@ -0,0 +1,116 @@
1
+ # 适配环节(Schema Adaptation)
2
+
3
+ > 存量卡 / 跨项目同步进来的卡 / 从别卡复制的片段,往往「结构合法、lint 也过」,但在
4
+ > 当前渲染契约或发布链路上会出错。适配环节就是**编辑与生成前的统一归一步骤**:
5
+ > 把这类历史形态一次性扫出来,能确定性修的自动修,需要语义判断的列成清单交人。
6
+
7
+ 执行器:`scripts/adapt_schema.mjs`。规则表在脚本顶部 `RULES`,本文是它的判定依据与事故来源。
8
+
9
+ ## 与相邻工具的边界(不要重复实现)
10
+
11
+ | 工具 | 回答的问题 | 改不改文件 |
12
+ |---|---|---|
13
+ | `validate_schema.py` | 结构合法吗、能渲染吗(契约硬卡点) | 否 |
14
+ | `autofix_schema.py` | 契约级机械错误(itemValueFrom / 重复 componentId / data.json 派生 / `$item.xxx` 别名) | 是(确定性) |
15
+ | `lint_card.mjs` / `lint_autofix.mjs` | 体验达标吗(漏 click、缺 color、切图命名…) | lint_autofix 带渲染守护才改 |
16
+ | **`adapt_schema.mjs`(本环节)** | **旧版本 / 旧编译器 / 跨宿主遗留的错误形态,在当前链路下会不会坏** | **`--write` 只改「改法唯一」的** |
17
+
18
+ 一条心法:**validate 管「能不能跑」,adapt 管「跑起来对不对」**。
19
+
20
+ ## 何时跑
21
+
22
+ 1. **Workflow B(编辑已有卡)第 0 步**——先适配再动手,避免在错基线上改。
23
+ 2. **Workflow A 收尾**(生成完成后)——新生成的卡不该有历史遗留,但复用模板/片段时可能带进来。
24
+ 3. **`platform-card-sync` 刚同步进来的卡**——远端存量卡是历史形态的最大来源。
25
+ 4. **从别卡复制子树后**——`$listData1/$listData2` 这类坏引用就是这么来的。
26
+
27
+ ## 用法
28
+
29
+ ```bash
30
+ node scripts/adapt_schema.mjs --id <卡id> # 只报告(默认)
31
+ node scripts/adapt_schema.mjs --id <卡id> --write # 落盘可确定性修复项
32
+ node scripts/adapt_schema.mjs --all # 全量库存巡检
33
+ node scripts/adapt_schema.mjs --all --json # 机器可读(接 CI / card-doctor)
34
+ node scripts/adapt_schema.mjs --list-rules # 打印规则表
35
+ ```
36
+
37
+ 退出码:`0` 无 error(或 `--write` 后清零)、`1` 存在未修复 error、`2` 用法/路径错误。
38
+ `--project-root <dir>` 可指定宿主工程根(默认 cwd)。
39
+
40
+ ## 规则表
41
+
42
+ 级别:`error` 会让卡出错;`warn` 有风险或需人工确认。
43
+ 修复:`auto`(`--write` 落盘)、`manual`(只报告)、`nolocal`(schema 无修点,属链路问题)。
44
+
45
+ ### AD-01 未声明变量引用(warn / manual)
46
+
47
+ - **判定**:表达式(properties / style / v-show 条件 / 事件代码)引用了既不在
48
+ `dictionary.inputParams` 声明、也不在列表项作用域(`slotScope`)、也不是内建的 `$var`。
49
+ - **分级**:
50
+ - 事件代码里有运行时写入(`this.setData({ x })` / `this.state.x =`)→ 动态 state 字段,
51
+ 只需确认注入时机早于首次渲染;
52
+ - 无写入痕迹 → 可能是复制残留,也可能是外部 `dataResponse` 直传字段,**需人工判定**。
53
+ - **为何不自动修**:外部数据字段是合法用法,机器无法与错误区分(实测全量 5 处,3 处是动态字段)。
54
+ - **实例**:`creditCardBill` 的 `column_cj` 引用了 `$listData1/$listData2`(从有 listData 结构的
55
+ 别卡复制残留),运行时求值抛错;修复是删掉该指令(父级已有等价守卫)。
56
+
57
+ ### AD-02 越界 `$_index`(error / manual)
58
+
59
+ - **判定**:节点不在 `slotScope: true` 的插槽内,却使用 `$_index`。
60
+ - **后果**:`$_index` 只由列表项作用域注入,域外求值为 `undefined`,条件恒 false → 节点永不渲染。
61
+ - **为何不自动修**:删节点还是去条件,取决于作者本意(要分隔线还是不要)。
62
+ - **实例**:`creditCardBill` 的 `divider_7l`/`divider_ep` 挂在「查看全部」行里(列表作用域外)
63
+ 却带 `$_index === 0`,从未渲染过;修复是删除(列表项模板内的 `divider_73/divider_d0` 合法保留)。
64
+
65
+ ### AD-03 布局容器上的条件显隐(warn / nolocal)
66
+
67
+ - **判定**:`className` ∈ {Root, Row, Column, SingleColumn, MultiColumn, GridLayout,
68
+ ListLayout, AbsoluteLayout} 且 v-show 的 `showType` 为 `01`/`02`。
69
+ - **后果**:v-show 在发布时由平台编译成内联 `display: (expr) ? 'block' : 'none'`。布局元素
70
+ 的 flex 来自样式类(`.ce_row{display:flex}`),内联 `display:block` 会把它压掉 →
71
+ justifyContent / alignItems / gap / grid 全失效。**schema 侧没有任何 display 可改**。
72
+ - **三层责任划分**(本次事故的完整结论):
73
+ 1. dsl-card 本地编译器(`server/core/flameCompile/{h5,client}.js`)已改为
74
+ `(expr) ? '' : 'none'`(提交 789573a,`tools/tests/flame-compile.test.mjs` 有断言);
75
+ 2. **线上产物由平台 Java 服务编译**(发布 → MinIO jsUrl),本地改不到,仍写 `'block'`;
76
+ 3. 兜底在宿主渲染层:`ai-assistant-h5/src/flame/cardStylePatch.js` 包装
77
+ `mCard.getCreateElement` 的 h,剔除 `style.display === 'block'`。
78
+ - **报告含义**:这条 warn 不是让你改 schema,而是提醒「这张卡在**未装 display 补丁的宿主**上
79
+ 会塌布局」。新宿主接入时必须装同类补丁。
80
+ - **实例**:`creditCardBill` 10 处(`row_f1`/`row_77`/`row_eg` 等)、全量库存 130 处。
81
+
82
+ ### AD-04 style 里写死 display(error / auto)
83
+
84
+ - **判定**:`style.properties[*].itemChildren.properties[*].itemKey === 'display'`。
85
+ - **后果**:`display` 不在 style-meta 白名单,validate 报 ERROR;旧渲染器里则会压掉样式类。
86
+ - **自动修**:删除该子项(display 只应由 v-show 产生,删掉等价于回到元素自身 display)。
87
+
88
+ ### AD-05 v-show 条件为空(error / auto)
89
+
90
+ - **判定**:`showType` 为 `01`/`02`,但 `condition.expression` 为空或缺失。
91
+ - **后果**:编译出的 display 表达式无意义,节点显隐不可控。
92
+ - **自动修**:`showType` 降级为 `'00'`(等价于「不做显隐控制」),语义安全。
93
+
94
+ ### AD-06 旧作用域别名 `$item`(warn / manual)
95
+
96
+ - **判定**:表达式出现 `$item.xxx` 或独立 `$item`,且卡片未声明同名根变量。
97
+ - **后果**:运行时插槽作用域是「外层 ∪ item 字段扁平展开 ∪ `{$$, _index}`」,**没有 `item` 键**,
98
+ `$item.xxx` 恒 undefined。
99
+ - **修法**:`python3 scripts/autofix_schema.py <schema>` 规则 5 归一为扁平字段名 / `$$` / `$_index`
100
+ (本脚本不重复实现,只负责发现)。
101
+
102
+ ## 扩展新规则(三步)
103
+
104
+ 1. `scripts/adapt_schema.mjs` 顶部 `RULES` 加一条:`{ title, level, fix, why }`;
105
+ 2. `analyzeCard` 里加检测(用现成的 `walkTree` / `expressionTexts` / `readVShow`);
106
+ 3. 若 `fix: 'auto'`,在 `applyFixes` 里补「改法唯一」的修复动作,并在本文补一节。
107
+
108
+ **准入标准**:每条规则必须有真实事故来源(哪张卡、什么现象、根因),否则不进规则表——
109
+ 没有证据的规则会变成噪音,最后没人看报告。
110
+
111
+ ## 已知的误报与边界
112
+
113
+ - 列表作用域内的自由变量一律放行(它们就是 item 字段);`slotScope: true` 的插槽子树整体豁免 AD-01。
114
+ - 事件代码里的 `$var` 命中按 warn 处理(代码里可能拼字符串,判定力弱于表达式)。
115
+ - AD-03 只看布局容器:`Text`(span)/`Divider`(div)被设 `block` 在 flex 容器里会被 blockify,
116
+ 视觉无差异,不单独报。
@@ -20,6 +20,7 @@ node scripts/ir_restore.mjs --list|--best|--round … # 迭代快
20
20
  node scripts/lint_card.mjs --id <卡id> | --all [--json] # 行为规则体检(条数以实跑输出为准,文档不复制数字)
21
21
  python3 scripts/validate_schema.py <schema.json> [--topology] # 结构合法性(CI 硬卡点)
22
22
  python3 scripts/autofix_schema.py <schema.json> [--check] # 机械修复 itemValueFrom/重复 id/data 漂移
23
+ node scripts/adapt_schema.mjs --id <卡id> | --all [--write] [--json] # 适配环节:旧形态/错误属性归一(编辑前必跑,规则见 schema_adaptation.md)
23
24
  node scripts/preflight.mjs --spec <spec.json> --id <卡id> # 14 项机械 Pre-flight
24
25
  node scripts/diff_card.mjs --id <卡id> [--baseline <path>] # 变更对比(铁律机械兜底,整体替换后必跑)
25
26
  node scripts/check_fidelity.mjs --spec <spec.json> --schema <schema.json> # 保真度门禁(元素级对齐断言,npm run check:fidelity)