@qingflow-tech/qingflow-app-builder-mcp 1.0.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.
Files changed (105) hide show
  1. package/README.md +32 -0
  2. package/docs/local-agent-install.md +332 -0
  3. package/entry_point.py +13 -0
  4. package/npm/bin/qingflow-app-builder-mcp.mjs +7 -0
  5. package/npm/lib/runtime.mjs +339 -0
  6. package/npm/scripts/postinstall.mjs +16 -0
  7. package/package.json +34 -0
  8. package/pyproject.toml +67 -0
  9. package/qingflow-app-builder-mcp +15 -0
  10. package/skills/qingflow-app-builder/SKILL.md +251 -0
  11. package/skills/qingflow-app-builder/agents/openai.yaml +4 -0
  12. package/skills/qingflow-app-builder/references/create-app.md +128 -0
  13. package/skills/qingflow-app-builder/references/environments.md +63 -0
  14. package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +123 -0
  15. package/skills/qingflow-app-builder/references/gotchas.md +64 -0
  16. package/skills/qingflow-app-builder/references/solution-playbooks.md +53 -0
  17. package/skills/qingflow-app-builder/references/tool-selection.md +93 -0
  18. package/skills/qingflow-app-builder/references/update-flow.md +158 -0
  19. package/skills/qingflow-app-builder/references/update-layout.md +68 -0
  20. package/skills/qingflow-app-builder/references/update-schema.md +68 -0
  21. package/skills/qingflow-app-builder/references/update-views.md +162 -0
  22. package/skills/qingflow-app-builder-code-integrations/SKILL.md +137 -0
  23. package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +4 -0
  24. package/skills/qingflow-app-builder-code-integrations/references/code-block.md +66 -0
  25. package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +77 -0
  26. package/src/qingflow_mcp/__init__.py +5 -0
  27. package/src/qingflow_mcp/__main__.py +5 -0
  28. package/src/qingflow_mcp/backend_client.py +649 -0
  29. package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
  30. package/src/qingflow_mcp/builder_facade/models.py +1836 -0
  31. package/src/qingflow_mcp/builder_facade/service.py +15044 -0
  32. package/src/qingflow_mcp/cli/__init__.py +1 -0
  33. package/src/qingflow_mcp/cli/commands/__init__.py +18 -0
  34. package/src/qingflow_mcp/cli/commands/app.py +40 -0
  35. package/src/qingflow_mcp/cli/commands/auth.py +44 -0
  36. package/src/qingflow_mcp/cli/commands/builder.py +538 -0
  37. package/src/qingflow_mcp/cli/commands/chart.py +18 -0
  38. package/src/qingflow_mcp/cli/commands/common.py +62 -0
  39. package/src/qingflow_mcp/cli/commands/imports.py +96 -0
  40. package/src/qingflow_mcp/cli/commands/portal.py +25 -0
  41. package/src/qingflow_mcp/cli/commands/record.py +331 -0
  42. package/src/qingflow_mcp/cli/commands/repo.py +80 -0
  43. package/src/qingflow_mcp/cli/commands/task.py +89 -0
  44. package/src/qingflow_mcp/cli/commands/view.py +18 -0
  45. package/src/qingflow_mcp/cli/commands/workspace.py +25 -0
  46. package/src/qingflow_mcp/cli/context.py +60 -0
  47. package/src/qingflow_mcp/cli/formatters.py +334 -0
  48. package/src/qingflow_mcp/cli/json_io.py +50 -0
  49. package/src/qingflow_mcp/cli/main.py +178 -0
  50. package/src/qingflow_mcp/config.py +513 -0
  51. package/src/qingflow_mcp/errors.py +66 -0
  52. package/src/qingflow_mcp/import_store.py +121 -0
  53. package/src/qingflow_mcp/json_types.py +18 -0
  54. package/src/qingflow_mcp/list_type_labels.py +76 -0
  55. package/src/qingflow_mcp/public_surface.py +233 -0
  56. package/src/qingflow_mcp/repository_store.py +71 -0
  57. package/src/qingflow_mcp/response_trim.py +470 -0
  58. package/src/qingflow_mcp/server.py +212 -0
  59. package/src/qingflow_mcp/server_app_builder.py +533 -0
  60. package/src/qingflow_mcp/server_app_user.py +362 -0
  61. package/src/qingflow_mcp/session_store.py +302 -0
  62. package/src/qingflow_mcp/solution/__init__.py +6 -0
  63. package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
  64. package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
  65. package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
  66. package/src/qingflow_mcp/solution/compiler/form_compiler.py +495 -0
  67. package/src/qingflow_mcp/solution/compiler/icon_utils.py +187 -0
  68. package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
  69. package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
  70. package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
  71. package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
  72. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  73. package/src/qingflow_mcp/solution/design_session.py +222 -0
  74. package/src/qingflow_mcp/solution/design_store.py +100 -0
  75. package/src/qingflow_mcp/solution/executor.py +2398 -0
  76. package/src/qingflow_mcp/solution/normalizer.py +23 -0
  77. package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
  78. package/src/qingflow_mcp/solution/run_store.py +244 -0
  79. package/src/qingflow_mcp/solution/spec_models.py +855 -0
  80. package/src/qingflow_mcp/tools/__init__.py +1 -0
  81. package/src/qingflow_mcp/tools/ai_builder_tools.py +3419 -0
  82. package/src/qingflow_mcp/tools/app_tools.py +925 -0
  83. package/src/qingflow_mcp/tools/approval_tools.py +1062 -0
  84. package/src/qingflow_mcp/tools/auth_tools.py +875 -0
  85. package/src/qingflow_mcp/tools/base.py +388 -0
  86. package/src/qingflow_mcp/tools/code_block_tools.py +777 -0
  87. package/src/qingflow_mcp/tools/custom_button_tools.py +202 -0
  88. package/src/qingflow_mcp/tools/directory_tools.py +675 -0
  89. package/src/qingflow_mcp/tools/feedback_tools.py +238 -0
  90. package/src/qingflow_mcp/tools/file_tools.py +409 -0
  91. package/src/qingflow_mcp/tools/import_tools.py +2189 -0
  92. package/src/qingflow_mcp/tools/navigation_tools.py +210 -0
  93. package/src/qingflow_mcp/tools/package_tools.py +326 -0
  94. package/src/qingflow_mcp/tools/portal_tools.py +158 -0
  95. package/src/qingflow_mcp/tools/qingbi_report_tools.py +374 -0
  96. package/src/qingflow_mcp/tools/record_tools.py +14037 -0
  97. package/src/qingflow_mcp/tools/repository_dev_tools.py +552 -0
  98. package/src/qingflow_mcp/tools/resource_read_tools.py +421 -0
  99. package/src/qingflow_mcp/tools/role_tools.py +112 -0
  100. package/src/qingflow_mcp/tools/solution_tools.py +4054 -0
  101. package/src/qingflow_mcp/tools/task_context_tools.py +2228 -0
  102. package/src/qingflow_mcp/tools/task_tools.py +890 -0
  103. package/src/qingflow_mcp/tools/view_tools.py +335 -0
  104. package/src/qingflow_mcp/tools/workflow_tools.py +376 -0
  105. package/src/qingflow_mcp/tools/workspace_tools.py +125 -0
@@ -0,0 +1,53 @@
1
+ # Builder Playbooks
2
+
3
+ Use these when you need a quick reminder of the standard v2 builder sequences.
4
+
5
+ ## Create a new app in an existing package
6
+
7
+ 1. `package_resolve`
8
+ 2. `app_resolve`
9
+ 3. `app_schema_apply`
10
+ 4. `package_attach_app`
11
+ 5. `app_publish_verify` only if the user asks for explicit live verification
12
+
13
+ ## Update fields on an existing app
14
+
15
+ 1. `app_resolve`
16
+ 2. `app_get_fields`
17
+ 3. `app_schema_apply`
18
+
19
+ ## Rework layout
20
+
21
+ 1. `app_get_layout`
22
+ 2. `app_layout_apply`
23
+
24
+ Prefer `mode=merge`. Use `mode=replace` only when every field placement is intentional.
25
+
26
+ ## Add or update workflow
27
+
28
+ 1. `app_get_fields`
29
+ 2. `app_get_flow`
30
+ 3. `role_search` or `member_search`
31
+ 4. `role_create` if the business wants a reusable role and no good exact role exists
32
+ 5. `app_flow_apply`
33
+
34
+ If `app_flow_apply` reports `FLOW_DEPENDENCY_MISSING`, fix schema first.
35
+ If it reports `FLOW_ASSIGNEE_REQUIRED`, resolve roles or members first and retry with canonical `assignees.*`.
36
+
37
+ ## Add or update views
38
+
39
+ 1. `app_get_fields`
40
+ 2. `app_get_views`
41
+ 3. `app_views_apply`
42
+
43
+ For both workflow and view work, prefer `suggested_next_call` over re-guessing arguments after a validation failure.
44
+
45
+ ## Final readback
46
+
47
+ Prefer these fields after writes:
48
+
49
+ - `app_get.tag_ids`
50
+ - `app_get.publish_status`
51
+ - `app_get_layout.unplaced_fields`
52
+ - `app_get_views.views`
53
+ - `app_get_flow.nodes`
@@ -0,0 +1,93 @@
1
+ # Tool Selection
2
+
3
+ Use the smallest v2 builder tool chain that can finish the task.
4
+
5
+ ## Default path
6
+
7
+ `resolve -> summary read -> apply -> attach -> publish_verify`
8
+
9
+ Public builder `apply` tools already perform server-side planning, normalization, and dependency checks internally. Do not route normal public builder work through explicit `*_plan` tools.
10
+
11
+ ## Hierarchy first
12
+
13
+ Before picking tools, decide which layer the request targets:
14
+
15
+ - `package`: a solution/app bundle like “研发项目管理” or “费控管理系统”
16
+ - `app`: one form/app inside that package
17
+ - `field`: one field inside one app
18
+ - `relation`: a field that links two apps
19
+
20
+ If the user asks for multiple forms/modules that relate to each other, this is a package-level multi-app task, not a single-app create.
21
+
22
+ ## Resolve
23
+
24
+ - `package_create`: create a new package only after the user confirms package creation; exact-name duplicates return `noop=true`
25
+ - `package_resolve`: exact package lookup by name
26
+ - `package_list`: read-only fallback when package resolution is ambiguous
27
+ - `member_search`: resolve named people from the directory
28
+ - `role_search`: resolve reusable roles from the directory
29
+ - `role_create`: create a reusable role when the business owner wants role-based routing
30
+ - `app_resolve`: locate an existing app by exactly one selector mode: `app_key`, or `app_name + package_tag_id`
31
+
32
+ ## Summary reads
33
+
34
+ - `app_get`: overall app config health, publish state, counts, and builder editability
35
+ - `app_get_fields`: field names, types, required flags, section ids
36
+ - `app_get_layout`: sections, rows, unplaced fields
37
+ - `app_get_views`: current view names, types, columns, group-by
38
+ - `app_get_flow`: workflow enabled state, nodes, transitions
39
+ - `app_get_charts`: current chart ids, names, types, order
40
+ - `portal_get`: current portal config detail and component inventory
41
+
42
+ ## Apply tools
43
+
44
+ These execute normalized patches and publish by default unless `publish=false`.
45
+
46
+ - `app_schema_apply`: create app shell or change fields
47
+ - `app_layout_apply`: merge or replace layout
48
+ - `app_flow_apply`: replace workflow
49
+ - `app_views_apply`: upsert or remove views
50
+ - `app_charts_apply`: upsert/remove/reorder QingBI charts; charts are immediate-live and do not publish; use `chart_id` when names are not unique
51
+ - `portal_apply`: create or replace-update portal pages; use `dash_key` for update mode or `package_tag_id + dash_name` for create mode; sections are replace-only and omission deletes old sections; `publish=false` only guarantees draft/base-info updates
52
+
53
+ ## Explicit post-apply tools
54
+
55
+ - `package_attach_app`: attach an app to a package with `tag_id + app_key`; do not assume create or publish attaches it
56
+ - `app_publish_verify`: explicit final publish verification when the user asks for live confirmation
57
+
58
+ ## Decision shortcuts
59
+
60
+ - Create one app inside an existing package:
61
+ `package_resolve -> app_resolve -> app_schema_apply -> package_attach_app`
62
+ - Create a brand new package, then create one app in it:
63
+ `package_create -> package_resolve -> app_schema_apply -> package_attach_app`
64
+ - Create a brand new multi-app system/package:
65
+ `package_create/resolve -> per-app app_schema_apply -> package_attach_app per app -> relation field patches`
66
+ - Update fields on an existing app:
67
+ `app_resolve -> app_get_fields -> app_schema_apply`
68
+ - Tidy layout:
69
+ `app_get_fields -> app_get_layout -> builder_tool_contract (if shape is unclear) -> app_layout_apply`
70
+ - Add workflow:
71
+ `builder_tool_contract -> app_get_fields -> app_get_flow -> role_search/member_search -> app_flow_apply -> app_get_flow`
72
+ - Add views:
73
+ `builder_tool_contract -> app_get_fields -> app_get_views -> app_views_apply -> app_get_views`
74
+ - Add QingBI charts:
75
+ `builder_tool_contract -> app_get_fields -> app_get_charts -> app_charts_apply -> app_get_charts`
76
+ - Create or update a portal:
77
+ `builder_tool_contract -> portal_get -> portal_apply -> portal_get`
78
+
79
+ ## Avoid
80
+
81
+ - Do not handcraft raw Qingflow schema payloads
82
+ - Do not rely on internal `solution_*` tools in public builder flows
83
+ - Do not create a new package without first asking the user to confirm package creation
84
+ - Do not treat a package/system name as `app_name` when the user clearly wants multiple apps inside it
85
+ - Do not compress multiple business objects into one app with several text fields
86
+ - Do not skip summary reads before flow or view work
87
+ - Do not emit `column_names`; always use `columns`
88
+ - Do not model layout shape with `fields`, `field_ids`, or top-level `columns`; custom layout sections should be `title + rows`
89
+ - Do not reuse internal flow keys such as `role_entries` or `editable_que_ids` in public builder calls
90
+ - Do not pass natural-language preset guesses such as `default_approval`; map them to canonical preset values first
91
+ - Do not omit assignees on approval/fill/copy nodes
92
+ - Do not patch preset flows with brand new approval/fill node ids unless you are intentionally replacing the skeleton; reuse preset ids like `approve_1` and `fill_1`
93
+ - Do not guess role ids, member ids, or editable field ids; resolve names first
@@ -0,0 +1,158 @@
1
+ # Update Flow
2
+
3
+ Use this when the app already exists and the task is only about workflow.
4
+
5
+ ## Minimal sequence
6
+
7
+ 1. `builder_tool_contract(tool_name="app_flow_apply")`
8
+ 2. `app_get_fields`
9
+ 3. `app_get_flow`
10
+ 4. `role_search` or `member_search`
11
+ 5. `role_create` if the user wants a reusable directory role and no good role exists
12
+ 6. start from a canonical preset when possible
13
+ 7. patch the skeleton instead of freehanding a full graph
14
+ 8. reuse preset node ids when patching:
15
+ - `basic_approval` -> patch `approve_1`
16
+ - `basic_fill_then_approve` -> patch `fill_1` and `approve_1`
17
+ Do not add a second approval/fill node with a new id unless you are intentionally replacing the skeleton.
18
+ The MCP now auto-aligns the simplest single-node preset overrides, but still prefer explicit preset ids so the merged graph stays predictable.
19
+ 9. `app_flow_apply`
20
+ 10. `app_get_flow` when apply returns `partial_success` or the user asked for verification
21
+
22
+ If you are unsure about presets or node shapes, call `builder_tool_contract(tool_name="app_flow_apply")` before guessing.
23
+
24
+ ## Example
25
+
26
+ Canonical preset mapping:
27
+
28
+ - “默认审批/基础审批/普通审批” -> `basic_approval`
29
+ - “先填报再审批/提交后审批” -> `basic_fill_then_approve`
30
+
31
+ Apply a simple approval flow with a role assignee and node-level editable fields:
32
+
33
+ ```json
34
+ {
35
+ "tool_name": "app_flow_apply",
36
+ "arguments": {
37
+ "profile": "default",
38
+ "app_key": "APP_123",
39
+ "preset": "basic_approval",
40
+ "publish": true,
41
+ "nodes": [
42
+ {
43
+ "id": "approve_1",
44
+ "type": "approve",
45
+ "name": "部门审批",
46
+ "assignees": {
47
+ "role_names": ["项目经理"]
48
+ },
49
+ "permissions": {
50
+ "editable_fields": ["状态", "审批意见"]
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ }
56
+ ```
57
+
58
+ For flexible business requirements, do not jump straight to a full custom graph. Use this safer pattern:
59
+
60
+ 1. build a base skeleton from a preset
61
+ 2. identify the business-specific changes
62
+ 3. patch nodes/transitions explicitly
63
+
64
+ Public flow building is intentionally limited to linear workflows. Use only:
65
+
66
+ - `start`
67
+ - `approve`
68
+ - `fill`
69
+ - `copy`
70
+ - `webhook`
71
+ - `end`
72
+
73
+ Do not generate `branch` or `condition` nodes through `app_flow_apply`. The backend workflow route is not front-end stable for those node types, and MCP now returns `FLOW_NODE_TYPE_UNSUPPORTED` instead of writing a visually broken flow.
74
+ After `app_flow_apply` returns blocking issues or canonical arguments, prefer reusing its `suggested_next_call.arguments` directly. Do not rewrite the result into internal fields such as `role_entries` or `editable_que_ids`.
75
+ When you patch a preset, patch the preset node itself. Do not leave the preset approval node unassigned while adding a second custom approval node.
76
+
77
+ ## Common failures
78
+
79
+ ### `FLOW_ASSIGNEE_REQUIRED`
80
+
81
+ Approval, fill, and copy nodes must declare at least one assignee.
82
+
83
+ If this happens after using a preset, check for this specific mistake first:
84
+
85
+ - the preset created `approve_1` or `fill_1`
86
+ - your patch created a different node id instead of patching that preset node
87
+ - the original preset node remained in the graph without assignees
88
+
89
+ Preferred fix order:
90
+
91
+ 1. `role_search`
92
+ 2. `member_search` only if the user explicitly named members
93
+ 3. `role_create` if the business needs a reusable role
94
+ 4. patch the preset node id itself with canonical `assignees.*`
95
+ 5. retry `app_flow_apply`
96
+
97
+ ### `FLOW_DEPENDENCY_MISSING`
98
+
99
+ The workflow depends on fields that do not exist yet, usually `status`. Fix schema first.
100
+
101
+ Preferred recovery:
102
+
103
+ 1. use the returned `suggested_next_call`
104
+ 2. apply the minimal schema patch
105
+ 3. rerun `app_get_fields`
106
+ 4. rerun `app_flow_apply`
107
+
108
+ ### `INVALID_FLOW_EDGE`
109
+
110
+ One or more transitions reference unknown nodes or create an invalid graph.
111
+
112
+ ### `UNKNOWN_FLOW_FIELD`
113
+
114
+ The workflow referenced a field name that does not exist, often in:
115
+
116
+ - `permissions.editable_fields`
117
+
118
+ Call `app_get_fields` and retry with the exact field names returned by the app.
119
+
120
+ ### `FLOW_NODE_TYPE_UNSUPPORTED`
121
+
122
+ The public workflow builder only supports linear flows. Remove `branch` and `condition` nodes and redesign the flow with stable sequential nodes instead of retrying the same graph.
123
+
124
+ ### `STATUS_FIELD_REQUIRED`
125
+
126
+ The app has no explicit status field recognized by the internal workflow compiler. Add one with `app_schema_apply`, then retry.
127
+
128
+ ### `FLOW_STAGE_CONTEXT_MISSING`
129
+
130
+ Internal flow stage context was missing or invalid. Re-run `app_flow_apply` with the normalized arguments, and do not switch to hidden `solution_*` tools.
131
+
132
+ ### `VALIDATION_ERROR`
133
+
134
+ Do not keep guessing preset names or node shapes. First:
135
+
136
+ 1. inspect `suggested_next_call`
137
+ 2. reuse `canonical_arguments` if present
138
+ 3. check `allowed_values`
139
+ 4. retry with canonical preset or canonical node types
140
+ 5. for workflow actors and permissions, always convert to:
141
+ - `assignees.role_names`
142
+ - `assignees.member_names`
143
+ - `permissions.editable_fields`
144
+
145
+ Do not copy internal keys from old plan outputs or logs, including:
146
+
147
+ - `role_entries`
148
+ - `editable_que_ids`
149
+
150
+ ## Notes
151
+
152
+ - `mode=replace` is the only supported flow apply mode
153
+ - `app_flow_apply` publishes by default
154
+ - Prefer roles over explicit members unless the user explicitly asks for named members
155
+ - `basic_approval` and `basic_fill_then_approve` are skeletons, not complete business workflows
156
+ - Report results precisely:
157
+ - “基础流程骨架已创建” when only the preset landed
158
+ - “业务定制规则已补齐” only after the patch phase is complete
@@ -0,0 +1,68 @@
1
+ # Update Layout
2
+
3
+ Use this when fields already exist and the task is only about form grouping or ordering.
4
+
5
+ ## Minimal sequence
6
+
7
+ 1. `app_get_fields`
8
+ 2. `app_get_layout`
9
+ 3. `builder_tool_contract` when the section shape is not already obvious
10
+ 4. `app_layout_apply`
11
+
12
+ ## Example
13
+
14
+ Apply a custom layout with the canonical public section shape:
15
+
16
+ ```json
17
+ {
18
+ "tool_name": "app_layout_apply",
19
+ "arguments": {
20
+ "profile": "default",
21
+ "app_key": "APP_123",
22
+ "mode": "merge",
23
+ "publish": true,
24
+ "sections": [
25
+ {
26
+ "title": "基础信息",
27
+ "rows": [
28
+ ["客户名称", "订单金额"],
29
+ ["状态", "跟进日期"]
30
+ ]
31
+ }
32
+ ]
33
+ }
34
+ }
35
+ ```
36
+
37
+ ## Common failures
38
+
39
+ ### `UNKNOWN_LAYOUT_FIELD`
40
+
41
+ At least one field name does not exist. Re-read with `app_get_fields`.
42
+
43
+ ### `DUPLICATE_LAYOUT_FIELD`
44
+
45
+ The same field appears more than once in the requested layout.
46
+
47
+ ### `INCOMPLETE_LAYOUT`
48
+
49
+ Only happens in `mode=replace`. Switch to `mode=merge` unless you intend to place every field exactly once.
50
+
51
+ ### `LAYOUT_APPLY_FAILED`
52
+
53
+ Re-read with `app_get_layout`. Check `current_field_names`, `request_id`, and `suggested_next_call`.
54
+
55
+ ### `VALIDATION_ERROR`
56
+
57
+ Do not keep guessing section keys. Reuse `suggested_next_call`, `canonical_arguments`, `section_allowed_keys`, and `minimal_section_example`.
58
+
59
+ If the same shape error repeats twice, stop free-form retries and re-read `builder_tool_contract(app_layout_apply)`.
60
+
61
+ ## Notes
62
+
63
+ - `section_id` is optional; it is generated from the section title
64
+ - `merge` is safer than `replace`
65
+ - Unmentioned fields stay in place or get auto-added to `未分组字段`
66
+ - Public builder layout sections use `title + rows`
67
+ - Do not treat “一行四个字段 / 四列布局 / 每行放四个” as a top-level `columns` parameter; translate it into a `rows` matrix
68
+ - Do not prefer `fields` or `field_ids` once `rows` is known, even though MCP may normalize those shorthands for recovery
@@ -0,0 +1,68 @@
1
+ # Update Schema
2
+
3
+ Use this when the app already exists and the task is only about fields.
4
+
5
+ ## Minimal sequence
6
+
7
+ 1. `app_resolve`
8
+ 2. `app_get_fields`
9
+ 3. `app_schema_apply`
10
+
11
+ ## Example
12
+
13
+ Read current fields first:
14
+
15
+ ```json
16
+ {
17
+ "tool_name": "app_get_fields",
18
+ "arguments": {
19
+ "profile": "default",
20
+ "app_key": "APP_123"
21
+ }
22
+ }
23
+ ```
24
+
25
+ Apply the patch:
26
+
27
+ ```json
28
+ {
29
+ "tool_name": "app_schema_apply",
30
+ "arguments": {
31
+ "profile": "default",
32
+ "app_key": "APP_123",
33
+ "publish": true,
34
+ "add_fields": [
35
+ {"name": "跟进日期", "type": "date"}
36
+ ],
37
+ "update_fields": [
38
+ {"selector": {"name": "金额"}, "set": {"name": "订单金额", "required": true}}
39
+ ],
40
+ "remove_fields": [
41
+ {"name": "旧字段"}
42
+ ]
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Common failures
48
+
49
+ ### `FIELD_NOT_FOUND`
50
+
51
+ The selector did not match current schema. Re-read with `app_get_fields` and use `name`, `field_id`, or `que_id`.
52
+
53
+ ### `DUPLICATE_FIELD`
54
+
55
+ The field already exists with a different shape. Switch from `add_fields` to `update_fields`.
56
+
57
+ ### `SCHEMA_APPLY_FAILED`
58
+
59
+ Treat it as uncertain write state. Read back with `app_get_fields` before retrying.
60
+
61
+ ## Notes
62
+
63
+ - `title` and `label` are accepted aliases for `name`
64
+ - `textarea -> long_text`
65
+ - `currency -> amount`
66
+ - `mobile -> phone`
67
+ - `select/radio -> single_select`
68
+ - `checkbox -> multi_select`
@@ -0,0 +1,162 @@
1
+ # Update Views
2
+
3
+ Use this when the task is only about table, card, board, or gantt views.
4
+
5
+ ## Minimal sequence
6
+
7
+ 1. `builder_tool_contract(tool_name="app_views_apply")`
8
+ 2. `app_get_fields`
9
+ 3. `app_get_views`
10
+ 4. `app_views_apply`
11
+ 5. `app_get_views` again whenever apply returns `failed` or `partial_success`
12
+
13
+ If you are unsure about keys or view types, call `builder_tool_contract(tool_name="app_views_apply")` before guessing.
14
+
15
+ Important verification rule:
16
+
17
+ - `app_views_apply` can create a view object before every filter is fully verified in readback
18
+ - Do not report “筛选已成功应用” unless the apply result also shows `verification.views_verified=true`
19
+ - If apply returns `partial_success`, inspect `verification.by_view` and `details.filter_mismatches` before claiming the filters are active
20
+
21
+ ## Example
22
+
23
+ Canonical rules before any example:
24
+
25
+ - Always use `columns`
26
+ - Do not emit `column_names`
27
+ - Treat `fields` only as a legacy alias the MCP may normalize, not as the preferred shape
28
+ - Use `filters` with canonical keys `field_name`, `operator`, `value`/`values`
29
+ - For gantt, use `start_field`, `end_field`, and optionally `title_field`
30
+ - If `app_get_views` shows duplicate view names, include `view_key` in `upsert_views[]` and update that exact target
31
+
32
+ Apply a default table view:
33
+
34
+ ```json
35
+ {
36
+ "tool_name": "app_views_apply",
37
+ "arguments": {
38
+ "profile": "default",
39
+ "app_key": "APP_123",
40
+ "publish": true,
41
+ "upsert_views": [
42
+ {
43
+ "name": "全部订单",
44
+ "view_key": "VIEW_KEY_IF_DUPLICATE_NAMES_EXIST",
45
+ "type": "table",
46
+ "columns": ["订单编号", "客户名称", "订单金额", "状态"]
47
+ }
48
+ ],
49
+ "remove_views": []
50
+ }
51
+ }
52
+ ```
53
+ After `app_views_apply` returns canonical arguments or blocking issues, prefer reusing its `suggested_next_call.arguments` directly. Do not rewrite aliases back into non-canonical keys such as `column_names`.
54
+
55
+ Board example:
56
+
57
+ ```json
58
+ {
59
+ "tool_name": "app_views_apply",
60
+ "arguments": {
61
+ "profile": "default",
62
+ "app_key": "APP_123",
63
+ "upsert_views": [
64
+ {
65
+ "name": "按状态看板",
66
+ "type": "board",
67
+ "group_by": "状态",
68
+ "columns": ["订单编号", "客户名称", "订单金额"]
69
+ }
70
+ ],
71
+ "remove_views": []
72
+ }
73
+ }
74
+ ```
75
+
76
+ Gantt example with filters:
77
+
78
+ ```json
79
+ {
80
+ "tool_name": "app_views_apply",
81
+ "arguments": {
82
+ "profile": "default",
83
+ "app_key": "APP_123",
84
+ "upsert_views": [
85
+ {
86
+ "name": "项目甘特图",
87
+ "type": "gantt",
88
+ "columns": ["项目名称", "开始日期", "结束日期", "状态"],
89
+ "start_field": "开始日期",
90
+ "end_field": "结束日期",
91
+ "title_field": "项目名称",
92
+ "filters": [
93
+ {
94
+ "field_name": "状态",
95
+ "operator": "eq",
96
+ "value": "进行中"
97
+ }
98
+ ]
99
+ }
100
+ ],
101
+ "remove_views": []
102
+ }
103
+ }
104
+ ```
105
+
106
+ ## Common failures
107
+
108
+ ### `UNKNOWN_VIEW_FIELD`
109
+
110
+ At least one `columns` or `group_by` field name does not exist.
111
+
112
+ ### `INVALID_VIEW_TYPE`
113
+
114
+ Public view types are only `table`, `card`, `board`, `gantt`.
115
+
116
+ Map old or intuitive labels before calling the tool:
117
+
118
+ - `tableView` -> `table`
119
+ - `cardView` -> `card`
120
+ - `kanban` -> `board`
121
+
122
+ ### `INVALID_GANTT_CONFIG`
123
+
124
+ Gantt views require at least:
125
+
126
+ - `start_field`
127
+ - `end_field`
128
+
129
+ Also make sure these field names already exist on the app.
130
+
131
+ ### `VIEW_APPLY_FAILED`
132
+
133
+ The backend rejected the normalized view payload. Re-read fields and inspect `request_id` before retrying.
134
+
135
+ Do not repeat `app_views_apply` with guessed keys. First:
136
+
137
+ 1. check `suggested_next_call`
138
+ 2. reuse `canonical_arguments` if present
139
+ 3. call `app_get_views` to see whether any requested views landed anyway
140
+ 4. if needed, call `builder_tool_contract`
141
+ 5. retry only the minimal failed view patch
142
+
143
+ ### `VIEW_FILTER_READBACK_MISMATCH`
144
+
145
+ The view object was created or updated, but the readback config did not keep the intended filter values.
146
+
147
+ Treat this as:
148
+
149
+ - the view exists
150
+ - the filter is **not yet verified**
151
+
152
+ Do not tell the user the filter is active until the readback verification matches the intended filter.
153
+
154
+ ## Notes
155
+
156
+ - `fields` is accepted as an alias for `columns`, but skill examples should still use `columns`
157
+ - `column_names` should not appear in skill examples
158
+ - `app_get_views` should be treated as canonical readback and now returns `columns`
159
+ - If `app_views_apply` returns `AMBIGUOUS_VIEW`, stop and re-run `app_get_views`; then retry with the exact `view_key`
160
+ - `filters` are ANDed together as one flat condition group
161
+ - `app_views_apply` publishes by default
162
+ - For select-style filters, success means the backend preserved the option value in readback, not just that the view name now exists