@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.
- package/README.md +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/backend_client.py +102 -0
- package/src/qingflow_mcp/builder_facade/models.py +121 -0
- package/src/qingflow_mcp/builder_facade/service.py +906 -71
- package/src/qingflow_mcp/cli/commands/builder.py +33 -1
- package/src/qingflow_mcp/cli/commands/repo.py +80 -0
- package/src/qingflow_mcp/cli/commands/task.py +17 -0
- package/src/qingflow_mcp/cli/context.py +3 -0
- package/src/qingflow_mcp/config.py +147 -0
- package/src/qingflow_mcp/public_surface.py +231 -0
- package/src/qingflow_mcp/repository_store.py +71 -0
- package/src/qingflow_mcp/response_trim.py +17 -246
- package/src/qingflow_mcp/server_app_builder.py +26 -1
- package/src/qingflow_mcp/server_app_user.py +5 -1
- package/src/qingflow_mcp/tools/ai_builder_tools.py +145 -5
- package/src/qingflow_mcp/tools/record_tools.py +298 -25
- package/src/qingflow_mcp/tools/repository_dev_tools.py +533 -0
- package/src/qingflow_mcp/tools/task_context_tools.py +146 -7
|
@@ -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 =
|
|
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 = {
|