@qingflow-tech/qingflow-cli 1.1.47-beta.1 → 1.1.47-beta.3

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.
@@ -9,15 +9,27 @@ from mcp.server.fastmcp import FastMCP
9
9
  from ..config import DEFAULT_PROFILE, get_web_base_url
10
10
  from ..errors import QingflowApiError
11
11
  from ..json_types import JSONObject
12
+ from ..resource_uri import parse_resource_path
12
13
  from .base import ToolBase
13
14
 
14
15
  LOGIN_LINK_DESCRIPTION = (
15
16
  "轻流页面入口:查看页面、继续编辑、处理业务、查看结果或进入工作区(open/view/visit page in browser,login)。"
16
17
  "从 AI 对话进入页面时,使用当前 MCP 身份和工作区生成短时(约 5 分钟)一次性免登录链接。"
17
18
  "redirect_path 可选:传已确认的站内业务路径,可带 query/hash;省略进入首页,不接受外部地址或认证入口。"
18
- "纯数据查询无需调用;用户指定页面但路径未知时先定位,不猜路径或静默改为首页。"
19
+ "用户指定页面但路径未知时先定位,不猜路径或静默改为首页。"
19
20
  "返回 url 和毫秒整数 expires_at;必要安全验证及原有页面权限仍然生效。"
20
- "用户要链接时仅交付,不提前消费;要求打开时才用浏览器打开返回的完整链接。"
21
+ "创建、修改或安装轻流资源后,最终回复主动提供主要结果的可点击页面入口,无需等待用户再次索要;"
22
+ "采用“完成结果 + 查看入口”,文案使用“在轻流中查看应用/应用包/视图”,不默认称为“继续编辑”。"
23
+ "安装方案默认提供应用包入口;直接创建或修改应用、视图时提供对应入口;用户明确要求多个主要对象时分别提供。"
24
+ "使用业务结果中的稳定 `uri`,按 URI 去重,不为全部子资源预签票据;主要对象没有可靠 URI 时说明限制,不猜地址或替换为不相关页面。"
25
+ "部分成功时仅交付已确认成功且可定位的主要结果,保留失败或未验证说明;"
26
+ "纯数据问答、中间读取、失败资源和删除操作不自动签发,用户明确要求不提供链接时遵从。"
27
+ "目标浏览器登录态未知时,临近交付用资源 URI 的同源 pathname 为每个实际展示的入口分别签发,使用返回的完整 URL,不额外追问登录态。"
28
+ "只有已有用户确认同一浏览器、网页域名、账号和工作区已登录且无失效信号的事实时,才直接交付稳定 URI;"
29
+ "调用过本工具或 Agent 自动化浏览器已登录不等于用户浏览器已登录,已消费链接不可复用。"
30
+ "用户未要求打开时不提前打开或消费链接;要求打开时才用浏览器打开返回的完整链接。"
31
+ "签发失败时说明免登录链接未生成,提供标注“需登录”的稳定 URI 作为备用入口,不重做业务操作。"
32
+ "机器结果继续保留稳定 URI,临时登录链接仅用于面向用户交付。"
21
33
  )
22
34
 
23
35
 
@@ -70,7 +82,23 @@ class LoginLinkTools(ToolBase):
70
82
  """执行工具方法逻辑。"""
71
83
 
72
84
  def runner(session_profile, context):
73
- target = validate_redirect_path(redirect_path)
85
+ requested_target = redirect_path or ""
86
+ if requested_target.startswith("/resources"):
87
+ target = requested_target
88
+ try:
89
+ resource = parse_resource_path(target)
90
+ except ValueError:
91
+ raise QingflowApiError(
92
+ category="validation",
93
+ message="redirect_path 必须是合法的稳定资源路径",
94
+ ) from None
95
+ if resource.ws_id != session_profile.selected_ws_id:
96
+ raise QingflowApiError(
97
+ category="validation",
98
+ message="redirect_path 的资源工作区必须与当前选中工作区一致",
99
+ )
100
+ else:
101
+ target = validate_redirect_path(requested_target)
74
102
  web_base_url = get_web_base_url()
75
103
  result = self.backend.request(
76
104
  "POST",
@@ -6,6 +6,7 @@ from typing import Any
6
6
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
7
7
  from ..json_types import JSONObject
8
8
  from ..list_type_labels import SYSTEM_VIEW_DEFINITIONS
9
+ from ..resource_uri import try_build_resource_uri
9
10
  from ..solution.compiler.icon_utils import workspace_icon_config
10
11
  from .app_tools import _analysis_supported_for_view_type
11
12
  from .base import ToolBase
@@ -227,6 +228,17 @@ class ResourceReadTools(ToolBase):
227
228
  "message": f"view_get supports exporting `{view_id}`, but the export call still needs an explicit `app_key` from the parent app context.",
228
229
  }
229
230
  )
231
+ uri = None
232
+ if resolved_app_key:
233
+ uri, uri_warning = try_build_resource_uri(
234
+ ws_id=session_profile.selected_ws_id,
235
+ resource_type="view",
236
+ app_key=resolved_app_key,
237
+ view_kind="custom",
238
+ view_key=view_key,
239
+ )
240
+ if uri_warning:
241
+ warnings.append(uri_warning)
230
242
  return {
231
243
  "profile": profile,
232
244
  "ws_id": session_profile.selected_ws_id,
@@ -249,6 +261,7 @@ class ResourceReadTools(ToolBase):
249
261
  ],
250
262
  "analysis_supported": _analysis_supported_for_view_type(raw_view_type or None),
251
263
  "export_capability": export_capability,
264
+ **({"uri": uri} if uri else {}),
252
265
  },
253
266
  }
254
267