@qingflow-tech/qingflow-cli 1.1.33 → 1.1.34

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 (37) hide show
  1. package/README.md +2 -2
  2. package/docs/local-agent-install.md +10 -0
  3. package/package.json +1 -1
  4. package/pyproject.toml +1 -1
  5. package/skills/qingflow-cli/SKILL.md +5 -5
  6. package/skills/qingflow-cli/reference/builder/90-workflow.md +6 -12
  7. package/skills/qingflow-cli/reference/builder/README.md +1 -1
  8. package/skills/qingflow-cli/reference/builder/reference/app-delivery-sop.md +3 -6
  9. package/skills/qingflow-cli/reference/builder/workflow/01-overview.md +6 -5
  10. package/skills/qingflow-cli/reference/builder/workflow/03-flow-patterns.md +1 -1
  11. package/skills/qingflow-cli/reference/builder/workflow/06-stage3-build-spec.md +33 -39
  12. package/skills/qingflow-cli/reference/builder/workflow/07-stage4-validate-spec.md +4 -10
  13. package/skills/qingflow-cli/reference/builder/workflow/08-stage5-apply-verify.md +2 -3
  14. package/skills/qingflow-cli/reference/builder/workflow/11-troubleshooting.md +2 -1
  15. package/skills/qingflow-cli/reference/builder/workflow/README.md +3 -3
  16. package/skills/qingflow-cli/scripts/workflow/validate_flow_spec.py +24 -2
  17. package/src/qingflow_mcp/builder_facade/service.py +41 -4
  18. package/src/qingflow_mcp/cli/commands/builder.py +15 -17
  19. package/src/qingflow_mcp/server_app_builder.py +1 -7
  20. package/src/qingflow_mcp/tools/ai_builder_tools.py +32 -51
  21. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/README.md +0 -308
  22. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/build-complete-system.md +0 -819
  23. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/build-single-app.md +0 -836
  24. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/complete-system-development-guide.md +0 -137
  25. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/create-app.md +0 -203
  26. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/environments.md +0 -63
  27. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/flow-actors-and-permissions.md +0 -142
  28. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/gotchas.md +0 -116
  29. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/match-rules.md +0 -114
  30. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/public-surface-sync.md +0 -75
  31. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/single-app-development-guide.md +0 -69
  32. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/solution-playbooks.md +0 -52
  33. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/tool-selection.md +0 -113
  34. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-flow.md +0 -7
  35. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-layout.md +0 -7
  36. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-schema.md +0 -7
  37. package/skills/qingflow-cli/reference/builder/reference/legacy-playbooks/update-views.md +0 -7
@@ -255,10 +255,10 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
255
255
 
256
256
  flow_apply_apply = flow_apply_subparsers.add_parser("apply", help="执行流程变更")
257
257
  flow_apply_apply.add_argument("--app-key", required=True)
258
- flow_apply_apply.add_argument("--mode", choices=["replace"], default="replace")
258
+ flow_apply_apply.add_argument("--mode", choices=["replace"], default="replace", help=argparse.SUPPRESS)
259
259
  flow_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
260
- flow_apply_apply.add_argument("--nodes-file")
261
- flow_apply_apply.add_argument("--transitions-file")
260
+ flow_apply_apply.add_argument("--nodes-file", help=argparse.SUPPRESS)
261
+ flow_apply_apply.add_argument("--transitions-file", help=argparse.SUPPRESS)
262
262
  flow_apply_apply.add_argument("--spec-file")
263
263
  flow_apply_apply.add_argument("--patch-nodes-file", help="节点局部更新 JSON 数组,每项含 id + set/unset")
264
264
  flow_apply_apply.add_argument("--idempotency-key", default="")
@@ -855,11 +855,18 @@ def _handle_flow_apply(args: argparse.Namespace, context: CliContext) -> dict:
855
855
  patch_nodes = load_list_arg(getattr(args, "patch_nodes_file", None), option_name="--patch-nodes-file")
856
856
  spec = load_object_arg(getattr(args, "spec_file", None), option_name="--spec-file")
857
857
  has_legacy_nodes = bool(getattr(args, "nodes_file", None) or getattr(args, "transitions_file", None))
858
+ if has_legacy_nodes:
859
+ raise_config_error(
860
+ "builder flow apply no longer exposes legacy --nodes-file/--transitions-file input.",
861
+ fix_hint="Use --spec-file for a complete WorkflowSpec, or --patch-nodes-file for targeted edits after builder flow get.",
862
+ error_code="FLOW_LEGACY_INPUT_DISABLED",
863
+ details={"allowed_input_modes": ["--spec-file", "--patch-nodes-file"]},
864
+ )
858
865
  selected_modes = sum(1 for selected in (bool(patch_nodes), bool(spec), has_legacy_nodes) if selected)
859
866
  if selected_modes != 1:
860
867
  raise_config_error(
861
- "builder flow apply requires exactly one input mode: --spec-file, --patch-nodes-file, or --nodes-file with --transitions-file.",
862
- fix_hint="Use --patch-nodes-file for local edits, --spec-file for full WorkflowSpec, or legacy --nodes-file plus --transitions-file.",
868
+ "builder flow apply requires exactly one input mode: --spec-file or --patch-nodes-file.",
869
+ fix_hint="Use --spec-file for a complete WorkflowSpec, or --patch-nodes-file for targeted edits after builder flow get.",
863
870
  )
864
871
  if patch_nodes:
865
872
  return context.builder.app_flow_apply(
@@ -879,18 +886,9 @@ def _handle_flow_apply(args: argparse.Namespace, context: CliContext) -> dict:
879
886
  idempotency_key=args.idempotency_key,
880
887
  schema_version=args.schema_version,
881
888
  )
882
- if not getattr(args, "nodes_file", None) or not getattr(args, "transitions_file", None):
883
- raise_config_error(
884
- "legacy builder flow apply requires both --nodes-file and --transitions-file.",
885
- fix_hint="Pass both files, or use --spec-file / --patch-nodes-file.",
886
- )
887
- return context.builder.app_flow_apply(
888
- profile=args.profile,
889
- app_key=args.app_key,
890
- mode=args.mode,
891
- publish=bool(args.publish),
892
- nodes=require_list_arg(args.nodes_file, option_name="--nodes-file"),
893
- transitions=require_list_arg(args.transitions_file, option_name="--transitions-file"),
889
+ raise_config_error(
890
+ "builder flow apply requires --spec-file or --patch-nodes-file.",
891
+ fix_hint="Use --spec-file for a complete WorkflowSpec, or --patch-nodes-file for targeted edits after builder flow get.",
894
892
  )
895
893
 
896
894
 
@@ -52,7 +52,7 @@ def build_builder_server() -> FastMCP:
52
52
  "For associated reports/views, use app_associated_resources_apply for both the app-level associated_resources pool and per-view display config; associated_item_id is the app-level form_asos_chart.id, and view_configs/remove/reorder may also pass an existing resource's chart_id/chart_key/view_key because the tool resolves those to the internal id. Before creating an associated resource, read app_get.associated_resources and reuse an existing matching target_app_key + view_key/chart_key through patch_resources; client_key only works inside one apply call and is not persisted. Do not ask agents to pass backend raw sourceType: views infer the internal Qingflow view source, reports default to BI app reports, and dataset reports use report_source=dataset. "
53
53
  "For code_block fields with output bindings, always use qf_output assignment rather than const/let qf_output, and use app_repair_code_blocks when an existing form hangs because output-bound fields stay loading. "
54
54
  "Use package_apply to manage package metadata, visibility, grouping, and ordering, and app_publish_verify for explicit final publish verification. "
55
- "For workflow edits, use app_flow_get_schema/app_flow_get when raw WorkflowSpec shape is needed, then app_flow_apply with spec for full replacement or patch_nodes for targeted node edits; the legacy nodes/transitions path is only for simple linear start/approve/fill/copy/webhook/end flows. Declare node assignees and editable fields explicitly. "
55
+ "For workflow edits, use app_flow_get_schema/app_flow_get when raw WorkflowSpec shape is needed, then app_flow_apply with spec for full replacement or patch_nodes for targeted node edits. Declare node assignees and editable fields explicitly. "
56
56
  "If builder writes are blocked by the current user's own edit lock, use app_release_edit_lock_if_mine with the lock owner details from the failed result. "
57
57
  "Do not handcraft internal solution payloads or rely on build_id/stage/repair. "
58
58
  "If the current MCP capability is unsupported, the workflow is awkward, or the user's need still cannot be satisfied after reasonable use, first summarize the gap, ask whether to submit feedback, and call feedback_submit only after explicit user confirmation."
@@ -513,10 +513,7 @@ def build_builder_server() -> FastMCP:
513
513
  def app_flow_apply(
514
514
  profile: str = DEFAULT_PROFILE,
515
515
  app_key: str = "",
516
- mode: str = "replace",
517
516
  publish: bool = True,
518
- nodes: list[dict] | None = None,
519
- transitions: list[dict] | None = None,
520
517
  spec: dict | None = None,
521
518
  idempotency_key: str = "",
522
519
  schema_version: str = "",
@@ -525,10 +522,7 @@ def build_builder_server() -> FastMCP:
525
522
  return ai_builder.app_flow_apply(
526
523
  profile=profile,
527
524
  app_key=app_key,
528
- mode=mode,
529
525
  publish=publish,
530
- nodes=nodes or [],
531
- transitions=transitions or [],
532
526
  spec=spec,
533
527
  idempotency_key=idempotency_key or None,
534
528
  schema_version=schema_version or None,
@@ -720,10 +720,7 @@ class AiBuilderTools(ToolBase):
720
720
  def app_flow_apply(
721
721
  profile: str = DEFAULT_PROFILE,
722
722
  app_key: str = "",
723
- mode: str = "replace",
724
723
  publish: bool = True,
725
- nodes: list[JSONObject] | None = None,
726
- transitions: list[JSONObject] | None = None,
727
724
  spec: JSONObject | None = None,
728
725
  idempotency_key: str = "",
729
726
  schema_version: str = "",
@@ -732,10 +729,7 @@ class AiBuilderTools(ToolBase):
732
729
  return self.app_flow_apply(
733
730
  profile=profile,
734
731
  app_key=app_key,
735
- mode=mode,
736
732
  publish=publish,
737
- nodes=nodes or [],
738
- transitions=transitions or [],
739
733
  spec=spec,
740
734
  idempotency_key=idempotency_key or None,
741
735
  schema_version=schema_version or None,
@@ -3573,7 +3567,7 @@ class AiBuilderTools(ToolBase):
3573
3567
  *,
3574
3568
  profile: str,
3575
3569
  app_key: str,
3576
- mode: str = "replace",
3570
+ mode: str | None = None,
3577
3571
  publish: bool = True,
3578
3572
  nodes: list[JSONObject] | None = None,
3579
3573
  transitions: list[JSONObject] | None = None,
@@ -3625,29 +3619,37 @@ class AiBuilderTools(ToolBase):
3625
3619
  normalized_args=normalized_args,
3626
3620
  suggested_next_call={"tool_name": "app_flow_get", "arguments": {"profile": profile, "app_key": app_key}},
3627
3621
  ))
3628
- effective_nodes = nodes or []
3629
- effective_transitions = transitions or []
3630
- result = self._app_flow_apply_once(
3631
- profile=profile,
3632
- app_key=app_key,
3633
- mode=mode,
3634
- publish=publish,
3635
- nodes=effective_nodes,
3636
- transitions=effective_transitions,
3637
- )
3638
- result = self._retry_after_self_lock_release(
3639
- profile=profile,
3640
- result=result,
3641
- retry_call=lambda: self._app_flow_apply_once(
3622
+ if nodes or transitions:
3623
+ effective_nodes = nodes or []
3624
+ effective_transitions = transitions or []
3625
+ result = self._app_flow_apply_once(
3642
3626
  profile=profile,
3643
3627
  app_key=app_key,
3644
- mode=mode,
3628
+ mode=mode or "replace",
3645
3629
  publish=publish,
3646
3630
  nodes=effective_nodes,
3647
3631
  transitions=effective_transitions,
3648
- ),
3649
- )
3650
- return _attach_builder_apply_envelope("app_flow_apply", result)
3632
+ )
3633
+ result = self._retry_after_self_lock_release(
3634
+ profile=profile,
3635
+ result=result,
3636
+ retry_call=lambda: self._app_flow_apply_once(
3637
+ profile=profile,
3638
+ app_key=app_key,
3639
+ mode=mode or "replace",
3640
+ publish=publish,
3641
+ nodes=effective_nodes,
3642
+ transitions=effective_transitions,
3643
+ ),
3644
+ )
3645
+ return _attach_builder_apply_envelope("app_flow_apply", result)
3646
+ normalized_args = {"app_key": app_key, "publish": publish}
3647
+ return _attach_builder_apply_envelope("app_flow_apply", _failed(
3648
+ "FLOW_SPEC_OR_PATCH_REQUIRED",
3649
+ "app_flow_apply requires spec for a complete WorkflowSpec write or patch_nodes for targeted edits.",
3650
+ normalized_args=normalized_args,
3651
+ suggested_next_call={"tool_name": "app_flow_get_schema", "arguments": {"profile": profile}},
3652
+ ))
3651
3653
 
3652
3654
  def _app_flow_apply_once(
3653
3655
  self,
@@ -7731,7 +7733,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
7731
7733
  "approve/fill/copy nodes require at least one assignee",
7732
7734
  ],
7733
7735
  "execution_notes": [
7734
- "app_flow_plan is a legacy helper for linear public node aliases; use app_flow_get/app_flow_get_schema plus app_flow_apply spec or patch_nodes for the full WorkflowSpec path",
7736
+ "app_flow_plan is private compatibility plumbing, not an agent-facing workflow path; use app_flow_get/app_flow_get_schema plus app_flow_apply spec or patch_nodes",
7735
7737
  "do not create platform system workflow fields such as 当前流程状态 / 当前处理人 / 当前处理节点 / 流程标题; use an explicit business status field instead",
7736
7738
  ],
7737
7739
  "minimal_example": {
@@ -7759,35 +7761,22 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
7759
7761
  "patch_nodes",
7760
7762
  "idempotency_key",
7761
7763
  "schema_version",
7762
- "mode",
7763
- "nodes",
7764
- "transitions",
7765
7764
  ],
7766
7765
  "aliases": {
7767
- "overwrite": "replace",
7768
7766
  "patchNodes": "patch_nodes",
7769
7767
  "idempotencyKey": "idempotency_key",
7770
7768
  "schemaVersion": "schema_version",
7771
- "node.role_names": "node.assignees.role_names",
7772
- "node.role_ids": "node.assignees.role_ids",
7773
- "node.member_names": "node.assignees.member_names",
7774
- "node.member_emails": "node.assignees.member_emails",
7775
- "node.member_uids": "node.assignees.member_uids",
7776
- "node.editable_fields": "node.permissions.editable_fields",
7777
- },
7778
- "allowed_values": {
7779
- "mode": ["replace"],
7780
- "node.type": PUBLIC_STABLE_FLOW_NODE_TYPES,
7781
7769
  },
7770
+ "allowed_values": {},
7782
7771
  "dependency_hints": [
7783
7772
  "approval-style workflows require an explicit business status select field before app_flow_apply, such as 状态 / 处理状态 / 审批状态 / 工单状态",
7784
- "approve/fill/copy nodes require at least one assignee",
7773
+ "WorkflowSpec nodes should declare sync=true for routing nodes and explicit assignees for approval/filling/cc nodes",
7785
7774
  ],
7786
7775
  "execution_notes": [
7787
7776
  "preferred full workflow path is app_flow_get_schema/app_flow_get -> app_flow_apply with spec",
7788
7777
  "use patch_nodes for targeted existing-node edits; each item uses id plus set/unset",
7789
- "legacy nodes/transitions remains available for simple linear start/approve/fill/copy/webhook/end flows only",
7790
- "do not mix spec, patch_nodes, and legacy nodes/transitions in one call",
7778
+ "public workflow writes use only spec or patch_nodes",
7779
+ "do not mix spec and patch_nodes in one call",
7791
7780
  "do not create platform system workflow fields such as 当前流程状态 / 当前处理人 / 当前处理节点 / 流程标题; use an explicit business status field instead",
7792
7781
  "workflow readback is app_flow_get; use app_flow_get_schema when raw spec shape is unclear",
7793
7782
  ],
@@ -7803,14 +7792,6 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
7803
7792
  "publish": True,
7804
7793
  "patch_nodes": [{"id": "approve_1", "set": {"name": "主管审批"}}],
7805
7794
  },
7806
- "legacy_linear_example": {
7807
- "profile": "default",
7808
- "app_key": "APP_KEY",
7809
- "mode": "replace",
7810
- "publish": True,
7811
- "nodes": [{"id": "start", "type": "start", "name": "发起"}, {"id": "end", "type": "end", "name": "结束"}],
7812
- "transitions": [{"from": "start", "to": "end"}],
7813
- },
7814
7795
  },
7815
7796
  "app_views_plan": {
7816
7797
  "allowed_keys": [
@@ -1,308 +0,0 @@
1
- # Qingflow CLI App Builder Playbooks
2
-
3
- ## Overview
4
-
5
- This section is for the current **public builder surface** through `qingflow builder ...`, not for legacy low-level builder writes.
6
-
7
- Before any write or verification flow, identify whether the task targets `test` or `prod` and read [environments.md](./environments.md). If the user did not specify one, default to `prod`.
8
-
9
- Before choosing a route, skim the shared maintenance baseline: [public-surface-sync.md](./public-surface-sync.md).
10
-
11
- ## CLI-only Execution Rule
12
-
13
- Examples in this directory are CLI payload examples and workflow notes. Execute through the matching `qingflow` command from [SKILL.md](../../../../SKILL.md), the command index, or the canonical builder reference files; do not call internal tool JSON.
14
-
15
- ## Current Public Mental Model
16
-
17
- Model builder requests in four layers and keep them separate:
18
-
19
- - `package`: the app bundle or solution container
20
- - `app`: one form/app inside that package
21
- - `field`: one field inside one app
22
- - `relation`: a field that links one app to another app
23
-
24
- Default modeling rules:
25
-
26
- - One business object -> one app
27
- - Attributes of that object -> fields inside that app
28
- - Another business object -> a separate app, not a text field
29
- - Cross-object links -> relation fields, not text fields
30
-
31
- ## Public Tools You Should Think In
32
-
33
- - Package: `qingflow builder package get/apply`
34
- - App reads: `qingflow builder app resolve/get`, including batch `--app-keys`
35
- - Builder reads: `qingflow builder portal/view/chart/contract`
36
- - Directory: `qingflow builder member/role`
37
- - Writes: `qingflow builder schema/layout/flow/views/button/associated-resource/charts/portal apply`
38
- - Verification: `qingflow builder publish verify`
39
-
40
- Treat these as the official surface. Do not default to `package_create`, `package_attach_app`, raw `portal_*` writes, or raw `qingbi_report_*` writes.
41
-
42
- ## Current Public Defaults
43
-
44
- - Package work:
45
- - use `package_get(package_id=...)` to read one known package
46
- - use `package_apply(...)` for package creation, rename, icon, visibility, grouping, ordering, and app/portal layout
47
- - Multi-app schema work:
48
- - use one CLI `builder schema apply --apps-file` when creating several apps in one package
49
- - same-call relation fields may use `target_app_ref` to point at another `apps[].client_key`
50
- - Batch reads:
51
- - `builder app get`, `button get`, `associated-resource get`, and `publish verify` accept `--app-keys`
52
- - when reading several apps, prefer one batch read and inspect both `apps[]` and `errors[]`
53
- - Batch writes:
54
- - `builder layout/views/button/associated-resource/charts apply --apps-file` accepts multi-app batch writes
55
- - each `apps[]` item carries its own `app_key` plus that tool's normal single-app payload
56
- - App base permissions:
57
- - trust `app_get.editability.can_edit_app_base` for app base-info writes like app name, icon, and visibility
58
- - `can_edit_form` only means schema/form-route capability; it no longer implies app base-info write capability
59
- - Partial update rule:
60
- - for existing views, custom buttons, associated resources, and charts, prefer `patch_views` / `patch_buttons` / `patch_resources` / `patch_charts`
61
- - for existing workflow nodes, use `builder flow apply --patch-nodes-file` instead of rewriting the full `spec`
62
- - for existing portal sections, use `builder portal apply --patch-sections-file` instead of replacing all `sections`
63
- - each patch item uses the object's real selector field (`view_key` / `button_id` / `associated_item_id` / `chart_id`, or unique name where supported) plus `set` and optional `unset`; do not send a literal `selector` key for these tools
64
- - use `upsert_*` for creation or full target configuration; do not send a partial `upsert_*` and expect the backend to merge missing required fields
65
- - Portal work:
66
- - `portal_apply` is the public write path
67
- - in edit mode, omitting `sections` means “preserve existing layout and update base info only”
68
- - supplying `sections` means full replace semantics for sections
69
- - portal sections use a 24-column PC grid; all components sharing the same `y` coordinate must have identical `rows` values and their `cols` must sum to exactly 24; mixing `rows` in the same row causes height misalignment, and a `cols` sum under 24 leaves blank space at the row end; the next row's `y` must equal the previous row's `y` + `rows`
70
- - standard workbench heights: metric cards `rows=5`, BI charts `rows=7`, data views `rows=11`
71
- - business-entry grid sections must include real `config.items[]`; do not submit an empty grid container
72
- - Chart work:
73
- - `app_charts_apply` is the public write path for app-source QingBI report bodies/configs; it creates/updates reports with `dataSourceType=qingflow`
74
- - dataset BI reports are not created or edited by `app_charts_apply` yet; create them in QingBI first, then attach the existing report with `app_associated_resources_apply` and `report_source="dataset"`
75
- - it does not attach the report to the Qingflow app associated-resource display; use `app_associated_resources_apply` for that
76
- - choose chart type by goal: `target/indicator` for one KPI, `bar/columnar/pie` for distribution, `line/area` for trend, `table/detail/summary` for tabular summaries, `dualaxes` for two-metric comparison
77
- - use semantic metrics: `count(*)`, `sum(金额)`, `avg(工时)`, `group_by`, `where`; do not handwrite raw `indicator_field_ids`, `selectedMetrics`, or QingBI filter matrices on the main path
78
- - supported `chart_type` values include legacy public aliases `target`, `table` and QingBI types such as `summary`, `columnar`, `area`, `stacked_area`, `funnel`, `waterfall`, `gauge`, `heatmap`, `histogram`, `treemap`, `radar`, `stacked_bar`, `stacked_column`, `scatter`, `ring`, `rose`, `dualaxes`, `map`, and `timeline`
79
- - use `patch_charts` for changing a chart name, visibility, filters, or one config fragment on an existing chart
80
- - `visibility` is a public capability and should be treated as a base-only permission update
81
- - do not model chart visibility changes as raw config rewrites
82
- - Button work:
83
- - ordinary view-specific buttons should be declared through `app_views_apply.action_buttons`
84
- - `app_custom_buttons_apply` is for advanced button maintenance: style/icon changes, cross-view reuse, deleting button bodies, bulk binding reorder, or exact qRobot/wings configs
85
- - use `patch_buttons` for changing a single existing button parameter such as URL, text, icon, style, or add-data mapping
86
- - action choice:
87
- - current record -> downstream/child record: use `add_data` in view `action_buttons`, or `addData` in standalone buttons, with `target_app_key + field_mappings`
88
- - global independent create: use `add_data`/`addData` on `header` without current-record `source_field`
89
- - SOP/external/fixed page: use `link` with `url`
90
- - existing automation only: use `qRobot`/`wings` only when the user provides exact config
91
- - approval/status transition/close task is not a generic button action; model workflow/task action first, or use existing automation. Do not fake it with `link`
92
- - for add-data buttons, use `trigger_add_data_config.target_app_key + field_mappings/default_values`; do not handwrite raw `que_relation`
93
- - use `field_mappings` for dynamic current-record values, including system fields such as `数据ID` (`field_id=-17`) and `编号` (`field_id=0`)
94
- - to prefill a target relation field with the current source record, map `{"source_field": "数据ID", "target_field": "目标引用字段"}`; use `default_values` only for static constants
95
- - if field type compatibility is unclear, read [match-rules.md](./match-rules.md)
96
- - placement choice: `header` is global and has no current-row context; `list` is row/list action and maps to backend `INSIDE`; `detail` is the safest current-record context action. Do not use current-record `field_mappings` on `header`
97
- - bind advanced standalone buttons to views through `view_configs[].buttons[]`; default to `placement`: `header` or `detail`
98
- - builder `view_configs[].view_key` uses the raw key from `app_get.views[].view_key`, without a `custom:` prefix
99
- - `buttons` is required in merge mode; do not send a view config with only `view_key`
100
- - `view_configs[].mode` defaults to `merge`; use `mode: "replace"` or an explicit empty `buttons: []` to clear a view's custom button bindings
101
- - `placement=list` configures row/list buttons and maps to the backend `INSIDE` button position
102
- - advanced bindings may use `button_limit`, `button_formula`, `button_formula_type`, and `print_tpls` only when visibility or print-template behavior is required
103
- - Associated resources:
104
- - `app_associated_resources_apply` is the public write path for the Qingflow app-level associated report/view pool and per-view display config
105
- - for multi-app systems, use `apps[]` to batch associated-resource writes; each item carries its own `app_key` plus `upsert_resources` / `patch_resources` / `view_configs`
106
- - it attaches existing BI reports/views for in-app display; it does not create or edit QingBI report bodies/configs, including dataset reports
107
- - use `patch_resources` for changing match rules or other existing associated-resource parameters; the tool preserves backend-required raw fields internally
108
- - `associated_item_id` is the backend internal associated-resource id; for `view_configs`, `remove_associated_item_ids`, and `reorder_associated_item_ids`, you may pass `associated_item_id` or an existing resource's `chart_id`/`chart_key`/`view_key`, and the tool resolves it to the internal id
109
- - before creating a resource, check `app_get.associated_resources` for the same `target_app_key + view_key/chart_key`; if it already exists, use `patch_resources` with that `associated_item_id`
110
- - `client_key` is only a same-call reference for `view_configs[].associated_item_refs`; it is not saved and cannot deduplicate later calls
111
- - do not pass backend raw `sourceType`; view resources infer the internal Qingflow view source, report/chart resources default to BI app reports, and existing dataset reports use `report_source="dataset"`
112
- - use `match_mappings` for associated view/report filters; dynamic conditions use `source_field`, static conditions use `value`
113
- - if field type compatibility is unclear, read [references/match-rules.md](./match-rules.md)
114
- - Views and flows:
115
- - stay on `app_views_apply` / `app_flow_apply`
116
- - use `patch_views` for existing-view parameter changes such as `query_conditions`, `filters`, `columns`, or visibility
117
- - builder view writes use raw `view_key` values from `app_get.views`; `custom:<viewKey>` is a record-data `view_id` form, not a builder `view_key`
118
- - use `qingflow --json builder contract` whenever the minimal legal shape is unclear
119
- - keep view `filters` and `query_conditions` separate: `filters` are fixed saved filters; `query_conditions` configure the frontend query panel fields and only take effect after users enter query values
120
- - when creating any new table or card view, always include `query_conditions` with `enabled: true`; populate `rows` with the fields most useful for searching — typically the data-title field, any status/type select fields, date fields, and member fields; do not omit `query_conditions` or leave `rows` empty on a new view
121
- - new views default the associated report/view display area to visible with `limit_type="all"`; existing views preserve their current associated-resource display unless `associated_resources` is explicitly patched
122
- - configure associated reports/views through `app_associated_resources_apply`, not through `app_views_apply`
123
-
124
- ## Standard Operating Order
125
-
126
- 1. Ensure auth exists
127
- 2. Ensure workspace is selected
128
- 3. Confirm whether the task is read-only or write-impacting
129
- 4. Resolve the smallest stable target:
130
- - app-scoped work -> `app_resolve`
131
- - package-scoped work with known id -> `package_get`
132
- - portal inventory -> `portal_list`
133
- 5. Read only the smallest config slice needed:
134
- - app map -> `app_get` (default entry; includes compact views, charts, custom buttons, and associated resource pool)
135
- - fields -> `app_get_fields`
136
- - layout -> `app_get_layout`
137
- - views -> `app_get_views` only when the app_get compact list is not enough
138
- - flow -> `app_get_flow`
139
- - charts -> `app_get_charts` only when the app_get compact list is not enough
140
- - portal -> `portal_get`
141
- 6. If the public shape is unclear, call `qingflow --json builder contract`
142
- 7. Apply the smallest patch tool that fits:
143
- - fields -> `app_schema_apply`
144
- - layout -> `app_layout_apply`
145
- - flow -> `app_flow_apply`
146
- - existing views -> `app_views_apply.patch_views`; new/full views -> `app_views_apply.upsert_views`
147
- - existing buttons -> `app_custom_buttons_apply.patch_buttons`; new/full buttons -> `app_custom_buttons_apply.upsert_buttons`
148
- - existing associated resources -> `app_associated_resources_apply.patch_resources`; new/full resources -> `app_associated_resources_apply.upsert_resources`
149
- - existing charts -> `app_charts_apply.patch_charts`; new/full charts -> `app_charts_apply.upsert_charts`
150
- - portal -> `portal_apply`
151
- - package metadata/layout -> `package_apply`
152
- 8. Use `app_publish_verify` only when the user explicitly wants final publish/live verification or you need a dedicated verification pass
153
-
154
- ## Safe Usage Rules
155
-
156
- - Do not guess package identity from a loose name. Public package work assumes a known `package_id`, or an explicit create/update intent through `package_apply`.
157
- - If `package_id` is unknown, derive it from related app/portal readback when possible; otherwise ask the user instead of falling back to hidden package lookup tools.
158
- - Do not use `package_create` or `package_attach_app` as a public default path. If they still appear in low-level code, treat them as internal/legacy implementation details.
159
- - Do not use raw `portal_*` writes or raw `qingbi_report_*` writes as the default builder strategy.
160
- - Always pass `publish: true` (or CLI `--publish`) explicitly on `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, `app_views_apply`, and `portal_apply` — do not rely on the default. `app_custom_buttons_apply` and `app_associated_resources_apply` publish automatically after at least one write succeeds and do not accept a `publish` parameter. `app_charts_apply` is immediate-live without a publish step.
161
- - When creating or updating fields, configure the app data title/cover directly in field JSON: `as_data_title: true` is required on exactly one readable top-level title field; `as_data_cover: true` is optional and only valid on one top-level `attachment` field.
162
- - When any tool returns `error_code` or `VALIDATION_ERROR`, read the `message` field verbatim first before guessing at parameter or CLI parsing issues. A clear `message` like "relation field requires visible_fields" is the root cause — do not redirect to unrelated hypotheses such as `create_if_missing` parsing or flag conflicts.
163
- - If the same validation error repeats twice, stop guessing and re-read `qingflow --json builder contract`.
164
- - For workflow assignees, prefer `role_search` over explicit members unless the user explicitly wants named members.
165
- - Public flow building is still intentionally limited to stable linear workflows. If a requirement sounds like branches/conditions, explain the limitation instead of freehanding unsupported graph shapes.
166
- - Respect collaborative edit locks. Only use `app_release_edit_lock_if_mine` when the lock owner is the current authenticated user.
167
- - If the supported builder surface is still awkward or blocked after reasonable use, summarize the gap, ask whether to submit feedback, and call `feedback_submit` only after explicit user confirmation.
168
-
169
- ## Response Interpretation
170
-
171
- - All builder apply/write tools return a standard UI envelope in addition to legacy fields:
172
- `schema_version`, `operation`, `summary`, and `resources[]`.
173
- - For UI cards or quick narration, read `resources[]` first. Each resource has `resource_type`, `operation`, `status`, `id`, `key`, `name`, typed `ids`, and `parent`.
174
- - Use legacy fields such as `field_diff`, `views_diff`, `chart_results`, `created/updated/removed`, and `verification` only for compatibility and troubleshooting.
175
- - Treat post-write readback as the source of truth, not just write status codes.
176
- - `success` means write and verification completed; `partial_success` means the write landed but verification is incomplete.
177
- - For portals, distinguish clearly between:
178
- - base-info-only update with layout preserved
179
- - full sections replace
180
- - patching one section with `patch_sections[]`
181
- - layout validity: same-row `rows`, same-row `cols` sum, and non-empty grid `items`
182
- - For object apply tools, distinguish clearly between:
183
- - `patch_*`: public partial parameter replacement; the tool hydrates current config and full-saves internally
184
- - `upsert_*`: create or full target configuration; omitted fields may mean default/clear depending on that object
185
- - For charts, distinguish clearly between:
186
- - base / visibility change
187
- - real chart-config change
188
- - For app permissions, report `can_edit_app_base` separately from `can_edit_form / can_edit_flow / can_edit_views / can_edit_charts`.
189
-
190
- ## Practical Patterns
191
-
192
- - Read one package: `package_get`
193
- - Create or update one package: `package_apply`
194
- - Resolve one app: `app_resolve`
195
- - Read one app map: `app_get`
196
- - Batch read app maps/slices: `app_get_*` with `app_keys[]`
197
- - Read fields only: `app_get_fields`
198
- - Read layout summary: `app_get_layout`
199
- - Read views summary: `app_get_views`
200
- - Read flow summary: `app_get_flow`
201
- - Read chart summary: `app_get_charts`
202
- - Read portal config: `portal_get`
203
- - Search members or roles: `member_search`, `role_search`
204
- - Create reusable role: `role_create`
205
- - Add/update/remove fields: `app_schema_apply`
206
- - Merge or replace layout: `app_layout_apply` (single app) or `apps[]` batch
207
- - Replace workflow or patch nodes: `app_flow_apply`
208
- - Upsert/patch/remove views: `app_views_apply` (single app) or `apps[]` batch
209
- - Upsert/patch/remove views, including ordinary view-specific buttons: `app_views_apply`
210
- - Advanced custom button maintenance and cross-view binding: `app_custom_buttons_apply` (single app) or `apps[]` batch
211
- - Upsert/patch/remove app associated reports/views and per-view display: `app_associated_resources_apply`
212
- - Upsert/patch/remove/reorder charts: `app_charts_apply` (single app) or `apps[]` batch
213
- - Create, update, or patch portal pages: `portal_apply`
214
- - Release your own stale edit lock: `app_release_edit_lock_if_mine`
215
- - Final publish verification: `app_publish_verify`
216
-
217
- ## Advanced Button Pattern
218
-
219
- For ordinary view-specific buttons, prefer `app_views_apply.action_buttons`. Use `app_custom_buttons_apply` only for standalone/advanced maintenance: custom style or icon, cross-view reuse, deleting button bodies, bulk binding reorder, or exact qRobot/wings config.
220
-
221
- > CLI-only note: this is the payload from former internal surface `app_custom_buttons_apply`. Execute it through the matching `qingflow` CLI command and `--*-file` flags from SKILL.md / builder reference; do not call internal tool JSON.
222
-
223
- ```json
224
- {
225
- "app_key": "EMPLOYEE_APP",
226
- "upsert_buttons": [
227
- {
228
- "client_key": "add_worklog",
229
- "button_text": "快捷添加工时",
230
- "style_preset": "primary_blue",
231
- "button_icon": "ex-plus-circle",
232
- "trigger_action": "addData",
233
- "trigger_add_data_config": {
234
- "target_app_key": "WORKLOG_APP",
235
- "field_mappings": [
236
- {
237
- "source_field": "数据ID",
238
- "target_field": "关联员工"
239
- },
240
- {
241
- "source_field": "员工名称",
242
- "target_field": "员工姓名"
243
- },
244
- {
245
- "source_field": "所属部门",
246
- "target_field": "部门名称"
247
- }
248
- ],
249
- "default_values": {
250
- "工时类型": "日常工作",
251
- "状态": "待提交"
252
- }
253
- }
254
- }
255
- ],
256
- "remove_buttons": [],
257
- "view_configs": [
258
- {
259
- "view_key": "EMPLOYEE_VIEW",
260
- "mode": "merge",
261
- "buttons": [
262
- {
263
- "button_ref": "add_worklog",
264
- "placement": "detail",
265
- "primary": true
266
- }
267
- ]
268
- }
269
- ]
270
- }
271
- ```
272
-
273
- `button_ref` may be a same-call `client_key` or an existing `button_id`. Supported placements are `header`, `detail`, and `list`; `list` maps to the backend `INSIDE` row/list button position.
274
-
275
- For add-data buttons that create a child record linked back to the current record, map `source_field: "数据ID"` to the target relation field. Do not use raw `que_relation` unless maintaining an existing backend config.
276
-
277
- ## Historical Playbook Selection
278
-
279
- This file is historical supporting material. For the current main route, start from [../../README.md](../../README.md). If you still use this page, route to the current resource document first:
280
-
281
- | User intent | Signal phrases | Playbook |
282
- |-------------|---------------|---------|
283
- | Multi-app business system with cross-app relations, shared workflow, and a portal dashboard | "建一套系统"、"包含 N 个模块"、"这几个表单之间建立关联"、"完整的业务系统" | [20-build-complete-system.md](../../20-build-complete-system.md) |
284
- | Single app end-to-end: rich schema, layout, flow, multiple view types, custom buttons, in-app charts, associated resources, and sample data | "建一个应用"、"帮我搭一个XX管理"、"从零开始建一个XX"、"我需要一个管理XX的应用" | [10-build-single-app.md](../../10-build-single-app.md) |
285
- | Add one new app inside an existing package | "在这个包里加一个表单"、"现有系统里新增一个模块" | [create-app.md](./create-app.md) |
286
- | Update fields or schema only | "加一个字段"、"改字段名"、"删除字段" | [30-schema-fields.md](../../30-schema-fields.md) |
287
- | Update layout only | "调整分组"、"改排列顺序" | [40-layout.md](../../40-layout.md) |
288
- | Update workflow only | "修改审批流"、"加一个审批节点" | [90-workflow.md](../../90-workflow.md) |
289
- | Update views only | "加一个看板"、"改筛选条件"、"新增视图" | [50-views.md](../../50-views.md) |
290
-
291
- Decision rule: if the user mentions **multiple related apps or a portal**, use [20-build-complete-system.md](../../20-build-complete-system.md). If it is **one app** with a from-scratch setup request, use [10-build-single-app.md](../../10-build-single-app.md). If the target app already exists and the user only wants to change one layer, use the matching resource document.
292
-
293
- ## Resources
294
-
295
- - Shared public-surface baseline: [public-surface-sync.md](./public-surface-sync.md)
296
- - Environment switching: [environments.md](./environments.md)
297
- - Tool choice and sequencing: [tool-selection.md](./tool-selection.md)
298
- - Field matching rules: [../match-rules.md](../match-rules.md)
299
- - Result semantics and gotchas: [gotchas.md](./gotchas.md)
300
- - Create one app in an existing package: [create-app.md](./create-app.md)
301
- - Update fields only: [../../30-schema-fields.md](../../30-schema-fields.md)
302
- - Update layout only: [../../40-layout.md](../../40-layout.md)
303
- - Update workflow only: [../../90-workflow.md](../../90-workflow.md)
304
- - Workflow assignees and node permissions: [flow-actors-and-permissions.md](./flow-actors-and-permissions.md)
305
- - Update views only: [../../50-views.md](../../50-views.md)
306
- - Standard end-to-end builder sequences: [solution-playbooks.md](./solution-playbooks.md)
307
- - Build a complete multi-app system from scratch: [../../20-build-complete-system.md](../../20-build-complete-system.md)
308
- - Build a single app end-to-end: [../../10-build-single-app.md](../../10-build-single-app.md)