@qingflow-tech/qingflow-app-user-mcp 1.0.9 → 1.0.11
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/skills/qingflow-record-update/SKILL.md +2 -0
- package/src/qingflow_mcp/builder_facade/models.py +43 -2
- package/src/qingflow_mcp/builder_facade/service.py +1476 -172
- package/src/qingflow_mcp/cli/commands/app.py +3 -16
- package/src/qingflow_mcp/cli/commands/builder.py +68 -13
- package/src/qingflow_mcp/cli/commands/record.py +16 -1
- package/src/qingflow_mcp/cli/formatters.py +32 -1
- package/src/qingflow_mcp/cli/main.py +204 -3
- package/src/qingflow_mcp/public_surface.py +3 -1
- package/src/qingflow_mcp/response_trim.py +70 -13
- package/src/qingflow_mcp/server.py +10 -9
- package/src/qingflow_mcp/server_app_builder.py +53 -7
- package/src/qingflow_mcp/server_app_user.py +12 -15
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +1642 -75
- package/src/qingflow_mcp/tools/app_tools.py +53 -8
- package/src/qingflow_mcp/tools/package_tools.py +16 -2
- package/src/qingflow_mcp/tools/record_tools.py +1423 -70
- package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @qingflow-tech/qingflow-app-user-mcp@1.0.
|
|
6
|
+
npm install @qingflow-tech/qingflow-app-user-mcp@1.0.11
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @qingflow-tech/qingflow-app-user-mcp@1.0.
|
|
12
|
+
npx -y -p @qingflow-tech/qingflow-app-user-mcp@1.0.11 qingflow-app-user-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -35,6 +35,8 @@ metadata:
|
|
|
35
35
|
13. Do not look for any extra context bucket in update schema; lookup behavior stays inline on the field definitions themselves
|
|
36
36
|
14. When update context feels unstable, trust `record_update_schema_get`'s route-aware matched-view result over guessed `view_id` or remembered UI scope
|
|
37
37
|
15. If single-record detail/readback matters, prefer `record_get` after the write and read top-level `fields[]`, `media_assets.items[].local_path`, `file_assets.items[].local_path`, `file_assets.items[].extraction.text_path`, and `semantic_context`; `record_get` follows the frontend storage cookie redirect path for Qingflow attachments, so prefer local paths over remote URLs; use `record_list(..., output_profile="normalized")` only for batch row-shaped normalized readback
|
|
38
|
+
16. For batch updates, read top-level `mode`, `dry_run`, `total`, `succeeded`, `failed`, `needs_confirmation`, `updated_record_ids`, `write_executed`, `safe_to_retry`, `verification_status`, and `items[].row_number/status/record_id`
|
|
39
|
+
17. If `write_executed=true`, do not blindly retry the whole batch; use `items[]` and `updated_record_ids` to decide whether only failed rows need repair
|
|
38
40
|
|
|
39
41
|
## Do Not
|
|
40
42
|
|
|
@@ -1893,8 +1893,9 @@ class PortalComponentPositionPatch(StrictModel):
|
|
|
1893
1893
|
pc_h: int = Field(default=8, validation_alias=AliasChoices("pc_h", "pcH", "h"))
|
|
1894
1894
|
mobile_x: int = Field(default=0, validation_alias=AliasChoices("mobile_x", "mobileX"))
|
|
1895
1895
|
mobile_y: int = Field(default=0, validation_alias=AliasChoices("mobile_y", "mobileY"))
|
|
1896
|
-
mobile_w: int = Field(default=
|
|
1896
|
+
mobile_w: int = Field(default=6, validation_alias=AliasChoices("mobile_w", "mobileW"))
|
|
1897
1897
|
mobile_h: int = Field(default=8, validation_alias=AliasChoices("mobile_h", "mobileH"))
|
|
1898
|
+
mobile_provided: bool = Field(default=False, exclude=True)
|
|
1898
1899
|
|
|
1899
1900
|
@model_validator(mode="before")
|
|
1900
1901
|
@classmethod
|
|
@@ -1904,6 +1905,8 @@ class PortalComponentPositionPatch(StrictModel):
|
|
|
1904
1905
|
payload = dict(value)
|
|
1905
1906
|
pc = payload.pop("pc", None)
|
|
1906
1907
|
mobile = payload.pop("mobile", None)
|
|
1908
|
+
mobile_keys = {"mobile_x", "mobileX", "mobile_y", "mobileY", "mobile_w", "mobileW", "mobile_h", "mobileH"}
|
|
1909
|
+
mobile_provided = isinstance(mobile, dict) or any(key in payload for key in mobile_keys)
|
|
1907
1910
|
if isinstance(pc, dict):
|
|
1908
1911
|
if "pc_x" not in payload and "x" in pc:
|
|
1909
1912
|
payload["pc_x"] = pc.get("x")
|
|
@@ -1922,6 +1925,7 @@ class PortalComponentPositionPatch(StrictModel):
|
|
|
1922
1925
|
payload["mobile_w"] = mobile.get("cols")
|
|
1923
1926
|
if "mobile_h" not in payload and "rows" in mobile:
|
|
1924
1927
|
payload["mobile_h"] = mobile.get("rows")
|
|
1928
|
+
payload["mobile_provided"] = mobile_provided
|
|
1925
1929
|
return payload
|
|
1926
1930
|
|
|
1927
1931
|
|
|
@@ -2003,9 +2007,10 @@ class PortalSectionPatch(StrictModel):
|
|
|
2003
2007
|
class PortalApplyRequest(StrictModel):
|
|
2004
2008
|
dash_key: str | None = None
|
|
2005
2009
|
dash_name: str | None = None
|
|
2006
|
-
package_tag_id: int | None = None
|
|
2010
|
+
package_tag_id: int | None = Field(default=None, validation_alias=AliasChoices("package_tag_id", "packageTagId", "package_id", "packageId"))
|
|
2007
2011
|
publish: bool = True
|
|
2008
2012
|
sections: list[PortalSectionPatch] = Field(default_factory=list)
|
|
2013
|
+
layout_preset: str | None = Field(default=None, validation_alias=AliasChoices("layout_preset", "layoutPreset"))
|
|
2009
2014
|
visibility: VisibilityPatch | None = None
|
|
2010
2015
|
auth: dict[str, Any] | None = None
|
|
2011
2016
|
icon: str | None = None
|
|
@@ -2014,6 +2019,33 @@ class PortalApplyRequest(StrictModel):
|
|
|
2014
2019
|
dash_global_config: dict[str, Any] | None = Field(default=None, validation_alias=AliasChoices("dash_global_config", "dashGlobalConfig"))
|
|
2015
2020
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
2016
2021
|
|
|
2022
|
+
@model_validator(mode="before")
|
|
2023
|
+
@classmethod
|
|
2024
|
+
def normalize_compat_payload(cls, value: Any) -> Any:
|
|
2025
|
+
if not isinstance(value, dict):
|
|
2026
|
+
return value
|
|
2027
|
+
payload = dict(value)
|
|
2028
|
+
if "dash_name" not in payload and "dashName" not in payload and "name" in payload:
|
|
2029
|
+
payload["dash_name"] = payload.pop("name")
|
|
2030
|
+
if "sections" not in payload and "pages" in payload:
|
|
2031
|
+
pages = payload.pop("pages")
|
|
2032
|
+
if not isinstance(pages, list):
|
|
2033
|
+
raise ValueError("portal pages must be a list")
|
|
2034
|
+
if len(pages) != 1:
|
|
2035
|
+
raise ValueError("portal_apply currently supports a single page; pass one page or flatten components into sections")
|
|
2036
|
+
page = pages[0]
|
|
2037
|
+
if not isinstance(page, dict):
|
|
2038
|
+
raise ValueError("portal pages[0] must be an object")
|
|
2039
|
+
components = page.get("components")
|
|
2040
|
+
if not isinstance(components, list) or not components:
|
|
2041
|
+
raise ValueError("portal pages[0].components must be a non-empty list")
|
|
2042
|
+
payload["sections"] = components
|
|
2043
|
+
if "theme" in payload:
|
|
2044
|
+
payload.pop("theme")
|
|
2045
|
+
if "type" in payload:
|
|
2046
|
+
payload.pop("type")
|
|
2047
|
+
return payload
|
|
2048
|
+
|
|
2017
2049
|
@model_validator(mode="after")
|
|
2018
2050
|
def validate_shape(self) -> "PortalApplyRequest":
|
|
2019
2051
|
if not self.dash_key and not self.package_tag_id:
|
|
@@ -2024,6 +2056,8 @@ class PortalApplyRequest(StrictModel):
|
|
|
2024
2056
|
raise ValueError("portal apply requires a non-empty sections list when creating a portal")
|
|
2025
2057
|
if self.visibility is not None and self.auth is not None:
|
|
2026
2058
|
raise ValueError("visibility and auth cannot be provided together")
|
|
2059
|
+
if self.layout_preset is not None and self.layout_preset not in {"auto", "dashboard_2col", "dashboard_3col"}:
|
|
2060
|
+
raise ValueError("layout_preset must be one of: auto, dashboard_2col, dashboard_3col")
|
|
2027
2061
|
return self
|
|
2028
2062
|
|
|
2029
2063
|
|
|
@@ -2034,8 +2068,11 @@ FieldUpdatePatch.model_rebuild()
|
|
|
2034
2068
|
|
|
2035
2069
|
class AppGetResponse(StrictModel):
|
|
2036
2070
|
app_key: str
|
|
2071
|
+
app_name: str | None = None
|
|
2072
|
+
name: str | None = None
|
|
2037
2073
|
title: str | None = None
|
|
2038
2074
|
app_icon: str | None = None
|
|
2075
|
+
icon_config: dict[str, Any] = Field(default_factory=dict)
|
|
2039
2076
|
visibility: dict[str, Any] = Field(default_factory=dict)
|
|
2040
2077
|
tag_ids: list[int] = Field(default_factory=list)
|
|
2041
2078
|
publish_status: int | None = None
|
|
@@ -2060,6 +2097,8 @@ class AppGetFieldsResponse(StrictModel):
|
|
|
2060
2097
|
app_key: str
|
|
2061
2098
|
fields: list[dict[str, Any]] = Field(default_factory=list)
|
|
2062
2099
|
field_count: int = 0
|
|
2100
|
+
chart_fields: list[dict[str, Any]] = Field(default_factory=list)
|
|
2101
|
+
chart_field_count: int = 0
|
|
2063
2102
|
form_settings: dict[str, Any] = Field(default_factory=dict)
|
|
2064
2103
|
|
|
2065
2104
|
|
|
@@ -2107,6 +2146,7 @@ class PortalReadSummaryResponse(StrictModel):
|
|
|
2107
2146
|
dash_name: str | None = None
|
|
2108
2147
|
package_tag_ids: list[int] = Field(default_factory=list)
|
|
2109
2148
|
dash_icon: str | None = None
|
|
2149
|
+
icon_config: dict[str, Any] = Field(default_factory=dict)
|
|
2110
2150
|
hide_copyright: bool | None = None
|
|
2111
2151
|
config_keys: list[str] = Field(default_factory=list)
|
|
2112
2152
|
dash_global_config_keys: list[str] = Field(default_factory=list)
|
|
@@ -2120,6 +2160,7 @@ class PortalGetResponse(StrictModel):
|
|
|
2120
2160
|
dash_name: str | None = None
|
|
2121
2161
|
package_tag_ids: list[int] = Field(default_factory=list)
|
|
2122
2162
|
dash_icon: str | None = None
|
|
2163
|
+
icon_config: dict[str, Any] = Field(default_factory=dict)
|
|
2123
2164
|
hide_copyright: bool | None = None
|
|
2124
2165
|
visibility: dict[str, Any] = Field(default_factory=dict)
|
|
2125
2166
|
auth: dict[str, Any] = Field(default_factory=dict)
|