@qingflow-tech/qingflow-cli 1.1.47-beta.2 → 1.1.47-beta.4
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 +3 -3
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-cli/SKILL.md +15 -5
- package/skills/qingflow-common/SKILL.md +10 -5
- package/src/qingflow_mcp/cli/main.py +4 -1
- package/src/qingflow_mcp/resource_uri.py +58 -2
- package/src/qingflow_mcp/server_app_builder.py +10 -1
- package/src/qingflow_mcp/server_app_user.py +6 -4
- package/src/qingflow_mcp/tools/login_link_tools.py +13 -5
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Qingflow CLI 是轻流面向开发者和 AI Agent 的命令行工具。它把轻
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install @qingflow-tech/qingflow-cli@1.1.47-beta.
|
|
10
|
+
npm install @qingflow-tech/qingflow-cli@1.1.47-beta.4
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
推荐从官网复制这一条一键安装 Qingflow CLI:
|
|
@@ -21,7 +21,7 @@ npx qingflow-cli@latest install
|
|
|
21
21
|
## 运行
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npx -y -p @qingflow-tech/qingflow-cli@1.1.47-beta.
|
|
24
|
+
npx -y -p @qingflow-tech/qingflow-cli@1.1.47-beta.4 qingflow
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
全局安装后可以直接运行:
|
|
@@ -62,7 +62,7 @@ qingflow-skills install --agent codex --scope user
|
|
|
62
62
|
如果你通过一次性 `npx -p` 执行 skills 安装,建议加 `--copy`,避免 symlink 指向 npm 临时执行缓存:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
npx -y -p @qingflow-tech/qingflow-cli@1.1.47-beta.
|
|
65
|
+
npx -y -p @qingflow-tech/qingflow-cli@1.1.47-beta.4 qingflow-skills install --agent codex --scope user --copy
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
`qingflow-skills install` 默认使用 symlink,且遇到同名 skill 不会覆盖;只有显式传入 `--force` 才会替换。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qingflow-tech/qingflow-cli",
|
|
3
|
-
"version": "1.1.47-beta.
|
|
3
|
+
"version": "1.1.47-beta.4",
|
|
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
|
@@ -126,13 +126,23 @@ qingflow --json auth whoami
|
|
|
126
126
|
|
|
127
127
|
### 交付网页资源链接
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
创建、修改或安装轻流资源后,最终回复主动提供主要结果的可点击页面入口,无需等待用户再次索要。采用“完成结果 + 查看入口”,文案使用“在轻流中查看应用/应用包/视图”,不默认称为“继续编辑”。
|
|
130
|
+
|
|
131
|
+
默认只交付用户请求的主要结果:安装方案默认提供应用包入口;直接创建或修改应用、视图时提供对应入口;用户明确要求多个主要对象时分别提供。使用业务结果中的稳定 `uri`,按 URI 去重,不为全部子资源预签票据。主要对象没有可靠 URI 时说明限制,不猜地址,也不替换为不相关页面。
|
|
132
|
+
|
|
133
|
+
CLI 返回的稳定 `uri` 以 `QINGFLOW_BASE_URL` 为当前环境来源:去除末尾 API 路径后使用同一 HTTP(S) 域名;仅当该变量为空时回退 `https://qingflow.com`。若非空配置非法,保留 URI 不可用诊断,不自行替换或拼接其他环境地址。
|
|
134
|
+
|
|
135
|
+
部分成功时仅交付已确认成功且可定位的主要结果,保留失败或未验证说明。纯数据问答、中间读取、失败资源和删除操作不自动签发;用户明确要求不提供链接时遵从。用户明确要求查看或打开页面时也使用已确认的路径。
|
|
136
|
+
|
|
137
|
+
目标浏览器登录态未知时,临近交付取该 URI 的 pathname 执行:
|
|
130
138
|
|
|
131
139
|
```bash
|
|
132
140
|
qingflow auth login-link --redirect-path "/resources/ws/<WS_ID>/app/<APP_KEY>"
|
|
133
141
|
```
|
|
134
142
|
|
|
135
|
-
|
|
143
|
+
对每个实际展示的入口分别签发,使用本次返回的完整 URL,不额外追问登录态,不复用已消费链接。只有已有用户确认同一浏览器、网页域名、账号和工作区已登录、没有失效信号的事实,才直接交付稳定 `uri`。CLI 已登录、自动化浏览器已登录或曾经成功签发票据都不能证明目标浏览器已登录。
|
|
144
|
+
|
|
145
|
+
用户未要求打开时不要提前打开或消费链接;签发失败时说明免登录链接未生成,并提供标注“需登录”的稳定 `uri` 作为备用入口,不重做业务操作。机器结果继续保留稳定 URI,临时登录链接仅用于面向用户交付。
|
|
136
146
|
|
|
137
147
|
常用参数:`--credential-stdin`、`--password-stdin`、`--persist` / `--forget-persisted`;详见 `qingflow auth --help`。
|
|
138
148
|
|
|
@@ -459,17 +469,17 @@ qingflow auth logout --forget-persisted
|
|
|
459
469
|
|
|
460
470
|
### 临时网页登录链接
|
|
461
471
|
|
|
462
|
-
|
|
472
|
+
按上文“交付网页资源链接”规则,在创建、修改或安装完成后主动为主要结果提供查看入口;用户明确要求进入页面时也适用,纯数据问答不自动调用:
|
|
463
473
|
|
|
464
474
|
```bash
|
|
465
475
|
qingflow --json auth login-link
|
|
466
|
-
qingflow --profile default --json auth login-link --redirect-path "/
|
|
476
|
+
qingflow --profile default --json auth login-link --redirect-path "/resources/ws/<WS_ID>/app/<APP_KEY>"
|
|
467
477
|
```
|
|
468
478
|
|
|
469
479
|
- 默认使用当前会话和已选工作区;缺失时按实际错误恢复,不额外预查或重新登录。
|
|
470
480
|
- `--redirect-path` 可选,仅接受已确认的站内业务路径,可包含 query/hash;不接受外域或认证入口。示例 ID 仅作格式展示,不得照抄或编造实际目标;省略时进入工作区首页。
|
|
471
481
|
- 将返回的 `url` 作为可点击链接交付,不修改或拼造。链接短时有效且仅可使用一次,失效后重新获取,不写入公共文档或日志。
|
|
472
|
-
-
|
|
482
|
+
- 命令不会自动打开浏览器;用户未要求打开时不提前打开或消费链接,明确要求打开时才调用浏览器。
|
|
473
483
|
|
|
474
484
|
**高发必败**:旧应用搜索入口 · **`record list`/`browse`/`access` 缺 `--view-id`** · **`task report` 缺 `--report-id`** · **`record update` 批量与单条参数混用**。
|
|
475
485
|
|
|
@@ -45,7 +45,12 @@ Each package includes this common Skill. The CLI package installs its CLI guidan
|
|
|
45
45
|
|
|
46
46
|
## 从 AI 对话进入轻流页面
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
创建、修改或安装轻流资源后,最终回复主动提供主要结果的可点击页面入口,无需等待用户再次索要。采用“完成结果 + 查看入口”,文案使用“在轻流中查看应用/应用包/视图”,不默认称为“继续编辑”。用户明确要求查看或打开页面时也适用以下规则。
|
|
49
|
+
|
|
50
|
+
- 默认只交付用户请求的主要结果:安装方案默认提供应用包入口;直接创建或修改应用、视图时提供对应入口;用户明确要求多个主要对象时分别提供。使用业务结果中的稳定 `uri`,按 URI 去重,不为全部子资源预签票据。
|
|
51
|
+
- 主要对象没有可靠 URI 时说明限制,不猜地址,也不替换为不相关页面。部分成功时仅交付已确认成功且可定位的主要结果,保留失败或未验证说明,不把链接当作整个任务成功的证明。
|
|
52
|
+
- 纯数据问答、中间读取、失败资源和删除操作不自动签发;用户明确要求不提供链接时遵从。
|
|
53
|
+
- MCP 调用 `get_login_link`;CLI 调用 `qingflow --json auth login-link --redirect-path <资源 pathname>`。
|
|
49
54
|
|
|
50
55
|
- 目标路径使用用户提供或业务工具确认的站内路径,不根据应用、记录标识猜测地址。
|
|
51
56
|
- 用户明确指定页面但路径未知时继续定位或说明限制,不猜测,也不静默替换成首页。搜索未命中时继续搜索 `login` 或查看服务工具列表,不擅自打开固定正式站点;失败时如实说明。
|
|
@@ -53,12 +58,12 @@ Each package includes this common Skill. The CLI package installs its CLI guidan
|
|
|
53
58
|
- 默认使用当前会话及已选工作区;需要指定会话时使用 MCP 的 `profile` 或 CLI 的 `--profile`。
|
|
54
59
|
- `redirect_path` 可选,默认空:省略时进入工作区首页;传入时仅支持以单个 `/` 开头的站内业务路径,可带 query/hash。不得传完整 URL、外部地址、认证入口或多层编码路径。
|
|
55
60
|
- 示例:`get_login_link({})`;指定目标示例:`get_login_link({"redirect_path":"/index/app/123?view=abc"})`。示例标识仅作格式展示,实际目标必须来自用户提供或已经确认的页面信息,不得编造应用、记录标识。
|
|
56
|
-
- 成功响应仅有 `url` 和毫秒整数 `expires_at
|
|
61
|
+
- 成功响应仅有 `url` 和毫秒整数 `expires_at`。临近交付时再签发,使用本次返回的完整链接作为主要点击入口,不展示工作区数字 ID 或原始 JSON。
|
|
57
62
|
- CLI 示例:`qingflow --json auth login-link`;指定目标使用 `qingflow --profile default --json auth login-link --redirect-path "/index/app/123?view=abc"`,同样不得编造实际路径。
|
|
58
|
-
-
|
|
63
|
+
- 目标浏览器状态未知时,默认按每个待交付资源分别签发新链接,不额外追问登录态。只有已有用户确认目标是同一浏览器、网页域名、账号和工作区且已登录、没有失效信号的事实,才直接交付稳定 `uri`。调用过票据工具、自动化浏览器已登录或之前签发过票据都不是该事实;已消费链接不可复用。
|
|
59
64
|
- 链接约 5 分钟内只能兑换一次,不作为长期书签;过期或使用后重新调用,不修改票据或拼造链接;只交付给请求用户,不写入公共文档或日志。
|
|
60
|
-
-
|
|
61
|
-
-
|
|
65
|
+
- 用户未要求打开时仅交付,不提前消费;要求“打开”时才使用可用浏览器打开。浏览器不可用时提供可点击链接,不假称已经打开。
|
|
66
|
+
- 签发失败时说明免登录链接未生成,并提供标注“需登录”的稳定 `uri` 作为备用入口,不重做业务操作。机器结果继续保留稳定 URI,临时登录链接仅用于面向用户交付。
|
|
62
67
|
- 必要的 MFA、密码安全验证仍执行,完成后先切换当前 MCP 工作区,再进入目标页面;业务权限仍由目标页面校验,不因链接而扩大。
|
|
63
68
|
- 工具拒绝非法跳转参数;浏览器收到被篡改的非法目标时忽略目标并进入首页。网页域名由 MCP 配置 `QINGFLOW_MCP_WEB_BASE_URL` 决定,不从目标路径选择其他环境。
|
|
64
69
|
|
|
@@ -2,11 +2,13 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import json
|
|
5
|
+
import os
|
|
5
6
|
import sys
|
|
6
7
|
from typing import Any, Callable, TextIO
|
|
7
8
|
|
|
8
9
|
from ..errors import QingflowApiError, backend_code_value_int, message_looks_like_invalid_token
|
|
9
10
|
from ..public_surface import cli_public_tool_spec_from_namespace
|
|
11
|
+
from ..resource_uri import cli_resource_base_url
|
|
10
12
|
from ..response_trim import resolve_cli_tool_name, trim_error_response, trim_public_response
|
|
11
13
|
from ..tools.ai_builder_tools import _attach_builder_apply_envelope
|
|
12
14
|
from ..version import get_cli_version, get_cli_version_info
|
|
@@ -94,7 +96,8 @@ def run(
|
|
|
94
96
|
context = context_factory()
|
|
95
97
|
if not bool(args.json):
|
|
96
98
|
_emit_cli_effective_context_notice(args, context, stream=err)
|
|
97
|
-
|
|
99
|
+
with cli_resource_base_url(os.getenv("QINGFLOW_BASE_URL") or ""):
|
|
100
|
+
result = handler(args, context)
|
|
98
101
|
except SystemExit as exc:
|
|
99
102
|
return int(exc.code or 0)
|
|
100
103
|
except RuntimeError as exc:
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
+
from collections.abc import Iterator
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from contextvars import ContextVar
|
|
4
7
|
from dataclasses import dataclass
|
|
5
8
|
from typing import Any
|
|
6
9
|
from urllib.parse import quote, unquote, urlsplit, urlunsplit
|
|
7
10
|
|
|
8
|
-
from .config import get_web_base_url
|
|
11
|
+
from .config import DEFAULT_WEB_BASE_URL, get_web_base_url
|
|
9
12
|
from .errors import QingflowApiError
|
|
10
13
|
from .json_types import JSONObject
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
SYSTEM_VIEW_NAMES = frozenset({"all", "initiated", "todo", "done", "cc"})
|
|
14
17
|
_ENCODED_OCTET = re.compile(r"%[0-9A-Fa-f]{2}")
|
|
18
|
+
_CLI_RESOURCE_BASE_URL: ContextVar[str | None] = ContextVar(
|
|
19
|
+
"qingflow_cli_resource_base_url",
|
|
20
|
+
default=None,
|
|
21
|
+
)
|
|
15
22
|
|
|
16
23
|
|
|
17
24
|
@dataclass(frozen=True, slots=True)
|
|
@@ -24,6 +31,16 @@ class ResourcePath:
|
|
|
24
31
|
view_key: str | None = None
|
|
25
32
|
|
|
26
33
|
|
|
34
|
+
@contextmanager
|
|
35
|
+
def cli_resource_base_url(value: str) -> Iterator[None]:
|
|
36
|
+
"""让一次 CLI 调用的资源 URI 使用 QINGFLOW_BASE_URL 对应的网页环境。"""
|
|
37
|
+
token = _CLI_RESOURCE_BASE_URL.set(value)
|
|
38
|
+
try:
|
|
39
|
+
yield
|
|
40
|
+
finally:
|
|
41
|
+
_CLI_RESOURCE_BASE_URL.reset(token)
|
|
42
|
+
|
|
43
|
+
|
|
27
44
|
def validate_resource_identity(value: object, field: str = "resource_id") -> str:
|
|
28
45
|
"""按资源 URI 单路径段合同校验并返回规范身份,不读取网页域名配置。"""
|
|
29
46
|
return _validate_identity(value, field)
|
|
@@ -64,7 +81,7 @@ def build_resource_uri(
|
|
|
64
81
|
path = f"/resources/ws/{workspace}/app/{app_segment}/view/{view_kind}/{view_segment}"
|
|
65
82
|
else:
|
|
66
83
|
raise ValueError("resource_type is not supported")
|
|
67
|
-
return f"{
|
|
84
|
+
return f"{_resolve_web_origin(web_origin)}{path}"
|
|
68
85
|
|
|
69
86
|
|
|
70
87
|
def parse_resource_path(value: str) -> ResourcePath:
|
|
@@ -142,6 +159,45 @@ def _normalize_web_origin(value: str) -> str:
|
|
|
142
159
|
return urlunsplit((parsed.scheme, parsed.netloc, "", "", ""))
|
|
143
160
|
|
|
144
161
|
|
|
162
|
+
def _resolve_web_origin(web_origin: str | None) -> str:
|
|
163
|
+
if web_origin is not None:
|
|
164
|
+
return _normalize_web_origin(web_origin)
|
|
165
|
+
cli_base_url = _CLI_RESOURCE_BASE_URL.get()
|
|
166
|
+
if cli_base_url is None:
|
|
167
|
+
return get_web_base_url()
|
|
168
|
+
return _web_origin_from_api_base_url(cli_base_url)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _web_origin_from_api_base_url(value: str) -> str:
|
|
172
|
+
normalized = value.strip()
|
|
173
|
+
if not normalized:
|
|
174
|
+
return DEFAULT_WEB_BASE_URL
|
|
175
|
+
try:
|
|
176
|
+
parsed = urlsplit(normalized)
|
|
177
|
+
host = parsed.hostname or ""
|
|
178
|
+
valid_host = bool(host) and (":" in host or all(
|
|
179
|
+
re.fullmatch(r"[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?", label)
|
|
180
|
+
for label in host.rstrip(".").split(".")
|
|
181
|
+
))
|
|
182
|
+
if (
|
|
183
|
+
parsed.scheme not in {"http", "https"}
|
|
184
|
+
or not valid_host
|
|
185
|
+
or host.lower() in {"null", "undefined"}
|
|
186
|
+
or parsed.username is not None
|
|
187
|
+
or parsed.password is not None
|
|
188
|
+
or parsed.query
|
|
189
|
+
or parsed.fragment
|
|
190
|
+
or any(character.isspace() or ord(character) < 32 for character in normalized)
|
|
191
|
+
):
|
|
192
|
+
raise ValueError
|
|
193
|
+
_ = parsed.port
|
|
194
|
+
return _normalize_web_origin(urlunsplit((parsed.scheme, parsed.netloc, "", "", "")))
|
|
195
|
+
except ValueError:
|
|
196
|
+
raise QingflowApiError.config_error(
|
|
197
|
+
"QINGFLOW_BASE_URL 必须是有效的 HTTP(S) API 地址,不包含查询参数、片段或用户凭证"
|
|
198
|
+
) from None
|
|
199
|
+
|
|
200
|
+
|
|
145
201
|
def _identity_segment(value: object, field: str) -> str:
|
|
146
202
|
raw = _validate_identity(value, field)
|
|
147
203
|
return quote(raw, safe="")
|
|
@@ -42,7 +42,16 @@ def build_builder_server() -> FastMCP:
|
|
|
42
42
|
"member_search/role_search/role_create when workflow assignees must come from the directory or role catalog, preferring roles over explicit members unless the user explicitly names members, "
|
|
43
43
|
"then app_form_apply for complete app form targets, explicit app_delete for application deletion, and app_flow_apply/app_views_apply/app_associated_resources_apply/app_charts_apply/portal_apply/portal_delete for non-form patches. app_custom_buttons_apply is maintenance-only for explicit standalone button work outside normal view design. These apply/delete tools perform validation, normalization, writes, and readback verification where applicable. AppForm publishes only after a draft change or when the published form lags behind; views noop requests skip publish, app_custom_buttons_apply and app_associated_resources_apply publish after at least one write succeeds and expose no draft-only parameter, charts are immediate-live without publish and resolve targets by chart_id first then exact unique chart name, portal updates use replace semantics only when sections are supplied and edit-mode base-info-only updates may omit sections, portal delete separates DELETE execution from readback verification, portal pc layout is a 24-column grid and mobile is a 6-column grid so omit position or use layout_preset when unsure, publish=false only guarantees draft/base-info updates for tools that still expose that parameter, and flow should use publish=false whenever you only want draft/precheck behavior. "
|
|
44
44
|
"Builder apply/write outputs include schema_version, operation, summary, and resources[]; use resources[].id/key/name/ids/parent as the stable UI and agent display entry, and keep legacy fields such as field_diff/views_diff/chart_results only for compatibility or troubleshooting. "
|
|
45
|
-
"
|
|
45
|
+
"创建、修改或安装轻流资源后,最终回复主动提供主要结果的可点击页面入口,无需等待用户再次索要。"
|
|
46
|
+
"采用“完成结果 + 查看入口”,文案使用“在轻流中查看应用/应用包/视图”,不默认称为“继续编辑”。"
|
|
47
|
+
"默认只交付用户请求的主要结果:安装方案默认提供应用包入口;直接创建或修改应用、视图时提供对应入口;用户明确要求多个主要对象时分别提供。"
|
|
48
|
+
"使用业务结果中的稳定 `uri`,按 URI 去重,不为全部子资源预签票据;主要对象没有可靠 URI 时说明限制,不猜地址,也不替换为不相关页面。"
|
|
49
|
+
"部分成功时仅交付已确认成功且可定位的主要结果,保留失败或未验证说明。"
|
|
50
|
+
"纯数据问答、中间读取、失败资源和删除操作不自动签发;用户明确要求不提供链接时遵从。用户明确要求查看或打开页面时也使用已确认的路径。"
|
|
51
|
+
"目标浏览器登录态未知时,临近交付用资源 URI 的同源 pathname 调用 get_login_link,为每个实际展示的入口分别签发,使用返回的完整 URL,不额外追问登录态。"
|
|
52
|
+
"只有已有用户确认同一浏览器、网页域名、账号和工作区已登录且无失效信号的事实时,才直接交付稳定 URI;调用过票据工具、自动化浏览器已登录或之前签发过票据均不能证明用户浏览器已登录,已消费链接不可复用。"
|
|
53
|
+
"用户未要求打开时不提前打开或消费链接;浏览器不可用时提供可点击链接,不假称已经打开。"
|
|
54
|
+
"签发失败时说明免登录链接未生成,提供标注“需登录”的稳定 URI 作为备用入口,不重做业务操作。机器结果继续保留稳定 URI,临时登录链接仅用于面向用户交付。 "
|
|
46
55
|
"For existing object parameter replacement, prefer patch_views, patch_buttons, patch_resources, and patch_charts with set/unset; the tool reads current config and full-saves internally, while upsert_* is for creation or full target configuration and should not be used as an incomplete partial update. "
|
|
47
56
|
"For builder delete/remove apply results, separate delete execution from readback verification: after DELETE is sent, resources expose delete_executed, readback_status, and safe_to_retry_delete=false. If readback_status is unavailable or still_exists, do not blindly repeat the delete; confirm later with app_get/view_get/chart_get or the relevant apply readback. Views/buttons use single-item readback; associated resources use one app-level resource-pool readback because there is no confirmed single-item GET. "
|
|
48
57
|
"For builder write/apply results, separate write execution from final readback verification: status=partial_success with write_executed=true and safe_to_retry=false means the write was sent or succeeded, while final readback, publish verification, or metadata confirmation is pending or permission-restricted. Report it as written but unverified; do not repeat the same write blindly. "
|
|
@@ -33,13 +33,15 @@ def build_user_server(*, stateless_http: bool = False) -> FastMCP:
|
|
|
33
33
|
|
|
34
34
|
## 页面交接
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
创建、修改或安装轻流资源后,最终回复主动提供主要结果的可点击页面入口,无需等待用户再次索要。采用“完成结果 + 查看入口”,文案使用“在轻流中查看应用/应用包/视图”,不默认称为“继续编辑”。用户明确要求查看或打开页面时也适用以下规则。
|
|
37
|
+
默认只交付用户请求的主要结果:安装方案默认提供应用包入口;直接创建或修改应用、视图时提供对应入口;用户明确要求多个主要对象时分别提供。使用业务结果中的稳定 `uri`,按 URI 去重,不为全部子资源预签票据。
|
|
38
|
+
主要对象没有可靠 URI 时说明限制,不猜地址,也不替换为不相关页面。部分成功时仅交付已确认成功且可定位的主要结果,保留失败或未验证说明。纯数据问答、中间读取、失败资源和删除操作不自动签发;用户明确要求不提供链接时遵从。
|
|
37
39
|
目标路径由业务工具或领域 Skill 根据真实前端路由确定,不由票据工具根据业务标识推导。
|
|
38
40
|
已知目标传可选 `redirect_path`;明确指定页面但路径未知时继续定位或说明限制,不猜测,也不静默改为首页。
|
|
39
41
|
搜索未命中时继续搜索 `login` 或查看服务工具列表,不擅自打开固定正式站点;鉴权或工具失败时如实说明。
|
|
40
|
-
|
|
41
|
-
临近交付时再签发,使用返回的完整 URL
|
|
42
|
-
|
|
42
|
+
目标浏览器登录态未知时,默认用资源 URI 的同源 pathname 调用 `get_login_link`,为每个实际展示的入口分别签发,不额外追问登录态;只有已有用户确认同一浏览器、网页域名、账号和工作区已登录且无失效信号的事实时,才直接交付稳定 URI。调用过票据工具、自动化浏览器已登录或之前签发过票据均不能证明用户浏览器已登录,已消费链接也不能复用。
|
|
43
|
+
临近交付时再签发,使用返回的完整 URL。用户未要求打开时仅交付,不提前消费;要求“打开”时才调用浏览器。签发失败时说明免登录链接未生成,并提供标注“需登录”的稳定 URI 作为备用入口,不重做业务操作。机器结果继续保留稳定 URI,临时登录链接仅用于面向用户交付。
|
|
44
|
+
浏览器不可用时提供可点击链接,不假称已经打开,不展示工作区数字 ID 或原始 JSON。
|
|
43
45
|
链接约 5 分钟内一次性有效,不能作为长期书签;安全验证及原有业务权限不变。
|
|
44
46
|
|
|
45
47
|
## App Discovery
|
|
@@ -16,12 +16,20 @@ LOGIN_LINK_DESCRIPTION = (
|
|
|
16
16
|
"轻流页面入口:查看页面、继续编辑、处理业务、查看结果或进入工作区(open/view/visit page in browser,login)。"
|
|
17
17
|
"从 AI 对话进入页面时,使用当前 MCP 身份和工作区生成短时(约 5 分钟)一次性免登录链接。"
|
|
18
18
|
"redirect_path 可选:传已确认的站内业务路径,可带 query/hash;省略进入首页,不接受外部地址或认证入口。"
|
|
19
|
-
"
|
|
19
|
+
"用户指定页面但路径未知时先定位,不猜路径或静默改为首页。"
|
|
20
20
|
"返回 url 和毫秒整数 expires_at;必要安全验证及原有页面权限仍然生效。"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
21
|
+
"创建、修改或安装轻流资源后,最终回复主动提供主要结果的可点击页面入口,无需等待用户再次索要;"
|
|
22
|
+
"采用“完成结果 + 查看入口”,文案使用“在轻流中查看应用/应用包/视图”,不默认称为“继续编辑”。"
|
|
23
|
+
"安装方案默认提供应用包入口;直接创建或修改应用、视图时提供对应入口;用户明确要求多个主要对象时分别提供。"
|
|
24
|
+
"使用业务结果中的稳定 `uri`,按 URI 去重,不为全部子资源预签票据;主要对象没有可靠 URI 时说明限制,不猜地址或替换为不相关页面。"
|
|
25
|
+
"部分成功时仅交付已确认成功且可定位的主要结果,保留失败或未验证说明;"
|
|
26
|
+
"纯数据问答、中间读取、失败资源和删除操作不自动签发,用户明确要求不提供链接时遵从。"
|
|
27
|
+
"目标浏览器登录态未知时,临近交付用资源 URI 的同源 pathname 为每个实际展示的入口分别签发,使用返回的完整 URL,不额外追问登录态。"
|
|
28
|
+
"只有已有用户确认同一浏览器、网页域名、账号和工作区已登录且无失效信号的事实时,才直接交付稳定 URI;"
|
|
29
|
+
"调用过本工具或 Agent 自动化浏览器已登录不等于用户浏览器已登录,已消费链接不可复用。"
|
|
30
|
+
"用户未要求打开时不提前打开或消费链接;要求打开时才用浏览器打开返回的完整链接。"
|
|
31
|
+
"签发失败时说明免登录链接未生成,提供标注“需登录”的稳定 URI 作为备用入口,不重做业务操作。"
|
|
32
|
+
"机器结果继续保留稳定 URI,临时登录链接仅用于面向用户交付。"
|
|
25
33
|
)
|
|
26
34
|
|
|
27
35
|
|