@josephyan/qingflow-cli 0.2.0-beta.82 → 0.2.0-beta.84
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/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/service.py +779 -20
- package/src/qingflow_mcp/cli/commands/builder.py +36 -95
- package/src/qingflow_mcp/public_surface.py +1 -5
- package/src/qingflow_mcp/response_trim.py +2 -4
- package/src/qingflow_mcp/server_app_builder.py +41 -61
- package/src/qingflow_mcp/tools/ai_builder_tools.py +219 -195
- package/src/qingflow_mcp/tools/package_tools.py +49 -0
|
@@ -69,13 +69,6 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
69
69
|
|
|
70
70
|
package = builder_subparsers.add_parser("package", help="应用包")
|
|
71
71
|
package_subparsers = package.add_subparsers(dest="builder_package_command", required=True)
|
|
72
|
-
package_list = package_subparsers.add_parser("list", help="列出应用包")
|
|
73
|
-
package_list.add_argument("--trial-status", default="all")
|
|
74
|
-
package_list.set_defaults(handler=_handle_package_list, format_hint="builder_summary")
|
|
75
|
-
|
|
76
|
-
package_resolve = package_subparsers.add_parser("resolve", help="解析应用包")
|
|
77
|
-
package_resolve.add_argument("--package-name", required=True)
|
|
78
|
-
package_resolve.set_defaults(handler=_handle_package_resolve, format_hint="builder_summary")
|
|
79
72
|
|
|
80
73
|
solution = builder_subparsers.add_parser("solution", help="解决方案")
|
|
81
74
|
solution_subparsers = solution.add_subparsers(dest="builder_solution_command", required=True)
|
|
@@ -85,30 +78,13 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
85
78
|
solution_install.add_argument("--solution-source", default="solutionDetail")
|
|
86
79
|
solution_install.set_defaults(handler=_handle_solution_install, format_hint="builder_summary")
|
|
87
80
|
|
|
88
|
-
package_create = package_subparsers.add_parser("create", help="创建应用包")
|
|
89
|
-
package_create.add_argument("--package-name", required=True)
|
|
90
|
-
package_create.add_argument("--icon")
|
|
91
|
-
package_create.add_argument("--color")
|
|
92
|
-
package_create.add_argument("--visibility-file")
|
|
93
|
-
package_create.set_defaults(handler=_handle_package_create, format_hint="builder_summary")
|
|
94
|
-
|
|
95
81
|
package_get = package_subparsers.add_parser("get", help="读取应用包详情")
|
|
96
|
-
package_get.add_argument("--
|
|
82
|
+
package_get.add_argument("--package-id", type=int, required=True)
|
|
97
83
|
package_get.set_defaults(handler=_handle_package_get, format_hint="builder_summary")
|
|
98
84
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
package_update.add_argument("--icon")
|
|
103
|
-
package_update.add_argument("--color")
|
|
104
|
-
package_update.add_argument("--visibility-file")
|
|
105
|
-
package_update.set_defaults(handler=_handle_package_update, format_hint="builder_summary")
|
|
106
|
-
|
|
107
|
-
package_attach_app = package_subparsers.add_parser("attach-app", help="将应用挂载到应用包")
|
|
108
|
-
package_attach_app.add_argument("--tag-id", type=int, required=True)
|
|
109
|
-
package_attach_app.add_argument("--app-key", required=True)
|
|
110
|
-
package_attach_app.add_argument("--app-title", dest="legacy_app_title", help=argparse.SUPPRESS)
|
|
111
|
-
package_attach_app.set_defaults(handler=_handle_package_attach_app, format_hint="builder_summary")
|
|
85
|
+
package_apply = package_subparsers.add_parser("apply", help="创建或更新应用包配置")
|
|
86
|
+
package_apply.add_argument("--config-file", required=True)
|
|
87
|
+
package_apply.set_defaults(handler=_handle_package_apply, format_hint="builder_summary")
|
|
112
88
|
|
|
113
89
|
app = builder_subparsers.add_parser("app", help="应用")
|
|
114
90
|
app_subparsers = app.add_subparsers(dest="builder_app_command", required=True)
|
|
@@ -116,7 +92,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
116
92
|
app_resolve = app_subparsers.add_parser("resolve", help="解析应用")
|
|
117
93
|
app_resolve.add_argument("--app-key", default="")
|
|
118
94
|
app_resolve.add_argument("--app-name", default="")
|
|
119
|
-
app_resolve.add_argument("--package-
|
|
95
|
+
app_resolve.add_argument("--package-id", type=int)
|
|
120
96
|
app_resolve.set_defaults(handler=_handle_app_resolve, format_hint="builder_summary")
|
|
121
97
|
|
|
122
98
|
app_release_lock = app_subparsers.add_parser("release-edit-lock-if-mine", help="释放当前账号持有的编辑锁")
|
|
@@ -182,7 +158,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
182
158
|
portal_apply = portal_subparsers.add_parser("apply", help="更新门户")
|
|
183
159
|
portal_apply.add_argument("--dash-key", default="")
|
|
184
160
|
portal_apply.add_argument("--dash-name", default="")
|
|
185
|
-
portal_apply.add_argument("--package-
|
|
161
|
+
portal_apply.add_argument("--package-id", type=int)
|
|
186
162
|
portal_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
187
163
|
portal_apply.add_argument("--sections-file", required=True)
|
|
188
164
|
portal_apply.add_argument("--visibility-file")
|
|
@@ -198,7 +174,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
198
174
|
schema_apply_subparsers = schema_apply.add_subparsers(dest="builder_schema_command", required=True)
|
|
199
175
|
schema_apply_apply = schema_apply_subparsers.add_parser("apply", help="执行字段变更")
|
|
200
176
|
schema_apply_apply.add_argument("--app-key", default="")
|
|
201
|
-
schema_apply_apply.add_argument("--package-
|
|
177
|
+
schema_apply_apply.add_argument("--package-id", type=int)
|
|
202
178
|
schema_apply_apply.add_argument("--app-name", default="")
|
|
203
179
|
schema_apply_apply.add_argument("--app-title", default="")
|
|
204
180
|
schema_apply_apply.add_argument("--icon")
|
|
@@ -252,7 +228,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
252
228
|
publish_verify_subparsers = publish_verify.add_subparsers(dest="builder_publish_command", required=True)
|
|
253
229
|
publish_verify_verify = publish_verify_subparsers.add_parser("verify", help="校验应用发布")
|
|
254
230
|
publish_verify_verify.add_argument("--app-key", required=True)
|
|
255
|
-
publish_verify_verify.add_argument("--expected-package-
|
|
231
|
+
publish_verify_verify.add_argument("--expected-package-id", type=int)
|
|
256
232
|
publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary")
|
|
257
233
|
|
|
258
234
|
view = builder_subparsers.add_parser("view", help="视图详情")
|
|
@@ -268,10 +244,6 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
268
244
|
chart_get.set_defaults(handler=_handle_chart_get, format_hint="builder_summary")
|
|
269
245
|
|
|
270
246
|
|
|
271
|
-
def _handle_package_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
272
|
-
return context.builder.package_list(profile=args.profile, trial_status=args.trial_status)
|
|
273
|
-
|
|
274
|
-
|
|
275
247
|
def _handle_file_upload_local(args: argparse.Namespace, context: CliContext) -> dict:
|
|
276
248
|
return context.files.file_upload_local(
|
|
277
249
|
profile=args.profile,
|
|
@@ -335,10 +307,6 @@ def _handle_role_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
335
307
|
)
|
|
336
308
|
|
|
337
309
|
|
|
338
|
-
def _handle_package_resolve(args: argparse.Namespace, context: CliContext) -> dict:
|
|
339
|
-
return context.builder.package_resolve(profile=args.profile, package_name=args.package_name)
|
|
340
|
-
|
|
341
|
-
|
|
342
310
|
def _handle_solution_install(args: argparse.Namespace, context: CliContext) -> dict:
|
|
343
311
|
return context.builder.solution_install(
|
|
344
312
|
profile=args.profile,
|
|
@@ -348,63 +316,36 @@ def _handle_solution_install(args: argparse.Namespace, context: CliContext) -> d
|
|
|
348
316
|
)
|
|
349
317
|
|
|
350
318
|
|
|
351
|
-
def _handle_package_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
352
|
-
return context.builder.package_create(
|
|
353
|
-
profile=args.profile,
|
|
354
|
-
package_name=args.package_name,
|
|
355
|
-
icon=args.icon,
|
|
356
|
-
color=args.color,
|
|
357
|
-
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
|
|
361
319
|
def _handle_package_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
362
|
-
return context.builder.package_get(profile=args.profile,
|
|
363
|
-
|
|
320
|
+
return context.builder.package_get(profile=args.profile, package_id=args.package_id)
|
|
364
321
|
|
|
365
|
-
def _handle_package_update(args: argparse.Namespace, context: CliContext) -> dict:
|
|
366
|
-
return context.builder.package_update(
|
|
367
|
-
profile=args.profile,
|
|
368
|
-
tag_id=args.tag_id,
|
|
369
|
-
package_name=args.package_name,
|
|
370
|
-
icon=args.icon,
|
|
371
|
-
color=args.color,
|
|
372
|
-
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
373
|
-
)
|
|
374
322
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
raise_config_error(
|
|
379
|
-
|
|
380
|
-
fix_hint="Use `--app-key` to identify the app to attach.",
|
|
381
|
-
)
|
|
382
|
-
return context.builder.package_attach_app(
|
|
383
|
-
profile=args.profile,
|
|
384
|
-
tag_id=args.tag_id,
|
|
385
|
-
app_key=args.app_key,
|
|
386
|
-
)
|
|
323
|
+
def _handle_package_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
324
|
+
config = load_object_arg(args.config_file, option_name="--config-file")
|
|
325
|
+
if not isinstance(config, dict):
|
|
326
|
+
raise_config_error("package apply --config-file must contain a JSON object.")
|
|
327
|
+
return context.builder.package_apply(profile=args.profile, **config)
|
|
387
328
|
|
|
388
329
|
|
|
389
330
|
def _handle_app_resolve(args: argparse.Namespace, context: CliContext) -> dict:
|
|
390
331
|
has_app_key = bool((args.app_key or "").strip())
|
|
391
332
|
has_app_name = bool((args.app_name or "").strip())
|
|
392
|
-
|
|
393
|
-
if has_app_key and (has_app_name or
|
|
333
|
+
has_package_id = args.package_id is not None
|
|
334
|
+
if has_app_key and (has_app_name or has_package_id):
|
|
394
335
|
raise_config_error(
|
|
395
336
|
"app resolve accepts exactly one selector mode.",
|
|
396
|
-
fix_hint="Use only `--app-key`, or use `--app-name` together with `--package-
|
|
337
|
+
fix_hint="Use only `--app-key`, or use `--app-name` together with `--package-id`.",
|
|
397
338
|
)
|
|
398
|
-
if not has_app_key and not (has_app_name and
|
|
339
|
+
if not has_app_key and not (has_app_name and has_package_id):
|
|
399
340
|
raise_config_error(
|
|
400
|
-
"app resolve requires either --app-key, or --app-name together with --package-
|
|
401
|
-
fix_hint="For an existing known app, pass `--app-key`. For package-scoped lookup, pass both `--app-name` and `--package-
|
|
341
|
+
"app resolve requires either --app-key, or --app-name together with --package-id.",
|
|
342
|
+
fix_hint="For an existing known app, pass `--app-key`. For package-scoped lookup, pass both `--app-name` and `--package-id`.",
|
|
402
343
|
)
|
|
403
344
|
return context.builder.app_resolve(
|
|
404
345
|
profile=args.profile,
|
|
405
346
|
app_key=args.app_key,
|
|
406
347
|
app_name=args.app_name,
|
|
407
|
-
|
|
348
|
+
package_id=args.package_id,
|
|
408
349
|
)
|
|
409
350
|
|
|
410
351
|
|
|
@@ -487,23 +428,23 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
487
428
|
has_app_key = bool((args.app_key or "").strip())
|
|
488
429
|
has_app_name = bool((args.app_name or "").strip())
|
|
489
430
|
has_app_title = bool((args.app_title or "").strip())
|
|
490
|
-
|
|
431
|
+
has_package_id = args.package_id is not None
|
|
491
432
|
if has_app_key:
|
|
492
|
-
if args.create_if_missing or
|
|
433
|
+
if args.create_if_missing or has_package_id:
|
|
493
434
|
raise_config_error(
|
|
494
435
|
"schema apply edit mode accepts --app-key and optional --app-name only.",
|
|
495
|
-
fix_hint="For existing apps, use `--app-key` and optionally `--app-name`. For create mode, use `--package-
|
|
436
|
+
fix_hint="For existing apps, use `--app-key` and optionally `--app-name`. For create mode, use `--package-id --app-name --create-if-missing`.",
|
|
496
437
|
)
|
|
497
438
|
else:
|
|
498
|
-
if not args.create_if_missing or not
|
|
439
|
+
if not args.create_if_missing or not has_package_id or not (has_app_name or has_app_title):
|
|
499
440
|
raise_config_error(
|
|
500
|
-
"schema apply create mode requires --package-
|
|
501
|
-
fix_hint="Use `--app-key` for existing apps, or pass `--package-
|
|
441
|
+
"schema apply create mode requires --package-id, --app-name, and --create-if-missing.",
|
|
442
|
+
fix_hint="Use `--app-key` for existing apps, or pass `--package-id --app-name --create-if-missing` to create a new app.",
|
|
502
443
|
)
|
|
503
444
|
return context.builder.app_schema_apply(
|
|
504
445
|
profile=args.profile,
|
|
505
446
|
app_key=args.app_key,
|
|
506
|
-
|
|
447
|
+
package_id=args.package_id,
|
|
507
448
|
app_name=args.app_name,
|
|
508
449
|
app_title=args.app_title,
|
|
509
450
|
icon=args.icon,
|
|
@@ -561,22 +502,22 @@ def _handle_charts_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
561
502
|
def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
562
503
|
has_dash_key = bool((args.dash_key or "").strip())
|
|
563
504
|
has_dash_name = bool((args.dash_name or "").strip())
|
|
564
|
-
|
|
565
|
-
if has_dash_key and
|
|
505
|
+
has_package_id = args.package_id is not None
|
|
506
|
+
if has_dash_key and has_package_id:
|
|
566
507
|
raise_config_error(
|
|
567
508
|
"portal apply accepts exactly one selector mode.",
|
|
568
|
-
fix_hint="Use `--dash-key` to update an existing portal, or use `--package-
|
|
509
|
+
fix_hint="Use `--dash-key` to update an existing portal, or use `--package-id --dash-name` to create a new portal.",
|
|
569
510
|
)
|
|
570
|
-
if not has_dash_key and not (
|
|
511
|
+
if not has_dash_key and not (has_package_id and has_dash_name):
|
|
571
512
|
raise_config_error(
|
|
572
|
-
"portal apply requires either --dash-key, or --package-
|
|
573
|
-
fix_hint="Use `--dash-key` for an existing portal. For create mode, pass `--package-
|
|
513
|
+
"portal apply requires either --dash-key, or --package-id together with --dash-name.",
|
|
514
|
+
fix_hint="Use `--dash-key` for an existing portal. For create mode, pass `--package-id --dash-name`.",
|
|
574
515
|
)
|
|
575
516
|
return context.builder.portal_apply(
|
|
576
517
|
profile=args.profile,
|
|
577
518
|
dash_key=args.dash_key,
|
|
578
519
|
dash_name=args.dash_name,
|
|
579
|
-
|
|
520
|
+
package_id=args.package_id,
|
|
580
521
|
publish=bool(args.publish),
|
|
581
522
|
sections=require_list_arg(args.sections_file, option_name="--sections-file"),
|
|
582
523
|
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
@@ -593,5 +534,5 @@ def _handle_publish_verify(args: argparse.Namespace, context: CliContext) -> dic
|
|
|
593
534
|
return context.builder.app_publish_verify(
|
|
594
535
|
profile=args.profile,
|
|
595
536
|
app_key=args.app_key,
|
|
596
|
-
|
|
537
|
+
expected_package_id=args.expected_package_id,
|
|
597
538
|
)
|
|
@@ -115,17 +115,13 @@ BUILDER_PUBLIC_TOOL_SPECS: tuple[PublicToolSpec, ...] = (
|
|
|
115
115
|
PublicToolSpec(BUILDER_DOMAIN, "workspace_select", ("workspace_select",), ("builder", "workspace", "select"), cli_public=False),
|
|
116
116
|
PublicToolSpec(BUILDER_DOMAIN, "file_upload_local", ("file_upload_local",), ("builder", "file", "upload-local"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
117
117
|
PublicToolSpec(BUILDER_DOMAIN, "feedback_submit", ("feedback_submit",), ("builder", "feedback", "submit"), has_contract=True),
|
|
118
|
-
PublicToolSpec(BUILDER_DOMAIN, "package_list", ("package_list",), ("builder", "package", "list"), has_contract=True, cli_show_effective_context=True),
|
|
119
|
-
PublicToolSpec(BUILDER_DOMAIN, "package_resolve", ("package_resolve",), ("builder", "package", "resolve"), has_contract=True, cli_show_effective_context=True),
|
|
120
118
|
PublicToolSpec(BUILDER_DOMAIN, "builder_tool_contract", ("builder_tool_contract",), ("builder", "contract"), has_contract=False),
|
|
121
|
-
PublicToolSpec(BUILDER_DOMAIN, "package_create", ("package_create",), ("builder", "package", "create"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
122
119
|
PublicToolSpec(BUILDER_DOMAIN, "package_get", ("package_get",), ("builder", "package", "get"), has_contract=True, cli_show_effective_context=True),
|
|
123
|
-
PublicToolSpec(BUILDER_DOMAIN, "
|
|
120
|
+
PublicToolSpec(BUILDER_DOMAIN, "package_apply", ("package_apply",), ("builder", "package", "apply"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
124
121
|
PublicToolSpec(BUILDER_DOMAIN, "solution_install", ("solution_install",), ("builder", "solution", "install"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
125
122
|
PublicToolSpec(BUILDER_DOMAIN, "member_search", ("member_search",), ("builder", "member", "search"), has_contract=True, cli_show_effective_context=True),
|
|
126
123
|
PublicToolSpec(BUILDER_DOMAIN, "role_search", ("role_search",), ("builder", "role", "search"), has_contract=True, cli_show_effective_context=True),
|
|
127
124
|
PublicToolSpec(BUILDER_DOMAIN, "role_create", ("role_create",), ("builder", "role", "create"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
128
|
-
PublicToolSpec(BUILDER_DOMAIN, "package_attach_app", ("package_attach_app",), ("builder", "package", "attach-app"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
129
125
|
PublicToolSpec(BUILDER_DOMAIN, "app_release_edit_lock_if_mine", ("app_release_edit_lock_if_mine",), ("builder", "app", "release-edit-lock-if-mine"), has_contract=True, cli_show_effective_context=True, cli_context_write=True),
|
|
130
126
|
PublicToolSpec(BUILDER_DOMAIN, "app_resolve", ("app_resolve",), ("builder", "app", "resolve"), has_contract=True, cli_show_effective_context=True),
|
|
131
127
|
PublicToolSpec(BUILDER_DOMAIN, "app_custom_button_list", ("app_custom_button_list",), ("builder", "button", "list"), has_contract=True, cli_show_effective_context=True),
|
|
@@ -445,15 +445,13 @@ _register_policy(
|
|
|
445
445
|
_register_policy(
|
|
446
446
|
(BUILDER_DOMAIN,),
|
|
447
447
|
(
|
|
448
|
-
"package_list",
|
|
449
|
-
"package_resolve",
|
|
450
448
|
"builder_tool_contract",
|
|
449
|
+
"package_get",
|
|
450
|
+
"package_apply",
|
|
451
451
|
"solution_install",
|
|
452
|
-
"package_create",
|
|
453
452
|
"member_search",
|
|
454
453
|
"role_search",
|
|
455
454
|
"role_create",
|
|
456
|
-
"package_attach_app",
|
|
457
455
|
"app_release_edit_lock_if_mine",
|
|
458
456
|
"app_resolve",
|
|
459
457
|
"app_custom_button_list",
|
|
@@ -32,15 +32,15 @@ def build_builder_server() -> FastMCP:
|
|
|
32
32
|
instructions=(
|
|
33
33
|
"Use this server for AI-native Qingflow builder workflows. "
|
|
34
34
|
"`feedback_submit` is always available as a cross-cutting helper when the current capability is unsupported, awkward, or still cannot satisfy the user's need after reasonable use; it does not require Qingflow login or workspace selection, and it should be called only after explicit user confirmation. "
|
|
35
|
-
"Follow the resource path resolve -> summary read -> apply ->
|
|
35
|
+
"Follow the resource path resolve -> summary read -> apply -> publish_verify. "
|
|
36
36
|
"Use builder_tool_contract when you need a machine-readable contract, aliases, allowed enums, or a minimal valid example for a public builder tool. "
|
|
37
37
|
"Use solution_install when the user explicitly wants to install a packaged solution/template by solution_key, optionally copying bundled demo data. "
|
|
38
|
-
"If creating
|
|
38
|
+
"If creating or updating an app package may be appropriate, use package_apply with explicit user intent; otherwise use package_get and app_resolve to locate resources, "
|
|
39
39
|
"app_get/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 configuration reads, "
|
|
40
40
|
"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, "
|
|
41
41
|
"then app_schema_apply/app_layout_apply/app_flow_apply/app_views_apply/app_charts_apply/portal_apply to execute normalized patches; these apply tools perform planning, normalization, and dependency checks internally where applicable. Schema/layout/views noop requests skip publish, charts are immediate-live without publish and resolve targets by chart_id first then exact unique chart name, portal updates are replace-only and publish=false only guarantees draft/base-info updates, and flow should use publish=false whenever you only want draft/precheck behavior. "
|
|
42
42
|
"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. "
|
|
43
|
-
"Use
|
|
43
|
+
"Use package_apply to manage package metadata, visibility, grouping, and ordering, and app_publish_verify for explicit final publish verification. "
|
|
44
44
|
"For workflow edits, keep the public builder surface on stable linear flows only: start/approve/fill/copy/webhook/end. Branch and condition nodes are intentionally disabled because the backend workflow route is not front-end stable for those node types. Declare node assignees and editable fields explicitly. "
|
|
45
45
|
"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. "
|
|
46
46
|
"Do not handcraft internal solution payloads or rely on build_id/stage/repair. "
|
|
@@ -179,48 +179,36 @@ def build_builder_server() -> FastMCP:
|
|
|
179
179
|
raise RuntimeError(json.dumps(trim_error_response(payload), ensure_ascii=False)) from None
|
|
180
180
|
raise
|
|
181
181
|
|
|
182
|
-
@server.tool()
|
|
183
|
-
def package_list(profile: str = DEFAULT_PROFILE, trial_status: str = "all") -> dict:
|
|
184
|
-
return ai_builder.package_list(profile=profile, trial_status=trial_status)
|
|
185
|
-
|
|
186
|
-
@server.tool()
|
|
187
|
-
def package_resolve(profile: str = DEFAULT_PROFILE, package_name: str = "") -> dict:
|
|
188
|
-
return ai_builder.package_resolve(profile=profile, package_name=package_name)
|
|
189
|
-
|
|
190
182
|
@server.tool()
|
|
191
183
|
def builder_tool_contract(tool_name: str = "") -> dict:
|
|
192
184
|
return ai_builder.builder_tool_contract(tool_name=tool_name)
|
|
193
185
|
|
|
194
186
|
@server.tool()
|
|
195
|
-
def
|
|
196
|
-
profile
|
|
197
|
-
package_name: str = "",
|
|
198
|
-
icon: str | None = None,
|
|
199
|
-
color: str | None = None,
|
|
200
|
-
visibility: dict | None = None,
|
|
201
|
-
) -> dict:
|
|
202
|
-
return ai_builder.package_create(profile=profile, package_name=package_name, icon=icon, color=color, visibility=visibility)
|
|
203
|
-
|
|
204
|
-
@server.tool()
|
|
205
|
-
def package_get(profile: str = DEFAULT_PROFILE, tag_id: int = 0) -> dict:
|
|
206
|
-
return ai_builder.package_get(profile=profile, tag_id=tag_id)
|
|
187
|
+
def package_get(profile: str = DEFAULT_PROFILE, package_id: int = 0) -> dict:
|
|
188
|
+
return ai_builder.package_get(profile=profile, package_id=package_id)
|
|
207
189
|
|
|
208
190
|
@server.tool()
|
|
209
|
-
def
|
|
191
|
+
def package_apply(
|
|
210
192
|
profile: str = DEFAULT_PROFILE,
|
|
211
|
-
|
|
193
|
+
package_id: int | None = None,
|
|
212
194
|
package_name: str | None = None,
|
|
195
|
+
create_if_missing: bool = False,
|
|
213
196
|
icon: str | None = None,
|
|
214
197
|
color: str | None = None,
|
|
215
198
|
visibility: dict | None = None,
|
|
199
|
+
items: list[dict] | None = None,
|
|
200
|
+
allow_detach: bool = False,
|
|
216
201
|
) -> dict:
|
|
217
|
-
return ai_builder.
|
|
202
|
+
return ai_builder.package_apply(
|
|
218
203
|
profile=profile,
|
|
219
|
-
|
|
204
|
+
package_id=package_id,
|
|
220
205
|
package_name=package_name,
|
|
206
|
+
create_if_missing=create_if_missing,
|
|
221
207
|
icon=icon,
|
|
222
208
|
color=color,
|
|
223
209
|
visibility=visibility,
|
|
210
|
+
items=items,
|
|
211
|
+
allow_detach=allow_detach,
|
|
224
212
|
)
|
|
225
213
|
|
|
226
214
|
@server.tool()
|
|
@@ -280,14 +268,6 @@ def build_builder_server() -> FastMCP:
|
|
|
280
268
|
role_icon=role_icon,
|
|
281
269
|
)
|
|
282
270
|
|
|
283
|
-
@server.tool()
|
|
284
|
-
def package_attach_app(
|
|
285
|
-
profile: str = DEFAULT_PROFILE,
|
|
286
|
-
tag_id: int = 0,
|
|
287
|
-
app_key: str = "",
|
|
288
|
-
) -> dict:
|
|
289
|
-
return ai_builder.package_attach_app(profile=profile, tag_id=tag_id, app_key=app_key)
|
|
290
|
-
|
|
291
271
|
@server.tool()
|
|
292
272
|
def app_release_edit_lock_if_mine(
|
|
293
273
|
profile: str = DEFAULT_PROFILE,
|
|
@@ -307,22 +287,22 @@ def build_builder_server() -> FastMCP:
|
|
|
307
287
|
profile: str = DEFAULT_PROFILE,
|
|
308
288
|
app_key: str = "",
|
|
309
289
|
app_name: str = "",
|
|
310
|
-
|
|
290
|
+
package_id: int | None = None,
|
|
311
291
|
) -> dict:
|
|
312
292
|
has_app_key = bool((app_key or "").strip())
|
|
313
293
|
has_app_name = bool((app_name or "").strip())
|
|
314
|
-
|
|
315
|
-
if has_app_key and (has_app_name or
|
|
294
|
+
has_package_id = package_id is not None
|
|
295
|
+
if has_app_key and (has_app_name or has_package_id):
|
|
316
296
|
return _config_failure(
|
|
317
297
|
"app_resolve accepts exactly one selector mode.",
|
|
318
|
-
fix_hint="Use only `app_key`, or use `app_name` together with `
|
|
298
|
+
fix_hint="Use only `app_key`, or use `app_name` together with `package_id`.",
|
|
319
299
|
)
|
|
320
|
-
if not has_app_key and not (has_app_name and
|
|
300
|
+
if not has_app_key and not (has_app_name and has_package_id):
|
|
321
301
|
return _config_failure(
|
|
322
|
-
"app_resolve requires either app_key, or app_name together with
|
|
323
|
-
fix_hint="For an existing known app, pass `app_key`. For package-scoped lookup, pass both `app_name` and `
|
|
302
|
+
"app_resolve requires either app_key, or app_name together with package_id.",
|
|
303
|
+
fix_hint="For an existing known app, pass `app_key`. For package-scoped lookup, pass both `app_name` and `package_id`.",
|
|
324
304
|
)
|
|
325
|
-
return ai_builder.app_resolve(profile=profile, app_key=app_key, app_name=app_name,
|
|
305
|
+
return ai_builder.app_resolve(profile=profile, app_key=app_key, app_name=app_name, package_id=package_id)
|
|
326
306
|
|
|
327
307
|
@server.tool()
|
|
328
308
|
def app_custom_button_list(profile: str = DEFAULT_PROFILE, app_key: str = "") -> dict:
|
|
@@ -406,7 +386,7 @@ def build_builder_server() -> FastMCP:
|
|
|
406
386
|
def app_schema_apply(
|
|
407
387
|
profile: str = DEFAULT_PROFILE,
|
|
408
388
|
app_key: str = "",
|
|
409
|
-
|
|
389
|
+
package_id: int | None = None,
|
|
410
390
|
app_name: str = "",
|
|
411
391
|
app_title: str = "",
|
|
412
392
|
icon: str = "",
|
|
@@ -421,22 +401,22 @@ def build_builder_server() -> FastMCP:
|
|
|
421
401
|
has_app_key = bool((app_key or "").strip())
|
|
422
402
|
has_app_name = bool((app_name or "").strip())
|
|
423
403
|
has_app_title = bool((app_title or "").strip())
|
|
424
|
-
|
|
404
|
+
has_package_id = package_id is not None
|
|
425
405
|
if has_app_key:
|
|
426
|
-
if create_if_missing or
|
|
406
|
+
if create_if_missing or has_package_id:
|
|
427
407
|
return _config_failure(
|
|
428
408
|
"app_schema_apply edit mode accepts app_key and optional app_name rename only.",
|
|
429
|
-
fix_hint="For existing apps, use `app_key` and optionally `app_name`. For create mode, use `
|
|
409
|
+
fix_hint="For existing apps, use `app_key` and optionally `app_name`. For create mode, use `package_id + app_name + create_if_missing=true`.",
|
|
430
410
|
)
|
|
431
|
-
elif not (create_if_missing and
|
|
411
|
+
elif not (create_if_missing and has_package_id and (has_app_name or has_app_title)):
|
|
432
412
|
return _config_failure(
|
|
433
|
-
"app_schema_apply create mode requires
|
|
434
|
-
fix_hint="Use `app_key` for existing apps, or pass `
|
|
413
|
+
"app_schema_apply create mode requires package_id, app_name, and create_if_missing=true.",
|
|
414
|
+
fix_hint="Use `app_key` for existing apps, or pass `package_id + app_name + create_if_missing=true` to create a new app.",
|
|
435
415
|
)
|
|
436
416
|
return ai_builder.app_schema_apply(
|
|
437
417
|
profile=profile,
|
|
438
418
|
app_key=app_key,
|
|
439
|
-
|
|
419
|
+
package_id=package_id,
|
|
440
420
|
app_name=app_name,
|
|
441
421
|
app_title=app_title,
|
|
442
422
|
icon=icon,
|
|
@@ -514,7 +494,7 @@ def build_builder_server() -> FastMCP:
|
|
|
514
494
|
profile: str = DEFAULT_PROFILE,
|
|
515
495
|
dash_key: str = "",
|
|
516
496
|
dash_name: str = "",
|
|
517
|
-
|
|
497
|
+
package_id: int | None = None,
|
|
518
498
|
publish: bool = True,
|
|
519
499
|
sections: list[dict] | None = None,
|
|
520
500
|
visibility: dict | None = None,
|
|
@@ -527,22 +507,22 @@ def build_builder_server() -> FastMCP:
|
|
|
527
507
|
) -> dict:
|
|
528
508
|
has_dash_key = bool((dash_key or "").strip())
|
|
529
509
|
has_dash_name = bool((dash_name or "").strip())
|
|
530
|
-
|
|
531
|
-
if has_dash_key and
|
|
510
|
+
has_package_id = package_id is not None
|
|
511
|
+
if has_dash_key and has_package_id:
|
|
532
512
|
return _config_failure(
|
|
533
513
|
"portal_apply accepts exactly one selector mode.",
|
|
534
|
-
fix_hint="Use `dash_key` to update an existing portal, or use `
|
|
514
|
+
fix_hint="Use `dash_key` to update an existing portal, or use `package_id + dash_name` to create a new portal.",
|
|
535
515
|
)
|
|
536
|
-
if not has_dash_key and not (
|
|
516
|
+
if not has_dash_key and not (has_package_id and has_dash_name):
|
|
537
517
|
return _config_failure(
|
|
538
|
-
"portal_apply requires either dash_key, or
|
|
539
|
-
fix_hint="Use `dash_key` for an existing portal. For create mode, pass `
|
|
518
|
+
"portal_apply requires either dash_key, or package_id together with dash_name.",
|
|
519
|
+
fix_hint="Use `dash_key` for an existing portal. For create mode, pass `package_id + dash_name`.",
|
|
540
520
|
)
|
|
541
521
|
return ai_builder.portal_apply(
|
|
542
522
|
profile=profile,
|
|
543
523
|
dash_key=dash_key,
|
|
544
524
|
dash_name=dash_name,
|
|
545
|
-
|
|
525
|
+
package_id=package_id,
|
|
546
526
|
publish=publish,
|
|
547
527
|
sections=sections or [],
|
|
548
528
|
visibility=visibility,
|
|
@@ -558,12 +538,12 @@ def build_builder_server() -> FastMCP:
|
|
|
558
538
|
def app_publish_verify(
|
|
559
539
|
profile: str = DEFAULT_PROFILE,
|
|
560
540
|
app_key: str = "",
|
|
561
|
-
|
|
541
|
+
expected_package_id: int | None = None,
|
|
562
542
|
) -> dict:
|
|
563
543
|
return ai_builder.app_publish_verify(
|
|
564
544
|
profile=profile,
|
|
565
545
|
app_key=app_key,
|
|
566
|
-
|
|
546
|
+
expected_package_id=expected_package_id,
|
|
567
547
|
)
|
|
568
548
|
|
|
569
549
|
return server
|