@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.
Files changed (92) hide show
  1. package/README.md +31 -0
  2. package/docs/local-agent-install.md +309 -0
  3. package/entry_point.py +13 -0
  4. package/npm/bin/qingflow.mjs +5 -0
  5. package/npm/lib/runtime.mjs +346 -0
  6. package/npm/scripts/postinstall.mjs +16 -0
  7. package/package.json +34 -0
  8. package/pyproject.toml +67 -0
  9. package/qingflow +15 -0
  10. package/src/qingflow_mcp/__init__.py +37 -0
  11. package/src/qingflow_mcp/__main__.py +5 -0
  12. package/src/qingflow_mcp/backend_client.py +649 -0
  13. package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
  14. package/src/qingflow_mcp/builder_facade/models.py +1846 -0
  15. package/src/qingflow_mcp/builder_facade/service.py +16502 -0
  16. package/src/qingflow_mcp/cli/__init__.py +1 -0
  17. package/src/qingflow_mcp/cli/commands/__init__.py +18 -0
  18. package/src/qingflow_mcp/cli/commands/app.py +40 -0
  19. package/src/qingflow_mcp/cli/commands/auth.py +112 -0
  20. package/src/qingflow_mcp/cli/commands/builder.py +539 -0
  21. package/src/qingflow_mcp/cli/commands/chart.py +18 -0
  22. package/src/qingflow_mcp/cli/commands/common.py +62 -0
  23. package/src/qingflow_mcp/cli/commands/imports.py +96 -0
  24. package/src/qingflow_mcp/cli/commands/portal.py +25 -0
  25. package/src/qingflow_mcp/cli/commands/record.py +331 -0
  26. package/src/qingflow_mcp/cli/commands/repo.py +80 -0
  27. package/src/qingflow_mcp/cli/commands/task.py +141 -0
  28. package/src/qingflow_mcp/cli/commands/view.py +18 -0
  29. package/src/qingflow_mcp/cli/commands/workspace.py +110 -0
  30. package/src/qingflow_mcp/cli/context.py +60 -0
  31. package/src/qingflow_mcp/cli/formatters.py +573 -0
  32. package/src/qingflow_mcp/cli/json_io.py +50 -0
  33. package/src/qingflow_mcp/cli/main.py +186 -0
  34. package/src/qingflow_mcp/cli/qingflow_login.py +116 -0
  35. package/src/qingflow_mcp/cli/terminal_ui.py +173 -0
  36. package/src/qingflow_mcp/config.py +407 -0
  37. package/src/qingflow_mcp/errors.py +66 -0
  38. package/src/qingflow_mcp/id_utils.py +49 -0
  39. package/src/qingflow_mcp/import_store.py +121 -0
  40. package/src/qingflow_mcp/json_types.py +18 -0
  41. package/src/qingflow_mcp/list_type_labels.py +76 -0
  42. package/src/qingflow_mcp/public_surface.py +243 -0
  43. package/src/qingflow_mcp/repository_store.py +71 -0
  44. package/src/qingflow_mcp/response_trim.py +841 -0
  45. package/src/qingflow_mcp/server.py +216 -0
  46. package/src/qingflow_mcp/server_app_builder.py +543 -0
  47. package/src/qingflow_mcp/server_app_user.py +386 -0
  48. package/src/qingflow_mcp/session_store.py +369 -0
  49. package/src/qingflow_mcp/solution/__init__.py +6 -0
  50. package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
  51. package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
  52. package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
  53. package/src/qingflow_mcp/solution/compiler/form_compiler.py +495 -0
  54. package/src/qingflow_mcp/solution/compiler/icon_utils.py +187 -0
  55. package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
  56. package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
  57. package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
  58. package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
  59. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  60. package/src/qingflow_mcp/solution/design_session.py +222 -0
  61. package/src/qingflow_mcp/solution/design_store.py +100 -0
  62. package/src/qingflow_mcp/solution/executor.py +2398 -0
  63. package/src/qingflow_mcp/solution/normalizer.py +23 -0
  64. package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
  65. package/src/qingflow_mcp/solution/run_store.py +244 -0
  66. package/src/qingflow_mcp/solution/spec_models.py +855 -0
  67. package/src/qingflow_mcp/tools/__init__.py +1 -0
  68. package/src/qingflow_mcp/tools/ai_builder_tools.py +3449 -0
  69. package/src/qingflow_mcp/tools/app_tools.py +926 -0
  70. package/src/qingflow_mcp/tools/approval_tools.py +1062 -0
  71. package/src/qingflow_mcp/tools/auth_tools.py +1133 -0
  72. package/src/qingflow_mcp/tools/base.py +281 -0
  73. package/src/qingflow_mcp/tools/code_block_tools.py +777 -0
  74. package/src/qingflow_mcp/tools/custom_button_tools.py +202 -0
  75. package/src/qingflow_mcp/tools/directory_tools.py +675 -0
  76. package/src/qingflow_mcp/tools/feedback_tools.py +238 -0
  77. package/src/qingflow_mcp/tools/file_tools.py +409 -0
  78. package/src/qingflow_mcp/tools/import_tools.py +2223 -0
  79. package/src/qingflow_mcp/tools/navigation_tools.py +210 -0
  80. package/src/qingflow_mcp/tools/package_tools.py +326 -0
  81. package/src/qingflow_mcp/tools/portal_tools.py +158 -0
  82. package/src/qingflow_mcp/tools/qingbi_report_tools.py +374 -0
  83. package/src/qingflow_mcp/tools/record_tools.py +14291 -0
  84. package/src/qingflow_mcp/tools/repository_dev_tools.py +552 -0
  85. package/src/qingflow_mcp/tools/resource_read_tools.py +503 -0
  86. package/src/qingflow_mcp/tools/role_tools.py +112 -0
  87. package/src/qingflow_mcp/tools/solution_tools.py +4054 -0
  88. package/src/qingflow_mcp/tools/task_context_tools.py +2986 -0
  89. package/src/qingflow_mcp/tools/task_tools.py +889 -0
  90. package/src/qingflow_mcp/tools/view_tools.py +335 -0
  91. package/src/qingflow_mcp/tools/workflow_tools.py +376 -0
  92. package/src/qingflow_mcp/tools/workspace_tools.py +266 -0
@@ -0,0 +1,202 @@
1
+ from __future__ import annotations
2
+
3
+ from copy import deepcopy
4
+
5
+ from ..config import DEFAULT_PROFILE
6
+ from ..errors import QingflowApiError, raise_tool_error
7
+ from ..json_types import JSONObject
8
+ from .base import ToolBase, tool_cn_name
9
+
10
+
11
+ class CustomButtonTools(ToolBase):
12
+ """自定义按钮工具(中文名:按钮配置管理)。
13
+
14
+ 类型:应用配置工具。
15
+ 主要职责:
16
+ 1. 查询应用自定义按钮;
17
+ 2. 创建、更新、删除按钮配置;
18
+ 3. 支持草稿与发布态按钮配置维护。
19
+ """
20
+
21
+ @tool_cn_name("自定义按钮列表")
22
+ def custom_button_list(
23
+ self,
24
+ *,
25
+ profile: str,
26
+ app_key: str,
27
+ being_draft: bool = True,
28
+ include_raw: bool = False,
29
+ ) -> JSONObject:
30
+ """执行工具方法逻辑。"""
31
+ self._require_app_key(app_key)
32
+
33
+ def runner(session_profile, context):
34
+ result = self.backend.request(
35
+ "GET",
36
+ context,
37
+ f"/app/{app_key}/customButton",
38
+ params={"beingDraft": being_draft},
39
+ )
40
+ items = []
41
+ raw_items = result.get("result") if isinstance(result, dict) and isinstance(result.get("result"), list) else []
42
+ for item in raw_items:
43
+ if not isinstance(item, dict):
44
+ continue
45
+ items.append(self._compact_button_base_info(item))
46
+ response = {
47
+ "profile": profile,
48
+ "ws_id": session_profile.selected_ws_id,
49
+ "app_key": app_key,
50
+ "being_draft": being_draft,
51
+ "items": result if include_raw else items,
52
+ "count": len(items),
53
+ "compact": not include_raw,
54
+ }
55
+ if include_raw:
56
+ response["summary"] = items
57
+ return response
58
+
59
+ return self._run(profile, runner)
60
+
61
+ @tool_cn_name("自定义按钮详情")
62
+ def custom_button_get(
63
+ self,
64
+ *,
65
+ profile: str,
66
+ app_key: str,
67
+ button_id: int,
68
+ being_draft: bool = True,
69
+ include_raw: bool = False,
70
+ ) -> JSONObject:
71
+ """执行工具方法逻辑。"""
72
+ self._require_app_key(app_key)
73
+ self._require_button_id(button_id)
74
+
75
+ def runner(session_profile, context):
76
+ params = {"beingDraft": being_draft}
77
+ result = self.backend.request("GET", context, f"/app/{app_key}/customButton/{button_id}", params=params)
78
+ response = {
79
+ "profile": profile,
80
+ "ws_id": session_profile.selected_ws_id,
81
+ "app_key": app_key,
82
+ "button_id": button_id,
83
+ "being_draft": being_draft,
84
+ "result": result if include_raw else self._compact_button_detail(result if isinstance(result, dict) else {}),
85
+ "compact": not include_raw,
86
+ }
87
+ if include_raw:
88
+ response["summary"] = self._compact_button_detail(result if isinstance(result, dict) else {})
89
+ return response
90
+
91
+ return self._run(profile, runner)
92
+
93
+ @tool_cn_name("创建自定义按钮")
94
+ def custom_button_create(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
95
+ """执行工具方法逻辑。"""
96
+ self._require_app_key(app_key)
97
+ body = self._require_dict(payload)
98
+
99
+ def runner(session_profile, context):
100
+ result = self.backend.request("POST", context, f"/app/{app_key}/customButton", json_body=deepcopy(body))
101
+ return {"profile": profile, "ws_id": session_profile.selected_ws_id, "app_key": app_key, "result": result}
102
+
103
+ return self._run(profile, runner)
104
+
105
+ @tool_cn_name("更新自定义按钮")
106
+ def custom_button_update(self, *, profile: str, app_key: str, button_id: int, payload: JSONObject) -> JSONObject:
107
+ """执行工具方法逻辑。"""
108
+ self._require_app_key(app_key)
109
+ self._require_button_id(button_id)
110
+ body = self._require_dict(payload)
111
+
112
+ def runner(session_profile, context):
113
+ result = self.backend.request(
114
+ "POST",
115
+ context,
116
+ f"/app/{app_key}/customButton/{button_id}",
117
+ json_body=deepcopy(body),
118
+ )
119
+ return self._attach_human_review_notice(
120
+ {
121
+ "profile": profile,
122
+ "ws_id": session_profile.selected_ws_id,
123
+ "app_key": app_key,
124
+ "button_id": button_id,
125
+ "result": result,
126
+ },
127
+ operation="update",
128
+ target="custom button configuration",
129
+ )
130
+
131
+ return self._run(profile, runner)
132
+
133
+ @tool_cn_name("删除自定义按钮")
134
+ def custom_button_delete(self, *, profile: str, app_key: str, button_id: int) -> JSONObject:
135
+ """执行工具方法逻辑。"""
136
+ self._require_app_key(app_key)
137
+ self._require_button_id(button_id)
138
+
139
+ def runner(session_profile, context):
140
+ result = self.backend.request("DELETE", context, f"/app/{app_key}/customButton/{button_id}")
141
+ return self._attach_human_review_notice(
142
+ {
143
+ "profile": profile,
144
+ "ws_id": session_profile.selected_ws_id,
145
+ "app_key": app_key,
146
+ "button_id": button_id,
147
+ "result": result,
148
+ },
149
+ operation="delete",
150
+ target="custom button configuration",
151
+ )
152
+
153
+ return self._run(profile, runner)
154
+
155
+ def _require_app_key(self, app_key: str) -> None:
156
+ """执行内部辅助逻辑。"""
157
+ if not str(app_key or "").strip():
158
+ raise_tool_error(QingflowApiError.config_error("app_key is required"))
159
+
160
+ def _require_button_id(self, button_id: int) -> None:
161
+ """执行内部辅助逻辑。"""
162
+ if not isinstance(button_id, int) or isinstance(button_id, bool) or button_id <= 0:
163
+ raise_tool_error(QingflowApiError.config_error("button_id must be a positive integer"))
164
+
165
+ def _compact_button_base_info(self, item: dict[str, object]) -> JSONObject:
166
+ """执行内部辅助逻辑。"""
167
+ creator = item.get("creatorUserInfo") if isinstance(item.get("creatorUserInfo"), dict) else {}
168
+ return {
169
+ "button_id": item.get("buttonId"),
170
+ "button_text": item.get("buttonText"),
171
+ "button_icon": item.get("buttonIcon"),
172
+ "icon_color": item.get("iconColor"),
173
+ "background_color": item.get("backgroundColor"),
174
+ "text_color": item.get("textColor"),
175
+ "creator_user_info": {
176
+ "uid": creator.get("uid"),
177
+ "name": creator.get("name"),
178
+ "email": creator.get("email"),
179
+ }
180
+ if creator
181
+ else None,
182
+ "used_in_chart_count": item.get("userInChartCount"),
183
+ "being_effective_external_qrobot": item.get("beingEffectiveExternalQRobot"),
184
+ }
185
+
186
+ def _compact_button_detail(self, item: dict[str, object]) -> JSONObject:
187
+ """执行内部辅助逻辑。"""
188
+ return {
189
+ "button_id": item.get("buttonId"),
190
+ "button_text": item.get("buttonText"),
191
+ "button_icon": item.get("buttonIcon"),
192
+ "icon_color": item.get("iconColor"),
193
+ "background_color": item.get("backgroundColor"),
194
+ "text_color": item.get("textColor"),
195
+ "trigger_action": item.get("triggerAction"),
196
+ "trigger_link_url": item.get("triggerLinkUrl"),
197
+ "trigger_add_data_config": deepcopy(item.get("triggerAddDataConfig")) if isinstance(item.get("triggerAddDataConfig"), dict) else None,
198
+ "external_qrobot_config": deepcopy(item.get("customButtonExternalQRobotRelationVO"))
199
+ if isinstance(item.get("customButtonExternalQRobotRelationVO"), dict)
200
+ else None,
201
+ "trigger_wings_config": deepcopy(item.get("triggerWingsConfig")) if isinstance(item.get("triggerWingsConfig"), dict) else None,
202
+ }