@josephyan/qingflow-app-user-mcp 0.2.0-beta.1007 → 0.2.0-beta.1008

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 CHANGED
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.1007
6
+ npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.1008
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.1007 qingflow-app-user-mcp
12
+ npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.1008 qingflow-app-user-mcp
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-app-user-mcp",
3
- "version": "0.2.0-beta.1007",
3
+ "version": "0.2.0-beta.1008",
4
4
  "description": "Operational end-user MCP for Qingflow records, tasks, comments, and directory workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "0.2.0b1007"
7
+ version = "0.2.0b1008"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
 
6
6
  __all__ = ["__version__"]
7
7
 
8
- _FALLBACK_VERSION = "0.2.0b1007"
8
+ _FALLBACK_VERSION = "0.2.0b1008"
9
9
 
10
10
 
11
11
  def _resolve_local_pyproject_version() -> str | None:
@@ -212,25 +212,15 @@ def _run_task_workbench_task_loop(args: argparse.Namespace, context: CliContext)
212
212
  detail_selection = _show_task_workbench_detail(args, task_context)
213
213
  if detail_selection.status == "cancelled":
214
214
  return "back", ""
215
- if str(detail_selection.value or "") == "exit":
215
+ selected_value = str(detail_selection.value or "").strip()
216
+ if selected_value == "exit":
216
217
  return "result", cancelled_result("已退出")
217
- if str(detail_selection.value or "") != "action":
218
+ if selected_value == "back":
218
219
  return "back", ""
219
-
220
- action_selection = _choose_task_action_interactively(
221
- args,
222
- task_context,
223
- fields={},
224
- title=_build_task_action_title(task_context),
225
- )
226
- if action_selection.status == "cancelled":
227
- continue
228
- if action_selection.status == "empty":
220
+ if not selected_value:
229
221
  continue
230
- if action_selection.status != "selected":
231
- return "result", cancelled_result("已退出")
232
222
 
233
- args.action = str(action_selection.value or "").strip()
223
+ args.action = selected_value
234
224
  payload_selection = _resolve_action_payload_or_select(args, task_context, payload={})
235
225
  if _is_cancelled_result(payload_selection):
236
226
  continue
@@ -421,35 +411,8 @@ def _choose_task_action_interactively(
421
411
  fields: dict[str, Any],
422
412
  title: str = "选择操作",
423
413
  ):
424
- data = task_context.get("data") if isinstance(task_context.get("data"), dict) else {}
425
- available_actions = [str(item).strip() for item in (data.get("available_actions") or []) if str(item).strip()]
426
- extras = data.get("extras") if isinstance(data.get("extras"), dict) else {}
427
- action_metadata = data.get("action_metadata") if isinstance(data.get("action_metadata"), dict) else {}
428
- feedback_required = {
429
- str(item).strip()
430
- for item in (action_metadata.get("feedback_required_for") or [])
431
- if str(item).strip()
432
- }
433
- rollback_count = _count_candidate_items(extras.get("rollback_candidates"))
434
- transfer_count = _count_candidate_items(extras.get("transfer_candidates"))
435
-
436
414
  def load_options() -> list[SelectionOption[str]]:
437
- options: list[SelectionOption[str]] = []
438
- for action in available_actions:
439
- if action == "save_only" and not fields:
440
- continue
441
- label = TASK_ACTION_LABELS.get(action, action)
442
- hint_parts = [action]
443
- if action in feedback_required:
444
- hint_parts.append("需要理由")
445
- if action == "rollback":
446
- hint_parts.append(f"可退回节点 {rollback_count}")
447
- if action == "transfer":
448
- hint_parts.append(f"可转交成员 {transfer_count}")
449
- if action == "save_only":
450
- hint_parts.append("仅保存字段,不推进流程")
451
- options.append(SelectionOption(value=action, label=label, hint=" · ".join(hint_parts)))
452
- return options
415
+ return _task_interactive_action_options(task_context, fields=fields)
453
416
 
454
417
  return resolve_interactive_selection(
455
418
  args,
@@ -461,14 +424,11 @@ def _choose_task_action_interactively(
461
424
 
462
425
 
463
426
  def _show_task_workbench_detail(args: argparse.Namespace, task_context: dict[str, Any]):
464
- has_actions = _task_has_interactive_actions(task_context)
465
-
466
427
  def load_options() -> list[SelectionOption[str]]:
467
- if has_actions:
468
- return [
469
- SelectionOption(value="action", label="执行操作", hint="查看当前节点可执行动作"),
470
- SelectionOption(value="back", label="返回列表", hint="回到待办列表"),
471
- ]
428
+ options = _task_interactive_action_options(task_context, fields={})
429
+ if options:
430
+ options.append(SelectionOption(value="back", label="返回列表", hint="回到待办列表"))
431
+ return options
472
432
  return [
473
433
  SelectionOption(value="back", label="返回列表", hint="当前节点没有可执行动作"),
474
434
  SelectionOption(value="exit", label="退出工作台", hint="结束当前待办工作台"),
@@ -697,10 +657,6 @@ def _build_task_detail_title(task_context: dict[str, Any]) -> str:
697
657
  return "\n".join(lines)
698
658
 
699
659
 
700
- def _build_task_action_title(task_context: dict[str, Any]) -> str:
701
- return _build_task_detail_title(task_context) + "\n\n选择操作"
702
-
703
-
704
660
  def _task_initiator_label(initiator: dict[str, Any]) -> str:
705
661
  for key in ("display_name", "displayName", "name", "email", "uid"):
706
662
  value = initiator.get(key)
@@ -709,10 +665,35 @@ def _task_initiator_label(initiator: dict[str, Any]) -> str:
709
665
  return "-"
710
666
 
711
667
 
712
- def _task_has_interactive_actions(task_context: dict[str, Any]) -> bool:
668
+ def _task_interactive_action_options(task_context: dict[str, Any], *, fields: dict[str, Any]) -> list[SelectionOption[str]]:
713
669
  data = task_context.get("data") if isinstance(task_context.get("data"), dict) else {}
714
670
  available_actions = [str(item).strip() for item in (data.get("available_actions") or []) if str(item).strip()]
715
- return any(action != "save_only" for action in available_actions)
671
+ action_metadata = data.get("action_metadata") if isinstance(data.get("action_metadata"), dict) else {}
672
+ extras = data.get("extras") if isinstance(data.get("extras"), dict) else {}
673
+ feedback_required = {
674
+ str(item).strip()
675
+ for item in (action_metadata.get("feedback_required_for") or [])
676
+ if str(item).strip()
677
+ }
678
+ rollback_count = _count_candidate_items(extras.get("rollback_candidates"))
679
+ transfer_count = _count_candidate_items(extras.get("transfer_candidates"))
680
+
681
+ options: list[SelectionOption[str]] = []
682
+ for action in available_actions:
683
+ if action == "save_only" and not fields:
684
+ continue
685
+ label = TASK_ACTION_LABELS.get(action, action)
686
+ hint_parts = [action]
687
+ if action in feedback_required:
688
+ hint_parts.append("需要理由")
689
+ if action == "rollback":
690
+ hint_parts.append(f"可退回节点 {rollback_count}")
691
+ if action == "transfer":
692
+ hint_parts.append(f"可转交成员 {transfer_count}")
693
+ if action == "save_only":
694
+ hint_parts.append("仅保存字段,不推进流程")
695
+ options.append(SelectionOption(value=action, label=label, hint=" · ".join(hint_parts)))
696
+ return options
716
697
 
717
698
 
718
699
  def _full_display(value: Any) -> str: