@josephyan/qingflow-app-builder-mcp 0.1.0-beta.13 → 0.1.0-beta.15
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/__init__.py +3 -0
- package/src/qingflow_mcp/builder_facade/models.py +156 -0
- package/src/qingflow_mcp/builder_facade/service.py +1189 -0
- package/src/qingflow_mcp/server_app_builder.py +58 -236
- package/src/qingflow_mcp/solution/compiler/__init__.py +19 -2
- package/src/qingflow_mcp/solution/executor.py +92 -0
- package/src/qingflow_mcp/solution/requirements_builder.py +38 -2
- package/src/qingflow_mcp/tools/ai_builder_tools.py +206 -0
- package/src/qingflow_mcp/tools/solution_tools.py +511 -22
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-app-builder-mcp@0.1.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-app-builder-mcp@0.1.0-beta.15
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-builder-mcp@0.1.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-builder-mcp@0.1.0-beta.15 qingflow-app-builder-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from pydantic import Field, model_validator
|
|
7
|
+
|
|
8
|
+
from ..solution.spec_models import StrictModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PublicFieldType(str, Enum):
|
|
12
|
+
text = "text"
|
|
13
|
+
long_text = "long_text"
|
|
14
|
+
number = "number"
|
|
15
|
+
amount = "amount"
|
|
16
|
+
date = "date"
|
|
17
|
+
datetime = "datetime"
|
|
18
|
+
member = "member"
|
|
19
|
+
department = "department"
|
|
20
|
+
single_select = "single_select"
|
|
21
|
+
multi_select = "multi_select"
|
|
22
|
+
phone = "phone"
|
|
23
|
+
email = "email"
|
|
24
|
+
address = "address"
|
|
25
|
+
attachment = "attachment"
|
|
26
|
+
boolean = "boolean"
|
|
27
|
+
relation = "relation"
|
|
28
|
+
subtable = "subtable"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PublicViewType(str, Enum):
|
|
32
|
+
table = "table"
|
|
33
|
+
card = "card"
|
|
34
|
+
board = "board"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class PublicFlowNodeType(str, Enum):
|
|
38
|
+
start = "start"
|
|
39
|
+
approve = "approve"
|
|
40
|
+
fill = "fill"
|
|
41
|
+
copy = "copy"
|
|
42
|
+
branch = "branch"
|
|
43
|
+
condition = "condition"
|
|
44
|
+
webhook = "webhook"
|
|
45
|
+
end = "end"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class FieldSelector(StrictModel):
|
|
49
|
+
field_id: str | None = None
|
|
50
|
+
que_id: int | None = None
|
|
51
|
+
name: str | None = None
|
|
52
|
+
|
|
53
|
+
@model_validator(mode="after")
|
|
54
|
+
def validate_selector(self) -> "FieldSelector":
|
|
55
|
+
if not any((self.field_id, self.que_id, self.name)):
|
|
56
|
+
raise ValueError("selector must include field_id, que_id, or name")
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class FieldPatch(StrictModel):
|
|
61
|
+
name: str
|
|
62
|
+
type: PublicFieldType
|
|
63
|
+
required: bool = False
|
|
64
|
+
description: str | None = None
|
|
65
|
+
options: list[str] = Field(default_factory=list)
|
|
66
|
+
target_app_key: str | None = None
|
|
67
|
+
subfields: list["FieldPatch"] = Field(default_factory=list)
|
|
68
|
+
|
|
69
|
+
@model_validator(mode="after")
|
|
70
|
+
def validate_shape(self) -> "FieldPatch":
|
|
71
|
+
if self.type == PublicFieldType.relation and not self.target_app_key:
|
|
72
|
+
raise ValueError("relation field requires target_app_key")
|
|
73
|
+
if self.type != PublicFieldType.relation and self.target_app_key:
|
|
74
|
+
raise ValueError("target_app_key is only allowed for relation fields")
|
|
75
|
+
if self.type == PublicFieldType.subtable and not self.subfields:
|
|
76
|
+
raise ValueError("subtable field requires subfields")
|
|
77
|
+
if self.type != PublicFieldType.subtable and self.subfields:
|
|
78
|
+
raise ValueError("subfields are only allowed for subtable fields")
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class FieldMutation(StrictModel):
|
|
83
|
+
name: str | None = None
|
|
84
|
+
type: PublicFieldType | None = None
|
|
85
|
+
required: bool | None = None
|
|
86
|
+
description: str | None = None
|
|
87
|
+
options: list[str] | None = None
|
|
88
|
+
target_app_key: str | None = None
|
|
89
|
+
subfields: list[FieldPatch] | None = None
|
|
90
|
+
|
|
91
|
+
@model_validator(mode="after")
|
|
92
|
+
def validate_shape(self) -> "FieldMutation":
|
|
93
|
+
if self.type == PublicFieldType.relation and not self.target_app_key:
|
|
94
|
+
raise ValueError("relation field requires target_app_key")
|
|
95
|
+
if self.type == PublicFieldType.subtable and not self.subfields:
|
|
96
|
+
raise ValueError("subtable field requires subfields")
|
|
97
|
+
return self
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class FieldUpdatePatch(StrictModel):
|
|
101
|
+
selector: FieldSelector
|
|
102
|
+
set: FieldMutation
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class FieldRemovePatch(StrictModel):
|
|
106
|
+
field_id: str | None = None
|
|
107
|
+
que_id: int | None = None
|
|
108
|
+
name: str | None = None
|
|
109
|
+
|
|
110
|
+
@model_validator(mode="after")
|
|
111
|
+
def validate_shape(self) -> "FieldRemovePatch":
|
|
112
|
+
if not any((self.field_id, self.que_id, self.name)):
|
|
113
|
+
raise ValueError("remove patch must include field_id, que_id, or name")
|
|
114
|
+
return self
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class LayoutSectionPatch(StrictModel):
|
|
118
|
+
section_id: str
|
|
119
|
+
title: str
|
|
120
|
+
rows: list[list[str]] = Field(default_factory=list)
|
|
121
|
+
|
|
122
|
+
@model_validator(mode="after")
|
|
123
|
+
def validate_rows(self) -> "LayoutSectionPatch":
|
|
124
|
+
if not self.rows:
|
|
125
|
+
raise ValueError("section rows must be a non-empty list")
|
|
126
|
+
return self
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class FlowNodePatch(StrictModel):
|
|
130
|
+
id: str
|
|
131
|
+
type: PublicFlowNodeType
|
|
132
|
+
name: str
|
|
133
|
+
config: dict[str, Any] = Field(default_factory=dict)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class FlowTransitionPatch(StrictModel):
|
|
137
|
+
source: str = Field(alias="from")
|
|
138
|
+
target: str = Field(alias="to")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class ViewUpsertPatch(StrictModel):
|
|
142
|
+
name: str
|
|
143
|
+
type: PublicViewType
|
|
144
|
+
columns: list[str] = Field(default_factory=list)
|
|
145
|
+
group_by: str | None = None
|
|
146
|
+
|
|
147
|
+
@model_validator(mode="after")
|
|
148
|
+
def validate_shape(self) -> "ViewUpsertPatch":
|
|
149
|
+
if self.type in {PublicViewType.table, PublicViewType.card} and not self.columns:
|
|
150
|
+
raise ValueError("table/card views require columns")
|
|
151
|
+
if self.type == PublicViewType.board and not self.group_by:
|
|
152
|
+
raise ValueError("board view requires group_by")
|
|
153
|
+
return self
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
FieldPatch.model_rebuild()
|