@josephyan/qingflow-cli 0.2.0-beta.66 → 0.2.0-beta.67
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 +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/builder_facade/service.py +42 -5
- package/src/qingflow_mcp/cli/commands/builder.py +23 -0
- package/src/qingflow_mcp/server_app_builder.py +7 -2
- package/src/qingflow_mcp/tools/ai_builder_tools.py +63 -6
- package/src/qingflow_mcp/tools/package_tools.py +1 -0
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-cli@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-cli@0.2.0-beta.67
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.67 qingflow
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@josephyan/qingflow-cli",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.67",
|
|
4
4
|
"description": "Human-friendly Qingflow command line interface for auth, record operations, import, tasks, and stable builder flows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/pyproject.toml
CHANGED
|
@@ -192,7 +192,11 @@ class AiBuilderFacade:
|
|
|
192
192
|
)
|
|
193
193
|
items = listing.get("items") if isinstance(listing.get("items"), list) else []
|
|
194
194
|
matches = [
|
|
195
|
-
{
|
|
195
|
+
{
|
|
196
|
+
"tag_id": item.get("tagId"),
|
|
197
|
+
"tag_name": item.get("tagName"),
|
|
198
|
+
"tag_icon": str(item.get("tagIcon") or "").strip() or None,
|
|
199
|
+
}
|
|
196
200
|
for item in items
|
|
197
201
|
if isinstance(item, dict) and item.get("tagName") == requested and _coerce_positive_int(item.get("tagId")) is not None
|
|
198
202
|
]
|
|
@@ -226,12 +230,24 @@ class AiBuilderFacade:
|
|
|
226
230
|
"verification": {},
|
|
227
231
|
"tag_id": match["tag_id"],
|
|
228
232
|
"tag_name": match["tag_name"],
|
|
233
|
+
"tag_icon": match.get("tag_icon"),
|
|
229
234
|
"match_mode": "exact",
|
|
230
235
|
}
|
|
231
236
|
|
|
232
|
-
def package_create(
|
|
237
|
+
def package_create(
|
|
238
|
+
self,
|
|
239
|
+
*,
|
|
240
|
+
profile: str,
|
|
241
|
+
package_name: str,
|
|
242
|
+
icon: str | None = None,
|
|
243
|
+
color: str | None = None,
|
|
244
|
+
) -> JSONObject:
|
|
233
245
|
requested = str(package_name or "").strip()
|
|
234
|
-
normalized_args = {
|
|
246
|
+
normalized_args = {
|
|
247
|
+
"package_name": requested,
|
|
248
|
+
**({"icon": icon} if icon else {}),
|
|
249
|
+
**({"color": color} if color else {}),
|
|
250
|
+
}
|
|
235
251
|
if not requested:
|
|
236
252
|
return _failed(
|
|
237
253
|
"PACKAGE_NAME_REQUIRED",
|
|
@@ -239,6 +255,12 @@ class AiBuilderFacade:
|
|
|
239
255
|
normalized_args=normalized_args,
|
|
240
256
|
suggested_next_call=None,
|
|
241
257
|
)
|
|
258
|
+
desired_tag_icon = encode_workspace_icon_with_defaults(
|
|
259
|
+
icon=icon,
|
|
260
|
+
color=color,
|
|
261
|
+
title=requested,
|
|
262
|
+
fallback_icon_name="files-folder",
|
|
263
|
+
)
|
|
242
264
|
existing = self.package_resolve(profile=profile, package_name=requested)
|
|
243
265
|
lookup_permission_blocked = None
|
|
244
266
|
if existing.get("status") == "success":
|
|
@@ -257,6 +279,7 @@ class AiBuilderFacade:
|
|
|
257
279
|
"verification": {"existing_package_reused": True},
|
|
258
280
|
"tag_id": existing.get("tag_id"),
|
|
259
281
|
"tag_name": existing.get("tag_name"),
|
|
282
|
+
"tag_icon": existing.get("tag_icon"),
|
|
260
283
|
}
|
|
261
284
|
if existing.get("error_code") == "AMBIGUOUS_PACKAGE":
|
|
262
285
|
return existing
|
|
@@ -271,7 +294,10 @@ class AiBuilderFacade:
|
|
|
271
294
|
elif existing.get("error_code") not in {"PACKAGE_NOT_FOUND"}:
|
|
272
295
|
return existing
|
|
273
296
|
try:
|
|
274
|
-
created = self.packages.package_create(
|
|
297
|
+
created = self.packages.package_create(
|
|
298
|
+
profile=profile,
|
|
299
|
+
payload={"tagName": requested, "tagIcon": desired_tag_icon},
|
|
300
|
+
)
|
|
275
301
|
except (QingflowApiError, RuntimeError) as error:
|
|
276
302
|
api_error = _coerce_api_error(error)
|
|
277
303
|
return _failed_from_api_error(
|
|
@@ -282,16 +308,26 @@ class AiBuilderFacade:
|
|
|
282
308
|
"package_name": requested,
|
|
283
309
|
**({"lookup_permission_blocked": lookup_permission_blocked} if lookup_permission_blocked is not None else {}),
|
|
284
310
|
},
|
|
285
|
-
suggested_next_call={
|
|
311
|
+
suggested_next_call={
|
|
312
|
+
"tool_name": "package_create",
|
|
313
|
+
"arguments": {
|
|
314
|
+
"profile": profile,
|
|
315
|
+
"package_name": requested,
|
|
316
|
+
**({"icon": icon} if icon else {}),
|
|
317
|
+
**({"color": color} if color else {}),
|
|
318
|
+
},
|
|
319
|
+
},
|
|
286
320
|
)
|
|
287
321
|
result = created.get("result") if isinstance(created.get("result"), dict) else {}
|
|
288
322
|
tag_id = _coerce_positive_int(result.get("tagId"))
|
|
289
323
|
tag_name = str(result.get("tagName") or requested).strip() or requested
|
|
324
|
+
tag_icon = str(result.get("tagIcon") or desired_tag_icon or "").strip() or None
|
|
290
325
|
if tag_id is None:
|
|
291
326
|
resolved = self.package_resolve(profile=profile, package_name=requested)
|
|
292
327
|
if resolved.get("status") == "success":
|
|
293
328
|
tag_id = _coerce_positive_int(resolved.get("tag_id"))
|
|
294
329
|
tag_name = str(resolved.get("tag_name") or tag_name)
|
|
330
|
+
tag_icon = str(resolved.get("tag_icon") or tag_icon or "").strip() or None
|
|
295
331
|
verified = tag_id is not None
|
|
296
332
|
return {
|
|
297
333
|
"status": "success" if verified else "partial_success",
|
|
@@ -310,6 +346,7 @@ class AiBuilderFacade:
|
|
|
310
346
|
"verification": {"tag_id_verified": verified},
|
|
311
347
|
"tag_id": tag_id,
|
|
312
348
|
"tag_name": tag_name,
|
|
349
|
+
"tag_icon": tag_icon,
|
|
313
350
|
}
|
|
314
351
|
|
|
315
352
|
def package_list(self, *, profile: str, trial_status: str = "all") -> JSONObject:
|
|
@@ -12,10 +12,20 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
12
12
|
|
|
13
13
|
package = builder_subparsers.add_parser("package", help="应用包")
|
|
14
14
|
package_subparsers = package.add_subparsers(dest="builder_package_command", required=True)
|
|
15
|
+
package_list = package_subparsers.add_parser("list", help="列出应用包")
|
|
16
|
+
package_list.add_argument("--trial-status", default="all")
|
|
17
|
+
package_list.set_defaults(handler=_handle_package_list, format_hint="builder_summary")
|
|
18
|
+
|
|
15
19
|
package_resolve = package_subparsers.add_parser("resolve", help="解析应用包")
|
|
16
20
|
package_resolve.add_argument("--package-name", required=True)
|
|
17
21
|
package_resolve.set_defaults(handler=_handle_package_resolve, format_hint="builder_summary")
|
|
18
22
|
|
|
23
|
+
package_create = package_subparsers.add_parser("create", help="创建应用包")
|
|
24
|
+
package_create.add_argument("--package-name", required=True)
|
|
25
|
+
package_create.add_argument("--icon")
|
|
26
|
+
package_create.add_argument("--color")
|
|
27
|
+
package_create.set_defaults(handler=_handle_package_create, format_hint="builder_summary")
|
|
28
|
+
|
|
19
29
|
app = builder_subparsers.add_parser("app", help="应用")
|
|
20
30
|
app_subparsers = app.add_subparsers(dest="builder_app_command", required=True)
|
|
21
31
|
|
|
@@ -119,10 +129,23 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
119
129
|
publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary")
|
|
120
130
|
|
|
121
131
|
|
|
132
|
+
def _handle_package_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
133
|
+
return context.builder.package_list(profile=args.profile, trial_status=args.trial_status)
|
|
134
|
+
|
|
135
|
+
|
|
122
136
|
def _handle_package_resolve(args: argparse.Namespace, context: CliContext) -> dict:
|
|
123
137
|
return context.builder.package_resolve(profile=args.profile, package_name=args.package_name)
|
|
124
138
|
|
|
125
139
|
|
|
140
|
+
def _handle_package_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
141
|
+
return context.builder.package_create(
|
|
142
|
+
profile=args.profile,
|
|
143
|
+
package_name=args.package_name,
|
|
144
|
+
icon=args.icon,
|
|
145
|
+
color=args.color,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
126
149
|
def _handle_app_resolve(args: argparse.Namespace, context: CliContext) -> dict:
|
|
127
150
|
return context.builder.app_resolve(
|
|
128
151
|
profile=args.profile,
|
|
@@ -138,8 +138,13 @@ def build_builder_server() -> FastMCP:
|
|
|
138
138
|
return ai_builder.builder_tool_contract(tool_name=tool_name)
|
|
139
139
|
|
|
140
140
|
@server.tool()
|
|
141
|
-
def package_create(
|
|
142
|
-
|
|
141
|
+
def package_create(
|
|
142
|
+
profile: str = DEFAULT_PROFILE,
|
|
143
|
+
package_name: str = "",
|
|
144
|
+
icon: str | None = None,
|
|
145
|
+
color: str | None = None,
|
|
146
|
+
) -> dict:
|
|
147
|
+
return ai_builder.package_create(profile=profile, package_name=package_name, icon=icon, color=color)
|
|
143
148
|
|
|
144
149
|
@server.tool()
|
|
145
150
|
def member_search(
|
|
@@ -82,8 +82,13 @@ class AiBuilderTools(ToolBase):
|
|
|
82
82
|
return self.builder_tool_contract(tool_name=tool_name)
|
|
83
83
|
|
|
84
84
|
@mcp.tool()
|
|
85
|
-
def package_create(
|
|
86
|
-
|
|
85
|
+
def package_create(
|
|
86
|
+
profile: str = DEFAULT_PROFILE,
|
|
87
|
+
package_name: str = "",
|
|
88
|
+
icon: str | None = None,
|
|
89
|
+
color: str | None = None,
|
|
90
|
+
) -> JSONObject:
|
|
91
|
+
return self.package_create(profile=profile, package_name=package_name, icon=icon, color=color)
|
|
87
92
|
|
|
88
93
|
@mcp.tool()
|
|
89
94
|
def member_search(
|
|
@@ -425,13 +430,32 @@ class AiBuilderTools(ToolBase):
|
|
|
425
430
|
"contract": contract,
|
|
426
431
|
}
|
|
427
432
|
|
|
428
|
-
def package_create(
|
|
429
|
-
|
|
433
|
+
def package_create(
|
|
434
|
+
self,
|
|
435
|
+
*,
|
|
436
|
+
profile: str,
|
|
437
|
+
package_name: str,
|
|
438
|
+
icon: str | None = None,
|
|
439
|
+
color: str | None = None,
|
|
440
|
+
) -> JSONObject:
|
|
441
|
+
normalized_args = {
|
|
442
|
+
"package_name": package_name,
|
|
443
|
+
**({"icon": icon} if icon else {}),
|
|
444
|
+
**({"color": color} if color else {}),
|
|
445
|
+
}
|
|
430
446
|
return _safe_tool_call(
|
|
431
|
-
lambda: self._facade.package_create(profile=profile, package_name=package_name),
|
|
447
|
+
lambda: self._facade.package_create(profile=profile, package_name=package_name, icon=icon, color=color),
|
|
432
448
|
error_code="PACKAGE_CREATE_FAILED",
|
|
433
449
|
normalized_args=normalized_args,
|
|
434
|
-
suggested_next_call={
|
|
450
|
+
suggested_next_call={
|
|
451
|
+
"tool_name": "package_create",
|
|
452
|
+
"arguments": {
|
|
453
|
+
"profile": profile,
|
|
454
|
+
"package_name": package_name,
|
|
455
|
+
**({"icon": icon} if icon else {}),
|
|
456
|
+
**({"color": color} if color else {}),
|
|
457
|
+
},
|
|
458
|
+
},
|
|
435
459
|
)
|
|
436
460
|
|
|
437
461
|
def member_search(
|
|
@@ -1708,6 +1732,39 @@ def _public_error_message(error_code: str, error: QingflowApiError) -> str:
|
|
|
1708
1732
|
|
|
1709
1733
|
|
|
1710
1734
|
_BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
1735
|
+
"package_list": {
|
|
1736
|
+
"allowed_keys": ["trial_status"],
|
|
1737
|
+
"aliases": {"trialStatus": "trial_status"},
|
|
1738
|
+
"allowed_values": {"trial_status": ["all", "trial", "formal"]},
|
|
1739
|
+
"minimal_example": {
|
|
1740
|
+
"profile": "default",
|
|
1741
|
+
"trial_status": "all",
|
|
1742
|
+
},
|
|
1743
|
+
},
|
|
1744
|
+
"package_resolve": {
|
|
1745
|
+
"allowed_keys": ["package_name"],
|
|
1746
|
+
"aliases": {"packageName": "package_name"},
|
|
1747
|
+
"allowed_values": {},
|
|
1748
|
+
"minimal_example": {
|
|
1749
|
+
"profile": "default",
|
|
1750
|
+
"package_name": "PLM(备用,施工中)",
|
|
1751
|
+
},
|
|
1752
|
+
},
|
|
1753
|
+
"package_create": {
|
|
1754
|
+
"allowed_keys": ["package_name", "icon", "color"],
|
|
1755
|
+
"aliases": {
|
|
1756
|
+
"packageName": "package_name",
|
|
1757
|
+
"iconName": "icon",
|
|
1758
|
+
"iconColor": "color",
|
|
1759
|
+
},
|
|
1760
|
+
"allowed_values": {},
|
|
1761
|
+
"minimal_example": {
|
|
1762
|
+
"profile": "default",
|
|
1763
|
+
"package_name": "项目管理",
|
|
1764
|
+
"icon": "files-folder",
|
|
1765
|
+
"color": "azure",
|
|
1766
|
+
},
|
|
1767
|
+
},
|
|
1711
1768
|
"member_search": {
|
|
1712
1769
|
"allowed_keys": ["query", "page_num", "page_size", "contain_disable"],
|
|
1713
1770
|
"aliases": {},
|
|
@@ -200,6 +200,7 @@ class PackageTools(ToolBase):
|
|
|
200
200
|
compact = {
|
|
201
201
|
"tagId": result.get("tagId"),
|
|
202
202
|
"tagName": result.get("tagName"),
|
|
203
|
+
"tagIcon": result.get("tagIcon") if result.get("tagIcon") is not None else permission_source.get("tagIcon"),
|
|
203
204
|
"publishStatus": result.get("publishStatus") if result.get("publishStatus") is not None else permission_source.get("publishStatus"),
|
|
204
205
|
"beingTrial": result.get("beingTrial"),
|
|
205
206
|
"itemCount": len(tag_items),
|