@josephyan/qingflow-cli 0.2.0-beta.61 → 0.2.0-beta.63
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 +225 -0
- package/src/qingflow_mcp/builder_facade/service.py +1024 -30
- package/src/qingflow_mcp/cli/commands/builder.py +58 -1
- package/src/qingflow_mcp/cli/commands/task.py +3 -1
- package/src/qingflow_mcp/cli/formatters.py +36 -0
- package/src/qingflow_mcp/server_app_builder.py +25 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +244 -2
- package/src/qingflow_mcp/tools/approval_tools.py +147 -12
- package/src/qingflow_mcp/tools/custom_button_tools.py +177 -0
- package/src/qingflow_mcp/tools/import_tools.py +217 -90
- package/src/qingflow_mcp/tools/task_context_tools.py +621 -29
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.63
|
|
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.63 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.63",
|
|
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
|
@@ -74,6 +74,23 @@ class PublicViewType(str, Enum):
|
|
|
74
74
|
gantt = "gantt"
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
class PublicButtonTriggerAction(str, Enum):
|
|
78
|
+
add_data = "addData"
|
|
79
|
+
link = "link"
|
|
80
|
+
qrobot = "qRobot"
|
|
81
|
+
wings = "wings"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class PublicViewButtonType(str, Enum):
|
|
85
|
+
system = "SYSTEM"
|
|
86
|
+
custom = "CUSTOM"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class PublicViewButtonConfigType(str, Enum):
|
|
90
|
+
top = "TOP"
|
|
91
|
+
detail = "DETAIL"
|
|
92
|
+
|
|
93
|
+
|
|
77
94
|
class PublicChartType(str, Enum):
|
|
78
95
|
target = "target"
|
|
79
96
|
pie = "pie"
|
|
@@ -473,6 +490,7 @@ class ViewUpsertPatch(StrictModel):
|
|
|
473
490
|
start_field: str | None = Field(default=None, validation_alias=AliasChoices("start_field", "startField"))
|
|
474
491
|
end_field: str | None = Field(default=None, validation_alias=AliasChoices("end_field", "endField"))
|
|
475
492
|
title_field: str | None = Field(default=None, validation_alias=AliasChoices("title_field", "titleField"))
|
|
493
|
+
buttons: list["ViewButtonBindingPatch"] | None = None
|
|
476
494
|
|
|
477
495
|
@model_validator(mode="before")
|
|
478
496
|
@classmethod
|
|
@@ -514,6 +532,207 @@ class ViewUpsertPatch(StrictModel):
|
|
|
514
532
|
return self
|
|
515
533
|
|
|
516
534
|
|
|
535
|
+
class CustomButtonJudgeValuePatch(StrictModel):
|
|
536
|
+
id: int | str | None = None
|
|
537
|
+
value: Any | None = None
|
|
538
|
+
|
|
539
|
+
@model_validator(mode="before")
|
|
540
|
+
@classmethod
|
|
541
|
+
def normalize_aliases(cls, value: Any) -> Any:
|
|
542
|
+
if not isinstance(value, dict):
|
|
543
|
+
return value
|
|
544
|
+
payload = dict(value)
|
|
545
|
+
if "opt_id" in payload and "id" not in payload:
|
|
546
|
+
payload["id"] = payload.pop("opt_id")
|
|
547
|
+
if "member_id" in payload and "id" not in payload:
|
|
548
|
+
payload["id"] = payload.pop("member_id")
|
|
549
|
+
return payload
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
class CustomButtonQuestionRefPatch(StrictModel):
|
|
553
|
+
que_id: int = Field(validation_alias=AliasChoices("que_id", "queId"))
|
|
554
|
+
que_title: str | None = Field(default=None, validation_alias=AliasChoices("que_title", "queTitle"))
|
|
555
|
+
que_type: int | None = Field(default=None, validation_alias=AliasChoices("que_type", "queType"))
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
class CustomButtonMatchRulePatch(StrictModel):
|
|
559
|
+
que_id: int = Field(validation_alias=AliasChoices("que_id", "queId"))
|
|
560
|
+
que_title: str | None = Field(default=None, validation_alias=AliasChoices("que_title", "queTitle"))
|
|
561
|
+
que_type: int | None = Field(default=None, validation_alias=AliasChoices("que_type", "queType"))
|
|
562
|
+
date_type: int | None = Field(default=None, validation_alias=AliasChoices("date_type", "dateType"))
|
|
563
|
+
judge_type: int | None = Field(default=None, validation_alias=AliasChoices("judge_type", "judgeType"))
|
|
564
|
+
match_type: int | None = Field(default=None, validation_alias=AliasChoices("match_type", "matchType"))
|
|
565
|
+
judge_values: list[str] = Field(default_factory=list, validation_alias=AliasChoices("judge_values", "judgeValues"))
|
|
566
|
+
judge_que_type: int | None = Field(default=None, validation_alias=AliasChoices("judge_que_type", "judgeQueType"))
|
|
567
|
+
judge_que_id: int | None = Field(default=None, validation_alias=AliasChoices("judge_que_id", "judgeQueId"))
|
|
568
|
+
judge_que_detail: CustomButtonQuestionRefPatch | None = Field(
|
|
569
|
+
default=None,
|
|
570
|
+
validation_alias=AliasChoices("judge_que_detail", "judgeQueDetail"),
|
|
571
|
+
)
|
|
572
|
+
judge_value_details: list[CustomButtonJudgeValuePatch] = Field(
|
|
573
|
+
default_factory=list,
|
|
574
|
+
validation_alias=AliasChoices("judge_value_details", "judgeValueDetails"),
|
|
575
|
+
)
|
|
576
|
+
path_value: str | None = Field(default=None, validation_alias=AliasChoices("path_value", "pathValue"))
|
|
577
|
+
table_update_type: int | None = Field(default=None, validation_alias=AliasChoices("table_update_type", "tableUpdateType"))
|
|
578
|
+
multi_value: bool | None = Field(default=None, validation_alias=AliasChoices("multi_value", "multiValue"))
|
|
579
|
+
add_rule: str | None = Field(default=None, validation_alias=AliasChoices("add_rule", "addRule"))
|
|
580
|
+
filter_condition: list[list["CustomButtonMatchRulePatch"]] = Field(
|
|
581
|
+
default_factory=list,
|
|
582
|
+
validation_alias=AliasChoices("filter_condition", "filterCondition"),
|
|
583
|
+
)
|
|
584
|
+
field_id_prefix: str | None = Field(default=None, validation_alias=AliasChoices("field_id_prefix", "fieldIdPrefix"))
|
|
585
|
+
|
|
586
|
+
@model_validator(mode="before")
|
|
587
|
+
@classmethod
|
|
588
|
+
def normalize_aliases(cls, value: Any) -> Any:
|
|
589
|
+
if not isinstance(value, dict):
|
|
590
|
+
return value
|
|
591
|
+
payload = dict(value)
|
|
592
|
+
if "judgeValue" in payload and "judge_values" not in payload and "judgeValues" not in payload:
|
|
593
|
+
payload["judge_values"] = [payload.pop("judgeValue")]
|
|
594
|
+
return payload
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
class CustomButtonAddDataConfigPatch(StrictModel):
|
|
598
|
+
related_app_key: str | None = Field(default=None, validation_alias=AliasChoices("related_app_key", "relatedAppKey"))
|
|
599
|
+
related_app_name: str | None = Field(default=None, validation_alias=AliasChoices("related_app_name", "relatedAppName"))
|
|
600
|
+
que_relation: list[CustomButtonMatchRulePatch] = Field(
|
|
601
|
+
default_factory=list,
|
|
602
|
+
validation_alias=AliasChoices("que_relation", "queRelation"),
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class CustomButtonExternalQRobotConfigPatch(StrictModel):
|
|
607
|
+
external_qrobot_config_id: int | None = Field(
|
|
608
|
+
default=None,
|
|
609
|
+
validation_alias=AliasChoices("external_qrobot_config_id", "externalQRobotConfigId"),
|
|
610
|
+
)
|
|
611
|
+
triggered_text: str | None = Field(default=None, validation_alias=AliasChoices("triggered_text", "triggeredText"))
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
class CustomButtonWingsConfigPatch(StrictModel):
|
|
615
|
+
wings_agent_id: int | None = Field(default=None, validation_alias=AliasChoices("wings_agent_id", "wingsAgentId"))
|
|
616
|
+
wings_agent_name: str | None = Field(default=None, validation_alias=AliasChoices("wings_agent_name", "wingsAgentName"))
|
|
617
|
+
bind_que_id_list: list[int] = Field(default_factory=list, validation_alias=AliasChoices("bind_que_id_list", "bindQueIdList"))
|
|
618
|
+
bind_file_que_id_list: list[int] = Field(
|
|
619
|
+
default_factory=list,
|
|
620
|
+
validation_alias=AliasChoices("bind_file_que_id_list", "bindFileQueIdList"),
|
|
621
|
+
)
|
|
622
|
+
default_prompt: str | None = Field(default=None, validation_alias=AliasChoices("default_prompt", "defaultPrompt"))
|
|
623
|
+
being_auto_send: bool | None = Field(default=None, validation_alias=AliasChoices("being_auto_send", "beingAutoSend"))
|
|
624
|
+
|
|
625
|
+
@model_validator(mode="before")
|
|
626
|
+
@classmethod
|
|
627
|
+
def normalize_aliases(cls, value: Any) -> Any:
|
|
628
|
+
if not isinstance(value, dict):
|
|
629
|
+
return value
|
|
630
|
+
payload = dict(value)
|
|
631
|
+
raw_agent_id = payload.get("wings_agent_id", payload.get("wingsAgentId"))
|
|
632
|
+
if isinstance(raw_agent_id, str) and raw_agent_id.strip().isdigit():
|
|
633
|
+
payload["wings_agent_id"] = int(raw_agent_id.strip())
|
|
634
|
+
return payload
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
class CustomButtonPatch(StrictModel):
|
|
638
|
+
button_text: str = Field(validation_alias=AliasChoices("button_text", "buttonText"))
|
|
639
|
+
background_color: str = Field(validation_alias=AliasChoices("background_color", "backgroundColor"))
|
|
640
|
+
text_color: str = Field(validation_alias=AliasChoices("text_color", "textColor"))
|
|
641
|
+
button_icon: str = Field(validation_alias=AliasChoices("button_icon", "buttonIcon"))
|
|
642
|
+
trigger_action: PublicButtonTriggerAction = Field(validation_alias=AliasChoices("trigger_action", "triggerAction"))
|
|
643
|
+
trigger_link_url: str | None = Field(default=None, validation_alias=AliasChoices("trigger_link_url", "triggerLinkUrl"))
|
|
644
|
+
trigger_add_data_config: CustomButtonAddDataConfigPatch | None = Field(
|
|
645
|
+
default=None,
|
|
646
|
+
validation_alias=AliasChoices("trigger_add_data_config", "triggerAddDataConfig"),
|
|
647
|
+
)
|
|
648
|
+
external_qrobot_config: CustomButtonExternalQRobotConfigPatch | None = Field(
|
|
649
|
+
default=None,
|
|
650
|
+
validation_alias=AliasChoices(
|
|
651
|
+
"external_qrobot_config",
|
|
652
|
+
"externalQrobotConfig",
|
|
653
|
+
"custom_button_external_qrobot_relation_vo",
|
|
654
|
+
"customButtonExternalQRobotRelationVO",
|
|
655
|
+
),
|
|
656
|
+
)
|
|
657
|
+
trigger_wings_config: CustomButtonWingsConfigPatch | None = Field(
|
|
658
|
+
default=None,
|
|
659
|
+
validation_alias=AliasChoices("trigger_wings_config", "triggerWingsConfig"),
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
@model_validator(mode="after")
|
|
663
|
+
def validate_shape(self) -> "CustomButtonPatch":
|
|
664
|
+
if self.trigger_action == PublicButtonTriggerAction.link and not str(self.trigger_link_url or "").strip():
|
|
665
|
+
raise ValueError("link buttons require trigger_link_url")
|
|
666
|
+
if self.trigger_action == PublicButtonTriggerAction.add_data and self.trigger_add_data_config is None:
|
|
667
|
+
raise ValueError("addData buttons require trigger_add_data_config")
|
|
668
|
+
if self.trigger_action == PublicButtonTriggerAction.qrobot and self.external_qrobot_config is None:
|
|
669
|
+
raise ValueError("qRobot buttons require external_qrobot_config")
|
|
670
|
+
if self.trigger_action == PublicButtonTriggerAction.wings and self.trigger_wings_config is None:
|
|
671
|
+
raise ValueError("wings buttons require trigger_wings_config")
|
|
672
|
+
return self
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
class ViewButtonBindingPatch(StrictModel):
|
|
676
|
+
button_type: PublicViewButtonType = Field(validation_alias=AliasChoices("button_type", "buttonType"))
|
|
677
|
+
config_type: PublicViewButtonConfigType = Field(validation_alias=AliasChoices("config_type", "configType"))
|
|
678
|
+
button_id: int = Field(validation_alias=AliasChoices("button_id", "buttonId", "id"))
|
|
679
|
+
button_text: str | None = Field(default=None, validation_alias=AliasChoices("button_text", "buttonText"))
|
|
680
|
+
button_icon: str | None = Field(default=None, validation_alias=AliasChoices("button_icon", "buttonIcon"))
|
|
681
|
+
background_color: str | None = Field(default=None, validation_alias=AliasChoices("background_color", "backgroundColor"))
|
|
682
|
+
text_color: str | None = Field(default=None, validation_alias=AliasChoices("text_color", "textColor"))
|
|
683
|
+
trigger_action: str | None = Field(default=None, validation_alias=AliasChoices("trigger_action", "triggerAction"))
|
|
684
|
+
print_tpls: list[Any] = Field(default_factory=list, validation_alias=AliasChoices("print_tpls", "printTpls"))
|
|
685
|
+
being_main: bool = Field(default=False, validation_alias=AliasChoices("being_main", "beingMain"))
|
|
686
|
+
button_limit: list[list[ViewFilterRulePatch]] = Field(
|
|
687
|
+
default_factory=list,
|
|
688
|
+
validation_alias=AliasChoices("button_limit", "buttonLimit"),
|
|
689
|
+
)
|
|
690
|
+
button_formula: str | None = Field(default=None, validation_alias=AliasChoices("button_formula", "buttonFormula"))
|
|
691
|
+
button_formula_type: int = Field(default=1, validation_alias=AliasChoices("button_formula_type", "buttonFormulaType"))
|
|
692
|
+
|
|
693
|
+
@model_validator(mode="before")
|
|
694
|
+
@classmethod
|
|
695
|
+
def normalize_aliases(cls, value: Any) -> Any:
|
|
696
|
+
if not isinstance(value, dict):
|
|
697
|
+
return value
|
|
698
|
+
payload = dict(value)
|
|
699
|
+
raw_button_type = payload.get("button_type", payload.get("buttonType"))
|
|
700
|
+
if isinstance(raw_button_type, str):
|
|
701
|
+
normalized_type = raw_button_type.strip().lower()
|
|
702
|
+
if normalized_type == "system":
|
|
703
|
+
payload["button_type"] = "SYSTEM"
|
|
704
|
+
elif normalized_type == "custom":
|
|
705
|
+
payload["button_type"] = "CUSTOM"
|
|
706
|
+
raw_config_type = payload.get("config_type", payload.get("configType"))
|
|
707
|
+
if isinstance(raw_config_type, str):
|
|
708
|
+
normalized_config = raw_config_type.strip().lower()
|
|
709
|
+
if normalized_config == "top":
|
|
710
|
+
payload["config_type"] = "TOP"
|
|
711
|
+
elif normalized_config == "detail":
|
|
712
|
+
payload["config_type"] = "DETAIL"
|
|
713
|
+
raw_limits = payload.get("button_limit", payload.get("buttonLimit"))
|
|
714
|
+
if isinstance(raw_limits, list) and raw_limits and all(isinstance(item, dict) for item in raw_limits):
|
|
715
|
+
payload["button_limit"] = [raw_limits]
|
|
716
|
+
return payload
|
|
717
|
+
|
|
718
|
+
@model_validator(mode="after")
|
|
719
|
+
def validate_shape(self) -> "ViewButtonBindingPatch":
|
|
720
|
+
if self.button_type == PublicViewButtonType.system:
|
|
721
|
+
missing = [
|
|
722
|
+
field_name
|
|
723
|
+
for field_name, value in (
|
|
724
|
+
("button_icon", self.button_icon),
|
|
725
|
+
("background_color", self.background_color),
|
|
726
|
+
("text_color", self.text_color),
|
|
727
|
+
("trigger_action", self.trigger_action),
|
|
728
|
+
)
|
|
729
|
+
if not str(value or "").strip()
|
|
730
|
+
]
|
|
731
|
+
if missing:
|
|
732
|
+
raise ValueError(f"system button bindings require {', '.join(missing)}")
|
|
733
|
+
return self
|
|
734
|
+
|
|
735
|
+
|
|
517
736
|
class ChartFilterRulePatch(StrictModel):
|
|
518
737
|
field_name: str = Field(validation_alias=AliasChoices("field_name", "fieldName", "field", "name"))
|
|
519
738
|
operator: ViewFilterOperator = Field(validation_alias=AliasChoices("operator", "op"))
|
|
@@ -983,3 +1202,9 @@ def _normalize_public_relation_mode(value: Any) -> str | None:
|
|
|
983
1202
|
}
|
|
984
1203
|
return aliases.get(normalized, normalized or None)
|
|
985
1204
|
return None
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
CustomButtonMatchRulePatch.model_rebuild()
|
|
1208
|
+
CustomButtonAddDataConfigPatch.model_rebuild()
|
|
1209
|
+
ViewButtonBindingPatch.model_rebuild()
|
|
1210
|
+
ViewUpsertPatch.model_rebuild()
|