@josephyan/qingflow-app-user-mcp 1.0.9 → 1.1.2
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 +6 -2
- package/npm/bin/qingflow-app-user-mcp.mjs +33 -2
- package/npm/lib/runtime.mjs +386 -15
- package/npm/scripts/postinstall.mjs +7 -2
- package/package.json +1 -1
- package/pyproject.toml +2 -1
- package/skills/qingflow-app-builder/SKILL.md +276 -0
- package/skills/qingflow-app-builder/agents/openai.yaml +4 -0
- package/skills/qingflow-app-builder/references/build-complete-system.md +428 -0
- package/skills/qingflow-app-builder/references/build-single-app.md +530 -0
- package/skills/qingflow-app-builder/references/create-app.md +149 -0
- package/skills/qingflow-app-builder/references/environments.md +63 -0
- package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +123 -0
- package/skills/qingflow-app-builder/references/gotchas.md +108 -0
- package/skills/qingflow-app-builder/references/match-rules.md +114 -0
- package/skills/qingflow-app-builder/references/public-surface-sync.md +75 -0
- package/skills/qingflow-app-builder/references/solution-playbooks.md +52 -0
- package/skills/qingflow-app-builder/references/tool-selection.md +107 -0
- package/skills/qingflow-app-builder/references/update-flow.md +186 -0
- package/skills/qingflow-app-builder/references/update-layout.md +68 -0
- package/skills/qingflow-app-builder/references/update-schema.md +72 -0
- package/skills/qingflow-app-builder/references/update-views.md +291 -0
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +137 -0
- package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +4 -0
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +66 -0
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +77 -0
- package/skills/qingflow-app-user/SKILL.md +2 -1
- package/skills/qingflow-app-user/references/data-gotchas.md +5 -3
- package/skills/qingflow-app-user/references/public-surface-sync.md +6 -3
- package/skills/qingflow-app-user/references/record-patterns.md +14 -4
- package/skills/qingflow-mcp-setup/SKILL.md +111 -0
- package/skills/qingflow-mcp-setup/agents/openai.yaml +4 -0
- package/skills/qingflow-mcp-setup/references/claude-desktop.md +34 -0
- package/skills/qingflow-mcp-setup/references/environments.md +61 -0
- package/skills/qingflow-mcp-setup/references/generic-stdio.md +31 -0
- package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +38 -0
- package/skills/qingflow-record-analysis/SKILL.md +94 -186
- package/skills/qingflow-record-analysis/agents/openai.yaml +2 -2
- package/skills/qingflow-record-analysis/references/analysis-gotchas.md +54 -113
- package/skills/qingflow-record-analysis/references/analysis-patterns.md +95 -134
- package/skills/qingflow-record-analysis/references/business-context.md +74 -0
- package/skills/qingflow-record-analysis/references/confidence-reporting.md +47 -74
- package/skills/qingflow-record-analysis/references/data-access-playbook.md +106 -0
- package/skills/qingflow-record-analysis/references/pandas-recipes.md +172 -0
- package/skills/qingflow-record-analysis/references/report-format.md +76 -0
- package/skills/qingflow-record-insert/SKILL.md +28 -7
- package/skills/qingflow-record-update/SKILL.md +3 -1
- package/skills/qingflow-workflow-builder/SKILL.md +96 -0
- package/skills/qingflow-workflow-builder/manifest.yaml +8 -0
- package/skills/qingflow-workflow-builder/references/01-overview.md +45 -0
- package/skills/qingflow-workflow-builder/references/02-update-mode.md +53 -0
- package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +57 -0
- package/skills/qingflow-workflow-builder/references/04-stage1-business-modeling.md +131 -0
- package/skills/qingflow-workflow-builder/references/05-stage2-members-roles.md +29 -0
- package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +165 -0
- package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +33 -0
- package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +51 -0
- package/skills/qingflow-workflow-builder/references/09-stage6-summary.md +88 -0
- package/skills/qingflow-workflow-builder/references/10-node-config-reference.md +93 -0
- package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +15 -0
- package/skills/qingflow-workflow-builder/scripts/diff_flow_spec.py +275 -0
- package/skills/qingflow-workflow-builder/scripts/validate_flow_spec.py +605 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/backend_client.py +55 -1
- package/src/qingflow_mcp/builder_facade/models.py +532 -48
- package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
- package/src/qingflow_mcp/cli/commands/app.py +3 -16
- package/src/qingflow_mcp/cli/commands/builder.py +354 -56
- package/src/qingflow_mcp/cli/commands/record.py +112 -6
- package/src/qingflow_mcp/cli/formatters.py +102 -2
- package/src/qingflow_mcp/cli/main.py +245 -3
- package/src/qingflow_mcp/public_surface.py +12 -9
- package/src/qingflow_mcp/response_trim.py +287 -22
- package/src/qingflow_mcp/server.py +29 -20
- package/src/qingflow_mcp/server_app_builder.py +108 -30
- package/src/qingflow_mcp/server_app_user.py +28 -23
- package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
- package/src/qingflow_mcp/solution/executor.py +3 -133
- package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
- 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 +14283 -9162
- package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
- package/src/qingflow_mcp/tools/solution_tools.py +30 -2
- package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
- package/src/qingflow_mcp/version.py +110 -0
- package/skills/qingflow-record-analysis/references/dsl-templates.md +0 -93
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..backend_client import BackendClient, BackendRequestContext
|
|
6
|
+
from ..json_types import JSONObject, JSONValue
|
|
7
|
+
|
|
8
|
+
WORKFLOW_SPEC_SCHEMA_PATH = "/api/workflow/spec/schema"
|
|
9
|
+
WORKFLOW_SPEC_GET_PATH = "/api/workflow/spec"
|
|
10
|
+
WORKFLOW_SPEC_APPLY_PATH = "/api/workflow/spec:apply"
|
|
11
|
+
DEFAULT_SCHEMA_VERSION = "vnext-2026-06"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def fetch_schema(
|
|
15
|
+
backend: BackendClient,
|
|
16
|
+
context: BackendRequestContext,
|
|
17
|
+
*,
|
|
18
|
+
schema_version: str | None = None,
|
|
19
|
+
) -> JSONValue:
|
|
20
|
+
params: JSONObject = {}
|
|
21
|
+
if schema_version:
|
|
22
|
+
params["schemaVersion"] = schema_version
|
|
23
|
+
return backend.request(
|
|
24
|
+
"GET",
|
|
25
|
+
context,
|
|
26
|
+
WORKFLOW_SPEC_SCHEMA_PATH,
|
|
27
|
+
params=params or None,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def fetch_spec(
|
|
32
|
+
backend: BackendClient,
|
|
33
|
+
context: BackendRequestContext,
|
|
34
|
+
*,
|
|
35
|
+
app_key: str,
|
|
36
|
+
version_id: str | None = None,
|
|
37
|
+
) -> JSONValue:
|
|
38
|
+
params: JSONObject = {"appKey": app_key}
|
|
39
|
+
if version_id:
|
|
40
|
+
params["versionId"] = version_id
|
|
41
|
+
return backend.request("GET", context, WORKFLOW_SPEC_GET_PATH, params=params)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def post_apply(
|
|
45
|
+
backend: BackendClient,
|
|
46
|
+
context: BackendRequestContext,
|
|
47
|
+
*,
|
|
48
|
+
apply_body: JSONObject,
|
|
49
|
+
) -> JSONValue:
|
|
50
|
+
return backend.request("POST", context, WORKFLOW_SPEC_APPLY_PATH, json_body=apply_body)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def verify_apply_response(
|
|
54
|
+
*,
|
|
55
|
+
input_spec: JSONObject,
|
|
56
|
+
apply_result: JSONObject,
|
|
57
|
+
) -> tuple[JSONObject, list[dict[str, Any]], bool]:
|
|
58
|
+
warnings: list[dict[str, Any]] = []
|
|
59
|
+
applied_spec = apply_result.get("appliedSpec")
|
|
60
|
+
diff_summary = apply_result.get("diffSummary")
|
|
61
|
+
semantic_lint = apply_result.get("semanticLint") if isinstance(apply_result.get("semanticLint"), list) else []
|
|
62
|
+
|
|
63
|
+
verification: JSONObject = {
|
|
64
|
+
"applied_spec_available": isinstance(applied_spec, dict),
|
|
65
|
+
"version_snapshot_confirmed": False,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
lint_errors = [
|
|
69
|
+
item
|
|
70
|
+
for item in semantic_lint
|
|
71
|
+
if isinstance(item, dict) and str(item.get("severity") or item.get("level") or "").upper() == "ERROR"
|
|
72
|
+
]
|
|
73
|
+
if lint_errors:
|
|
74
|
+
verification["semantic_lint_error_count"] = len(lint_errors)
|
|
75
|
+
for item in lint_errors:
|
|
76
|
+
warnings.append(
|
|
77
|
+
{
|
|
78
|
+
"code": item.get("code") or "SEMANTIC_LINT_ERROR",
|
|
79
|
+
"message": item.get("message") or "workflow spec semantic lint error",
|
|
80
|
+
"path": item.get("path"),
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
diff_failed = False
|
|
85
|
+
input_ids: set[str] = set()
|
|
86
|
+
if isinstance(input_spec, dict):
|
|
87
|
+
input_ids = {
|
|
88
|
+
str(node.get("id"))
|
|
89
|
+
for node in (input_spec.get("nodes") or [])
|
|
90
|
+
if isinstance(node, dict) and node.get("id") is not None
|
|
91
|
+
}
|
|
92
|
+
if isinstance(diff_summary, dict) and input_ids:
|
|
93
|
+
removed = diff_summary.get("nodes", {}).get("removed") if isinstance(diff_summary.get("nodes"), dict) else None
|
|
94
|
+
if isinstance(removed, list):
|
|
95
|
+
unexpected = [node_id for node_id in removed if str(node_id) in input_ids]
|
|
96
|
+
if unexpected:
|
|
97
|
+
diff_failed = True
|
|
98
|
+
verification["unexpected_removed_node_ids"] = unexpected
|
|
99
|
+
|
|
100
|
+
if isinstance(applied_spec, dict) and isinstance(input_spec, dict):
|
|
101
|
+
applied_ids = {
|
|
102
|
+
str(node.get("id"))
|
|
103
|
+
for node in (applied_spec.get("nodes") or [])
|
|
104
|
+
if isinstance(node, dict) and node.get("id") is not None
|
|
105
|
+
}
|
|
106
|
+
missing_input_ids = sorted(node_id for node_id in input_ids if node_id not in applied_ids)
|
|
107
|
+
if missing_input_ids and not diff_failed:
|
|
108
|
+
verification["missing_input_node_ids"] = missing_input_ids
|
|
109
|
+
|
|
110
|
+
verified = not lint_errors and not diff_failed and verification.get("applied_spec_available") is True
|
|
111
|
+
return verification, warnings, verified
|
|
@@ -13,30 +13,17 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
13
13
|
app_subparsers = parser.add_subparsers(dest="app_command", required=True)
|
|
14
14
|
|
|
15
15
|
list_parser = app_subparsers.add_parser("list", help="列出可见应用")
|
|
16
|
+
list_parser.add_argument("--query", default="", help="按关键词在可见应用列表中本地过滤")
|
|
17
|
+
list_parser.add_argument("--keyword", default="", help="兼容别名;建议使用 --query")
|
|
16
18
|
list_parser.set_defaults(handler=_handle_list, format_hint="app_list")
|
|
17
19
|
|
|
18
|
-
search = app_subparsers.add_parser("search", help="搜索应用")
|
|
19
|
-
search.add_argument("--keyword", default="")
|
|
20
|
-
search.add_argument("--page", type=int, default=1)
|
|
21
|
-
search.add_argument("--page-size", type=int, default=50)
|
|
22
|
-
search.set_defaults(handler=_handle_search, format_hint="app_search")
|
|
23
|
-
|
|
24
20
|
get = app_subparsers.add_parser("get", help="读取应用可访问视图与导入能力")
|
|
25
21
|
get.add_argument("--app-key", help="不传时在交互终端中选择应用")
|
|
26
22
|
get.set_defaults(handler=_handle_get, format_hint="app_get")
|
|
27
23
|
|
|
28
24
|
|
|
29
25
|
def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
30
|
-
return context.app.app_list(profile=args.profile)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def _handle_search(args: argparse.Namespace, context: CliContext) -> dict:
|
|
34
|
-
return context.app.app_search(
|
|
35
|
-
profile=args.profile,
|
|
36
|
-
keyword=args.keyword,
|
|
37
|
-
page_num=args.page,
|
|
38
|
-
page_size=args.page_size,
|
|
39
|
-
)
|
|
26
|
+
return context.app.app_list(profile=args.profile, query=args.query, keyword=args.keyword)
|
|
40
27
|
|
|
41
28
|
|
|
42
29
|
def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
|