@qingflow-tech/qingflow-cli 1.1.43 → 1.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +13 -6
  2. package/entry_point.py +1 -1
  3. package/npm/bin/qingflow.mjs +1 -2
  4. package/npm/lib/runtime.mjs +3 -7
  5. package/package.json +2 -2
  6. package/pyproject.toml +3 -4
  7. package/skills/qingflow-app-form/SKILL.md +66 -0
  8. package/skills/qingflow-app-form/agents/openai.yaml +4 -0
  9. package/skills/qingflow-cli/SKILL.md +8 -6
  10. package/skills/qingflow-cli/manifest.yaml +1 -1
  11. package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md +4 -4
  12. package/skills/qingflow-cli/reference/QINGFLOW_CLI_EXPLORATION_REPORT.md +1 -1
  13. package/skills/qingflow-cli/reference/QINGFLOW_CLI_FIELD_DATA_TYPES.md +1 -1
  14. package/skills/qingflow-cli/reference/QINGFLOW_CLI_SCHEMA_APPLY_FIELD_TYPES_AND_SCENARIOS.md +4 -4
  15. package/skills/qingflow-cli/reference/builder/10-build-single-app.md +5 -5
  16. package/skills/qingflow-cli/reference/builder/20-build-complete-system.md +14 -14
  17. package/skills/qingflow-cli/reference/builder/30-schema-fields.md +102 -103
  18. package/skills/qingflow-cli/reference/builder/40-layout.md +39 -31
  19. package/skills/qingflow-cli/reference/builder/README.md +9 -9
  20. package/skills/qingflow-cli/reference/builder/code-integrations/README.md +4 -2
  21. package/skills/qingflow-cli/reference/builder/code-integrations/code-block.md +2 -0
  22. package/skills/qingflow-cli/reference/builder/code-integrations/q-linker.md +2 -0
  23. package/skills/qingflow-cli/reference/builder/reference/app-delivery-sop.md +45 -38
  24. package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_EXPLORATION_REPORT.md +1 -1
  25. package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_FIELD_DATA_TYPES.md +1 -1
  26. package/skills/qingflow-cli/reference/examples/README.md +3 -3
  27. package/skills/qingflow-common/SKILL.md +47 -0
  28. package/skills/qingflow-common/agents/openai.yaml +4 -0
  29. package/src/qingflow_mcp/__main__.py +2 -3
  30. package/src/qingflow_mcp/app_form_compat.py +104 -0
  31. package/src/qingflow_mcp/app_form_validator.py +462 -0
  32. package/src/qingflow_mcp/builder_facade/app_form.py +3992 -0
  33. package/src/qingflow_mcp/builder_facade/app_form_schema.py +425 -0
  34. package/src/qingflow_mcp/builder_facade/schemas/app_form/manifest.json +42 -0
  35. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/complete.json +2969 -0
  36. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/address.json +392 -0
  37. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/amount.json +236 -0
  38. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/attachment.json +425 -0
  39. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/code_block.json +318 -0
  40. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/data_relation.json +580 -0
  41. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/date.json +150 -0
  42. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/datetime.json +150 -0
  43. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/department.json +345 -0
  44. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/email.json +190 -0
  45. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/link.json +190 -0
  46. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/long_text.json +190 -0
  47. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/member.json +484 -0
  48. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/multi_select.json +214 -0
  49. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/number.json +236 -0
  50. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/phone.json +199 -0
  51. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/q_linker.json +412 -0
  52. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/relation.json +454 -0
  53. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/single_choice.json +214 -0
  54. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/single_select.json +214 -0
  55. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/subtable.json +1921 -0
  56. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/text.json +190 -0
  57. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/formula.json +1594 -0
  58. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/summary.json +718 -0
  59. package/src/qingflow_mcp/builder_facade/service.py +8 -4
  60. package/src/qingflow_mcp/cli/commands/builder.py +93 -28
  61. package/src/qingflow_mcp/cli/json_io.py +21 -2
  62. package/src/qingflow_mcp/cli/main.py +3 -39
  63. package/src/qingflow_mcp/public_surface.py +5 -2
  64. package/src/qingflow_mcp/response_trim.py +50 -0
  65. package/src/qingflow_mcp/server.py +24 -3
  66. package/src/qingflow_mcp/server_app_builder.py +44 -87
  67. package/src/qingflow_mcp/tools/ai_builder_tools.py +103 -100
  68. package/src/qingflow_mcp/tools/app_tools.py +46 -65
  69. package/src/qingflow_mcp/tools/record_tools.py +3 -3
  70. package/src/qingflow_mcp/version.py +2 -4
  71. package/docs/local-agent-install.md +0 -370
  72. package/skills/qingflow-mcp-setup/SKILL.md +0 -115
  73. package/skills/qingflow-mcp-setup/agents/openai.yaml +0 -4
  74. package/skills/qingflow-mcp-setup/references/claude-desktop.md +0 -34
  75. package/skills/qingflow-mcp-setup/references/environments.md +0 -62
  76. package/skills/qingflow-mcp-setup/references/generic-stdio.md +0 -32
  77. package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +0 -38
@@ -1,53 +1,62 @@
1
- # Builder Schema And Fields
1
+ # Builder Field Modeling And AppForm Pointer
2
2
 
3
3
  Read this when the task is about app creation fields, schema updates, field types, data title, data cover, relation fields, or system fields.
4
4
 
5
5
  ## Scope
6
6
 
7
- Responsible for: `builder schema apply`, app creation through `form`, field type aliases, data title/cover, relation field shape, and existing-app schema maintenance.
7
+ Responsible for: field modeling notes, AppForm field types, data title/cover, relation field shape, and the CLI form write sequence.
8
8
 
9
- Not responsible for: standalone form layout operations. For normal app creation, put fields directly under `form` so fields and placement are written together.
9
+ Not responsible for: record data operations. Form layout is part of the AppForm `spec.body`; do not use a separate schema/layout write path.
10
10
 
11
11
  ## Main chain
12
12
 
13
13
  ```text
14
- app/package resolve -> schema apply with form -> app get fields/layout readback -> publish/readback verify
14
+ app/package resolve -> builder app-form schema -> draft get for updates -> validate declaration -> apply declaration -> app get fields/layout readback -> publish/readback verify
15
15
  ```
16
16
 
17
- For complete systems, use `builder schema apply --apps-file` with `{package_id, apps}` and put each app's fields and form layout under `apps[].form`. For one app, use `--form-file` in create mode. Use `add_fields/update_fields/remove_fields` only for later schema maintenance.
17
+ For every app, run `qingflow --json builder app-form schema` and pin the returned schema version. For an update, read `qingflow --json builder app-form get --app-key APP_KEY --being-draft`; validate the complete declaration with `qingflow --json builder app-form validate --schema-version VERSION --file DECLARATION.json`, then apply it with `qingflow --json builder app-form apply --file DECLARATION.json`. The old `builder schema apply`, `--apps-file`, `--form-file`, and `add_fields/update_fields/remove_fields` routes are retired compatibility adapters, not current public commands.
18
18
 
19
19
  ## Demo files
20
20
 
21
21
  | Scenario | Example |
22
22
  |----------|---------|
23
- | New single app `--form-file` | [schema_single_app_form_standard.example.json](../examples/schema/schema_single_app_form_standard.example.json) |
24
- | New complete system `--apps-file` | [schema_multi_app_form_relation_layout.example.json](../examples/schema/schema_multi_app_form_relation_layout.example.json) |
25
- | Existing-app field capability probe | [schema_apply_add_fields_all_types.json](../examples/schema/schema_apply_add_fields_all_types.json) |
23
+ | AppForm declaration shape and CLI sequence | This document: [Create app with AppForm](#create-app-with-appform) and [AppForm scenario matrix](#3-appform-场景矩阵) |
24
+ | Historical schema capability probe (not the current 21-type manifest) | [schema_apply_add_fields_all_types.json](../examples/schema/schema_apply_add_fields_all_types.json) |
25
+ | Historical existing-app field capability probe | [schema_apply_add_fields_all_types.json](../examples/schema/schema_apply_add_fields_all_types.json) |
26
26
 
27
- ## Create app with `form`
27
+ ## Create app with AppForm
28
28
 
29
- `form` is the only recommended creation shape. Each section contains rows; each row contains field objects. For new apps, `form` is both the field schema and the form layout. Do not create a separate `layout` object and do not call `builder layout apply` after app creation just to place those fields.
29
+ The current creation shape is a complete AppForm declaration: `spec.body` contains fields, sections, rows, and settings. Pin the version with `qingflow --json builder app-form schema`. For updates, preserve IDs from `qingflow --json builder app-form get --app-key APP_KEY --being-draft`; validate and apply through the CLI commands above. Do not call the retired schema/layout CLI adapters.
30
30
 
31
31
  ```json
32
- [
33
- {
34
- "section": "基础信息",
35
- "rows": [
36
- [
37
- {"name": "工单编号", "type": "text", "data_title": true},
38
- {"name": "产品", "type": "text"},
39
- {"name": "状态", "type": "select", "options": ["待排产", "生产中", "已完工"]}
40
- ],
41
- [
42
- {"name": "计划数量", "type": "number"},
43
- {"name": "计划完成日期", "type": "date"}
44
- ]
32
+ {
33
+ "apiVersion": "builder.qingflow.com/v1alpha1",
34
+ "packageId": 123456,
35
+ "spec": {
36
+ "appName": "生产工单",
37
+ "dataTitleField": {"name": "工单编号"},
38
+ "body": [
39
+ {
40
+ "kind": "section",
41
+ "title": "基础信息",
42
+ "rows": [
43
+ {"fields": [
44
+ {"name": "工单编号", "type": "text"},
45
+ {"name": "产品", "type": "text"},
46
+ {"name": "状态", "type": "single_select", "config": {"options": ["待排产", "生产中", "已完工"]}}
47
+ ]},
48
+ {"fields": [
49
+ {"name": "计划数量", "type": "number"},
50
+ {"name": "计划完成日期", "type": "date"}
51
+ ]}
52
+ ]
53
+ }
45
54
  ]
46
55
  }
47
- ]
56
+ }
48
57
  ```
49
58
 
50
- Single-app CLI:
59
+ Historical CLI shape (retired; do not run):
51
60
 
52
61
  ```bash
53
62
  qingflow --json builder schema apply \
@@ -59,7 +68,7 @@ qingflow --json builder schema apply \
59
68
  > tmp/schema_apply_production_order.json
60
69
  ```
61
70
 
62
- Complete-system `apps-file` item:
71
+ Historical complete-system item shape (retired; do not run):
63
72
 
64
73
  ```json
65
74
  {
@@ -76,7 +85,7 @@ Complete-system `apps-file` item:
76
85
  }
77
86
  ```
78
87
 
79
- Complete-system CLI:
88
+ Historical complete-system CLI (retired; do not run):
80
89
 
81
90
  ```bash
82
91
  qingflow --json builder schema apply \
@@ -84,7 +93,7 @@ qingflow --json builder schema apply \
84
93
  > tmp/schema_apply_system.json
85
94
  ```
86
95
 
87
- For the complete-system apps-file, use the object shape below. The same file carries app identity, fields, relation fields, and layout:
96
+ The following is retained only to recognize a historical `apps-file` payload. It is not a current template: create each app with its own AppForm declaration, save the returned `appKey`, then bind relations with `targetAppKey`.
88
97
 
89
98
  ```json
90
99
  {
@@ -141,131 +150,124 @@ For the complete-system apps-file, use the object shape below. The same file car
141
150
  }
142
151
  ```
143
152
 
144
- ## Existing-app schema maintenance only
153
+ ## Existing-app field maintenance notes
145
154
 
146
- - Re-read fields before updating; selectors may use `name`, `field_id`, or `que_id`.
147
- - Switch from `add_fields` to `update_fields` when a field already exists.
148
- - Use `remove_fields` only when deletion is explicitly intended.
149
- - If apply returns uncertain write state, re-read fields before retrying.
150
- - Do not use this section for new complete-system creation. New apps should stay on the `apps[].form` path above.
155
+ - Re-read the published and draft AppForm before updating; preserve every field and ID that should remain.
156
+ - Use complete AppForm target state for additions, edits, layout changes, and removals; never replay a partial field patch.
157
+ - Run `qingflow --json builder app-form validate --schema-version VERSION --file DECLARATION.json` before every apply and follow AppForm recovery rules for uncertain write state.
151
158
 
152
- Example patch:
153
-
154
- ```json
155
- {
156
- "app_key": "APP_KEY",
157
- "publish": true,
158
- "add_fields": [{"name": "跟进日期", "type": "date"}],
159
- "update_fields": [
160
- {
161
- "selector": {"name": "金额"},
162
- "set": {"name": "订单金额", "required": true}
163
- }
164
- ],
165
- "remove_fields": [{"name": "旧字段"}]
166
- }
167
- ```
159
+ Current updates must be complete AppForm declarations. Start from
160
+ `qingflow --json builder app-form get --app-key APP_KEY --being-draft`, keep the existing `appKey`/IDs, change the
161
+ desired `spec.body`, validate the complete declaration, and apply it. The old
162
+ `add_fields`/`update_fields`/`remove_fields` patch shape is retired and is not a
163
+ current CLI payload.
168
164
 
169
165
  ## Field type reference
170
166
 
171
- > **口径**:`field.type` 枚举以 **`qingflow --json builder contract --tool-name app_schema_apply`**(及包内 `PublicFieldType`)为准;**形状校验**以 `qingflow_mcp` 的 **`FieldPatch`**(`builder_facade/models.py`)与 **`app_schema_apply` 编排**(`builder_facade/service.py`)为准。
172
- > **CLI**:`qingflow [--profile NAME] builder schema apply [--app-key APP_KEY | 创建模式… | --apps-file 多应用对象] [--publish|--no-publish] [--form-file …] [--update-fields-file …] [--remove-fields-file …]`;**`qingflow` 未在 PATH 时**可用 `npx @qingflow-tech/qingflow-cli` 前缀,并把 `--profile` 放在 `builder` 之前。
173
- > **新建应用主规则**:`form` 里必须有且仅有一个顶层字段标记 `data_title: true`;数据封面可选,只能在顶层 `attachment` 字段标记 `data_cover: true`。
167
+ > **口径**:`field.questionType` 枚举和字段形状以固定版本的 **`qingflow --json builder app-form schema`** 返回结果为准;每个 canonical 类型还可用 `--field-type TYPE` 获取细节,`defaultType: 3` 的公式语法和函数目录用 `--schema-kind formula` 获取。不要从已退休的 `app_schema_apply` contract 推断当前 AppForm payload。
168
+ > **CLI**:表单写入使用 `qingflow [--profile NAME] --json builder app-form schema/get/validate/apply`;`validate/apply` 接受 `--file`,`get` 接受 `--app-key`。旧 `builder schema apply` 及 `builder layout apply` 不在当前 parser 的公开命令集合中。
169
+ > **新建应用主规则**:`spec.body` 非空时必须用 `spec.dataTitleField` 唯一选择一个顶层字段作为数据标题;数据封面可选,只能用 `spec.dataCoverField` 选择顶层 `attachment` 字段。
174
170
  > **权限**:包内新建应用按后端 `CreateAppBean` 链路只预检目标包 **AddAppAuth**;已有应用的字段/基础信息变更才走应用自身 **EditAppAuth**。
175
171
 
176
172
  ## 0. 字段建模一眼决策表
177
173
 
178
- 先按业务语义选字段类型。主路径可以写智能体友好的别名,CLI 会归一化;读回出现 canonical 类型不是失败。
174
+ 先按业务语义选字段类型。当前主路径使用 pinned AppForm Schema 返回的 canonical 类型;历史别名只在迁移旧草稿时识别,不能作为新声明模板。
179
175
 
180
176
  | 业务语义 | 推荐写法 | 注意 |
181
177
  | --- | --- | --- |
182
- | 名称、标题、编号、短文本 | `text` | 新建应用必须且只能有一个顶层可读字段标记 `data_title: true` |
183
- | 说明、备注、描述、长文本 | `multiline` | 写入归一化为 `long_text`;不要因为读回 `long_text` 而重建字段 |
184
- | 状态、类型、等级、阶段、是否枚举 | `select` | 写入归一化为 `single_select`;必须同时定义 `options` |
185
- | 标签、多选项、多个类别 | `multi_select` | `checkbox` 是兼容别名;必须定义 `options` |
178
+ | 名称、标题、编号、短文本 | `text` | 非空表单必须通过应用级 `dataTitleField` 唯一选择一个顶层字段 |
179
+ | 说明、备注、描述、长文本 | `long_text` | 多行文本 |
180
+ | 状态、类型、等级、阶段、是否枚举 | `single_select` | 必须在 `config.options` 定义非空字符串数组 |
181
+ | 标签、多选项、多个类别 | `multi_select` | 必须在 `config.options` 定义非空字符串数组 |
186
182
  | 数量、比例、分数、工时、百分比、时长 | `number` | 需要小数或计算时优先 `number` |
187
183
  | 金额、费用、单价、预算 | `amount` | 只用于货币/金额语义,不要拿它存比例或普通数量 |
188
184
  | 日期、计划日、截止日 | `date` | 同时需要时分秒才用 `datetime` |
189
185
  | 负责人、审批人、参与人 | `member` | 不要创建“申请人/提交人”等平台系统字段 |
190
- | 部门、组织 | `department` | 可按需要补 `department_scope` |
191
- | 图片、文件、附件 | `attachment` | 只有顶层 `attachment` 可标记 `data_cover: true` |
192
- | 跨应用业务对象关系 | `relation` | 同批应用只用 `target_app_ref`;已存在应用维护才用 `target_app_key`;`display_field` / `visible_fields` 必须写对象选择器 |
186
+ | 部门、组织 | `department` | 可按需要补 `config.departmentScope` |
187
+ | 图片、文件、附件 | `attachment` | 只有顶层 `attachment` 可被应用级 `dataCoverField` 选择 |
188
+ | 跨应用业务对象关系 | `relation` | 使用已确认的 `targetAppKey`;`displayField` / `visibleFields` 必须写对象选择器 |
193
189
 
194
190
  禁止创建平台系统字段:`数据ID`、`编号`、`申请人`、`申请时间`、`创建人`、`创建时间`、`提交人`、`提交时间`、`更新时间`、`更新人`、`当前流程状态`、`当前处理人`、`当前处理节点`、`流程标题`。需要引用系统字段时,只在工具明确支持的位置引用,例如按钮 `source_field: "数据ID"`。
195
191
 
196
192
  ---
197
193
 
198
- ## 1. 全部 `field.type`(19 种)
194
+ ## 1. 全部 `field.type`(21 种)
199
195
 
200
- 与契约一致时,搭建侧 **`add_fields[]` / `update_fields[]`** 可用类型为:
196
+ 固定 AppForm Schema 中可用的字段类型为:
201
197
 
202
- | `type` | 说明(搭建语义) |
198
+ | `questionType` | 说明(搭建语义) |
203
199
  |--------|------------------|
204
200
  | `text` | 单行文本 |
205
201
  | `long_text` | 多行文本 |
206
202
  | `number` | 数字 |
207
203
  | `amount` | 金额 |
204
+ | `link` | 链接 |
208
205
  | `date` | 日期 |
209
206
  | `datetime` | 日期时间 |
210
207
  | `member` | 成员 |
211
- | `department` | 部门(可带 `department_scope`) |
208
+ | `department` | 部门(可带 `config.departmentScope`) |
212
209
  | `single_select` | 单选 |
213
210
  | `multi_select` | 多选 |
214
211
  | `phone` | 电话 |
215
212
  | `email` | 邮箱 |
216
213
  | `address` | 地址 |
217
214
  | `attachment` | 附件 |
218
- | `boolean` | 是否 |
219
- | `q_linker` | 远程查询 / 数据获取(**`q_linker_binding`**) |
220
- | `code_block` | 代码块(**`code_block_binding`** + 编译后的 `code_block_config`) |
221
- | `relation` | 关联记录(**`relation_mode`**:`single` \| `multiple`) |
215
+ | `single_choice` | 兼容的单选类型;新声明优先使用 `single_select` |
216
+ | `q_linker` | 远程查询 / 数据获取(**`config.qLinkerBinding`**) |
217
+ | `code_block` | 代码块(**`config.codeBlockBinding`**) |
218
+ | `relation` | 关联记录(**`config.relationMode`**:`single` \| `multiple`) |
219
+ | `data_relation` | 数据关联/引用填充 |
222
220
  | `subtable` | 子表(**`subfields[]`**) |
223
221
 
224
- **`relation_mode`**:仅 **`relation`** 使用,取值为 **`single`** 或 **`multiple`**。一个应用可以有多个 `relation` 字段;不要因为 relation 数量超过 1 就改成文本字段。
222
+ **`config.relationMode`**:仅 **`relation`** 使用,取值为 **`single`** 或 **`multiple`**。一个应用可以有多个 `relation` 字段;不要因为 relation 数量超过 1 就改成文本字段。
225
223
 
226
- ### 1.1 智能体友好字段类型别名
224
+ ### 1.1 历史字段类型别名
227
225
 
228
- 主路径可以写更符合直觉的字段类型;工具写入前自动归一化,读回和排障时仍使用 canonical 类型:
226
+ 主路径使用 pinned AppForm Schema 返回的 canonical 类型;下列别名只用于识别历史载荷,不作为当前声明模板:
229
227
 
230
- | 智能体写法 | canonical 类型 |
228
+ | 历史写法 | 当前 canonical 类型 |
231
229
  |------------|----------------|
232
230
  | `multiline` / `multiline_text` / `textarea` | `long_text` |
233
231
  | `select` / `single_choice` / `dropdown` | `single_select` |
234
232
  | `multi_select` / `multi_choice` / `multiple_choice` / `checkbox` | `multi_select` |
235
233
 
236
- 完整映射以 `builder contract --tool-name app_schema_apply` 的 `$.contract.allowed_values["field.type_aliases"]` 为准。
234
+ `boolean`、`multiline`、`select`、`checkbox` 等仅是兼容输入,归一化结果以固定版本的 `qingflow --json builder app-form schema --field-type TYPE` 类型详情为准;新声明不要使用这些别名。
237
235
 
238
236
  ---
239
237
 
240
238
  ## 2. 按类型的必填 / 常用可选(写意图)
241
239
 
242
- | `type` | 通常必填 | 常见可选 / 约束 |
240
+ | `questionType` | 通常必填 | 常见可选 / 约束 |
243
241
  |--------|----------|-----------------|
244
- | 标量与选择器 | `name` + `type`(+ 业务 `required` 等) | `description`、`required`;新建应用时其中一个顶层可读字段须 `data_title: true`;**`single_select` / `multi_select` 的 `options` 可用字符串数组或对象数组**,如 `["A", "B"]` 或 `[{"label":"A","value":"a"}]`,工具会归一化为选项文案 |
245
- | `department` | 同左 | **`department_scope`**:`mode: all \| custom`;`custom` 时 **`departments[]`**(含 `dept_id` 等) |
246
- | `relation` | 同批新建:**`target_app_ref`**;已有目标应用维护:**`target_app_key`**;另需 **`display_field`**、**`visible_fields[]`** | **`relation_mode`**;目标应用元数据不可读时可多写 **`name`** 降级 |
247
- | `subtable` | **`subfields[]` 非空** | 子列递归同父级规则;更新已存在子列优先契约 **`subfield_updates`** |
248
- | `q_linker` | **`q_linker_binding`**:`inputs`、`request`、**`outputs[]` 每项须含 `target_field`**(能解析到本表单字段) | `request.url` 等须符合**租户/后端远程查询策略**;读回 JSON 可能**缺** `outputs[].target_field`,会导致本地再编译失败(见 §5) |
249
- | `code_block` | **`code_block_binding`**:`inputs`、`code`、**`outputs[]` + `target_field`**;代码体须能被规范识别 **`qf_output` 赋值** | **`auto_trigger`**、按钮文案;勿与 **`code_block_config.code_content`** 与 **`binding.code`** 冲突 |
242
+ | 标量与选择器 | `name` + `questionType`(+ 业务 `beingRequired` 等) | `questionDescription`、`beingRequired`;数据标题和封面在应用级 `dataTitleField/dataCoverField` 中选择;**`single_select` / `multi_select` 的 `config.options` 是非空字符串数组**,如 `["A", "B"]` |
243
+ | `department` | 同左 | **`config.departmentScope`**:`mode: all \| custom`;`custom` 时 **`departments[]`**(含 `deptId` 等) |
244
+ | `relation` | **`targetAppKey`**;另需 **`displayField`**、**`visibleFields[]`** | **`relationMode`**;目标应用元数据不可读时先读已发布表单,不要猜目标 key |
245
+ | `subtable` | **`subfields[]` 非空** | 子列递归同父级规则;使用 Schema 返回的 camelCase 子字段配置 |
246
+ | `q_linker` | **`config.qLinkerBinding`**:`inputs`、`request`、**`outputs[]` 每项须含 `targetField`**(能解析到本表单字段) | `request.url` 等须符合**租户/后端远程查询策略**;以字段类型 Schema 返回的配置为准 |
247
+ | `code_block` | **`config.codeBlockBinding`**:`inputs`、`code`、**`outputs[]` + `targetField`**;配置 outputs 时,代码必须显式写 **`qf_output = {...}`**,仅 `return {...}` 不会产生可回写结果,且每个 `outputs[].path` 必须从 `qf_output` 取值 | 以字段类型 Schema 返回的 camelCase 配置为准 |
250
248
 
251
249
  别名:契约会把 `title`/`label` 映射到 **`name`** 等;字段类型自然别名见 §1.1。
252
250
 
253
251
  ### 2.1 `relation` 选择器形态
254
252
 
255
- `relation` 的目标应用可以用字符串键,但展示字段选择器必须写对象,不要写裸字符串:
253
+ `relation` 的配置必须使用已确认的目标应用 key;展示字段选择器必须写对象,不要写裸字符串:
256
254
 
257
255
  ```json
258
256
  {
259
257
  "name": "关联产品",
260
258
  "type": "relation",
261
- "target_app_ref": "product",
262
- "relation_mode": "single",
263
- "display_field": {"name": "产品编码"},
264
- "visible_fields": [{"name": "产品名称"}, {"name": "产品线"}]
259
+ "config": {
260
+ "targetAppKey": "PRODUCT_APP_KEY",
261
+ "relationMode": "single",
262
+ "displayField": {"name": "产品编码"},
263
+ "visibleFields": [{"name": "产品名称"}, {"name": "产品线"}]
264
+ }
265
265
  }
266
266
  ```
267
267
 
268
- 允许的目标应用写法:同批多应用只写 `target_app_ref`,已存在且已读回确认的目标应用才写 `target_app_key`。如果返回 `display_field` / `visible_fields` 的 Pydantic 错误,通常是把选择器写成了字符串;只修这一段字段 payload,不要重建应用或改 app_key。
268
+ 只在目标应用已经创建并通过 readback 确认后填写 `targetAppKey`。如果返回选择器校验错误,修复 `config.displayField` / `config.visibleFields`,不要重建应用或改 `appKey`。
269
+
270
+ 引用字段的公式默认值写在 `config.defaultValueFormula`,表达式必须符合固定版本 `relation` 字段详情中的 `FormulaExpression`。不要把后端 `referenceConfig` 字段名或其他 Schema 版本的公式写法直接放进声明。
269
271
 
270
272
  ### 2.2 工作流状态字段
271
273
 
@@ -273,18 +275,14 @@ Example patch:
273
275
 
274
276
  ---
275
277
 
276
- ## 3. `builder schema apply` 场景矩阵
278
+ ## 3. AppForm 场景矩阵
277
279
 
278
- | 场景 | 必备 CLI 参数 | 说明 |
280
+ | 场景 | 当前入口 | 说明 |
279
281
  |------|----------------|------|
280
- | 编辑已有应用 | `--app-key`;可选 `--no-publish` | **不要**与 `--package-id` 同用 |
281
- | 包内新建应用 | `--package-id`、`--app-name`(或 title 映射)、`--form-file` | `form` 内必须有且仅有一个顶层可读字段标记 `data_title: true` |
282
- | 多应用一次性新建 | `--apps-file`,文件顶层写 `package_id` + `apps`,每个应用写 `apps[].form` | 应用包/系统里有 2 个以上应用,或同批应用之间有 `relation` 时使用;多应用按 `app_name` 直接提交创建,不自动查重或按名称复用;重名/冲突按后端结果和写后读回处理;`apps[].client_key` 被同批 relation 的 `target_app_ref` 引用;不要在主链路使用 raw apps array、singleton wrapper array、单独 layout 或逐个创建后回填 `target_app_key` |
283
- | 仅增字段 | `--add-fields-file`(JSON 数组) | 与 **`update_fields`/`remove_fields`** 可同次组合(以契约为准) |
284
- | 改字段 | `--update-fields-file` | 每项 **`selector`**(`name`/`que_id`/`field_id`)+ **`set`** |
285
- | 删字段 | `--remove-fields-file` | 每项至少 **`name`/`que_id`/`field_id`** 之一 |
286
- | 可见性(新建/部分元数据) | `--visibility-file` | `mode` / `external_mode` / `selectors` 见交付文 §3.2 |
287
- | 发布 | 默认或 `--publish`;探针常用 **`--no-publish`** | 与 **`app_publish_verify`** 配合 |
282
+ | 编辑已有应用 | `qingflow --json builder app-form get --app-key APP_KEY --being-draft` -> `qingflow --json builder app-form validate --schema-version VERSION --file DECLARATION.json` -> `qingflow --json builder app-form apply --file DECLARATION.json` | 保留完整 `body` 和现有 IDs;不要提交部分字段 patch |
283
+ | 包内新建应用 | `qingflow --json builder app-form schema` -> declaration without `appKey` -> `qingflow --json builder app-form validate --schema-version VERSION --file DECLARATION.json` -> `qingflow --json builder app-form apply --file DECLARATION.json` | 须含 `packageId`、`spec.appName` 和完整 `body`;图标与颜色按应用名生成 |
284
+ | 多应用系统 | 每个 app 独立走 AppForm;先创建无关系 app,再用已确认 `appKey` 更新关系 | 不使用旧 `apps-file` 批量 schema 路径 |
285
+ | 删除应用 | 显式用户意图 -> `qingflow --json builder app delete --app-key APP_KEY` | 不通过字段删除 |
288
286
 
289
287
  ---
290
288
 
@@ -292,9 +290,10 @@ Example patch:
292
290
 
293
291
  | 内容 | 位置 |
294
292
  |------|------|
295
- | **完整系统新建主示例:多应用 + 同批 relation + form 布局** | [schema_multi_app_form_relation_layout.example.json](../examples/schema/schema_multi_app_form_relation_layout.example.json) |
296
- | **19 种 `type` + `code_block` + `q_linker` + 1 个 `relation`(字段能力探针,不是新建主模板)** | [schema_apply_add_fields_all_types.json](../examples/schema/schema_apply_add_fields_all_types.json)(用于字段类型覆盖测试;正式新建应用优先用上文 `form`) |
297
- | **`q_linker_example` / `code_block_example`**(契约内置形状) | `ai_builder_tools.py` 中 `app_schema_apply` 合约 |
293
+ | **当前完整系统主入口** | [20-build-complete-system.md](./20-build-complete-system.md) |
294
+ | **历史字段类型能力探针(不是新建主模板)** | [schema_apply_add_fields_all_types.json](../examples/schema/schema_apply_add_fields_all_types.json)(仅用于旧字段能力覆盖测试;当前新建和更新统一使用上文 AppForm) |
295
+ | **`q_linker` / `code_block` / relation 配置**(契约内置形状) | `qingflow --json builder app-form schema --schema-version VERSION --field-type TYPE` 返回的固定版本字段详情 |
296
+ | **默认值与其他公式文本** | `qingflow --json builder app-form schema --schema-version VERSION --schema-kind formula` 返回的同版本公式语法、字段引用、运算符和函数目录 |
298
297
  | 最小新建字段(1 个 text 标题字段) | [schema_add_fields_minimal.example.json](../examples/schema/schema_add_fields_minimal.example.json) |
299
298
  | 历史 scalar / complex 批测(可选) | [_batch_schema_scalar.json](../examples/schema/_batch_schema_scalar.json)、[_batch_schema_complex.json](../examples/schema/_batch_schema_complex.json) |
300
299
 
@@ -302,11 +301,11 @@ Example patch:
302
301
 
303
302
  ## 5. 实跑结论
304
303
 
305
- **一次性新建应用**:`--package-id` + `--app-name` + `--form-file` 是当前推荐写法;`form` 同时表达字段和表单分组布局。字段类型覆盖测试文件只用于能力探针,不作为正式业务应用模板。
304
+ **新建应用**:固定 AppForm schema 版本,使用无 `appKey` 的完整声明创建;字段、分组、行布局和设置统一在 `spec.body` 内表达。字段类型覆盖测试文件只用于能力探针,不作为正式业务应用模板。
306
305
 
307
- **一次性新建多个应用**:用 `builder schema apply --apps-file tmp/apps.json`,其中 `tmp/apps.json` 唯一主写法为 `{ "package_id": 123, "apps": [...] }`,每个 `apps[]` 写顶层 `client_key + app_name + icon + color + form`;多应用模式按 `app_name` 直接提交创建,不在工具内查重或按名称复用。若后端返回重名/冲突,或写入结果不确定,先读回应用包和字段,再决定复用、补齐缺失资源或询问用户。`apps[].client_key` 可被同批 relation 字段的 `target_app_ref` 引用,工具会编译成真实 `target_app_key`。CLI 内部会并发创建 app 壳,再并发写入每个 app 的完整 schema;智能体仍只写同一个 `apps-file`。这是应用包/系统搭建的默认路径,尤其适合“商机 + 订单 + 回款”“花名册 + 工时”等互相关联场景;不要为了拿 `app_key` 先逐个创建再二次补关联字段。
306
+ **多应用系统**:先创建 relation-independent AppForms,立即记录每个返回的 `appKey`,再用完整 AppForm 更新依赖关系。若写入结果不确定,先读 draft/published form,禁止重放创建、猜名称或使用后缀应用。
308
307
 
309
- **限制(平台硬性)**:`--app-key` 向已有应用追加字段时须 **字段名不重复**;`relation` 字段数量不做“每应用只能一个”的智能体侧限制,按后端实际校验和写后读回为准。**`example.com`** 作 `q_linker` URL 易触发 **`46031`**,本清单改用 httpbin。**读回缺 `outputs[].target_field` 的 `q_linker`** 会拖死后续 `schema apply`,须修复或删除该题。
308
+ **限制(平台硬性)**:relation 字段数量不做“每应用只能一个”的智能体侧限制,按 pinned AppForm Schema、后端校验和写后读回为准。`q_linker` / `code_block` 的配置必须使用当前字段 Schema 返回的 camelCase 形状。
310
309
 
311
310
  **排障**:`--json`;**`DUPLICATE_FIELD`**;真实写入失败看 `SCHEMA_APPLY_FAILED` 的 `backend_code`、`details.relation_field_count` 和读回矩阵。
312
311
 
@@ -1,43 +1,52 @@
1
- # Builder Layout
1
+ # Builder Form Layout (AppForm)
2
2
 
3
3
  Read this only when the task is about repairing or changing the form layout of an existing app.
4
4
 
5
5
  ## Scope
6
6
 
7
- Responsible for: `builder layout apply`, section titles, `rows` matrix, merge/replace mode, and existing-app layout repair.
7
+ Responsible for: AppForm section titles, `rows` matrix, and existing-app layout repair.
8
8
 
9
- Not responsible for: creating new apps, adding fields, or complete-system app creation. New apps must put layout directly in `form` through [30-schema-fields.md](./30-schema-fields.md).
9
+ Not responsible for: creating new apps, adding fields, or complete-system app creation. New apps must put layout directly in `spec.body` through [30-schema-fields.md](./30-schema-fields.md).
10
10
 
11
- Do not read this as part of the normal complete-system creation path. If the app is new, write field objects inside `form[].rows[]` and submit them with `builder schema apply`.
11
+ Do not read this as a standalone CLI write path. For new or existing apps, edit the complete canonical AppForm `body` through the CLI AppForm sequence in [30-schema-fields.md](./30-schema-fields.md).
12
12
 
13
13
  ## Main chain
14
14
 
15
15
  ```text
16
- existing app get fields -> existing app get layout -> prepare sections -> builder layout apply -> readback when needed
16
+ qingflow --json builder app-form get --app-key APP_KEY --being-draft -> edit spec.body sections/rows -> qingflow --json builder app-form validate --schema-version VERSION --file DECLARATION.json -> qingflow --json builder app-form apply --file DECLARATION.json -> readback on recovery
17
17
  ```
18
18
 
19
19
  ## Demo file
20
20
 
21
- Use [layout_sections_full.example.json](../examples/layout/layout_sections_full.example.json) as the existing-app layout maintenance base. Replace `app_key` and field names after reading the app fields.
21
+ Use [layout_sections_full.example.json](../examples/layout/layout_sections_full.example.json) only as a historical layout probe. For current work, start from `qingflow --json builder app-form get --app-key APP_KEY --being-draft` and preserve the complete canonical declaration.
22
22
 
23
- ## Public shape
23
+ ## Canonical shape
24
24
 
25
- For existing-app layout maintenance, use section `title + rows`. This is form layout: each `rows[]` item is a row of field names. Do not invent top-level `columns`, and do not use portal `x/y/cols/rows` here.
25
+ For AppForm layout maintenance, use canonical sections and rows from the pinned AppForm Schema. Each row contains the allowed field objects/IDs for that version. Do not invent top-level `columns`, and do not use portal `x/y/cols/rows` here.
26
26
 
27
27
  ```json
28
28
  {
29
- "app_key": "APP_KEY",
30
- "mode": "merge",
31
- "publish": true,
32
- "sections": [
33
- {
34
- "title": "基础信息",
35
- "rows": [
36
- ["客户名称", "订单金额"],
37
- ["状态", "负责人"]
38
- ]
39
- }
40
- ]
29
+ "apiVersion": "builder.qingflow.com/v1alpha1",
30
+ "appKey": "APP_KEY",
31
+ "spec": {
32
+ "body": [
33
+ {
34
+ "kind": "section",
35
+ "sectionId": "30001",
36
+ "title": "基础信息",
37
+ "rows": [
38
+ {"fields": [
39
+ {"queId": 101, "name": "客户名称", "type": "text", "dataTitle": true},
40
+ {"queId": 102, "name": "订单金额", "type": "amount"}
41
+ ]},
42
+ {"fields": [
43
+ {"queId": 103, "name": "状态", "type": "single_select", "config": {"options": ["待处理", "已完成"]}},
44
+ {"queId": 104, "name": "负责人", "type": "member"}
45
+ ]}
46
+ ]
47
+ }
48
+ ]
49
+ }
41
50
  }
42
51
  ```
43
52
 
@@ -45,26 +54,25 @@ For existing-app layout maintenance, use section `title + rows`. This is form la
45
54
 
46
55
  | Intent | Correct shape | Avoid |
47
56
  | --- | --- | --- |
48
- | Group fields on a form | `sections[].title + sections[].rows` | Portal `position.pc` / `x` / `y` / `cols` |
57
+ | Group fields on a form | `spec.body[].title + spec.body[].rows` | Portal `position.pc` / `x` / `y` / `cols` |
49
58
  | Put fields on one horizontal form row | `["客户名称", "订单金额"]` inside `rows` | Top-level `columns` |
50
- | Keep existing layout and add/update groups | `mode: "merge"` | `replace` unless intentionally rewriting everything |
59
+ | Keep existing layout and add/update groups | complete AppForm body preserving existing blocks | partial `mode`/`sections` payloads |
51
60
  | Repair missing/unknown field errors | Re-read `app get fields` and remove/correct names | Guessing field ids from old payload |
52
61
 
53
62
  Short rule: **form layout rows arrange fields; portal rows arrange components. Do not mix the two.**
54
63
 
55
64
  ## Update existing layout
56
65
 
57
- - Prefer `mode: "merge"` unless intentionally replacing the entire layout.
58
- - Re-read `app get fields` before writing; every field in `rows` must exist.
59
- - Re-read `app get layout` when apply returns `partial_success` or layout validation details.
60
- - Batch layout writes are for existing-app maintenance only; each `apps[]` item carries its own `app_key` and layout payload.
61
- - If you are creating apps, stop and use `builder schema apply --apps-file` with `apps[].form` instead.
66
+ - Preserve the complete current AppForm body unless intentionally removing fields or sections.
67
+ - Re-read `qingflow --json builder app-form get --app-key APP_KEY --being-draft` before writing; every field in rows must be retained with its canonical ID.
68
+ - If apply returns `partial_success` or layout validation details, read the draft and published forms before retrying.
69
+ - There is no current batch layout CLI; update each app's complete AppForm independently.
62
70
 
63
71
  ## Common failures
64
72
 
65
73
  | Failure | Action |
66
74
  |---------|--------|
67
- | `UNKNOWN_LAYOUT_FIELD` | Re-read fields and remove or correct the missing field name. |
68
- | `DUPLICATE_LAYOUT_FIELD` | Keep each field in only one row. |
69
- | `INCOMPLETE_LAYOUT` | Switch to `merge` unless replacing the whole layout intentionally. |
70
- | repeated shape errors | Read `builder contract --tool-name app_layout_apply`; reuse the canonical section example. |
75
+ | `UNKNOWN_LAYOUT_FIELD` | Re-read the pinned AppForm Schema and draft; correct the field pointer. |
76
+ | `DUPLICATE_LAYOUT_FIELD` | Keep each field in only one row in the complete AppForm body. |
77
+ | `INCOMPLETE_LAYOUT` | Rebuild the complete body from the latest draft; do not submit a partial patch. |
78
+ | repeated shape errors | Re-run `qingflow --json builder app-form schema --schema-version VERSION` and validate before apply. |
@@ -1,6 +1,6 @@
1
1
  # Builder Index
2
2
 
3
- This directory is for Qingflow system-building work through `qingflow builder ...`.
3
+ This directory is for Qingflow system-building work through `qingflow builder ...`. Form fields, form layout, form settings, and application deletion use the direct CLI commands documented in [30-schema-fields.md](./30-schema-fields.md).
4
4
 
5
5
  ## Choose the main path
6
6
 
@@ -23,16 +23,16 @@ This directory is for Qingflow system-building work through `qingflow builder ..
23
23
  ## Default build order
24
24
 
25
25
  ```text
26
- package -> schema/apps with form -> workflow if requested/needed -> views -> portal with chart -> publish/readback verify
26
+ package -> AppForm per app -> workflow if requested/needed -> views -> portal with chart -> publish/readback verify
27
27
  ```
28
28
 
29
29
  Rules:
30
30
 
31
- - Complete systems create app shells, fields, relation fields, and form layout with one `builder schema apply --apps-file` call.
32
- - Complete systems use exactly one main schema shape: `{package_id, apps}`, with each app carrying `client_key + app_name + icon + color + form`.
33
- - Same-batch relations use `relation.target_app_ref` pointing to another `apps[].client_key`; do not create apps first just to get `target_app_key`.
34
- - Complete systems and new single apps define fields through `form`; fields and form sections/rows are one creation intent.
35
- - Do not use `add_fields`, separate `layout` payloads, or `builder layout apply` for new app creation. Use them only for existing-app maintenance.
31
+ - Complete systems create apps with `builder app-form schema`, `validate --schema-version VERSION --file DECLARATION.json`, and `apply --file DECLARATION.json`, one complete declaration per app, and retain each returned `appKey`.
32
+ - Pin the AppForm schema version and preserve every existing field, section, row, and ID on updates.
33
+ - Create relation-independent apps first; use confirmed target `appKey`s in later complete AppForm declarations.
34
+ - The CLI commands for form work are `builder app-form schema`, `builder app-form get`, `builder app-form validate`, and `builder app-form apply --file`.
35
+ - The old `builder schema apply` and `builder layout apply` routes are retired compatibility adapters, not public commands.
36
36
  - Single-app builds use one app path; do not add relation fields unless the user asks for cross-app modeling.
37
37
  - Workflow is conditional: build it only when the user asks for approval, fill/copy, reminders, process routing, task handling, or the business process clearly cannot work without it.
38
38
  - Portal chart sections use one `chart` field: `{"chart_id":"..."}` to reuse an existing QingBI chart, or `{"app_key":"...","name":"...","chart_type":"...",...}` to create/update the needed chart inline.
@@ -46,8 +46,8 @@ Rules:
46
46
  |------|----------------|
47
47
  | [10-build-single-app.md](./10-build-single-app.md) | One-app delivery order and completion standard |
48
48
  | [20-build-complete-system.md](./20-build-complete-system.md) | Multi-app package delivery order and relation strategy |
49
- | [30-schema-fields.md](./30-schema-fields.md) | Field types, schema apply, data title/cover, schema updates |
50
- | [40-layout.md](./40-layout.md) | Existing-app form layout maintenance only; new app creation uses `form` in schema apply |
49
+ | [30-schema-fields.md](./30-schema-fields.md) | Field modeling notes and AppForm pointer |
50
+ | [40-layout.md](./40-layout.md) | Retired layout-patch pointer; use the direct AppForm CLI sequence for form layout |
51
51
  | [50-views.md](./50-views.md) | Table/card/board/gantt views, filters, query panel, view patches, ordinary view action buttons |
52
52
  | [60-charts.md](./60-charts.md) | Standalone QingBI chart maintenance; portal dashboards normally use section `chart` for missing reports |
53
53
  | [70-portal.md](./70-portal.md) | Portal apply/delete, standard workbench layout, component config, section `chart` |
@@ -45,6 +45,8 @@ Current builder support:
45
45
  - one-step high-level config through `q_linker_binding`
46
46
  - internal compilation into existing backend payloads
47
47
 
48
+ `q_linker_binding` is the compatibility/high-level builder shorthand. In a current AppForm declaration, write the canonical `config.qLinkerBinding` shape returned by the pinned field Schema.
49
+
48
50
  ## Operating Order
49
51
 
50
52
  For code block or Q-Linker work, use this order:
@@ -53,8 +55,8 @@ For code block or Q-Linker work, use this order:
53
55
  - `qingflow builder app resolve`
54
56
  - `qingflow builder app get fields`
55
57
  2. Confirm the target field set already exists.
56
- 3. Apply schema updates with `qingflow builder schema apply`.
57
- 4. Read fields again and verify:
58
+ 3. Read the AppForm schema and the update draft, preserve the complete declaration, run `qingflow --json builder app-form validate --schema-version VERSION --file DECLARATION.json`, then run `qingflow --json builder app-form apply --file DECLARATION.json`.
59
+ 4. Read the published AppForm again and verify:
58
60
  - field type
59
61
  - alias config
60
62
  - target field binding shape
@@ -9,6 +9,8 @@
9
9
  - auto trigger
10
10
  - custom button text
11
11
 
12
+ For current AppForm declarations, use `config.codeBlockBinding` from the pinned field Schema. The snake_case `code_block_binding` name is a compatibility shorthand used by the high-level builder layer.
13
+
12
14
  ## Stable Writing Rules
13
15
 
14
16
  - Always emit `qf_output = {...}`
@@ -8,6 +8,8 @@
8
8
  - auto trigger
9
9
  - custom button text
10
10
 
11
+ For current AppForm declarations, use `config.qLinkerBinding` from the pinned field Schema. The snake_case `q_linker_binding` name is a compatibility shorthand used by the high-level builder layer.
12
+
11
13
  ## Current Supported Scope
12
14
 
13
15
  - custom mode only