@josephyan/qingflow-cli 0.2.0-beta.984 → 0.2.0-beta.986

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 (43) hide show
  1. package/README.md +2 -2
  2. package/docs/local-agent-install.md +70 -11
  3. package/package.json +1 -1
  4. package/pyproject.toml +1 -1
  5. package/src/qingflow_mcp/__init__.py +1 -1
  6. package/src/qingflow_mcp/builder_facade/service.py +47 -21
  7. package/src/qingflow_mcp/cli/commands/auth.py +14 -43
  8. package/src/qingflow_mcp/cli/commands/task.py +4 -1
  9. package/src/qingflow_mcp/cli/commands/workspace.py +0 -8
  10. package/src/qingflow_mcp/cli/formatters.py +0 -21
  11. package/src/qingflow_mcp/config.py +39 -0
  12. package/src/qingflow_mcp/errors.py +2 -2
  13. package/src/qingflow_mcp/public_surface.py +2 -6
  14. package/src/qingflow_mcp/response_trim.py +1 -8
  15. package/src/qingflow_mcp/server.py +1 -1
  16. package/src/qingflow_mcp/server_app_builder.py +4 -28
  17. package/src/qingflow_mcp/server_app_user.py +4 -28
  18. package/src/qingflow_mcp/session_store.py +31 -5
  19. package/src/qingflow_mcp/tools/ai_builder_tools.py +117 -1
  20. package/src/qingflow_mcp/tools/app_tools.py +51 -1
  21. package/src/qingflow_mcp/tools/approval_tools.py +82 -1
  22. package/src/qingflow_mcp/tools/auth_tools.py +258 -288
  23. package/src/qingflow_mcp/tools/base.py +204 -4
  24. package/src/qingflow_mcp/tools/code_block_tools.py +21 -0
  25. package/src/qingflow_mcp/tools/custom_button_tools.py +24 -1
  26. package/src/qingflow_mcp/tools/directory_tools.py +28 -1
  27. package/src/qingflow_mcp/tools/feedback_tools.py +8 -0
  28. package/src/qingflow_mcp/tools/file_tools.py +25 -1
  29. package/src/qingflow_mcp/tools/import_tools.py +40 -1
  30. package/src/qingflow_mcp/tools/navigation_tools.py +34 -1
  31. package/src/qingflow_mcp/tools/package_tools.py +37 -1
  32. package/src/qingflow_mcp/tools/portal_tools.py +28 -1
  33. package/src/qingflow_mcp/tools/qingbi_report_tools.py +38 -1
  34. package/src/qingflow_mcp/tools/record_tools.py +255 -2
  35. package/src/qingflow_mcp/tools/repository_dev_tools.py +21 -2
  36. package/src/qingflow_mcp/tools/resource_read_tools.py +23 -1
  37. package/src/qingflow_mcp/tools/role_tools.py +19 -1
  38. package/src/qingflow_mcp/tools/solution_tools.py +56 -1
  39. package/src/qingflow_mcp/tools/task_context_tools.py +205 -6
  40. package/src/qingflow_mcp/tools/task_tools.py +49 -3
  41. package/src/qingflow_mcp/tools/view_tools.py +56 -1
  42. package/src/qingflow_mcp/tools/workflow_tools.py +65 -1
  43. package/src/qingflow_mcp/tools/workspace_tools.py +14 -225
@@ -56,38 +56,18 @@ def build_builder_server() -> FastMCP:
56
56
  feedback = FeedbackTools(backend, mcp_side="App Builder MCP")
57
57
 
58
58
  @server.tool()
59
- def auth_login(
59
+ def auth_use_credential(
60
60
  profile: str = DEFAULT_PROFILE,
61
61
  base_url: str | None = None,
62
62
  qf_version: str | None = None,
63
- email: str = "",
64
- password: str = "",
65
- persist: bool = True,
66
- ) -> dict:
67
- return auth.auth_login(
68
- profile=profile,
69
- base_url=base_url,
70
- qf_version=qf_version,
71
- email=email,
72
- password=password,
73
- persist=persist,
74
- )
75
-
76
- @server.tool()
77
- def auth_use_token(
78
- profile: str = DEFAULT_PROFILE,
79
- base_url: str | None = None,
80
- qf_version: str | None = None,
81
- token: str = "",
82
- ws_id: int | None = None,
63
+ credential: str = "",
83
64
  persist: bool = False,
84
65
  ) -> dict:
85
- return auth.auth_use_token(
66
+ return auth.auth_use_credential(
86
67
  profile=profile,
87
68
  base_url=base_url,
88
69
  qf_version=qf_version,
89
- token=token,
90
- ws_id=ws_id,
70
+ credential=credential,
91
71
  persist=persist,
92
72
  )
93
73
 
@@ -113,10 +93,6 @@ def build_builder_server() -> FastMCP:
113
93
  include_external=include_external,
114
94
  )
115
95
 
116
- @server.tool()
117
- def workspace_select(profile: str = DEFAULT_PROFILE, ws_id: int = 0) -> dict:
118
- return workspace.workspace_select(profile=profile, ws_id=ws_id)
119
-
120
96
  @server.tool()
121
97
  def file_upload_local(
122
98
  profile: str = DEFAULT_PROFILE,
@@ -191,38 +191,18 @@ If the current MCP capability is unsupported, the workflow is awkward, or the us
191
191
  directory_tools = wrap_trimmed_methods(DirectoryTools(sessions, backend), USER_SERVER_METHOD_MAP)
192
192
 
193
193
  @server.tool()
194
- def auth_login(
194
+ def auth_use_credential(
195
195
  profile: str = DEFAULT_PROFILE,
196
196
  base_url: str | None = None,
197
197
  qf_version: str | None = None,
198
- email: str = "",
199
- password: str = "",
200
- persist: bool = True,
201
- ) -> dict:
202
- return auth.auth_login(
203
- profile=profile,
204
- base_url=base_url,
205
- qf_version=qf_version,
206
- email=email,
207
- password=password,
208
- persist=persist,
209
- )
210
-
211
- @server.tool()
212
- def auth_use_token(
213
- profile: str = DEFAULT_PROFILE,
214
- base_url: str | None = None,
215
- qf_version: str | None = None,
216
- token: str = "",
217
- ws_id: int | None = None,
198
+ credential: str = "",
218
199
  persist: bool = False,
219
200
  ) -> dict:
220
- return auth.auth_use_token(
201
+ return auth.auth_use_credential(
221
202
  profile=profile,
222
203
  base_url=base_url,
223
204
  qf_version=qf_version,
224
- token=token,
225
- ws_id=ws_id,
205
+ credential=credential,
226
206
  persist=persist,
227
207
  )
228
208
 
@@ -248,10 +228,6 @@ If the current MCP capability is unsupported, the workflow is awkward, or the us
248
228
  include_external=include_external,
249
229
  )
250
230
 
251
- @server.tool()
252
- def workspace_select(profile: str = DEFAULT_PROFILE, ws_id: int = 0) -> dict:
253
- return workspace.workspace_select(profile=profile, ws_id=ws_id)
254
-
255
231
  @server.tool()
256
232
  def app_list(profile: str = DEFAULT_PROFILE) -> dict:
257
233
  return apps.app_list(profile=profile)
@@ -29,6 +29,9 @@ class SessionProfile:
29
29
  base_url: str
30
30
  qf_version: str | None
31
31
  qf_version_source: str | None
32
+ token: str | None
33
+ login_token: str | None
34
+ credential: str | None
32
35
  uid: int
33
36
  email: str | None
34
37
  nick_name: str | None
@@ -45,6 +48,9 @@ class SessionProfile:
45
48
  base_url=value["base_url"],
46
49
  qf_version=value.get("qf_version"),
47
50
  qf_version_source=value.get("qf_version_source"),
51
+ token=value.get("token"),
52
+ login_token=value.get("login_token"),
53
+ credential=value.get("credential"),
48
54
  uid=value["uid"],
49
55
  email=value.get("email"),
50
56
  nick_name=value.get("nick_name"),
@@ -60,6 +66,7 @@ class SessionProfile:
60
66
  class BackendSession:
61
67
  token: str
62
68
  login_token: str | None
69
+ credential: str | None
63
70
  profile: str
64
71
  base_url: str
65
72
  qf_version: str | None
@@ -85,6 +92,7 @@ class SessionStore:
85
92
  qf_version_source: str | None = None,
86
93
  token: str,
87
94
  login_token: str | None,
95
+ credential: str | None = None,
88
96
  uid: int,
89
97
  email: str | None,
90
98
  nick_name: str | None,
@@ -99,14 +107,22 @@ class SessionStore:
99
107
  self._set_secret(self._login_token_key(profile), login_token)
100
108
  else:
101
109
  self._delete_secret(self._login_token_key(profile))
110
+ if credential:
111
+ self._set_secret(self._credential_key(profile), credential)
112
+ else:
113
+ self._delete_secret(self._credential_key(profile))
102
114
  else:
103
115
  self._delete_secret(self._token_key(profile))
104
116
  self._delete_secret(self._login_token_key(profile))
117
+ self._delete_secret(self._credential_key(profile))
105
118
  session_profile = SessionProfile(
106
119
  profile=profile,
107
120
  base_url=normalize_base_url(base_url) or base_url,
108
121
  qf_version=(str(qf_version).strip() or None) if qf_version is not None else None,
109
122
  qf_version_source=(str(qf_version_source).strip() or None) if qf_version_source is not None else None,
123
+ token=str(token).strip() or None,
124
+ login_token=(str(login_token).strip() or None) if login_token is not None else None,
125
+ credential=(str(credential).strip() or None) if credential is not None else None,
110
126
  uid=uid,
111
127
  email=email,
112
128
  nick_name=nick_name,
@@ -117,8 +133,9 @@ class SessionStore:
117
133
  updated_at=now,
118
134
  )
119
135
  self._memory_sessions[profile] = BackendSession(
120
- token=token,
121
- login_token=login_token,
136
+ token=session_profile.token or token,
137
+ login_token=session_profile.login_token,
138
+ credential=session_profile.credential,
122
139
  profile=profile,
123
140
  base_url=session_profile.base_url,
124
141
  qf_version=session_profile.qf_version,
@@ -146,14 +163,19 @@ class SessionStore:
146
163
  memory_session.qf_version = session_profile.qf_version
147
164
  memory_session.qf_version_source = session_profile.qf_version_source
148
165
  return memory_session
149
- if not session_profile or not session_profile.persisted:
166
+ if not session_profile:
150
167
  return None
151
- token = self._get_secret(self._token_key(profile))
168
+ token = self._get_secret(self._token_key(profile)) if session_profile.persisted else None
169
+ if not token:
170
+ token = session_profile.token
152
171
  if not token:
153
172
  return None
173
+ login_token = self._get_secret(self._login_token_key(profile)) if session_profile.persisted else None
174
+ credential = self._get_secret(self._credential_key(profile)) if session_profile.persisted else None
154
175
  backend_session = BackendSession(
155
176
  token=token,
156
- login_token=self._get_secret(self._login_token_key(profile)),
177
+ login_token=login_token or session_profile.login_token,
178
+ credential=credential or session_profile.credential,
157
179
  profile=profile,
158
180
  base_url=session_profile.base_url,
159
181
  qf_version=session_profile.qf_version,
@@ -234,6 +256,7 @@ class SessionStore:
234
256
  self._logged_out_profiles.discard(profile)
235
257
  self._delete_secret(self._token_key(profile))
236
258
  self._delete_secret(self._login_token_key(profile))
259
+ self._delete_secret(self._credential_key(profile))
237
260
  payload = self._load_profiles()
238
261
  profiles = payload.get("profiles", {})
239
262
  if profile in profiles:
@@ -249,6 +272,9 @@ class SessionStore:
249
272
  def _login_token_key(self, profile: str) -> str:
250
273
  return f"{profile}:login-token"
251
274
 
275
+ def _credential_key(self, profile: str) -> str:
276
+ return f"{profile}:credential"
277
+
252
278
  def _upsert_profile(self, profile: SessionProfile) -> None:
253
279
  payload = self._load_profiles()
254
280
  payload.setdefault("profiles", {})[profile.profile] = asdict(profile)