@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 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.13
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.13 qingflow-app-builder-mcp
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-app-builder-mcp",
3
- "version": "0.1.0-beta.13",
3
+ "version": "0.1.0-beta.15",
4
4
  "description": "Builder MCP for Qingflow app/package/system design and staged solution workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "0.1.0b13"
7
+ version = "0.1.0b15"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -2,4 +2,4 @@ from __future__ import annotations
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.1.0b13"
5
+ __version__ = "0.1.0b15"
@@ -0,0 +1,3 @@
1
+ from .service import AiBuilderFacade
2
+
3
+ __all__ = ["AiBuilderFacade"]
@@ -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()