@josephyan/qingflow-cli 0.2.0-beta.74 → 0.2.0-beta.76
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/builder_facade/models.py +121 -0
- package/src/qingflow_mcp/builder_facade/service.py +297 -66
- package/src/qingflow_mcp/public_surface.py +230 -0
- package/src/qingflow_mcp/response_trim.py +14 -248
- package/src/qingflow_mcp/server_app_user.py +4 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +35 -5
- package/src/qingflow_mcp/tools/approval_tools.py +0 -16
- package/src/qingflow_mcp/tools/record_tools.py +298 -25
- package/src/qingflow_mcp/tools/task_context_tools.py +130 -7
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-cli@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-cli@0.2.0-beta.76
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.76 qingflow
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@josephyan/qingflow-cli",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.76",
|
|
4
4
|
"description": "Human-friendly Qingflow command line interface for auth, record operations, import, tasks, and stable builder flows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/pyproject.toml
CHANGED
|
@@ -35,6 +35,11 @@ class PublicRelationMode(str, Enum):
|
|
|
35
35
|
multiple = "multiple"
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
class PublicDepartmentScopeMode(str, Enum):
|
|
39
|
+
all = "all"
|
|
40
|
+
custom = "custom"
|
|
41
|
+
|
|
42
|
+
|
|
38
43
|
FIELD_TYPE_ALIASES: dict[str, PublicFieldType] = {
|
|
39
44
|
"textarea": PublicFieldType.long_text,
|
|
40
45
|
"amount": PublicFieldType.amount,
|
|
@@ -291,6 +296,56 @@ class FieldSelector(StrictModel):
|
|
|
291
296
|
return self
|
|
292
297
|
|
|
293
298
|
|
|
299
|
+
class DepartmentSelectorPatch(StrictModel):
|
|
300
|
+
dept_id: int | None = Field(default=None, validation_alias=AliasChoices("dept_id", "deptId", "id"))
|
|
301
|
+
dept_name: str | None = Field(default=None, validation_alias=AliasChoices("dept_name", "deptName", "name", "value"))
|
|
302
|
+
|
|
303
|
+
@model_validator(mode="after")
|
|
304
|
+
def validate_selector(self) -> "DepartmentSelectorPatch":
|
|
305
|
+
if self.dept_id is None and not str(self.dept_name or "").strip():
|
|
306
|
+
raise ValueError("department selector must include dept_id or dept_name")
|
|
307
|
+
return self
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class DepartmentScopePatch(StrictModel):
|
|
311
|
+
mode: PublicDepartmentScopeMode | None = None
|
|
312
|
+
departments: list[DepartmentSelectorPatch] = Field(
|
|
313
|
+
default_factory=list,
|
|
314
|
+
validation_alias=AliasChoices("departments", "departs", "depart"),
|
|
315
|
+
)
|
|
316
|
+
include_sub_departs: bool | None = Field(
|
|
317
|
+
default=None,
|
|
318
|
+
validation_alias=AliasChoices("include_sub_departs", "includeSubDeparts"),
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
@model_validator(mode="before")
|
|
322
|
+
@classmethod
|
|
323
|
+
def normalize_aliases(cls, value: Any) -> Any:
|
|
324
|
+
if not isinstance(value, dict):
|
|
325
|
+
return value
|
|
326
|
+
payload = dict(value)
|
|
327
|
+
if "depart" in payload and "departments" not in payload:
|
|
328
|
+
payload["departments"] = payload.pop("depart")
|
|
329
|
+
if "departs" in payload and "departments" not in payload:
|
|
330
|
+
payload["departments"] = payload.pop("departs")
|
|
331
|
+
normalized_mode = _normalize_public_department_scope_mode(payload.get("mode"))
|
|
332
|
+
if normalized_mode is None:
|
|
333
|
+
if "departments" in payload:
|
|
334
|
+
normalized_mode = PublicDepartmentScopeMode.custom.value
|
|
335
|
+
else:
|
|
336
|
+
normalized_mode = PublicDepartmentScopeMode.all.value
|
|
337
|
+
payload["mode"] = normalized_mode
|
|
338
|
+
return payload
|
|
339
|
+
|
|
340
|
+
@model_validator(mode="after")
|
|
341
|
+
def validate_shape(self) -> "DepartmentScopePatch":
|
|
342
|
+
if self.mode == PublicDepartmentScopeMode.custom and not self.departments:
|
|
343
|
+
raise ValueError("custom department scope requires departments")
|
|
344
|
+
if self.mode == PublicDepartmentScopeMode.custom and any(item.dept_id is None for item in self.departments):
|
|
345
|
+
raise ValueError("custom department scope requires departments[].dept_id")
|
|
346
|
+
return self
|
|
347
|
+
|
|
348
|
+
|
|
294
349
|
class CodeBlockAliasPathPatch(StrictModel):
|
|
295
350
|
alias_name: str = Field(validation_alias=AliasChoices("alias_name", "aliasName"))
|
|
296
351
|
alias_path: str = Field(validation_alias=AliasChoices("alias_path", "aliasPath"))
|
|
@@ -555,6 +610,10 @@ class FieldPatch(StrictModel):
|
|
|
555
610
|
display_field: FieldSelector | None = None
|
|
556
611
|
visible_fields: list[FieldSelector] = Field(default_factory=list)
|
|
557
612
|
relation_mode: PublicRelationMode | None = Field(default=None, validation_alias=AliasChoices("relation_mode", "relationMode", "selection_mode", "selectionMode"))
|
|
613
|
+
department_scope: DepartmentScopePatch | None = Field(
|
|
614
|
+
default=None,
|
|
615
|
+
validation_alias=AliasChoices("department_scope", "departmentScope"),
|
|
616
|
+
)
|
|
558
617
|
remote_lookup_config: RemoteLookupConfigPatch | None = Field(
|
|
559
618
|
default=None,
|
|
560
619
|
validation_alias=AliasChoices("remote_lookup_config", "remoteLookupConfig"),
|
|
@@ -586,10 +645,16 @@ class FieldPatch(StrictModel):
|
|
|
586
645
|
def validate_shape(self) -> "FieldPatch":
|
|
587
646
|
if self.type == PublicFieldType.relation and not self.target_app_key:
|
|
588
647
|
raise ValueError("relation field requires target_app_key")
|
|
648
|
+
if self.type == PublicFieldType.relation and self.display_field is None:
|
|
649
|
+
raise ValueError("relation field requires display_field")
|
|
650
|
+
if self.type == PublicFieldType.relation and not self.visible_fields:
|
|
651
|
+
raise ValueError("relation field requires visible_fields")
|
|
589
652
|
if self.type != PublicFieldType.relation and self.target_app_key:
|
|
590
653
|
raise ValueError("target_app_key is only allowed for relation fields")
|
|
591
654
|
if self.type != PublicFieldType.relation and (self.display_field is not None or self.visible_fields or self.relation_mode is not None):
|
|
592
655
|
raise ValueError("display_field, visible_fields, and relation_mode are only allowed for relation fields")
|
|
656
|
+
if self.type != PublicFieldType.department and self.department_scope is not None:
|
|
657
|
+
raise ValueError("department_scope is only allowed for department fields")
|
|
593
658
|
if self.type != PublicFieldType.q_linker and (
|
|
594
659
|
self.remote_lookup_config is not None
|
|
595
660
|
or self.q_linker_binding is not None
|
|
@@ -625,6 +690,10 @@ class FieldMutation(StrictModel):
|
|
|
625
690
|
display_field: FieldSelector | None = None
|
|
626
691
|
visible_fields: list[FieldSelector] | None = None
|
|
627
692
|
relation_mode: PublicRelationMode | None = Field(default=None, validation_alias=AliasChoices("relation_mode", "relationMode", "selection_mode", "selectionMode"))
|
|
693
|
+
department_scope: DepartmentScopePatch | None = Field(
|
|
694
|
+
default=None,
|
|
695
|
+
validation_alias=AliasChoices("department_scope", "departmentScope"),
|
|
696
|
+
)
|
|
628
697
|
remote_lookup_config: RemoteLookupConfigPatch | None = Field(
|
|
629
698
|
default=None,
|
|
630
699
|
validation_alias=AliasChoices("remote_lookup_config", "remoteLookupConfig"),
|
|
@@ -656,8 +725,17 @@ class FieldMutation(StrictModel):
|
|
|
656
725
|
def validate_shape(self) -> "FieldMutation":
|
|
657
726
|
if self.type == PublicFieldType.relation and not self.target_app_key:
|
|
658
727
|
raise ValueError("relation field requires target_app_key")
|
|
728
|
+
relation_patch = (
|
|
729
|
+
self.type == PublicFieldType.relation
|
|
730
|
+
or self.target_app_key is not None
|
|
731
|
+
or self.display_field is not None
|
|
732
|
+
or self.visible_fields is not None
|
|
733
|
+
or self.relation_mode is not None
|
|
734
|
+
)
|
|
659
735
|
if self.type is not None and self.type != PublicFieldType.relation and (self.display_field is not None or self.visible_fields or self.relation_mode is not None):
|
|
660
736
|
raise ValueError("display_field, visible_fields, and relation_mode are only allowed for relation fields")
|
|
737
|
+
if self.type is not None and self.type != PublicFieldType.department and self.department_scope is not None:
|
|
738
|
+
raise ValueError("department_scope is only allowed for department fields")
|
|
661
739
|
if self.type is not None and self.type != PublicFieldType.q_linker and (
|
|
662
740
|
self.remote_lookup_config is not None
|
|
663
741
|
or self.q_linker_binding is not None
|
|
@@ -981,6 +1059,17 @@ class CustomButtonWingsConfigPatch(StrictModel):
|
|
|
981
1059
|
return payload
|
|
982
1060
|
|
|
983
1061
|
|
|
1062
|
+
def _is_white_button_color(value: str | None) -> bool:
|
|
1063
|
+
normalized = str(value or "").strip().lower().replace(" ", "")
|
|
1064
|
+
return normalized in {
|
|
1065
|
+
"#fff",
|
|
1066
|
+
"#ffffff",
|
|
1067
|
+
"white",
|
|
1068
|
+
"rgb(255,255,255)",
|
|
1069
|
+
"rgba(255,255,255,1)",
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
|
|
984
1073
|
class CustomButtonPatch(StrictModel):
|
|
985
1074
|
button_text: str = Field(validation_alias=AliasChoices("button_text", "buttonText"))
|
|
986
1075
|
background_color: str = Field(validation_alias=AliasChoices("background_color", "backgroundColor"))
|
|
@@ -1017,6 +1106,8 @@ class CustomButtonPatch(StrictModel):
|
|
|
1017
1106
|
raise ValueError("qRobot buttons require external_qrobot_config")
|
|
1018
1107
|
if self.trigger_action == PublicButtonTriggerAction.wings and self.trigger_wings_config is None:
|
|
1019
1108
|
raise ValueError("wings buttons require trigger_wings_config")
|
|
1109
|
+
if _is_white_button_color(self.background_color) and _is_white_button_color(self.text_color):
|
|
1110
|
+
raise ValueError("background_color and text_color cannot both be white")
|
|
1020
1111
|
return self
|
|
1021
1112
|
|
|
1022
1113
|
|
|
@@ -1079,6 +1170,8 @@ class ViewButtonBindingPatch(StrictModel):
|
|
|
1079
1170
|
]
|
|
1080
1171
|
if missing:
|
|
1081
1172
|
raise ValueError(f"system button bindings require {', '.join(missing)}")
|
|
1173
|
+
if _is_white_button_color(self.background_color) and _is_white_button_color(self.text_color):
|
|
1174
|
+
raise ValueError("background_color and text_color cannot both be white")
|
|
1082
1175
|
return self
|
|
1083
1176
|
|
|
1084
1177
|
|
|
@@ -1599,6 +1692,34 @@ def _normalize_public_relation_mode(value: Any) -> str | None:
|
|
|
1599
1692
|
return None
|
|
1600
1693
|
|
|
1601
1694
|
|
|
1695
|
+
def _normalize_public_department_scope_mode(value: Any) -> str | None:
|
|
1696
|
+
if value is None:
|
|
1697
|
+
return None
|
|
1698
|
+
if isinstance(value, int):
|
|
1699
|
+
if value == 1:
|
|
1700
|
+
return PublicDepartmentScopeMode.all.value
|
|
1701
|
+
if value == 2:
|
|
1702
|
+
return PublicDepartmentScopeMode.custom.value
|
|
1703
|
+
return None
|
|
1704
|
+
if isinstance(value, str):
|
|
1705
|
+
normalized = value.strip().lower()
|
|
1706
|
+
aliases = {
|
|
1707
|
+
"all": PublicDepartmentScopeMode.all.value,
|
|
1708
|
+
"workspace_all": PublicDepartmentScopeMode.all.value,
|
|
1709
|
+
"workspace-all": PublicDepartmentScopeMode.all.value,
|
|
1710
|
+
"default": PublicDepartmentScopeMode.all.value,
|
|
1711
|
+
"default_all": PublicDepartmentScopeMode.all.value,
|
|
1712
|
+
"default-all": PublicDepartmentScopeMode.all.value,
|
|
1713
|
+
"1": PublicDepartmentScopeMode.all.value,
|
|
1714
|
+
"custom": PublicDepartmentScopeMode.custom.value,
|
|
1715
|
+
"explicit": PublicDepartmentScopeMode.custom.value,
|
|
1716
|
+
"selected": PublicDepartmentScopeMode.custom.value,
|
|
1717
|
+
"2": PublicDepartmentScopeMode.custom.value,
|
|
1718
|
+
}
|
|
1719
|
+
return aliases.get(normalized, normalized or None)
|
|
1720
|
+
return None
|
|
1721
|
+
|
|
1722
|
+
|
|
1602
1723
|
CustomButtonMatchRulePatch.model_rebuild()
|
|
1603
1724
|
CustomButtonAddDataConfigPatch.model_rebuild()
|
|
1604
1725
|
CodeBlockAliasPathPatch.model_rebuild()
|