@qingflow-tech/qingflow-app-builder-mcp 1.0.1 → 1.0.3
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/docs/local-agent-install.md +9 -3
- package/npm/lib/runtime.mjs +10 -3
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +88 -184
- package/skills/qingflow-app-builder/references/create-app.md +15 -34
- package/skills/qingflow-app-builder/references/gotchas.md +3 -3
- package/skills/qingflow-app-builder/references/solution-playbooks.md +1 -2
- package/skills/qingflow-app-builder/references/tool-selection.md +9 -10
- package/src/qingflow_mcp/__init__.py +33 -1
- package/src/qingflow_mcp/builder_facade/models.py +14 -4
- package/src/qingflow_mcp/builder_facade/service.py +1582 -124
- package/src/qingflow_mcp/cli/commands/auth.py +69 -1
- package/src/qingflow_mcp/cli/commands/builder.py +4 -3
- package/src/qingflow_mcp/cli/commands/record.py +5 -5
- package/src/qingflow_mcp/cli/commands/task.py +74 -22
- package/src/qingflow_mcp/cli/commands/workspace.py +22 -0
- package/src/qingflow_mcp/cli/formatters.py +287 -48
- package/src/qingflow_mcp/cli/main.py +6 -1
- package/src/qingflow_mcp/cli/qingflow_login.py +116 -0
- package/src/qingflow_mcp/config.py +8 -0
- package/src/qingflow_mcp/errors.py +2 -2
- package/src/qingflow_mcp/id_utils.py +49 -0
- package/src/qingflow_mcp/public_surface.py +11 -1
- package/src/qingflow_mcp/response_trim.py +380 -9
- package/src/qingflow_mcp/server.py +4 -0
- package/src/qingflow_mcp/server_app_builder.py +11 -1
- package/src/qingflow_mcp/server_app_user.py +24 -0
- package/src/qingflow_mcp/session_store.py +69 -15
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +2 -2
- package/src/qingflow_mcp/solution/executor.py +2 -2
- package/src/qingflow_mcp/tools/ai_builder_tools.py +48 -18
- package/src/qingflow_mcp/tools/app_tools.py +1 -0
- package/src/qingflow_mcp/tools/auth_tools.py +271 -12
- package/src/qingflow_mcp/tools/base.py +6 -2
- package/src/qingflow_mcp/tools/code_block_tools.py +2 -2
- package/src/qingflow_mcp/tools/import_tools.py +36 -2
- package/src/qingflow_mcp/tools/record_tools.py +410 -156
- package/src/qingflow_mcp/tools/resource_read_tools.py +114 -32
- package/src/qingflow_mcp/tools/task_context_tools.py +899 -141
- package/src/qingflow_mcp/tools/workspace_tools.py +141 -0
|
@@ -4,7 +4,7 @@ Use the smallest v2 builder tool chain that can finish the task.
|
|
|
4
4
|
|
|
5
5
|
## Default path
|
|
6
6
|
|
|
7
|
-
`
|
|
7
|
+
`summary read -> apply -> publish_verify`
|
|
8
8
|
|
|
9
9
|
Public builder `apply` tools already perform server-side planning, normalization, and dependency checks internally. Do not route normal public builder work through explicit `*_plan` tools.
|
|
10
10
|
|
|
@@ -21,13 +21,12 @@ If the user asks for multiple forms/modules that relate to each other, this is a
|
|
|
21
21
|
|
|
22
22
|
## Resolve
|
|
23
23
|
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `package_list`: read-only fallback when package resolution is ambiguous
|
|
24
|
+
- `package_get`: read one known package by `package_id`
|
|
25
|
+
- `package_apply`: create or update one package; use `create_if_missing=true` only after explicit user intent
|
|
27
26
|
- `member_search`: resolve named people from the directory
|
|
28
27
|
- `role_search`: resolve reusable roles from the directory
|
|
29
28
|
- `role_create`: create a reusable role when the business owner wants role-based routing
|
|
30
|
-
- `app_resolve`: locate an existing app by exactly one selector mode: `app_key`, or `app_name +
|
|
29
|
+
- `app_resolve`: locate an existing app by exactly one selector mode: `app_key`, or `app_name + package_id`
|
|
31
30
|
|
|
32
31
|
## Summary reads
|
|
33
32
|
|
|
@@ -48,21 +47,20 @@ These execute normalized patches and publish by default unless `publish=false`.
|
|
|
48
47
|
- `app_flow_apply`: replace workflow
|
|
49
48
|
- `app_views_apply`: upsert or remove views
|
|
50
49
|
- `app_charts_apply`: upsert/remove/reorder QingBI charts; charts are immediate-live and do not publish; use `chart_id` when names are not unique
|
|
51
|
-
- `portal_apply`: create or replace-update portal pages; use `dash_key` for update mode or `
|
|
50
|
+
- `portal_apply`: create or replace-update portal pages; use `dash_key` for update mode or `package_id + dash_name` for create mode; edit mode may omit `sections` for base-info-only updates; when sections are supplied they still use replace semantics
|
|
52
51
|
|
|
53
52
|
## Explicit post-apply tools
|
|
54
53
|
|
|
55
|
-
- `package_attach_app`: attach an app to a package with `tag_id + app_key`; do not assume create or publish attaches it
|
|
56
54
|
- `app_publish_verify`: explicit final publish verification when the user asks for live confirmation
|
|
57
55
|
|
|
58
56
|
## Decision shortcuts
|
|
59
57
|
|
|
60
58
|
- Create one app inside an existing package:
|
|
61
|
-
`
|
|
59
|
+
`package_get -> app_resolve -> app_schema_apply`
|
|
62
60
|
- Create a brand new package, then create one app in it:
|
|
63
|
-
`
|
|
61
|
+
`package_apply(create_if_missing=true) -> app_schema_apply`
|
|
64
62
|
- Create a brand new multi-app system/package:
|
|
65
|
-
`
|
|
63
|
+
`package_apply(create_if_missing=true) -> per-app app_schema_apply -> relation field patches`
|
|
66
64
|
- Update fields on an existing app:
|
|
67
65
|
`app_resolve -> app_get_fields -> app_schema_apply`
|
|
68
66
|
- Tidy layout:
|
|
@@ -81,6 +79,7 @@ These execute normalized patches and publish by default unless `publish=false`.
|
|
|
81
79
|
- Do not handcraft raw Qingflow schema payloads
|
|
82
80
|
- Do not rely on internal `solution_*` tools in public builder flows
|
|
83
81
|
- Do not create a new package without first asking the user to confirm package creation
|
|
82
|
+
- Do not regress to `package_create` or `package_attach_app` as the public default story
|
|
84
83
|
- Do not treat a package/system name as `app_name` when the user clearly wants multiple apps inside it
|
|
85
84
|
- Do not compress multiple business objects into one app with several text fields
|
|
86
85
|
- Do not skip summary reads before flow or view work
|
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, packages_distributions, version as _dist_version
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
3
6
|
__all__ = ["__version__"]
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
_FALLBACK_VERSION = "0.2.0b998"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _resolve_local_pyproject_version() -> str | None:
|
|
12
|
+
module_path = Path(__file__).resolve()
|
|
13
|
+
for parent in module_path.parents:
|
|
14
|
+
candidate = parent / "pyproject.toml"
|
|
15
|
+
if not candidate.is_file():
|
|
16
|
+
continue
|
|
17
|
+
for line in candidate.read_text(encoding="utf-8").splitlines():
|
|
18
|
+
stripped = line.strip()
|
|
19
|
+
if stripped.startswith("version = "):
|
|
20
|
+
return stripped.split("=", 1)[1].strip().strip('"')
|
|
21
|
+
break
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _resolve_runtime_version() -> str:
|
|
26
|
+
local_version = _resolve_local_pyproject_version()
|
|
27
|
+
if local_version:
|
|
28
|
+
return local_version
|
|
29
|
+
for dist_name in packages_distributions().get("qingflow_mcp", []):
|
|
30
|
+
try:
|
|
31
|
+
return _dist_version(dist_name)
|
|
32
|
+
except PackageNotFoundError:
|
|
33
|
+
continue
|
|
34
|
+
return _FALLBACK_VERSION
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__version__ = _resolve_runtime_version()
|
|
@@ -819,6 +819,10 @@ class FieldMutation(StrictModel):
|
|
|
819
819
|
validation_alias=AliasChoices("custom_button_text", "customButtonText", "custom_btn_text", "customBtnText"),
|
|
820
820
|
)
|
|
821
821
|
subfields: list[FieldPatch] | None = None
|
|
822
|
+
subfield_updates: list["FieldUpdatePatch"] | None = Field(
|
|
823
|
+
default=None,
|
|
824
|
+
validation_alias=AliasChoices("subfield_updates", "subfieldUpdates"),
|
|
825
|
+
)
|
|
822
826
|
|
|
823
827
|
@model_validator(mode="after")
|
|
824
828
|
def validate_shape(self) -> "FieldMutation":
|
|
@@ -848,8 +852,12 @@ class FieldMutation(StrictModel):
|
|
|
848
852
|
or self.custom_button_text is not None
|
|
849
853
|
):
|
|
850
854
|
raise ValueError("code_block_config, code_block_binding, auto_trigger, custom_button_text_enabled, and custom_button_text are only allowed for code_block fields")
|
|
851
|
-
if self.type == PublicFieldType.subtable and not self.subfields:
|
|
852
|
-
raise ValueError("subtable field requires subfields")
|
|
855
|
+
if self.type == PublicFieldType.subtable and not self.subfields and not self.subfield_updates:
|
|
856
|
+
raise ValueError("subtable field requires subfields or subfield_updates")
|
|
857
|
+
if self.type is not None and self.type != PublicFieldType.subtable and self.subfield_updates:
|
|
858
|
+
raise ValueError("subfield_updates are only allowed for subtable fields")
|
|
859
|
+
if self.subfields and self.subfield_updates:
|
|
860
|
+
raise ValueError("subfields and subfield_updates cannot be used together")
|
|
853
861
|
return self
|
|
854
862
|
|
|
855
863
|
@model_validator(mode="before")
|
|
@@ -1528,14 +1536,16 @@ class PortalApplyRequest(StrictModel):
|
|
|
1528
1536
|
raise ValueError("package_tag_id is required when dash_key is empty")
|
|
1529
1537
|
if not self.dash_key and not self.dash_name:
|
|
1530
1538
|
raise ValueError("dash_name is required when creating a portal")
|
|
1531
|
-
if not self.sections:
|
|
1532
|
-
raise ValueError("portal apply requires a non-empty sections list")
|
|
1539
|
+
if not self.dash_key and not self.sections:
|
|
1540
|
+
raise ValueError("portal apply requires a non-empty sections list when creating a portal")
|
|
1533
1541
|
if self.visibility is not None and self.auth is not None:
|
|
1534
1542
|
raise ValueError("visibility and auth cannot be provided together")
|
|
1535
1543
|
return self
|
|
1536
1544
|
|
|
1537
1545
|
|
|
1538
1546
|
FieldPatch.model_rebuild()
|
|
1547
|
+
FieldMutation.model_rebuild()
|
|
1548
|
+
FieldUpdatePatch.model_rebuild()
|
|
1539
1549
|
|
|
1540
1550
|
|
|
1541
1551
|
class AppGetResponse(StrictModel):
|