@josephyan/qingflow-cli 0.2.0-beta.73 → 0.2.0-beta.75

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.
@@ -6,6 +6,7 @@ import time
6
6
 
7
7
  from pydantic import ValidationError
8
8
 
9
+ from ..public_surface import public_builder_contract_tool_names
9
10
  from ..config import DEFAULT_PROFILE
10
11
  from ..errors import QingflowApiError
11
12
  from ..json_types import JSONObject
@@ -90,6 +91,20 @@ class AiBuilderTools(ToolBase):
90
91
  ) -> JSONObject:
91
92
  return self.package_create(profile=profile, package_name=package_name, icon=icon, color=color)
92
93
 
94
+ @mcp.tool()
95
+ def solution_install(
96
+ profile: str = DEFAULT_PROFILE,
97
+ solution_key: str = "",
98
+ being_copy_data: bool = True,
99
+ solution_source: str = "solutionDetail",
100
+ ) -> JSONObject:
101
+ return self.solution_install(
102
+ profile=profile,
103
+ solution_key=solution_key,
104
+ being_copy_data=being_copy_data,
105
+ solution_source=solution_source,
106
+ )
107
+
93
108
  @mcp.tool()
94
109
  def member_search(
95
110
  profile: str = DEFAULT_PROFILE,
@@ -216,6 +231,15 @@ class AiBuilderTools(ToolBase):
216
231
  def app_get_fields(profile: str = DEFAULT_PROFILE, app_key: str = "") -> JSONObject:
217
232
  return self.app_get_fields(profile=profile, app_key=app_key)
218
233
 
234
+ @mcp.tool()
235
+ def app_repair_code_blocks(
236
+ profile: str = DEFAULT_PROFILE,
237
+ app_key: str = "",
238
+ field: str | None = None,
239
+ apply: bool = False,
240
+ ) -> JSONObject:
241
+ return self.app_repair_code_blocks(profile=profile, app_key=app_key, field=field, apply=apply)
242
+
219
243
  @mcp.tool()
220
244
  def app_get_layout(profile: str = DEFAULT_PROFILE, app_key: str = "") -> JSONObject:
221
245
  return self.app_get_layout(profile=profile, app_key=app_key)
@@ -439,11 +463,7 @@ class AiBuilderTools(ToolBase):
439
463
 
440
464
  def builder_tool_contract(self, *, tool_name: str) -> JSONObject:
441
465
  requested = str(tool_name or "").strip()
442
- public_tool_names = sorted(
443
- name
444
- for name in _BUILDER_TOOL_CONTRACTS.keys()
445
- if name not in _PRIVATE_BUILDER_TOOL_CONTRACTS and name not in _BUILDER_TOOL_CONTRACT_ALIASES
446
- )
466
+ public_tool_names = public_builder_contract_tool_names()
447
467
  if requested in _PRIVATE_BUILDER_TOOL_CONTRACTS:
448
468
  lookup_name = ""
449
469
  elif requested in _BUILDER_TOOL_CONTRACTS:
@@ -519,6 +539,31 @@ class AiBuilderTools(ToolBase):
519
539
  },
520
540
  )
521
541
 
542
+ def solution_install(
543
+ self,
544
+ *,
545
+ profile: str,
546
+ solution_key: str,
547
+ being_copy_data: bool = True,
548
+ solution_source: str = "solutionDetail",
549
+ ) -> JSONObject:
550
+ normalized_args = {
551
+ "solution_key": solution_key,
552
+ "being_copy_data": being_copy_data,
553
+ "solution_source": solution_source,
554
+ }
555
+ return _safe_tool_call(
556
+ lambda: self._facade.solution_install(
557
+ profile=profile,
558
+ solution_key=solution_key,
559
+ being_copy_data=being_copy_data,
560
+ solution_source=solution_source,
561
+ ),
562
+ error_code="SOLUTION_INSTALL_FAILED",
563
+ normalized_args=normalized_args,
564
+ suggested_next_call={"tool_name": "solution_install", "arguments": {"profile": profile, **normalized_args}},
565
+ )
566
+
522
567
  def member_search(
523
568
  self,
524
569
  *,
@@ -768,6 +813,22 @@ class AiBuilderTools(ToolBase):
768
813
  suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}},
769
814
  )
770
815
 
816
+ def app_repair_code_blocks(
817
+ self,
818
+ *,
819
+ profile: str,
820
+ app_key: str,
821
+ field: str | None = None,
822
+ apply: bool = False,
823
+ ) -> JSONObject:
824
+ normalized_args = {"app_key": app_key, "field": field, "apply": apply}
825
+ return _safe_tool_call(
826
+ lambda: self._facade.app_repair_code_blocks(profile=profile, app_key=app_key, field=field, apply=apply),
827
+ error_code="APP_REPAIR_CODE_BLOCKS_FAILED",
828
+ normalized_args=normalized_args,
829
+ suggested_next_call={"tool_name": "app_repair_code_blocks", "arguments": {"profile": profile, **normalized_args}},
830
+ )
831
+
771
832
  def app_read_layout_summary(self, *, profile: str, app_key: str) -> JSONObject:
772
833
  normalized_args = {"app_key": app_key}
773
834
  return _safe_tool_call(
@@ -1889,6 +1950,7 @@ def _public_error_message(error_code: str, error: QingflowApiError) -> str:
1889
1950
  mapping = {
1890
1951
  "PACKAGE_LIST_FAILED": "package list is unavailable in the current route",
1891
1952
  "PACKAGE_RESOLVE_FAILED": "package resolution is unavailable in the current route",
1953
+ "SOLUTION_INSTALL_FAILED": "solution install could not complete because the app creation route or solution source is unavailable",
1892
1954
  "PACKAGE_ATTACH_FAILED": "package attachment could not be verified in the current route",
1893
1955
  "APP_RESOLVE_FAILED": "app resolution is unavailable in the current route",
1894
1956
  "CUSTOM_BUTTON_LIST_FAILED": "custom button list is unavailable in the current route",
@@ -1994,6 +2056,32 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
1994
2056
  "color": "azure",
1995
2057
  },
1996
2058
  },
2059
+ "solution_install": {
2060
+ "allowed_keys": ["solution_key", "being_copy_data", "solution_source"],
2061
+ "aliases": {
2062
+ "solutionKey": "solution_key",
2063
+ "beingCopyData": "being_copy_data",
2064
+ "copy_data": "being_copy_data",
2065
+ "copyData": "being_copy_data",
2066
+ "solutionSource": "solution_source",
2067
+ "source": "solution_source",
2068
+ },
2069
+ "allowed_values": {
2070
+ "being_copy_data": [True, False],
2071
+ "solution_source": ["solutionDetail"],
2072
+ },
2073
+ "execution_notes": [
2074
+ "solution_install calls the backend app creation route with a solutionKey payload",
2075
+ "this is a write operation that may create multiple apps at once",
2076
+ "app_keys are verified from the backend response when available",
2077
+ ],
2078
+ "minimal_example": {
2079
+ "profile": "default",
2080
+ "solution_key": "cfqrhth99401",
2081
+ "being_copy_data": True,
2082
+ "solution_source": "solutionDetail",
2083
+ },
2084
+ },
1997
2085
  "member_search": {
1998
2086
  "allowed_keys": ["query", "page_num", "page_size", "contain_disable"],
1999
2087
  "aliases": {},
@@ -2116,6 +2204,11 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2116
2204
  "allowed_values": {
2117
2205
  "payload.trigger_action": [member.value for member in PublicButtonTriggerAction],
2118
2206
  },
2207
+ "execution_notes": [
2208
+ "custom button writes now auto-publish the current app draft as a fixed closing step",
2209
+ "background_color and text_color cannot both be white",
2210
+ "for addData buttons, put field mappings in payload.trigger_add_data_config.que_relation",
2211
+ ],
2119
2212
  "minimal_example": {
2120
2213
  "profile": "default",
2121
2214
  "app_key": "APP_KEY",
@@ -2149,6 +2242,11 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2149
2242
  "allowed_values": {
2150
2243
  "payload.trigger_action": [member.value for member in PublicButtonTriggerAction],
2151
2244
  },
2245
+ "execution_notes": [
2246
+ "custom button writes now auto-publish the current app draft as a fixed closing step",
2247
+ "background_color and text_color cannot both be white",
2248
+ "for addData buttons, put field mappings in payload.trigger_add_data_config.que_relation",
2249
+ ],
2152
2250
  "minimal_example": {
2153
2251
  "profile": "default",
2154
2252
  "app_key": "APP_KEY",
@@ -2190,6 +2288,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2190
2288
  "field.allow_multiple": "field.relation_mode",
2191
2289
  "field.optional_data_num": "field.relation_mode",
2192
2290
  "field.optionalDataNum": "field.relation_mode",
2291
+ "field.departmentScope": "field.department_scope",
2193
2292
  "field.remoteLookupConfig": "field.remote_lookup_config",
2194
2293
  "field.qLinkerBinding": "field.q_linker_binding",
2195
2294
  "field.codeBlockConfig": "field.code_block_config",
@@ -2247,6 +2346,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2247
2346
  "field.allow_multiple": "field.relation_mode",
2248
2347
  "field.optional_data_num": "field.relation_mode",
2249
2348
  "field.optionalDataNum": "field.relation_mode",
2349
+ "field.departmentScope": "field.department_scope",
2250
2350
  "field.remoteLookupConfig": "field.remote_lookup_config",
2251
2351
  "field.qLinkerBinding": "field.q_linker_binding",
2252
2352
  "field.codeBlockConfig": "field.code_block_config",
@@ -2258,6 +2358,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2258
2358
  "allowed_values": {
2259
2359
  "field.type": [member.value for member in PublicFieldType],
2260
2360
  "field.relation_mode": [member.value for member in PublicRelationMode],
2361
+ "field.department_scope.mode": ["all", "custom"],
2261
2362
  "field.code_block_binding.outputs.target_field.type": list(INTEGRATION_OUTPUT_TARGET_FIELD_TYPES),
2262
2363
  "field.q_linker_binding.outputs.target_field.type": list(INTEGRATION_OUTPUT_TARGET_FIELD_TYPES),
2263
2364
  "field_type_ids": sorted(FIELD_TYPE_ID_ALIASES.keys()),
@@ -2269,10 +2370,14 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2269
2370
  "multiple relation fields are backend-risky; read verification.relation_field_limit_verified and warnings before declaring the schema stable",
2270
2371
  "backend 49614 is normalized to MULTIPLE_RELATION_FIELDS_UNSUPPORTED with a workaround message",
2271
2372
  "relation_mode=multiple maps to referenceConfig.optionalDataNum=0",
2373
+ "relation fields now require both display_field and visible_fields in MCP/CLI payloads",
2272
2374
  "if relation target metadata lookup is blocked by 40161/40002/40027, explicit display_field.name and visible_fields[].name let builder degrade verification and still continue schema write",
2375
+ "department fields accept department_scope with mode=all or mode=custom; custom scope requires explicit departments[].dept_id and optional include_sub_departs",
2273
2376
  "q_linker_binding lets you declare request config, dynamic inputs, alias parsing, and target-field bindings in one step; builder writes remoteLookupConfig plus the existing backend relation-default and questionRelations structures",
2274
2377
  "code_block_binding lets you declare inputs, code, alias parsing, and target-field bindings in one step; builder writes codeBlockConfig plus the existing backend relation-default and questionRelations structures",
2275
2378
  "builder configures code blocks only; it does not execute or trigger code blocks",
2379
+ "code block outputs must be emitted through qf_output assignment; use qf_output = {...} or assign qf_output after building the result object, never const/let qf_output =",
2380
+ "builder automatically normalizes const/let qf_output assignments on write and rejects output-bound code blocks that still do not contain a valid qf_output assignment",
2276
2381
  "code_block_binding and q_linker_binding target fields are limited to text, long_text, number, amount, date, datetime, single_select, multi_select, and boolean",
2277
2382
  ],
2278
2383
  "minimal_example": {
@@ -2304,6 +2409,24 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2304
2409
  "update_fields": [],
2305
2410
  "remove_fields": [],
2306
2411
  },
2412
+ "department_scope_example": {
2413
+ "profile": "default",
2414
+ "app_key": "APP_LEAD",
2415
+ "publish": True,
2416
+ "add_fields": [
2417
+ {
2418
+ "name": "归属部门",
2419
+ "type": "department",
2420
+ "department_scope": {
2421
+ "mode": "custom",
2422
+ "departments": [{"dept_id": 334952, "dept_name": "生产"}],
2423
+ "include_sub_departs": False,
2424
+ },
2425
+ }
2426
+ ],
2427
+ "update_fields": [],
2428
+ "remove_fields": [],
2429
+ },
2307
2430
  "code_block_example": {
2308
2431
  "profile": "default",
2309
2432
  "app_key": "APP_SCRIPT",
@@ -2858,6 +2981,23 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2858
2981
  "expected_package_tag_id": 1001,
2859
2982
  },
2860
2983
  },
2984
+ "app_repair_code_blocks": {
2985
+ "allowed_keys": ["app_key", "field", "apply"],
2986
+ "aliases": {},
2987
+ "allowed_values": {},
2988
+ "execution_notes": [
2989
+ "scan existing code_block fields for qf_output shadowing, missing output assignment, and broken writeback defaults",
2990
+ "apply=false is a dry-run and returns a repair plan without writing builder config",
2991
+ "apply=true rewrites only safe cases: const/let qf_output shadowing and stale relation-default output bindings reconstructed from readable code_block_binding config",
2992
+ "this tool does not invent missing output aliases or guess missing target bindings when only low-level codeBlockConfig is present",
2993
+ ],
2994
+ "minimal_example": {
2995
+ "profile": "default",
2996
+ "app_key": "APP_KEY",
2997
+ "field": "线索价值评估",
2998
+ "apply": False,
2999
+ },
3000
+ },
2861
3001
  }
2862
3002
 
2863
3003
  _PRIVATE_BUILDER_TOOL_CONTRACTS = {