@josephyan/qingflow-app-builder-mcp 1.1.21 → 1.1.23
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.
- package/README.md +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +1 -1
- package/skills/qingflow-app-builder/references/complete-system-development-guide.md +2 -2
- package/skills/qingflow-app-builder/references/create-app.md +3 -6
- package/skills/qingflow-app-builder/references/tool-selection.md +4 -4
- package/src/qingflow_mcp/builder_facade/models.py +0 -1
- package/src/qingflow_mcp/builder_facade/service.py +1581 -487
- package/src/qingflow_mcp/cli/commands/builder.py +7 -19
- package/src/qingflow_mcp/server_app_builder.py +8 -13
- package/src/qingflow_mcp/tools/ai_builder_tools.py +719 -371
|
@@ -212,7 +212,6 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
212
212
|
schema_apply_apply.add_argument("--icon")
|
|
213
213
|
schema_apply_apply.add_argument("--color")
|
|
214
214
|
schema_apply_apply.add_argument("--visibility-file")
|
|
215
|
-
schema_apply_apply.add_argument("--create-if-missing", action="store_true")
|
|
216
215
|
schema_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=None)
|
|
217
216
|
schema_apply_apply.add_argument("--apps-file", help="多应用 schema JSON 对象;每项可带 client_key/app_name/form,支持 relation target_app_ref")
|
|
218
217
|
schema_apply_apply.add_argument("--form-file", help="单应用表单结构 JSON 数组;form[].rows[][] 同时声明字段和表单分组布局")
|
|
@@ -386,6 +385,7 @@ def _handle_package_apply(args: argparse.Namespace, context: CliContext) -> dict
|
|
|
386
385
|
config = load_object_arg(args.config_file, option_name="--config-file")
|
|
387
386
|
if not isinstance(config, dict):
|
|
388
387
|
raise_config_error("package apply --config-file must contain a JSON object.")
|
|
388
|
+
config.pop("create_if_missing", None)
|
|
389
389
|
return context.builder.package_apply(profile=args.profile, **config)
|
|
390
390
|
|
|
391
391
|
|
|
@@ -561,17 +561,11 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
561
561
|
if package_id is None and apps_payload.get("package_id") is not None:
|
|
562
562
|
package_id = _coerce_apps_file_package_id(apps_payload["package_id"])
|
|
563
563
|
if args.apps_file:
|
|
564
|
-
file_create_if_missing = _coerce_apps_file_bool(
|
|
565
|
-
apps_payload.get("create_if_missing"),
|
|
566
|
-
field_name="create_if_missing",
|
|
567
|
-
default=True,
|
|
568
|
-
)
|
|
569
564
|
file_publish = _coerce_apps_file_bool(
|
|
570
565
|
apps_payload.get("publish"),
|
|
571
566
|
field_name="publish",
|
|
572
567
|
default=True,
|
|
573
568
|
)
|
|
574
|
-
effective_create_if_missing = bool(args.create_if_missing or file_create_if_missing)
|
|
575
569
|
effective_publish = bool(args.publish if args.publish is not None else file_publish)
|
|
576
570
|
if not apps:
|
|
577
571
|
raise_config_error(
|
|
@@ -581,7 +575,7 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
581
575
|
)
|
|
582
576
|
if args.app_key or args.app_name or args.app_title or args.form_file or args.add_fields_file or args.update_fields_file or args.remove_fields_file:
|
|
583
577
|
raise_config_error(
|
|
584
|
-
"schema apply multi-app mode accepts --package-id plus --apps-file only
|
|
578
|
+
"schema apply multi-app mode accepts --package-id plus --apps-file only.",
|
|
585
579
|
fix_hint="Use apps[].form inside --apps-file for batch mode, or remove --apps-file and use --form-file for a single app.",
|
|
586
580
|
)
|
|
587
581
|
if package_id is None:
|
|
@@ -593,7 +587,6 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
593
587
|
profile=args.profile,
|
|
594
588
|
package_id=package_id,
|
|
595
589
|
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
596
|
-
create_if_missing=effective_create_if_missing,
|
|
597
590
|
publish=effective_publish,
|
|
598
591
|
apps=apps,
|
|
599
592
|
form=None,
|
|
@@ -611,16 +604,16 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
611
604
|
has_app_title = bool((args.app_title or "").strip())
|
|
612
605
|
has_package_id = args.package_id is not None
|
|
613
606
|
if has_app_key:
|
|
614
|
-
if
|
|
607
|
+
if has_package_id:
|
|
615
608
|
raise_config_error(
|
|
616
609
|
"schema apply edit mode accepts --app-key and optional --app-name only.",
|
|
617
|
-
fix_hint="For existing apps, use `--app-key` and optionally `--app-name`. For create mode, use `--package-id --app-name
|
|
610
|
+
fix_hint="For existing apps, use `--app-key` and optionally `--app-name`. For create mode, use `--package-id --app-name`.",
|
|
618
611
|
)
|
|
619
612
|
else:
|
|
620
|
-
if not
|
|
613
|
+
if not has_package_id or not (has_app_name or has_app_title):
|
|
621
614
|
raise_config_error(
|
|
622
|
-
"schema apply create mode requires --package-id
|
|
623
|
-
fix_hint="Use `--app-key` for existing apps, or pass `--package-id --app-name
|
|
615
|
+
"schema apply create mode requires --package-id and --app-name.",
|
|
616
|
+
fix_hint="Use `--app-key` for existing apps, or pass `--package-id --app-name` to create a new app.",
|
|
624
617
|
)
|
|
625
618
|
return context.builder.app_schema_apply(
|
|
626
619
|
profile=args.profile,
|
|
@@ -631,7 +624,6 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
631
624
|
icon=args.icon,
|
|
632
625
|
color=args.color,
|
|
633
626
|
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
634
|
-
create_if_missing=bool(args.create_if_missing),
|
|
635
627
|
publish=True if args.publish is None else bool(args.publish),
|
|
636
628
|
form=load_list_arg(args.form_file, option_name="--form-file") if args.form_file else [],
|
|
637
629
|
add_fields=load_list_arg(args.add_fields_file, option_name="--add-fields-file"),
|
|
@@ -685,8 +677,6 @@ def _load_apps_file_arg(path: str | None) -> dict[str, object]:
|
|
|
685
677
|
}
|
|
686
678
|
if wrapper.get("package_id") is not None:
|
|
687
679
|
result["package_id"] = wrapper.get("package_id")
|
|
688
|
-
if wrapper.get("create_if_missing") is not None:
|
|
689
|
-
result["create_if_missing"] = wrapper.get("create_if_missing")
|
|
690
680
|
if wrapper.get("publish") is not None:
|
|
691
681
|
result["publish"] = wrapper.get("publish")
|
|
692
682
|
return result
|
|
@@ -710,8 +700,6 @@ def _load_apps_file_arg(path: str | None) -> dict[str, object]:
|
|
|
710
700
|
result: dict[str, object] = {"apps": apps}
|
|
711
701
|
if payload.get("package_id") is not None:
|
|
712
702
|
result["package_id"] = payload.get("package_id")
|
|
713
|
-
if payload.get("create_if_missing") is not None:
|
|
714
|
-
result["create_if_missing"] = payload.get("create_if_missing")
|
|
715
703
|
if payload.get("publish") is not None:
|
|
716
704
|
result["publish"] = payload.get("publish")
|
|
717
705
|
return result
|
|
@@ -39,7 +39,7 @@ def build_builder_server() -> FastMCP:
|
|
|
39
39
|
"Use workspace_icon_catalog_get before creating app packages, apps, or portals when supported icon/color candidates are needed; new workspace resources require explicit non-template icon + color, and the CLI validates choices without inferring business defaults. "
|
|
40
40
|
"app_get as the default app map read, then app_get_fields/app_repair_code_blocks/app_get_layout/app_get_views/app_get_flow/app_get_charts/portal_list/portal_get/view_get/chart_get for focused configuration reads, "
|
|
41
41
|
"member_search/role_search/role_create when workflow assignees must come from the directory or role catalog, preferring roles over explicit members unless the user explicitly names members, "
|
|
42
|
-
"then app_schema_apply/app_layout_apply/app_flow_apply/app_views_apply/app_custom_buttons_apply/app_associated_resources_apply/app_charts_apply/portal_apply/portal_delete to execute normalized patches; these apply/delete tools perform
|
|
42
|
+
"then app_schema_apply/app_layout_apply/app_flow_apply/app_views_apply/app_custom_buttons_apply/app_associated_resources_apply/app_charts_apply/portal_apply/portal_delete to execute normalized patches; these apply/delete tools perform basic validation, normalization, writes, and readback verification where applicable. Schema/layout/views noop requests skip publish, app_custom_buttons_apply and app_associated_resources_apply publish after at least one write succeeds and expose no draft-only parameter, charts are immediate-live without publish and resolve targets by chart_id first then exact unique chart name, portal updates use replace semantics only when sections are supplied and edit-mode base-info-only updates may omit sections, portal delete separates DELETE execution from readback verification, portal pc layout is a 24-column grid and mobile is a 6-column grid so omit position or use layout_preset when unsure, publish=false only guarantees draft/base-info updates for tools that still expose that parameter, and flow should use publish=false whenever you only want draft/precheck behavior. "
|
|
43
43
|
"Builder apply/write outputs include schema_version, operation, summary, and resources[]; use resources[].id/key/name/ids/parent as the stable UI and agent display entry, and keep legacy fields such as field_diff/views_diff/chart_results only for compatibility or troubleshooting. "
|
|
44
44
|
"For existing object parameter replacement, prefer patch_views, patch_buttons, patch_resources, and patch_charts with set/unset; the tool reads current config and full-saves internally, while upsert_* is for creation or full target configuration and should not be used as an incomplete partial update. "
|
|
45
45
|
"For builder delete/remove apply results, separate delete execution from readback verification: after DELETE is sent, resources expose delete_executed, readback_status, and safe_to_retry_delete=false. If readback_status is unavailable or still_exists, do not blindly repeat the delete; confirm later with app_get/view_get/chart_get or the relevant apply readback. Views/buttons use single-item readback; associated resources use one app-level resource-pool readback because there is no confirmed single-item GET. "
|
|
@@ -197,7 +197,6 @@ def build_builder_server() -> FastMCP:
|
|
|
197
197
|
profile: str = DEFAULT_PROFILE,
|
|
198
198
|
package_id: int | None = None,
|
|
199
199
|
package_name: str | None = None,
|
|
200
|
-
create_if_missing: bool | None = None,
|
|
201
200
|
icon: str | None = None,
|
|
202
201
|
color: str | None = None,
|
|
203
202
|
visibility: dict | None = None,
|
|
@@ -208,7 +207,6 @@ def build_builder_server() -> FastMCP:
|
|
|
208
207
|
profile=profile,
|
|
209
208
|
package_id=package_id,
|
|
210
209
|
package_name=package_name,
|
|
211
|
-
create_if_missing=create_if_missing,
|
|
212
210
|
icon=icon,
|
|
213
211
|
color=color,
|
|
214
212
|
visibility=visibility,
|
|
@@ -426,7 +424,6 @@ def build_builder_server() -> FastMCP:
|
|
|
426
424
|
icon: str = "",
|
|
427
425
|
color: str = "",
|
|
428
426
|
visibility: dict | None = None,
|
|
429
|
-
create_if_missing: bool | None = None,
|
|
430
427
|
publish: bool = True,
|
|
431
428
|
form: list[dict] | None = None,
|
|
432
429
|
add_fields: list[dict] | None = None,
|
|
@@ -437,7 +434,7 @@ def build_builder_server() -> FastMCP:
|
|
|
437
434
|
if apps:
|
|
438
435
|
if app_key or app_name or app_title or form or add_fields or update_fields or remove_fields:
|
|
439
436
|
return _config_failure(
|
|
440
|
-
"app_schema_apply multi-app mode accepts package_id plus apps only
|
|
437
|
+
"app_schema_apply multi-app mode accepts package_id plus apps only.",
|
|
441
438
|
fix_hint="Use apps[].form for batch mode, or use the single-app arguments without apps.",
|
|
442
439
|
)
|
|
443
440
|
if package_id is None:
|
|
@@ -449,7 +446,6 @@ def build_builder_server() -> FastMCP:
|
|
|
449
446
|
profile=profile,
|
|
450
447
|
package_id=package_id,
|
|
451
448
|
visibility=visibility,
|
|
452
|
-
create_if_missing=True if create_if_missing is None else bool(create_if_missing),
|
|
453
449
|
publish=publish,
|
|
454
450
|
form=None,
|
|
455
451
|
add_fields=[],
|
|
@@ -461,17 +457,17 @@ def build_builder_server() -> FastMCP:
|
|
|
461
457
|
has_app_name = bool((app_name or "").strip())
|
|
462
458
|
has_app_title = bool((app_title or "").strip())
|
|
463
459
|
has_package_id = package_id is not None
|
|
464
|
-
|
|
460
|
+
create_by_shape = has_package_id and (has_app_name or has_app_title)
|
|
465
461
|
if has_app_key:
|
|
466
|
-
if
|
|
462
|
+
if has_package_id:
|
|
467
463
|
return _config_failure(
|
|
468
464
|
"app_schema_apply edit mode accepts app_key and optional app_name rename only.",
|
|
469
|
-
fix_hint="For existing apps, use `app_key` and optionally `app_name`. For create mode, use `package_id + app_name
|
|
465
|
+
fix_hint="For existing apps, use `app_key` and optionally `app_name`. For create mode, use `package_id + app_name`.",
|
|
470
466
|
)
|
|
471
|
-
elif not
|
|
467
|
+
elif not create_by_shape:
|
|
472
468
|
return _config_failure(
|
|
473
|
-
"app_schema_apply create mode requires package_id
|
|
474
|
-
fix_hint="Use `app_key` for existing apps, or pass `package_id + app_name
|
|
469
|
+
"app_schema_apply create mode requires package_id and app_name.",
|
|
470
|
+
fix_hint="Use `app_key` for existing apps, or pass `package_id + app_name` to create a new app.",
|
|
475
471
|
)
|
|
476
472
|
return ai_builder.app_schema_apply(
|
|
477
473
|
profile=profile,
|
|
@@ -482,7 +478,6 @@ def build_builder_server() -> FastMCP:
|
|
|
482
478
|
icon=icon,
|
|
483
479
|
color=color,
|
|
484
480
|
visibility=visibility,
|
|
485
|
-
create_if_missing=effective_create_if_missing,
|
|
486
481
|
publish=publish,
|
|
487
482
|
form=form or [],
|
|
488
483
|
add_fields=add_fields or [],
|