@qingflow-tech/qingflow-cli 1.1.50-beta.5 → 1.1.51
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 +4 -4
- package/npm/lib/runtime.mjs +13 -29
- package/package.json +1 -1
- package/pyproject.toml +2 -8
- package/skills/qingflow-cli/SKILL.md +322 -93
- package/skills/qingflow-cli/manifest.yaml +1 -1
- package/skills/qingflow-cli/reference/00-INDEX.md +4 -4
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_ADMIN_CHEATSHEET.md +1 -1
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md +9 -3
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md +137 -3
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_EXPLORATION_REPORT.md +4 -6
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_FIELD_DATA_TYPES.md +14 -14
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_MEMBER_CHEATSHEET.md +19 -20
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md +14 -18
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md +12 -7
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md +1 -2
- package/skills/qingflow-cli/reference/builder/20-build-complete-system.md +2 -3
- package/skills/qingflow-cli/reference/builder/30-schema-fields.md +5 -9
- package/skills/qingflow-cli/reference/builder/50-views.md +191 -192
- package/skills/qingflow-cli/reference/builder/80-buttons-associated-resources.md +0 -2
- package/skills/qingflow-cli/reference/builder/README.md +1 -1
- package/skills/qingflow-cli/reference/builder/reference/app-delivery-sop.md +6 -6
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_ADMIN_CHEATSHEET.md +1 -1
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md +95 -76
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_EXPLORATION_REPORT.md +4 -6
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_FIELD_DATA_TYPES.md +13 -13
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_MEMBER_CHEATSHEET.md +19 -20
- package/skills/qingflow-cli/reference/core/QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md +14 -18
- package/skills/qingflow-cli/reference/examples/README.md +1 -1
- package/skills/qingflow-cli/reference/examples/views/views_batch_full.example.json +159 -0
- package/skills/qingflow-cli/reference/examples/views/views_upsert_table_minimal.example.json +36 -30
- package/skills/qingflow-cli/reference/record/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md +1 -2
- package/skills/qingflow-cli/reference/record/analysis/README.md +113 -21
- package/skills/qingflow-cli/reference/record/analysis/analysis-gotchas.md +10 -10
- package/skills/qingflow-cli/reference/record/analysis/analysis-patterns.md +9 -9
- package/skills/qingflow-cli/reference/record/analysis/business-context.md +1 -1
- package/skills/qingflow-cli/reference/record/analysis/confidence-reporting.md +10 -10
- package/skills/qingflow-cli/reference/record/analysis/data-access-playbook.md +80 -52
- package/skills/qingflow-cli/reference/record/analysis/pandas-recipes.md +2 -2
- package/skills/qingflow-cli/reference/views_upsert_table_minimal.example.json +42 -0
- package/skills/qingflow-common/SKILL.md +4 -7
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/app_form_compat.py +0 -3
- package/src/qingflow_mcp/app_form_validator.py +17 -69
- package/src/qingflow_mcp/builder_facade/app_form.py +100 -497
- package/src/qingflow_mcp/builder_facade/models.py +17 -227
- package/src/qingflow_mcp/builder_facade/schemas/app_form/manifest.json +0 -1
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/complete.json +30 -64
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/address.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/amount.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/attachment.json +10 -6
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/code_block.json +10 -6
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/data_relation.json +18 -11
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/date.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/datetime.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/department.json +10 -6
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/email.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/link.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/long_text.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/member.json +10 -6
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/multi_select.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/number.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/phone.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/q_linker.json +10 -6
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/relation.json +15 -46
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/single_choice.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/single_select.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/subtable.json +27 -61
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/text.json +8 -4
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/formula.json +0 -43
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/summary.json +12 -7
- package/src/qingflow_mcp/builder_facade/service.py +539 -1671
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +1 -1
- package/src/qingflow_mcp/cli/commands/__init__.py +1 -2
- package/src/qingflow_mcp/cli/commands/builder.py +55 -76
- package/src/qingflow_mcp/cli/commands/record.py +1 -1
- package/src/qingflow_mcp/cli/context.py +0 -3
- package/src/qingflow_mcp/cli/formatters.py +1 -97
- package/src/qingflow_mcp/config.py +1 -0
- package/src/qingflow_mcp/public_surface.py +0 -8
- package/src/qingflow_mcp/response_trim.py +2 -11
- package/src/qingflow_mcp/server.py +0 -2
- package/src/qingflow_mcp/server_app_builder.py +10 -34
- package/src/qingflow_mcp/server_app_user.py +0 -4
- package/src/qingflow_mcp/solution/compiler/view_compiler.py +1 -2
- package/src/qingflow_mcp/solution/executor.py +8 -96
- package/src/qingflow_mcp/solution/spec_models.py +0 -1
- package/src/qingflow_mcp/tools/ai_builder_tools.py +398 -218
- package/src/qingflow_mcp/tools/base.py +42 -10
- package/src/qingflow_mcp/tools/record_tools.py +46 -11
- package/src/qingflow_mcp/tools/solution_tools.py +0 -2
- package/src/qingflow_mcp/tools/view_tools.py +6 -0
- package/skills/qingflow-cli/reference/data/README.md +0 -32
- package/skills/qingflow-cli/reference/examples/views/views_apply_v1alpha1.example.json +0 -14
- package/skills/qingflow-cli/reference/record/QINGFLOW_CLI_RECORD_SPECIALIZED_WORKFLOW.md +0 -50
- package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/rich_text.json +0 -146
- package/src/qingflow_mcp/builder_facade/schemas/views/manifest.json +0 -42
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/complete.json +0 -1245
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/button-config.json +0 -53
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/data-permission.json +0 -60
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/display.json +0 -73
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/operation-permission.json +0 -48
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/details/query-condition.json +0 -47
- package/src/qingflow_mcp/builder_facade/schemas/views/v1alpha1/summary.json +0 -319
- package/src/qingflow_mcp/builder_facade/views_extract.py +0 -592
- package/src/qingflow_mcp/builder_facade/views_schema.py +0 -400
- package/src/qingflow_mcp/cli/commands/data.py +0 -134
- package/src/qingflow_mcp/tools/csv_export.py +0 -168
- package/src/qingflow_mcp/tools/data_tools.py +0 -284
- package/src/qingflow_mcp/tools/view_writer.py +0 -44
|
@@ -8,6 +8,7 @@ from ..backend_client import BackendRequestContext, BackendClient
|
|
|
8
8
|
from ..auth_provider import CliSessionFacade
|
|
9
9
|
from ..cloud_context import current_call_platform, current_cloud_context
|
|
10
10
|
from ..config import (
|
|
11
|
+
DEFAULT_MEMBER_CREDIT_AVAILABILITY_PATH,
|
|
11
12
|
get_credit_meter_enabled,
|
|
12
13
|
get_credit_usage_base_url,
|
|
13
14
|
get_credit_usage_path,
|
|
@@ -19,6 +20,16 @@ from ..session_store import BackendSession, SessionProfile, SessionStore
|
|
|
19
20
|
|
|
20
21
|
T = TypeVar("T")
|
|
21
22
|
_RUN_DEPTH: ContextVar[int] = ContextVar("qingflow_mcp_tool_run_depth", default=0)
|
|
23
|
+
_MEMBER_CREDIT_DENIAL_MESSAGES = {
|
|
24
|
+
"WORKSPACE_EXHAUSTED": "当前工作区流币余额不足,请充值后再使用 MCP",
|
|
25
|
+
"MEMBER_MONTHLY_EXHAUSTED": "本月个人流币额度已用完,请联系工作区管理员调整额度",
|
|
26
|
+
"MEMBER_TOTAL_EXHAUSTED": "个人流币总额度已用完,请联系工作区管理员调整额度",
|
|
27
|
+
"MEMBER_MONTHLY_AND_TOTAL_EXHAUSTED": (
|
|
28
|
+
"本月和个人总流币额度均已用完,请联系工作区管理员调整额度"
|
|
29
|
+
),
|
|
30
|
+
"MEMBER_QUOTA_NOT_CONFIGURED": "当前成员尚未配置流币额度,请联系工作区管理员",
|
|
31
|
+
"MEMBER_USAGE_QUERY_FAILED": "成员流币额度校验失败,请稍后重试",
|
|
32
|
+
}
|
|
22
33
|
|
|
23
34
|
|
|
24
35
|
class ToolBase:
|
|
@@ -332,28 +343,49 @@ class ToolBase:
|
|
|
332
343
|
if context.ws_id is None:
|
|
333
344
|
raise_tool_error(QingflowApiError(category="payment", message="credit meter requires wsId in current session context"))
|
|
334
345
|
|
|
346
|
+
credit_context = BackendRequestContext(
|
|
347
|
+
base_url=get_credit_usage_base_url() or context.base_url,
|
|
348
|
+
token=context.token,
|
|
349
|
+
ws_id=context.ws_id,
|
|
350
|
+
qf_request_id=context.qf_request_id,
|
|
351
|
+
qf_version=context.qf_version,
|
|
352
|
+
qf_version_source=context.qf_version_source,
|
|
353
|
+
)
|
|
354
|
+
self._require_member_credit_available(context=credit_context)
|
|
335
355
|
self._record_credit_usage(
|
|
336
356
|
tool_name=tool_name,
|
|
337
|
-
context=
|
|
357
|
+
context=credit_context,
|
|
338
358
|
)
|
|
339
359
|
|
|
360
|
+
def _require_member_credit_available(self, *, context: BackendRequestContext) -> None:
|
|
361
|
+
availability = self.backend.request("GET", context, DEFAULT_MEMBER_CREDIT_AVAILABILITY_PATH)
|
|
362
|
+
if not isinstance(availability, dict) or not isinstance(availability.get("allowed"), bool):
|
|
363
|
+
raise_tool_error(QingflowApiError(
|
|
364
|
+
category="payment",
|
|
365
|
+
message="成员流币额度校验失败,请稍后重试",
|
|
366
|
+
))
|
|
367
|
+
if availability["allowed"]:
|
|
368
|
+
return
|
|
369
|
+
|
|
370
|
+
deny_reason = self._normalize_text(availability.get("denyReason")) or "UNKNOWN"
|
|
371
|
+
raise_tool_error(QingflowApiError(
|
|
372
|
+
category="payment",
|
|
373
|
+
message=_MEMBER_CREDIT_DENIAL_MESSAGES.get(
|
|
374
|
+
deny_reason,
|
|
375
|
+
"当前成员无法使用流币,请联系工作区管理员",
|
|
376
|
+
),
|
|
377
|
+
details={"deny_reason": deny_reason},
|
|
378
|
+
))
|
|
379
|
+
|
|
340
380
|
def _record_credit_usage(
|
|
341
381
|
self,
|
|
342
382
|
*,
|
|
343
383
|
tool_name: str,
|
|
344
384
|
context: BackendRequestContext,
|
|
345
385
|
) -> None:
|
|
346
|
-
usage_context = BackendRequestContext(
|
|
347
|
-
base_url=get_credit_usage_base_url() or context.base_url,
|
|
348
|
-
token=context.token,
|
|
349
|
-
ws_id=context.ws_id,
|
|
350
|
-
qf_request_id=context.qf_request_id,
|
|
351
|
-
qf_version=context.qf_version,
|
|
352
|
-
qf_version_source=context.qf_version_source,
|
|
353
|
-
)
|
|
354
386
|
self.backend.request(
|
|
355
387
|
"POST",
|
|
356
|
-
|
|
388
|
+
context,
|
|
357
389
|
get_credit_usage_path(),
|
|
358
390
|
json_body={
|
|
359
391
|
"skuType": "MCP",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import csv
|
|
3
4
|
import html
|
|
4
5
|
import mimetypes
|
|
5
6
|
import json
|
|
@@ -33,7 +34,6 @@ from ..list_type_labels import (
|
|
|
33
34
|
)
|
|
34
35
|
from .base import ToolBase
|
|
35
36
|
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
|
|
@@ -2284,22 +2284,57 @@ class RecordTools(ToolBase):
|
|
|
2284
2284
|
}
|
|
2285
2285
|
|
|
2286
2286
|
run_dir = _record_access_run_dir()
|
|
2287
|
+
run_dir.mkdir(parents=True, exist_ok=True)
|
|
2287
2288
|
header = ["record_id"] + [str(field["column_name"]) for field in fields_payload]
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2289
|
+
files: list[JSONObject] = []
|
|
2290
|
+
shard_part = 0
|
|
2291
|
+
shard_rows = 0
|
|
2292
|
+
row_count = 0
|
|
2293
|
+
file_handle: Any | None = None
|
|
2294
|
+
writer: Any | None = None
|
|
2295
|
+
|
|
2296
|
+
def close_shard() -> None:
|
|
2297
|
+
nonlocal file_handle, writer, shard_rows
|
|
2298
|
+
if file_handle is None:
|
|
2299
|
+
return
|
|
2300
|
+
path = Path(file_handle.name)
|
|
2301
|
+
file_handle.close()
|
|
2302
|
+
files.append(
|
|
2303
|
+
{
|
|
2304
|
+
"local_path": str(path),
|
|
2305
|
+
"row_count": shard_rows,
|
|
2306
|
+
"part": len(files) + 1,
|
|
2307
|
+
}
|
|
2308
|
+
)
|
|
2309
|
+
file_handle = None
|
|
2310
|
+
writer = None
|
|
2311
|
+
shard_rows = 0
|
|
2312
|
+
|
|
2313
|
+
def ensure_writer() -> Any:
|
|
2314
|
+
nonlocal file_handle, writer, shard_part
|
|
2315
|
+
if writer is not None:
|
|
2316
|
+
return writer
|
|
2317
|
+
shard_part += 1
|
|
2318
|
+
path = run_dir / f"records-{shard_part:04d}.csv"
|
|
2319
|
+
file_handle = path.open("w", newline="", encoding="utf-8-sig")
|
|
2320
|
+
writer = csv.writer(file_handle)
|
|
2321
|
+
writer.writerow(header)
|
|
2322
|
+
return writer
|
|
2294
2323
|
|
|
2295
2324
|
def write_record(apply_id: int | None, answer_list: list[JSONValue]) -> None:
|
|
2325
|
+
nonlocal row_count, shard_rows
|
|
2296
2326
|
if apply_id is None:
|
|
2297
2327
|
return
|
|
2328
|
+
if shard_rows >= DEFAULT_RECORD_ACCESS_SHARD_ROWS:
|
|
2329
|
+
close_shard()
|
|
2330
|
+
csv_writer = ensure_writer()
|
|
2298
2331
|
values: list[str] = [_public_record_id_text(apply_id) or ""]
|
|
2299
2332
|
for field in selected_fields:
|
|
2300
2333
|
answer = _find_answer_for_field(answer_list, field)
|
|
2301
2334
|
values.append(_record_access_csv_cell(_normalize_answer_field_value_for_output(answer, field)))
|
|
2302
|
-
|
|
2335
|
+
csv_writer.writerow(values)
|
|
2336
|
+
row_count += 1
|
|
2337
|
+
shard_rows += 1
|
|
2303
2338
|
|
|
2304
2339
|
current_page = 1
|
|
2305
2340
|
has_more = False
|
|
@@ -2339,7 +2374,7 @@ class RecordTools(ToolBase):
|
|
|
2339
2374
|
break
|
|
2340
2375
|
page = fetch_page(current_page, BACKEND_RECORD_ACCESS_PAGE_SIZE)
|
|
2341
2376
|
finally:
|
|
2342
|
-
|
|
2377
|
+
close_shard()
|
|
2343
2378
|
|
|
2344
2379
|
if stopped_reason == "TIME_BUDGET_EXCEEDED":
|
|
2345
2380
|
warnings.append(_record_access_time_budget_warning(reported_total=reported_total, fetched_pages=fetched_pages))
|
|
@@ -2364,11 +2399,11 @@ class RecordTools(ToolBase):
|
|
|
2364
2399
|
"view_id": view_route.view_id,
|
|
2365
2400
|
"format": "csv",
|
|
2366
2401
|
"local_dir": str(run_dir),
|
|
2367
|
-
"row_count":
|
|
2402
|
+
"row_count": row_count,
|
|
2368
2403
|
"complete": complete,
|
|
2369
2404
|
"truncated": not complete,
|
|
2370
2405
|
"safe_for_final_conclusion": safe_for_final_conclusion,
|
|
2371
|
-
"files":
|
|
2406
|
+
"files": files,
|
|
2372
2407
|
"fields": fields_payload,
|
|
2373
2408
|
"warnings": warnings,
|
|
2374
2409
|
"verification": verification_payload,
|
|
@@ -38,7 +38,6 @@ from .qingbi_report_tools import QingbiReportTools
|
|
|
38
38
|
from .record_tools import RecordTools
|
|
39
39
|
from .role_tools import RoleTools
|
|
40
40
|
from .view_tools import ViewTools
|
|
41
|
-
from .view_writer import ViewWriter
|
|
42
41
|
from .workspace_tools import WorkspaceTools
|
|
43
42
|
|
|
44
43
|
STAGED_BUILD_MODES = {"preflight", "plan", "apply", "repair"}
|
|
@@ -1428,7 +1427,6 @@ class SolutionTools(ToolBase):
|
|
|
1428
1427
|
app_tools=AppTools(self.sessions, self.backend),
|
|
1429
1428
|
record_tools=RecordTools(self.sessions, self.backend),
|
|
1430
1429
|
view_tools=ViewTools(self.sessions, self.backend),
|
|
1431
|
-
view_writer=ViewWriter(self.sessions, self.backend),
|
|
1432
1430
|
chart_tools=QingbiReportTools(self.sessions, self.backend),
|
|
1433
1431
|
portal_tools=PortalTools(self.sessions, self.backend),
|
|
1434
1432
|
navigation_tools=NavigationTools(self.sessions, self.backend),
|
|
@@ -111,6 +111,12 @@ class ViewTools(ToolBase):
|
|
|
111
111
|
body = self._require_dict(payload)
|
|
112
112
|
return self._request(profile, "POST", f"/app/{app_key}/view/que/width", app_key=app_key, tool_name="设置视图列宽", json_body=body)
|
|
113
113
|
|
|
114
|
+
def view_create(self, *, profile: str, payload: JSONObject) -> JSONObject:
|
|
115
|
+
"""执行视图相关逻辑。"""
|
|
116
|
+
body = self._require_dict(payload)
|
|
117
|
+
app_key = str(body.get("appKey") or "")
|
|
118
|
+
return self._request(profile, "POST", "/view/viewConfig", app_key=app_key, tool_name="创建视图", json_body=body)
|
|
119
|
+
|
|
114
120
|
def view_get_config(self, *, profile: str, viewgraph_key: str) -> JSONObject:
|
|
115
121
|
"""执行视图相关逻辑。"""
|
|
116
122
|
self._require_viewgraph_key(viewgraph_key)
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Qingflow CLI 直接数据操作
|
|
2
|
-
|
|
3
|
-
直接查询、读取、新增、更新和删除分别使用:
|
|
4
|
-
|
|
5
|
-
- `qingflow data query`
|
|
6
|
-
- `qingflow data get`
|
|
7
|
-
- `qingflow data insert`
|
|
8
|
-
- `qingflow data update`
|
|
9
|
-
- `qingflow data delete`
|
|
10
|
-
|
|
11
|
-
参数、JSON 文件形状和可选项必须来自当前工具 schema、当次 `--help` 或响应字段能力,不得从其他命令推测。
|
|
12
|
-
|
|
13
|
-
## 字段能力合同
|
|
14
|
-
|
|
15
|
-
1. 首次操作当前应用时,只通过只读 `data query/get` 请求 `include_schema=true`,读取同一次响应中的 `schema` 与递归 `field_capabilities`;不得用 insert/update 探测能力。
|
|
16
|
-
2. 构造 `where` 时,只使用目标字段 `filter_operators` 实际暴露的 `op`,并匹配对应 `value_shape`;不要在本文复制操作符矩阵。
|
|
17
|
-
3. 写入前优先执行不设置 `columns` 的只读 `data query` 并请求 schema,检查响应中的 `access`,再检查 `insertable`、`updatable` 与 `required_on_insert`。
|
|
18
|
-
4. `write_kind`、schema 与当次 `--help` 共同决定 payload 形状;运行时字段错误和权限结果优先于预检。
|
|
19
|
-
|
|
20
|
-
## 执行与恢复
|
|
21
|
-
|
|
22
|
-
- 已知 `app_key` 时直接执行目标业务命令;只有应用名称时先用 `app list --query` 查找并核对 `app_name/title`,目标明确且唯一时取其 `app_key`,否则请用户确认。不能把名称传给 `--app-key`。只有业务命令明确报告会话或工作区错误后才恢复认证上下文。
|
|
23
|
-
- 定位目标记录时先 query,再按需 get。字段只使用当前 schema 与字段能力允许的 id、能力和形状。
|
|
24
|
-
- insert、update、delete 会改变真实业务数据。删除、覆盖已有值或批量写入前,必须确认目标和影响范围。
|
|
25
|
-
- 返回后先检查 `write_executed`、`retry_safe`、字段错误和 hints。已执行、部分成功或状态不明时不得重放原请求。
|
|
26
|
-
- data 命令失败时只修正响应明确指出的问题,不得切换其他数据入口绕过权限或校验。
|
|
27
|
-
|
|
28
|
-
## 任务分流
|
|
29
|
-
|
|
30
|
-
- 批量导入:阅读 [批量导入 SOP](../record/QINGFLOW_CLI_RECORD_IMPORT_WORKFLOW.md)。
|
|
31
|
-
- 统计分析:阅读 [数据分析说明](../record/analysis/README.md),使用 `data query --all --output csv` 并读取全部 CSV 分片。
|
|
32
|
-
- 待办和流程动作:阅读 [任务上下文 SOP](../task/QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md)。
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "项目台账视图",
|
|
3
|
-
"type": "table",
|
|
4
|
-
"columns": [100, 101, 102, 103],
|
|
5
|
-
"data_permission": {"type": "custom", "scope": "dept"},
|
|
6
|
-
"sort": [{"que_id": 100, "ascending": false}],
|
|
7
|
-
"display": {"row_height": "compact", "pin_navigate": true},
|
|
8
|
-
"query_conditions": {
|
|
9
|
-
"enabled": true,
|
|
10
|
-
"exact": false,
|
|
11
|
-
"hide_before_query": false,
|
|
12
|
-
"rows": [["项目名称", "负责人"], ["创建时间"]]
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Qingflow CLI:record 日志与附件参考
|
|
2
|
-
|
|
3
|
-
> **适用范围**:任务需要完整数据/流程日志、附件或图片上下文时使用。普通应用数据查询使用 [`data query/get`](../core/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md)。
|
|
4
|
-
|
|
5
|
-
## record 查询链
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
app get(解析 accessible_views,选定 VIEW_ID)
|
|
9
|
-
→ record schema browse(读取该视图字段口径)
|
|
10
|
-
→ record list(样本浏览或模糊定位候选)
|
|
11
|
-
→ record get(可选:详情页首屏、附件与图片上下文)
|
|
12
|
-
→ record logs(可选:完整数据日志与流程日志)
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## 命令形状
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
qingflow --json app get --app-key APP_KEY > tmp/qingflow_app_get.json
|
|
19
|
-
|
|
20
|
-
qingflow --json record schema browse \
|
|
21
|
-
--app-key APP_KEY --view-id VIEW_ID \
|
|
22
|
-
> tmp/qingflow_record_schema.json
|
|
23
|
-
|
|
24
|
-
qingflow --json record list \
|
|
25
|
-
--app-key APP_KEY --view-id VIEW_ID \
|
|
26
|
-
> tmp/qingflow_record_list.json
|
|
27
|
-
|
|
28
|
-
qingflow --json record get \
|
|
29
|
-
--app-key APP_KEY --record-id RECORD_ID --view-id VIEW_ID \
|
|
30
|
-
> tmp/qingflow_record_get.json
|
|
31
|
-
|
|
32
|
-
qingflow --json record logs \
|
|
33
|
-
--app-key APP_KEY --record-id RECORD_ID --view-id VIEW_ID \
|
|
34
|
-
> tmp/qingflow_record_logs.json
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
`VIEW_ID` 只能来自 `app get.accessible_views`、已经确认的前端 URL 或用户明确提供的上下文。显式视图失败时不要自动换成另一系统视图。
|
|
38
|
-
|
|
39
|
-
## 专有结果
|
|
40
|
-
|
|
41
|
-
- `record get`:用于详情页字段、首屏日志、引用、关联资源、`media_assets` 和 `file_assets`。附件与图片优先使用返回的本地路径,不直接访问远端附件 URL。
|
|
42
|
-
- `record logs`:用于完整可见数据日志和流程日志。响应只读取摘要与 JSONL 文件路径,按需筛选本地文件,不把全文放入上下文。
|
|
43
|
-
- `record list`:只在用户明确指定该命令时用于样本浏览/模糊定位,不用于完整统计结论。
|
|
44
|
-
|
|
45
|
-
## 边界
|
|
46
|
-
|
|
47
|
-
- 统计分析仍转 `data query --all --output csv -> Python/pandas`。
|
|
48
|
-
- `CUSTOM_VIEW_LIST_UNAVAILABLE` 只说明自定义视图列表读取受限;不要据此断言应用整体不可读。
|
|
49
|
-
- 待办、已办和抄送属于 `task list --task-box ...`,不使用 `record list --view-id system:todo/done/cc`。
|
|
50
|
-
- 所有大 JSON、附件清单和日志摘要必须落盘。
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$defs": {
|
|
3
|
-
"EmptyConfig": {
|
|
4
|
-
"additionalProperties": false,
|
|
5
|
-
"description": "该字段类型没有特殊配置。",
|
|
6
|
-
"type": "object"
|
|
7
|
-
},
|
|
8
|
-
"FieldCommon": {
|
|
9
|
-
"allOf": [
|
|
10
|
-
{
|
|
11
|
-
"if": {
|
|
12
|
-
"properties": {
|
|
13
|
-
"defaultType": {
|
|
14
|
-
"const": 2
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"required": [
|
|
18
|
-
"defaultType"
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
"then": {
|
|
22
|
-
"properties": {
|
|
23
|
-
"defaultValue": {
|
|
24
|
-
"type": "null"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"if": {
|
|
31
|
-
"properties": {
|
|
32
|
-
"defaultType": {
|
|
33
|
-
"const": 3
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"required": [
|
|
37
|
-
"defaultType"
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
|
-
"then": {
|
|
41
|
-
"properties": {
|
|
42
|
-
"defaultValue": {
|
|
43
|
-
"minLength": 1,
|
|
44
|
-
"type": [
|
|
45
|
-
"string",
|
|
46
|
-
"null"
|
|
47
|
-
]
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
],
|
|
53
|
-
"anyOf": [
|
|
54
|
-
{
|
|
55
|
-
"required": [
|
|
56
|
-
"queId"
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"required": [
|
|
61
|
-
"name"
|
|
62
|
-
]
|
|
63
|
-
}
|
|
64
|
-
],
|
|
65
|
-
"description": "顶层业务字段的公共属性;字段类型由 TopField 的判别分支定义。",
|
|
66
|
-
"properties": {
|
|
67
|
-
"beingRequired": {
|
|
68
|
-
"description": "该字段是否必填;缺失时保留已有字段当前值。",
|
|
69
|
-
"type": "boolean"
|
|
70
|
-
},
|
|
71
|
-
"defaultType": {
|
|
72
|
-
"default": 1,
|
|
73
|
-
"description": "默认值类型,与 defaultValue 联动;1 表示静态值,2 表示关联/绑定值且 defaultValue 只能省略或为 null,3 表示公式值且提供 defaultValue 时必须为非空公式文本。省略 defaultType 但提供 defaultValue 时按 1 处理。",
|
|
74
|
-
"enum": [
|
|
75
|
-
1,
|
|
76
|
-
2,
|
|
77
|
-
3
|
|
78
|
-
],
|
|
79
|
-
"type": "integer"
|
|
80
|
-
},
|
|
81
|
-
"defaultValue": {
|
|
82
|
-
"$ref": "#/$defs/ScalarDefaultValue",
|
|
83
|
-
"description": "普通字段的默认值;后端 queDefaultValue 为字符串,因此数字等字面量也必须以字符串传入。defaultType 为 1 时表示静态文本,为 3 时表示公式文本,为 2 时不携带字面量默认值。表格、地址、附件、引用等结构化默认值必须放在具体字段 config.defaultValues。显式 null 表示清除默认值。"
|
|
84
|
-
},
|
|
85
|
-
"name": {
|
|
86
|
-
"description": "字段展示名称;新增字段必填,已有字段可在携带 queId 时省略;同父级允许同名(后端以 queId 为字段身份),配置引用建议携带 queId。",
|
|
87
|
-
"minLength": 1,
|
|
88
|
-
"type": "string"
|
|
89
|
-
},
|
|
90
|
-
"queId": {
|
|
91
|
-
"description": "已有字段的后端 ID;更新时用于精确定位并复用,新增字段通常省略。",
|
|
92
|
-
"minimum": 1,
|
|
93
|
-
"type": "integer"
|
|
94
|
-
},
|
|
95
|
-
"questionDescription": {
|
|
96
|
-
"description": "字段说明;null 或空字符串表示清空。",
|
|
97
|
-
"type": [
|
|
98
|
-
"string",
|
|
99
|
-
"null"
|
|
100
|
-
]
|
|
101
|
-
},
|
|
102
|
-
"questionType": {
|
|
103
|
-
"description": "字段类型;具体可用值由当前字段详情 Schema 的判别分支约束。",
|
|
104
|
-
"type": "string"
|
|
105
|
-
},
|
|
106
|
-
"width": {
|
|
107
|
-
"description": "字段在所在行的宽度百分比(1-100 整数);后端不校验总和与取值,存量数据存在 33/34 等三等分布值。",
|
|
108
|
-
"maximum": 100,
|
|
109
|
-
"minimum": 1,
|
|
110
|
-
"type": "integer"
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
"type": "object"
|
|
114
|
-
},
|
|
115
|
-
"ScalarDefaultValue": {
|
|
116
|
-
"description": "后端 queDefaultValue 支持的普通字段默认值;非空值必须是字符串,显式 null 表示清除默认值。数字和布尔值应先转换为字符串,对象和数组必须使用字段专用默认值配置。defaultType 为 3 时,通过 AppForm Schema 查询能力传入当前 schema_version 并设置 schema_kind=formula 获取公式语法、字段引用、运算符和全部函数说明;CLI 使用 builder app-form schema --schema-kind formula。需要配置结构化默认值时,传入当前 schema_version,并将字段的 questionType 作为 field_type 获取字段详细 Schema。",
|
|
117
|
-
"type": [
|
|
118
|
-
"null",
|
|
119
|
-
"string"
|
|
120
|
-
]
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
"$id": "https://builder.qingflow.com/schemas/app-form-apply/v1alpha1/fields/rich_text.json",
|
|
124
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
125
|
-
"allOf": [
|
|
126
|
-
{
|
|
127
|
-
"$ref": "#/$defs/FieldCommon"
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
"properties": {
|
|
131
|
-
"config": {
|
|
132
|
-
"$ref": "#/$defs/EmptyConfig"
|
|
133
|
-
},
|
|
134
|
-
"questionType": {
|
|
135
|
-
"const": "rich_text"
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
"required": [
|
|
139
|
-
"questionType"
|
|
140
|
-
]
|
|
141
|
-
}
|
|
142
|
-
],
|
|
143
|
-
"title": "Qingflow AppForm v1alpha1 rich_text field",
|
|
144
|
-
"type": "object",
|
|
145
|
-
"unevaluatedProperties": false
|
|
146
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"manifestDescription": "面向 app_views_apply 的版本化公开视图契约。summary 提供最小声明,complete 覆盖当前可写能力,details 提供按配置域读取的自包含专项 Schema。后端已知但尚不可写的能力以说明性元数据列出,不会被误报为公开能力。",
|
|
3
|
-
"latestVersion": "v1alpha1",
|
|
4
|
-
"versions": {
|
|
5
|
-
"v1alpha1": {
|
|
6
|
-
"versionDescription": "AI 和 CLI/MCP 使用的 canonical views DSL。字段名、更新语义和约束与 app_views_apply 对齐;schema 返回会内联专项 Schema 的依赖定义。",
|
|
7
|
-
"apiVersion": "builder.qingflow.com/v1alpha1",
|
|
8
|
-
"applyDto": "v1alpha1",
|
|
9
|
-
"contractSource": "app_views_apply",
|
|
10
|
-
"contractVersion": "v1alpha1",
|
|
11
|
-
"enabledByDefault": true,
|
|
12
|
-
"schemaKinds": [
|
|
13
|
-
"summary",
|
|
14
|
-
"complete",
|
|
15
|
-
"display",
|
|
16
|
-
"data-permission",
|
|
17
|
-
"operation-permission",
|
|
18
|
-
"query-condition",
|
|
19
|
-
"button-config"
|
|
20
|
-
],
|
|
21
|
-
"schemaFiles": {
|
|
22
|
-
"summary": "v1alpha1/summary.json",
|
|
23
|
-
"complete": "v1alpha1/complete.json",
|
|
24
|
-
"display": "v1alpha1/details/display.json",
|
|
25
|
-
"data-permission": "v1alpha1/details/data-permission.json",
|
|
26
|
-
"operation-permission": "v1alpha1/details/operation-permission.json",
|
|
27
|
-
"query-condition": "v1alpha1/details/query-condition.json",
|
|
28
|
-
"button-config": "v1alpha1/details/button-config.json"
|
|
29
|
-
},
|
|
30
|
-
"viewTypes": [
|
|
31
|
-
"table",
|
|
32
|
-
"card",
|
|
33
|
-
"board",
|
|
34
|
-
"gantt",
|
|
35
|
-
"hierarchy",
|
|
36
|
-
"calendar"
|
|
37
|
-
],
|
|
38
|
-
"backendKnownUnsupportedViewTypes": [],
|
|
39
|
-
"status": "active"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|