@qingflow-tech/qingflow-app-user-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-user/SKILL.md +21 -12
- package/skills/qingflow-app-user/references/data-gotchas.md +1 -1
- package/skills/qingflow-app-user/references/public-surface-sync.md +70 -0
- package/skills/qingflow-app-user/references/record-patterns.md +1 -1
- package/skills/qingflow-record-analysis/SKILL.md +44 -2
- package/skills/qingflow-record-insert/SKILL.md +3 -0
- package/skills/qingflow-record-update/SKILL.md +3 -0
- package/skills/qingflow-task-ops/SKILL.md +31 -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
|
@@ -91,7 +91,7 @@ class CodeBlockTools(RecordTools):
|
|
|
91
91
|
def record_code_block_run(
|
|
92
92
|
profile: str = DEFAULT_PROFILE,
|
|
93
93
|
app_key: str = "",
|
|
94
|
-
record_id:
|
|
94
|
+
record_id: str = "",
|
|
95
95
|
code_block_field: str = "",
|
|
96
96
|
role: int = 1,
|
|
97
97
|
workflow_node_id: int | None = None,
|
|
@@ -197,7 +197,7 @@ class CodeBlockTools(RecordTools):
|
|
|
197
197
|
*,
|
|
198
198
|
profile: str,
|
|
199
199
|
app_key: str,
|
|
200
|
-
record_id: int,
|
|
200
|
+
record_id: int | str,
|
|
201
201
|
code_block_field: str,
|
|
202
202
|
role: int = 1,
|
|
203
203
|
workflow_node_id: int | None = None,
|
|
@@ -783,6 +783,8 @@ class ImportTools(ToolBase):
|
|
|
783
783
|
error_code="CONFIG_ERROR",
|
|
784
784
|
message="record_import_status_get accepts import_id or process_id_str, but not both at the same time",
|
|
785
785
|
extra={
|
|
786
|
+
"import_id": normalized_import_id,
|
|
787
|
+
"process_id_str": normalized_process_id,
|
|
786
788
|
"details": {
|
|
787
789
|
"fix_hint": "Use only one of `import_id` or `process_id_str`. You may pass `app_key` as an optional routing hint for direct method compatibility.",
|
|
788
790
|
}
|
|
@@ -793,6 +795,8 @@ class ImportTools(ToolBase):
|
|
|
793
795
|
error_code="CONFIG_ERROR",
|
|
794
796
|
message="record_import_status_get requires at least one selector: process_id_str, import_id, or app_key",
|
|
795
797
|
extra={
|
|
798
|
+
"import_id": normalized_import_id,
|
|
799
|
+
"process_id_str": normalized_process_id,
|
|
796
800
|
"details": {
|
|
797
801
|
"fix_hint": "Use `process_id_str` or `import_id` for a known import, or use only `app_key` to inspect the latest import in that app.",
|
|
798
802
|
}
|
|
@@ -806,6 +810,9 @@ class ImportTools(ToolBase):
|
|
|
806
810
|
if local_job is None and normalized_process_id:
|
|
807
811
|
matches = [item for item in self._job_store.list() if _normalize_optional_text(item.get("process_id_str")) == normalized_process_id]
|
|
808
812
|
local_job = matches[0] if len(matches) == 1 else None
|
|
813
|
+
effective_process_id = normalized_process_id
|
|
814
|
+
if effective_process_id is None and isinstance(local_job, dict):
|
|
815
|
+
effective_process_id = _normalize_optional_text(local_job.get("process_id_str"))
|
|
809
816
|
resolved_app_key = normalized_app_key
|
|
810
817
|
if not resolved_app_key and isinstance(local_job, dict):
|
|
811
818
|
resolved_app_key = str(local_job.get("app_key") or "").strip()
|
|
@@ -814,6 +821,8 @@ class ImportTools(ToolBase):
|
|
|
814
821
|
error_code="CONFIG_ERROR",
|
|
815
822
|
message="record_import_status_get could not determine app_key from the provided selector",
|
|
816
823
|
extra={
|
|
824
|
+
"import_id": normalized_import_id,
|
|
825
|
+
"process_id_str": effective_process_id,
|
|
817
826
|
"details": {
|
|
818
827
|
"fix_hint": "Use the original `app_key`, or call import status with the latest-import mode: only `app_key`.",
|
|
819
828
|
}
|
|
@@ -832,13 +841,18 @@ class ImportTools(ToolBase):
|
|
|
832
841
|
matched_record, matched_by = _match_import_record(
|
|
833
842
|
records,
|
|
834
843
|
local_job=local_job,
|
|
835
|
-
|
|
844
|
+
import_id=normalized_import_id,
|
|
845
|
+
process_id_str=effective_process_id,
|
|
836
846
|
)
|
|
837
847
|
if matched_record is None:
|
|
838
848
|
return self._failed_status_result(
|
|
839
849
|
error_code="IMPORT_STATUS_AMBIGUOUS",
|
|
840
850
|
message="could not uniquely resolve an import record from the provided identifiers",
|
|
841
|
-
extra={
|
|
851
|
+
extra={
|
|
852
|
+
"import_id": normalized_import_id,
|
|
853
|
+
"process_id_str": effective_process_id,
|
|
854
|
+
"matched_by": matched_by,
|
|
855
|
+
},
|
|
842
856
|
)
|
|
843
857
|
normalized_process = _normalize_optional_text(
|
|
844
858
|
matched_record.get("processIdStr") or matched_record.get("processId") or matched_record.get("process_id_str")
|
|
@@ -2118,6 +2132,7 @@ def _match_import_record(
|
|
|
2118
2132
|
records: list[JSONObject],
|
|
2119
2133
|
*,
|
|
2120
2134
|
local_job: dict[str, Any] | None,
|
|
2135
|
+
import_id: str | None,
|
|
2121
2136
|
process_id_str: str | None,
|
|
2122
2137
|
) -> tuple[JSONObject | None, str | None]:
|
|
2123
2138
|
if process_id_str:
|
|
@@ -2130,6 +2145,16 @@ def _match_import_record(
|
|
|
2130
2145
|
return exact[0], "process_id_str"
|
|
2131
2146
|
if len(exact) > 1:
|
|
2132
2147
|
return None, "process_id_str"
|
|
2148
|
+
if import_id:
|
|
2149
|
+
exact = [
|
|
2150
|
+
item
|
|
2151
|
+
for item in records
|
|
2152
|
+
if import_id in _extract_import_record_ids(item)
|
|
2153
|
+
]
|
|
2154
|
+
if len(exact) == 1:
|
|
2155
|
+
return exact[0], "import_id"
|
|
2156
|
+
if len(exact) > 1:
|
|
2157
|
+
return None, "import_id"
|
|
2133
2158
|
if isinstance(local_job, dict):
|
|
2134
2159
|
source_file_name = _normalize_optional_text(local_job.get("source_file_name"))
|
|
2135
2160
|
started_at = _parse_utc(local_job.get("started_at"))
|
|
@@ -2160,6 +2185,15 @@ def _match_import_record(
|
|
|
2160
2185
|
return None, None
|
|
2161
2186
|
|
|
2162
2187
|
|
|
2188
|
+
def _extract_import_record_ids(record: JSONObject) -> set[str]:
|
|
2189
|
+
identifiers: set[str] = set()
|
|
2190
|
+
for key in ("importId", "import_id", "dataImportId", "data_import_id"):
|
|
2191
|
+
normalized = _normalize_optional_text(record.get(key))
|
|
2192
|
+
if normalized:
|
|
2193
|
+
identifiers.add(normalized)
|
|
2194
|
+
return identifiers
|
|
2195
|
+
|
|
2196
|
+
|
|
2163
2197
|
def _parse_utc(value: Any) -> datetime | None:
|
|
2164
2198
|
text = _normalize_optional_text(value)
|
|
2165
2199
|
if text is None:
|