@josephyan/qingflow-cli 0.2.0-beta.1000
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 +31 -0
- package/docs/local-agent-install.md +309 -0
- package/entry_point.py +13 -0
- package/npm/bin/qingflow.mjs +5 -0
- package/npm/lib/runtime.mjs +346 -0
- package/npm/scripts/postinstall.mjs +16 -0
- package/package.json +34 -0
- package/pyproject.toml +67 -0
- package/qingflow +15 -0
- package/src/qingflow_mcp/__init__.py +37 -0
- package/src/qingflow_mcp/__main__.py +5 -0
- package/src/qingflow_mcp/backend_client.py +649 -0
- package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
- package/src/qingflow_mcp/builder_facade/models.py +1846 -0
- package/src/qingflow_mcp/builder_facade/service.py +16502 -0
- package/src/qingflow_mcp/cli/__init__.py +1 -0
- package/src/qingflow_mcp/cli/commands/__init__.py +18 -0
- package/src/qingflow_mcp/cli/commands/app.py +40 -0
- package/src/qingflow_mcp/cli/commands/auth.py +112 -0
- package/src/qingflow_mcp/cli/commands/builder.py +539 -0
- package/src/qingflow_mcp/cli/commands/chart.py +18 -0
- package/src/qingflow_mcp/cli/commands/common.py +62 -0
- package/src/qingflow_mcp/cli/commands/imports.py +96 -0
- package/src/qingflow_mcp/cli/commands/portal.py +25 -0
- package/src/qingflow_mcp/cli/commands/record.py +331 -0
- package/src/qingflow_mcp/cli/commands/repo.py +80 -0
- package/src/qingflow_mcp/cli/commands/task.py +141 -0
- package/src/qingflow_mcp/cli/commands/view.py +18 -0
- package/src/qingflow_mcp/cli/commands/workspace.py +110 -0
- package/src/qingflow_mcp/cli/context.py +60 -0
- package/src/qingflow_mcp/cli/formatters.py +573 -0
- package/src/qingflow_mcp/cli/json_io.py +50 -0
- package/src/qingflow_mcp/cli/main.py +186 -0
- package/src/qingflow_mcp/cli/qingflow_login.py +116 -0
- package/src/qingflow_mcp/cli/terminal_ui.py +173 -0
- package/src/qingflow_mcp/config.py +407 -0
- package/src/qingflow_mcp/errors.py +66 -0
- package/src/qingflow_mcp/id_utils.py +49 -0
- package/src/qingflow_mcp/import_store.py +121 -0
- package/src/qingflow_mcp/json_types.py +18 -0
- package/src/qingflow_mcp/list_type_labels.py +76 -0
- package/src/qingflow_mcp/public_surface.py +243 -0
- package/src/qingflow_mcp/repository_store.py +71 -0
- package/src/qingflow_mcp/response_trim.py +841 -0
- package/src/qingflow_mcp/server.py +216 -0
- package/src/qingflow_mcp/server_app_builder.py +543 -0
- package/src/qingflow_mcp/server_app_user.py +386 -0
- package/src/qingflow_mcp/session_store.py +369 -0
- package/src/qingflow_mcp/solution/__init__.py +6 -0
- package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
- package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
- package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +495 -0
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +187 -0
- package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
- package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
- package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
- package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
- package/src/qingflow_mcp/solution/design_session.py +222 -0
- package/src/qingflow_mcp/solution/design_store.py +100 -0
- package/src/qingflow_mcp/solution/executor.py +2398 -0
- package/src/qingflow_mcp/solution/normalizer.py +23 -0
- package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
- package/src/qingflow_mcp/solution/run_store.py +244 -0
- package/src/qingflow_mcp/solution/spec_models.py +855 -0
- package/src/qingflow_mcp/tools/__init__.py +1 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +3449 -0
- package/src/qingflow_mcp/tools/app_tools.py +926 -0
- package/src/qingflow_mcp/tools/approval_tools.py +1062 -0
- package/src/qingflow_mcp/tools/auth_tools.py +1133 -0
- package/src/qingflow_mcp/tools/base.py +281 -0
- package/src/qingflow_mcp/tools/code_block_tools.py +777 -0
- package/src/qingflow_mcp/tools/custom_button_tools.py +202 -0
- package/src/qingflow_mcp/tools/directory_tools.py +675 -0
- package/src/qingflow_mcp/tools/feedback_tools.py +238 -0
- package/src/qingflow_mcp/tools/file_tools.py +409 -0
- package/src/qingflow_mcp/tools/import_tools.py +2223 -0
- package/src/qingflow_mcp/tools/navigation_tools.py +210 -0
- package/src/qingflow_mcp/tools/package_tools.py +326 -0
- package/src/qingflow_mcp/tools/portal_tools.py +158 -0
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +374 -0
- package/src/qingflow_mcp/tools/record_tools.py +14291 -0
- package/src/qingflow_mcp/tools/repository_dev_tools.py +552 -0
- package/src/qingflow_mcp/tools/resource_read_tools.py +503 -0
- package/src/qingflow_mcp/tools/role_tools.py +112 -0
- package/src/qingflow_mcp/tools/solution_tools.py +4054 -0
- package/src/qingflow_mcp/tools/task_context_tools.py +2986 -0
- package/src/qingflow_mcp/tools/task_tools.py +889 -0
- package/src/qingflow_mcp/tools/view_tools.py +335 -0
- package/src/qingflow_mcp/tools/workflow_tools.py +376 -0
- package/src/qingflow_mcp/tools/workspace_tools.py +266 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from ..context import CliContext
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
9
|
+
parser = subparsers.add_parser("view", help="视图访问")
|
|
10
|
+
view_subparsers = parser.add_subparsers(dest="view_command", required=True)
|
|
11
|
+
|
|
12
|
+
get_parser = view_subparsers.add_parser("get", help="读取视图资源描述")
|
|
13
|
+
get_parser.add_argument("--view-id", required=True)
|
|
14
|
+
get_parser.set_defaults(handler=_handle_get, format_hint="generic")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
18
|
+
return context.resource.view_get(profile=args.profile, view_id=args.view_id)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from ..context import CliContext
|
|
7
|
+
from ..terminal_ui import SelectionOption, select_option
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
11
|
+
parser = subparsers.add_parser("workspace", help="工作区")
|
|
12
|
+
workspace_subparsers = parser.add_subparsers(dest="workspace_command", required=True)
|
|
13
|
+
|
|
14
|
+
list_parser = workspace_subparsers.add_parser("list", help="列出工作区")
|
|
15
|
+
list_parser.add_argument("--page", type=int, default=1)
|
|
16
|
+
list_parser.add_argument("--page-size", type=int, default=20)
|
|
17
|
+
list_parser.add_argument("--include-external", action="store_true")
|
|
18
|
+
list_parser.set_defaults(handler=_handle_list, format_hint="workspace_list")
|
|
19
|
+
|
|
20
|
+
get_parser = workspace_subparsers.add_parser("get", help="读取工作区详情")
|
|
21
|
+
get_parser.add_argument("--ws-id", type=int, default=0)
|
|
22
|
+
get_parser.set_defaults(handler=_handle_get, format_hint="workspace_get")
|
|
23
|
+
|
|
24
|
+
select_parser = workspace_subparsers.add_parser("select", help="切换当前工作区")
|
|
25
|
+
select_parser.add_argument("--ws-id", type=int, default=0, help="不传时在交互终端中选择工作区")
|
|
26
|
+
select_parser.set_defaults(handler=_handle_select, format_hint="workspace_get")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
30
|
+
return context.workspace.workspace_list(
|
|
31
|
+
profile=args.profile,
|
|
32
|
+
page_num=args.page,
|
|
33
|
+
page_size=args.page_size,
|
|
34
|
+
include_external=bool(args.include_external),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
39
|
+
return context.workspace.workspace_get(
|
|
40
|
+
profile=args.profile,
|
|
41
|
+
ws_id=args.ws_id if int(args.ws_id or 0) > 0 else None,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _handle_select(args: argparse.Namespace, context: CliContext) -> dict:
|
|
46
|
+
if int(args.ws_id or 0) <= 0:
|
|
47
|
+
selected_ws_id = _choose_workspace_interactively(args, context)
|
|
48
|
+
if selected_ws_id is None:
|
|
49
|
+
raise RuntimeError(
|
|
50
|
+
json.dumps(
|
|
51
|
+
{
|
|
52
|
+
"category": "config",
|
|
53
|
+
"message": "workspace select requires --ws-id, or an interactive terminal to choose a workspace",
|
|
54
|
+
},
|
|
55
|
+
ensure_ascii=False,
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
args.ws_id = selected_ws_id
|
|
59
|
+
return context.workspace.workspace_select(
|
|
60
|
+
profile=args.profile,
|
|
61
|
+
ws_id=int(args.ws_id),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _choose_workspace_interactively(args: argparse.Namespace, context: CliContext) -> int | None:
|
|
66
|
+
input_stream = getattr(args, "_stdin", None)
|
|
67
|
+
output_stream = getattr(args, "_stderr_stream", None)
|
|
68
|
+
if input_stream is None or output_stream is None:
|
|
69
|
+
return None
|
|
70
|
+
if not bool(getattr(input_stream, "isatty", lambda: False)()):
|
|
71
|
+
return None
|
|
72
|
+
page = context.workspace.workspace_list(
|
|
73
|
+
profile=args.profile,
|
|
74
|
+
page_num=1,
|
|
75
|
+
page_size=100,
|
|
76
|
+
include_external=False,
|
|
77
|
+
).get("page")
|
|
78
|
+
items = page.get("list") if isinstance(page, dict) and isinstance(page.get("list"), list) else []
|
|
79
|
+
if not items:
|
|
80
|
+
return None
|
|
81
|
+
current_ws_id = None
|
|
82
|
+
sessions = getattr(context, "sessions", None)
|
|
83
|
+
if sessions is not None and hasattr(sessions, "get_profile"):
|
|
84
|
+
try:
|
|
85
|
+
session_profile = sessions.get_profile(args.profile)
|
|
86
|
+
except Exception:
|
|
87
|
+
session_profile = None
|
|
88
|
+
current_ws_id = getattr(session_profile, "selected_ws_id", None) if session_profile is not None else None
|
|
89
|
+
options: list[SelectionOption[int]] = []
|
|
90
|
+
for item in items:
|
|
91
|
+
if not isinstance(item, dict):
|
|
92
|
+
continue
|
|
93
|
+
ws_id = int(item.get("wsId") or 0)
|
|
94
|
+
if ws_id <= 0:
|
|
95
|
+
continue
|
|
96
|
+
workspace_name = str(item.get("workspaceName") or item.get("wsName") or f"Workspace {ws_id}")
|
|
97
|
+
remark = str(item.get("remark") or "").strip()
|
|
98
|
+
label = workspace_name
|
|
99
|
+
if remark:
|
|
100
|
+
label = f"{workspace_name} - {remark}"
|
|
101
|
+
hint = f"ws_id={ws_id}"
|
|
102
|
+
if current_ws_id == ws_id:
|
|
103
|
+
hint += " · 当前"
|
|
104
|
+
options.append(SelectionOption(value=ws_id, label=label, hint=hint))
|
|
105
|
+
return select_option(
|
|
106
|
+
title="选择工作区",
|
|
107
|
+
options=options,
|
|
108
|
+
input_stream=input_stream,
|
|
109
|
+
output_stream=output_stream,
|
|
110
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from ..backend_client import BackendClient
|
|
6
|
+
from ..session_store import SessionStore
|
|
7
|
+
from ..tools.ai_builder_tools import AiBuilderTools
|
|
8
|
+
from ..tools.app_tools import AppTools
|
|
9
|
+
from ..tools.auth_tools import AuthTools
|
|
10
|
+
from ..tools.code_block_tools import CodeBlockTools
|
|
11
|
+
from ..tools.feedback_tools import FeedbackTools
|
|
12
|
+
from ..tools.file_tools import FileTools
|
|
13
|
+
from ..tools.import_tools import ImportTools
|
|
14
|
+
from ..tools.record_tools import RecordTools
|
|
15
|
+
from ..tools.repository_dev_tools import RepositoryDevTools
|
|
16
|
+
from ..tools.resource_read_tools import ResourceReadTools
|
|
17
|
+
from ..tools.task_context_tools import TaskContextTools
|
|
18
|
+
from ..tools.workspace_tools import WorkspaceTools
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(slots=True)
|
|
22
|
+
class CliContext:
|
|
23
|
+
sessions: SessionStore
|
|
24
|
+
backend: BackendClient
|
|
25
|
+
auth: AuthTools
|
|
26
|
+
workspace: WorkspaceTools
|
|
27
|
+
app: AppTools
|
|
28
|
+
resource: ResourceReadTools
|
|
29
|
+
record: RecordTools
|
|
30
|
+
code_block: CodeBlockTools
|
|
31
|
+
imports: ImportTools
|
|
32
|
+
task: TaskContextTools
|
|
33
|
+
files: FileTools
|
|
34
|
+
builder_feedback: FeedbackTools
|
|
35
|
+
builder: AiBuilderTools
|
|
36
|
+
repo: RepositoryDevTools
|
|
37
|
+
|
|
38
|
+
def close(self) -> None:
|
|
39
|
+
self.backend.close()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def build_cli_context() -> CliContext:
|
|
43
|
+
sessions = SessionStore()
|
|
44
|
+
backend = BackendClient()
|
|
45
|
+
return CliContext(
|
|
46
|
+
sessions=sessions,
|
|
47
|
+
backend=backend,
|
|
48
|
+
auth=AuthTools(sessions, backend),
|
|
49
|
+
workspace=WorkspaceTools(sessions, backend),
|
|
50
|
+
app=AppTools(sessions, backend),
|
|
51
|
+
resource=ResourceReadTools(sessions, backend),
|
|
52
|
+
record=RecordTools(sessions, backend),
|
|
53
|
+
code_block=CodeBlockTools(sessions, backend),
|
|
54
|
+
imports=ImportTools(sessions, backend),
|
|
55
|
+
task=TaskContextTools(sessions, backend),
|
|
56
|
+
files=FileTools(sessions, backend),
|
|
57
|
+
builder_feedback=FeedbackTools(backend, mcp_side="App Builder MCP"),
|
|
58
|
+
builder=AiBuilderTools(sessions, backend),
|
|
59
|
+
repo=RepositoryDevTools(sessions, backend),
|
|
60
|
+
)
|