@qingflow-tech/qingflow-cli 1.1.47 → 1.1.48-beta.1
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 +3 -3
- package/npm/lib/runtime.mjs +29 -13
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-cli/SKILL.md +37 -1
- package/skills/qingflow-common/SKILL.md +7 -1
- package/src/qingflow_mcp/builder_facade/service.py +119 -1
- package/src/qingflow_mcp/cli/commands/__init__.py +2 -1
- package/src/qingflow_mcp/cli/commands/auth.py +8 -0
- package/src/qingflow_mcp/cli/commands/data.py +134 -0
- package/src/qingflow_mcp/cli/context.py +6 -0
- package/src/qingflow_mcp/cli/formatters.py +163 -3
- package/src/qingflow_mcp/cli/main.py +4 -1
- package/src/qingflow_mcp/config.py +39 -0
- package/src/qingflow_mcp/public_surface.py +7 -0
- package/src/qingflow_mcp/resource_uri.py +241 -0
- package/src/qingflow_mcp/response_trim.py +10 -2
- package/src/qingflow_mcp/server.py +4 -0
- package/src/qingflow_mcp/server_app_builder.py +16 -0
- package/src/qingflow_mcp/server_app_user.py +24 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +208 -39
- package/src/qingflow_mcp/tools/app_tools.py +52 -13
- package/src/qingflow_mcp/tools/csv_export.py +168 -0
- package/src/qingflow_mcp/tools/data_tools.py +271 -0
- package/src/qingflow_mcp/tools/login_link_tools.py +142 -0
- package/src/qingflow_mcp/tools/record_tools.py +11 -46
- package/src/qingflow_mcp/tools/resource_read_tools.py +13 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import csv
|
|
4
3
|
import html
|
|
5
4
|
import mimetypes
|
|
6
5
|
import json
|
|
@@ -34,6 +33,7 @@ from ..list_type_labels import (
|
|
|
34
33
|
)
|
|
35
34
|
from .base import ToolBase
|
|
36
35
|
from .directory_tools import _directory_has_more, _directory_items
|
|
36
|
+
from .csv_export import CsvShardWriter
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
DEFAULT_QUERY_PAGE_SIZE = 50
|
|
@@ -2263,57 +2263,22 @@ class RecordTools(ToolBase):
|
|
|
2263
2263
|
}
|
|
2264
2264
|
|
|
2265
2265
|
run_dir = _record_access_run_dir()
|
|
2266
|
-
run_dir.mkdir(parents=True, exist_ok=True)
|
|
2267
2266
|
header = ["record_id"] + [str(field["column_name"]) for field in fields_payload]
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
def close_shard() -> None:
|
|
2276
|
-
nonlocal file_handle, writer, shard_rows
|
|
2277
|
-
if file_handle is None:
|
|
2278
|
-
return
|
|
2279
|
-
path = Path(file_handle.name)
|
|
2280
|
-
file_handle.close()
|
|
2281
|
-
files.append(
|
|
2282
|
-
{
|
|
2283
|
-
"local_path": str(path),
|
|
2284
|
-
"row_count": shard_rows,
|
|
2285
|
-
"part": len(files) + 1,
|
|
2286
|
-
}
|
|
2287
|
-
)
|
|
2288
|
-
file_handle = None
|
|
2289
|
-
writer = None
|
|
2290
|
-
shard_rows = 0
|
|
2291
|
-
|
|
2292
|
-
def ensure_writer() -> Any:
|
|
2293
|
-
nonlocal file_handle, writer, shard_part
|
|
2294
|
-
if writer is not None:
|
|
2295
|
-
return writer
|
|
2296
|
-
shard_part += 1
|
|
2297
|
-
path = run_dir / f"records-{shard_part:04d}.csv"
|
|
2298
|
-
file_handle = path.open("w", newline="", encoding="utf-8-sig")
|
|
2299
|
-
writer = csv.writer(file_handle)
|
|
2300
|
-
writer.writerow(header)
|
|
2301
|
-
return writer
|
|
2267
|
+
shard_writer = CsvShardWriter(
|
|
2268
|
+
output_dir=run_dir,
|
|
2269
|
+
file_prefix="records",
|
|
2270
|
+
header=header,
|
|
2271
|
+
shard_rows=DEFAULT_RECORD_ACCESS_SHARD_ROWS,
|
|
2272
|
+
)
|
|
2302
2273
|
|
|
2303
2274
|
def write_record(apply_id: int | None, answer_list: list[JSONValue]) -> None:
|
|
2304
|
-
nonlocal row_count, shard_rows
|
|
2305
2275
|
if apply_id is None:
|
|
2306
2276
|
return
|
|
2307
|
-
if shard_rows >= DEFAULT_RECORD_ACCESS_SHARD_ROWS:
|
|
2308
|
-
close_shard()
|
|
2309
|
-
csv_writer = ensure_writer()
|
|
2310
2277
|
values: list[str] = [_public_record_id_text(apply_id) or ""]
|
|
2311
2278
|
for field in selected_fields:
|
|
2312
2279
|
answer = _find_answer_for_field(answer_list, field)
|
|
2313
2280
|
values.append(_record_access_csv_cell(_normalize_answer_field_value_for_output(answer, field)))
|
|
2314
|
-
|
|
2315
|
-
row_count += 1
|
|
2316
|
-
shard_rows += 1
|
|
2281
|
+
shard_writer.write(values)
|
|
2317
2282
|
|
|
2318
2283
|
current_page = 1
|
|
2319
2284
|
has_more = False
|
|
@@ -2353,7 +2318,7 @@ class RecordTools(ToolBase):
|
|
|
2353
2318
|
break
|
|
2354
2319
|
page = fetch_page(current_page, BACKEND_RECORD_ACCESS_PAGE_SIZE)
|
|
2355
2320
|
finally:
|
|
2356
|
-
close_shard()
|
|
2321
|
+
shard_writer.close_shard()
|
|
2357
2322
|
|
|
2358
2323
|
if stopped_reason == "TIME_BUDGET_EXCEEDED":
|
|
2359
2324
|
warnings.append(_record_access_time_budget_warning(reported_total=reported_total, fetched_pages=fetched_pages))
|
|
@@ -2378,11 +2343,11 @@ class RecordTools(ToolBase):
|
|
|
2378
2343
|
"view_id": view_route.view_id,
|
|
2379
2344
|
"format": "csv",
|
|
2380
2345
|
"local_dir": str(run_dir),
|
|
2381
|
-
"row_count": row_count,
|
|
2346
|
+
"row_count": shard_writer.row_count,
|
|
2382
2347
|
"complete": complete,
|
|
2383
2348
|
"truncated": not complete,
|
|
2384
2349
|
"safe_for_final_conclusion": safe_for_final_conclusion,
|
|
2385
|
-
"files": files,
|
|
2350
|
+
"files": shard_writer.files,
|
|
2386
2351
|
"fields": fields_payload,
|
|
2387
2352
|
"warnings": warnings,
|
|
2388
2353
|
"verification": verification_payload,
|
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
|
6
6
|
from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
|
|
7
7
|
from ..json_types import JSONObject
|
|
8
8
|
from ..list_type_labels import SYSTEM_VIEW_DEFINITIONS
|
|
9
|
+
from ..resource_uri import try_build_resource_uri
|
|
9
10
|
from ..solution.compiler.icon_utils import workspace_icon_config
|
|
10
11
|
from .app_tools import _analysis_supported_for_view_type
|
|
11
12
|
from .base import ToolBase
|
|
@@ -227,6 +228,17 @@ class ResourceReadTools(ToolBase):
|
|
|
227
228
|
"message": f"view_get supports exporting `{view_id}`, but the export call still needs an explicit `app_key` from the parent app context.",
|
|
228
229
|
}
|
|
229
230
|
)
|
|
231
|
+
uri = None
|
|
232
|
+
if resolved_app_key:
|
|
233
|
+
uri, uri_warning = try_build_resource_uri(
|
|
234
|
+
ws_id=session_profile.selected_ws_id,
|
|
235
|
+
resource_type="view",
|
|
236
|
+
app_key=resolved_app_key,
|
|
237
|
+
view_kind="custom",
|
|
238
|
+
view_key=view_key,
|
|
239
|
+
)
|
|
240
|
+
if uri_warning:
|
|
241
|
+
warnings.append(uri_warning)
|
|
230
242
|
return {
|
|
231
243
|
"profile": profile,
|
|
232
244
|
"ws_id": session_profile.selected_ws_id,
|
|
@@ -249,6 +261,7 @@ class ResourceReadTools(ToolBase):
|
|
|
249
261
|
],
|
|
250
262
|
"analysis_supported": _analysis_supported_for_view_type(raw_view_type or None),
|
|
251
263
|
"export_capability": export_capability,
|
|
264
|
+
**({"uri": uri} if uri else {}),
|
|
252
265
|
},
|
|
253
266
|
}
|
|
254
267
|
|