@alipay/alipay-aipay 1.5.4 → 1.5.5
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/package.json +1 -1
- package/skill/VERSION +1 -1
- package/skill/references/normal/alipay-cli-env.md +1 -0
- package/skill/references/normal/scripts/common.sh +75 -0
- package/skill/references/onboarding/flow.md +5 -2
- package/skill/references/onboarding/modules/authorization.md +1 -0
- package/skill/references/onboarding/modules/error-handling.md +2 -1
- package/skill/references/onboarding/modules/scripts/auth.sh +41 -8
- package/skill/references/onboarding/modules/scripts/error_handler.sh +42 -4
package/package.json
CHANGED
package/skill/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.5.
|
|
1
|
+
1.5.5
|
|
@@ -43,6 +43,7 @@ fi
|
|
|
43
43
|
- 对已知需要联网的命令,如果当前 Agent 环境网络受限且支持显式授权,应首次执行即申请可联网权限,不要先在受限沙箱内试跑。
|
|
44
44
|
- 若命令已经因网络失败,重试时必须复用同一条命令并申请可联网权限;不要把该失败解释为用户网络故障。
|
|
45
45
|
- `auth.sh init|confirm|mismatch` 返回 `AUTH_FLOW:RETRY_WITH_NETWORK` 时,表示当前 Agent 执行环境没有取得可确认 CLI 结果;必须申请联网权限后重试同一条完整脚本命令,不得解释为支付宝业务失败、logout 失败或 login 失败,也不得要求用户手动 logout/login 代替本轮脚本事实。
|
|
46
|
+
- `auth.sh init|wait|confirm|mismatch` 返回 `AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION` 时,仅表示授权状态命令缺少 CLI 私有状态目录权限。宿主支持时,允许当前同一条受控 runtime 命令访问 `$HOME/.alipay-cli/credentials` 和 `${XDG_DATA_HOME:-$HOME/.local/share}/alipay-cli/logs` 后原样重试一次;权限只供 CLI 自身使用,Agent 禁止读取、列举、打印或复制已有凭据与日志。该规则不改变 MCP、上传或沙箱脚本边界。
|
|
46
47
|
- 本地纯解析、文件检查、`bash -n`、`jq` 校验等不联网命令仍可在默认沙箱内执行。
|
|
47
48
|
|
|
48
49
|
**减少重复授权:**
|
|
@@ -12,6 +12,81 @@ require_command() {
|
|
|
12
12
|
fi
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE=77
|
|
16
|
+
ALIPAY_CLI_LOCAL_STATE_ACCESS_CONFIRMED=false
|
|
17
|
+
|
|
18
|
+
alipay_cli_credentials_dir() {
|
|
19
|
+
case "${HOME:-}" in
|
|
20
|
+
/*) [ "$HOME" != "/" ] || return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE" ;;
|
|
21
|
+
*) return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE" ;;
|
|
22
|
+
esac
|
|
23
|
+
printf '%s/.alipay-cli/credentials' "$HOME"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
alipay_cli_logs_dir() {
|
|
27
|
+
local data_home="${XDG_DATA_HOME:-}"
|
|
28
|
+
if [ -z "$data_home" ]; then
|
|
29
|
+
case "${HOME:-}" in
|
|
30
|
+
/*) [ "$HOME" != "/" ] || return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE" ;;
|
|
31
|
+
*) return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE" ;;
|
|
32
|
+
esac
|
|
33
|
+
data_home="$HOME/.local/share"
|
|
34
|
+
fi
|
|
35
|
+
case "$data_home" in
|
|
36
|
+
/*) ;;
|
|
37
|
+
*) return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE" ;;
|
|
38
|
+
esac
|
|
39
|
+
printf '%s/alipay-cli/logs' "$data_home"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
alipay_cli_has_local_state_permission_error() {
|
|
43
|
+
local raw="${1:-}" permission_pattern private_state_pattern local_state_failure_pattern
|
|
44
|
+
[ -n "$raw" ] || return 1
|
|
45
|
+
|
|
46
|
+
permission_pattern='permission denied|operation not permitted|(^|[^[:alnum:]_])(EACCES|EPERM)([^[:alnum:]_]|$)'
|
|
47
|
+
private_state_pattern='poll_state\.enc\.tmp|session\.enc|\.alipay-cli[/\\]credentials|alipay-cli[/\\]logs'
|
|
48
|
+
local_state_failure_pattern='写入临时文件失败|删除凭据文件失败|can.?t rename log file'
|
|
49
|
+
|
|
50
|
+
printf '%s' "$raw" | grep -qiE "$local_state_failure_pattern" && return 0
|
|
51
|
+
printf '%s' "$raw" | grep -qiE "$permission_pattern" || return 1
|
|
52
|
+
printf '%s' "$raw" | grep -qiE "$private_state_pattern"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
require_alipay_cli_local_state_access() {
|
|
56
|
+
local state_dir probe_file renamed_file
|
|
57
|
+
if [ "$ALIPAY_CLI_LOCAL_STATE_ACCESS_CONFIRMED" = true ]; then
|
|
58
|
+
return 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
for state_dir in "$(alipay_cli_credentials_dir)" "$(alipay_cli_logs_dir)"; do
|
|
62
|
+
probe_file=""
|
|
63
|
+
renamed_file=""
|
|
64
|
+
[ -d "$state_dir" ] || mkdir -p "$state_dir" 2>/dev/null \
|
|
65
|
+
|| return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
66
|
+
probe_file=$(mktemp "$state_dir/.alipay-aipay-access.XXXXXX" 2>/dev/null) \
|
|
67
|
+
|| return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
68
|
+
chmod 600 "$probe_file" 2>/dev/null || {
|
|
69
|
+
rm -f "$probe_file" 2>/dev/null || true
|
|
70
|
+
return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
71
|
+
}
|
|
72
|
+
if ! printf 'alipay-cli-local-state-access\n' >"$probe_file" 2>/dev/null; then
|
|
73
|
+
rm -f "$probe_file" 2>/dev/null || true
|
|
74
|
+
return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
75
|
+
fi
|
|
76
|
+
renamed_file="${probe_file}.renamed"
|
|
77
|
+
if ! mv "$probe_file" "$renamed_file" 2>/dev/null; then
|
|
78
|
+
rm -f "$probe_file" "$renamed_file" 2>/dev/null || true
|
|
79
|
+
return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
80
|
+
fi
|
|
81
|
+
if ! rm -f "$renamed_file" 2>/dev/null; then
|
|
82
|
+
rm -f "$renamed_file" 2>/dev/null || true
|
|
83
|
+
return "$ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
84
|
+
fi
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
ALIPAY_CLI_LOCAL_STATE_ACCESS_CONFIRMED=true
|
|
88
|
+
}
|
|
89
|
+
|
|
15
90
|
emit_control() {
|
|
16
91
|
printf 'ALIPAY_AIPAY_INTERNAL:%s\n' "$*" >&2
|
|
17
92
|
}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
- `P-DETERMINISTIC-HANDOFF`:flow 已登记脚本或 renderer 时只执行动作发生位置的固定命令;退出码和登记终态标记满足后立即按 flow 转移,禁止追加 jq、cat、grep、curl 或临时脚本重复解析、复核或解释同一结果。失败只走登记恢复分支;项目代码实现和运行验证除外,但不得把沙箱配置或其他敏感文件打印到工具输出。
|
|
43
43
|
<!-- GENERATED:ONBOARDING-GUARDS:END -->
|
|
44
44
|
|
|
45
|
-
生成区块与 `SKILL.md` 红线适用于全部步骤。Onboarding 禁止修改用户项目代码或支付配置文件,只输出需由用户自行应用的配置;CLI 调用均由脚本设置 `PLATFORM`、`PLATFORM_ID`、`PRODUCT`;`aipay|webpay|apppay` 严格映射为 `AIPAY|WEBPAY|APPPAY`,`PRODUCT` 不进入 MCP 请求 JSON;禁止硬编码 `PLATFORM` 或分号拼环境变量。scope/MCC 不匹配只走 `auth.sh mismatch`;logout 后置条件未成立不得重授权;`
|
|
45
|
+
生成区块与 `SKILL.md` 红线适用于全部步骤。Onboarding 禁止修改用户项目代码或支付配置文件,只输出需由用户自行应用的配置;CLI 调用均由脚本设置 `PLATFORM`、`PLATFORM_ID`、`PRODUCT`;`aipay|webpay|apppay` 严格映射为 `AIPAY|WEBPAY|APPPAY`,`PRODUCT` 不进入 MCP 请求 JSON;禁止硬编码 `PLATFORM` 或分号拼环境变量。scope/MCC 不匹配只走 `auth.sh mismatch`;logout 后置条件未成立不得重授权;`RETRY_WITH_NETWORK|RETRY_WITH_LOCAL_FS_PERMISSION` 分别申请联网或 CLI 私有状态目录权限后原样重试,均不得解释为用户本机 login/logout 失败或支付宝业务失败。签约 `request+ctx` 与应用/服务 `request` 由脚本冻结,禁止绕开脚本混用或重组。
|
|
46
46
|
|
|
47
47
|
### 标准消息执行规则
|
|
48
48
|
|
|
@@ -190,7 +190,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-execute-read
|
|
|
190
190
|
|
|
191
191
|
当前方案基于完整确定事实送达后,`execute` 阶段 loader 已在原位置记录兼容 stage `onboarding.user_confirmed`;`auth.sh init` 会在固定授权上下文机器校验通过、开始授权业务动作前记录 `onboarding.auth.start`。两者都不替代登录、scope 或 MCC 完成条件,也不表示收到额外用户回复;不得另行执行 telemetry 命令造成重复事件。
|
|
192
192
|
|
|
193
|
-
这些脚本是联网命令,首次执行即按 `../normal/alipay-cli-env.md` 申请权限。`AUTH_FLOW:RETRY_WITH_NETWORK`
|
|
193
|
+
这些脚本是联网命令,首次执行即按 `../normal/alipay-cli-env.md` 申请权限。`AUTH_FLOW:RETRY_WITH_NETWORK` 只申请联网后重试同一完整命令。`AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION` 只表示授权状态命令 preflight 失败或命中 `poll_state/session/log` 本地状态写失败证据;可恢复阶段 stdout 为空,取得 CLI 私有状态目录权限后原样重试当前 `auth.sh` 命令一次,`wait|confirm` 不重建授权页或轮询。拒绝、不支持或重试仍命中同一 marker 时才输出最小失败说明。两者都不得解释为本机 login/logout 失败、网络故障或支付宝业务失败。
|
|
194
194
|
|
|
195
195
|
Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY 都是授权前置;产品或 MCC 仍缺失、冲突、非唯一或环境未就绪时禁止 login,`full_process` 也不得绕过。
|
|
196
196
|
|
|
@@ -204,6 +204,7 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
|
|
|
204
204
|
│ └─ 若同时存在 AUTH_STATE:SAVE_FAILED:授权页 stdout 已送达,后续 open 仅可降级为 AUTH_OPEN:LINK_ONLY;wait/confirm 仍使用本条命令显式上下文继续,禁止重新生成授权页
|
|
205
205
|
├─ AUTH_FLOW:SCOPE_MISMATCH / MCC_MISMATCH → 执行第 4 项
|
|
206
206
|
├─ AUTH_FLOW:RETRY_WITH_NETWORK → 取得联网权限后重试同一完整命令
|
|
207
|
+
├─ AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION → 取得 CLI 私有状态目录权限后原样重试本命令一次
|
|
207
208
|
└─ AUTH_FLOW:FAILED → 停止并按错误输出恢复,禁止进入 Step 3.1
|
|
208
209
|
2. 仅 AUTH_FLOW:READY_TO_OPEN:把 init 的 stdout 原文作为独立对客消息送达后,立即执行 node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" auth open --scope "$SCOPE" --sales-code "$SALES_CODE" --mcc-code "$MCC_CODE" --product-name "$PRODUCT_NAME" --mcc-name "$MCC_NAME";open 无对客 stdout,打开失败不影响已交付 URL。随后执行 node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" auth wait --scope "$SCOPE" --sales-code "$SALES_CODE" --mcc-code "$MCC_CODE" --product-name "$PRODUCT_NAME" --mcc-name "$MCC_NAME"
|
|
209
210
|
├─ open 返回 AUTH_FLOW:CONTEXT_MISMATCH → 不执行 wait;使用当前已确认的完整参数重新执行第 1 项
|
|
@@ -215,6 +216,7 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
|
|
|
215
216
|
├─ AUTH_FLOW:EXPIRED → 重新执行第 1 项生成授权链接
|
|
216
217
|
├─ AUTH_FLOW:CONTEXT_MISMATCH → 当前动作未执行 login --complete/logout;使用当前已确认的完整参数重新执行第 1 项
|
|
217
218
|
├─ AUTH_FLOW:RETRY_WITH_NETWORK → 取得联网权限后重试同一完整命令
|
|
219
|
+
├─ AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION → 保留当前授权页短时状态,取得 CLI 私有状态目录权限后原样重试当前 wait 命令一次
|
|
218
220
|
├─ AUTH_FLOW:FAILED → 停止并按错误输出恢复,禁止进入 Step 3.1
|
|
219
221
|
└─ AUTH_FLOW:SCOPE_MISMATCH / MCC_MISMATCH → 执行第 4 项
|
|
220
222
|
3. 仅 PENDING 后把用户原始回复传给 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-recovery auth-confirm --reply "$USER_REPLY" --scope "$SCOPE" --sales-code "$SALES_CODE" --mcc-code "$MCC_CODE" --product-name "$PRODUCT_NAME" --mcc-name "$MCC_NAME"`;runner 复用统一肯定语义判定(包括 `1`、“继续”“好了”“已完成”“OK”等),接受后只执行一次原 `auth.sh confirm`。否定、疑问、取消、修改意见或含糊输入返回内部拒绝且不得查询;成功后的转移同第 2 项,PENDING 继续等待且不重启轮询
|
|
@@ -222,6 +224,7 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
|
|
|
222
224
|
├─ AUTH_FLOW:READY_TO_OPEN → 输出非阻塞授权页并按第 2 项执行 open + wait
|
|
223
225
|
├─ AUTH_FLOW:CONTEXT_MISMATCH → 未执行 logout;使用当前已确认的完整参数重新执行第 1 项
|
|
224
226
|
├─ AUTH_FLOW:RETRY_WITH_NETWORK → 取得联网权限后重试同一完整命令
|
|
227
|
+
├─ AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION → 未重启授权链路,取得 CLI 私有状态目录权限后原样重试本命令一次
|
|
225
228
|
├─ AUTH_FLOW:LOGOUT_STILL_LOGGED_IN → logout 后置条件未成立;禁止 login、签约查询和其他 onboarding 动作,排除本机登录态后重试第 4 项
|
|
226
229
|
└─ mismatch 统一 logout;后置条件成立后用正确 scope 重建授权页
|
|
227
230
|
```
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
- `AUTH_FLOW:EXPIRED`:当前页面实际返回过期,旧页面和旧回复失效,重新执行 flow 登记的 init。
|
|
24
24
|
- `AUTH_FLOW:SCOPE_MISMATCH|MCC_MISMATCH`:只能走 `auth.sh mismatch`;logout 后置条件未成立前不得重授权;仍登录返回 `AUTH_FLOW:LOGOUT_STILL_LOGGED_IN`。
|
|
25
25
|
- `AUTH_FLOW:RETRY_WITH_NETWORK`:当前 Agent 环境无法确认结果,申请联网权限后原样重试同一命令;不得解释为用户本机登录失败。
|
|
26
|
+
- `AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION`:授权状态命令 preflight 失败,或实际输出命中 CLI 私有状态写失败证据。可恢复阶段 stdout 为空;仅允许当前受控 runtime 命令访问 CLI 私有状态目录后原样重试一次;`wait|confirm` 保留短时授权状态,不重建授权页。Agent 禁止读取、列举、打印或复制已有凭据与日志;拒绝、不支持或重试仍命中同一 marker 时才输出最小失败说明。
|
|
26
27
|
|
|
27
28
|
CLI `login --complete` 成功只表示页面侧确认完成,不代表本机已取得可用登录态。返回成功但状态字段不在白名单时,脚本先用 `whoami` 复核:有效登录继续 scope/MCC 校验,仍未形成登录态则保持 `PENDING`,不可确认则 `RETRY_WITH_NETWORK`。脚本仍需复核 `whoami`、scope,并以固定授权 URL 绑定 MCC;当前后端查询没有权威 MCC 返回字段,禁止声称做了响应 MCC 等值比较。
|
|
28
29
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| `MCP_AUTH_ERROR` | HTTP 401、`Authorization is empty`、非法认证信息 | 停止查询组;logout 后置条件成立后重授权。仍登录则阻断;不可确认或无网络时只重试同一动作,不解释为用户本机或支付宝业务失败 |
|
|
10
10
|
| `AUTH_MISMATCH` | `mccCode is not auth`、`salesProductCodes is not auth`、`scope is not auth` | 停止当前动作,只进 `auth.sh mismatch`;logout 后置条件未成立前禁重授权 |
|
|
11
11
|
| `MCP_SERVICE_ERROR` / `SERVICE_UNSTABLE` | 已识别连接、网络或服务异常 | 按下方有限重试规则处理;耗尽后记录受影响分支,依赖允许时继续其他独立分支,最终统一收口 |
|
|
12
|
+
| `CLI_LOCAL_FS_PERMISSION` | 授权状态命令 preflight 失败;或原始 stdout+stderr 命中私有状态写失败强证据,或私有状态路径与权限错误组合 | 仅用于 `auth.sh init|wait|confirm|mismatch` 的 `login/login --complete/logout` 链路;可恢复阶段 stdout 为空,只输出唯一 `AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION`,取得 CLI 私有状态目录权限后原样重试一次,不改产品、scope、MCC 或授权页 |
|
|
12
13
|
| `ERROR:<code>` | 当前响应中存在可识别业务错误 | 展示登记且脱敏的业务错误,修正业务条件前不重试 |
|
|
13
14
|
| `CLI_ERROR:<message>` | CLI 失败、异常结构或结果不可唯一解析 | 隐藏原始输出,停止并按登记 CLI 错误恢复,不猜成功或空结果 |
|
|
14
15
|
| `SUCCESS` | 唯一合法成功结构 | 才允许进入当前脚本的业务字段解析 |
|
|
@@ -19,7 +20,7 @@ discovery runner 和截图上传这类并发/分组动作不得让每个子进
|
|
|
19
20
|
|
|
20
21
|
## 解包与业务错误
|
|
21
22
|
|
|
22
|
-
`unwrap_mcp` 兼容纯业务 JSON、唯一 MCP `content[0].text`
|
|
23
|
+
`unwrap_mcp` 兼容纯业务 JSON、唯一 MCP `content[0].text` 信封和混合日志。授权状态命令捕获先合并 stdout/stderr 检查 `写入临时文件失败|删除凭据文件失败|can't rename log file` 强证据,或 `poll_state.enc.tmp|session.enc|.alipay-cli/credentials|alipay-cli/logs` 与 `permission denied|operation not permitted|EACCES|EPERM` 组合;命中时不得按 `network_error` 处理,裸后端 `permission denied` 不算本地权限。其他 CLI 捕获再执行唯一性解析:单个 JSON 加普通日志可接受,相同 JSON 重复可去重,多个不同 JSON 或成功/失败冲突不得选择任一路,也不得回显原始响应。每次 MCP 调用先把唯一原始结果交给 `handle_error`,返回成功后才调用 `unwrap_mcp` 和当前脚本的业务解析;不得统一假定成功字段位于 `.success`。
|
|
23
24
|
|
|
24
25
|
每次 logout 失败后只执行一次 `whoami` 后置核验;logout 明确成功时无需额外核验,最多尝试 3 次 logout。`whoami` 后置核验必须先满足唯一 JSON、退出码为 0 且 `detect_error=SUCCESS`,再读取类型正确的 `logged_in/is_expired`;业务失败响应即使携带 `logged_in=false` 也不能证明已退出。logout 网络/服务异常、冲突输出或结果无法确认时,即使 `whoami` 仍显示已登录,也只能转 `AUTH_FLOW:RETRY_WITH_NETWORK` 并重试同一动作。logout 是可由 `whoami` 验证最终状态的幂等恢复动作:明确业务失败且仍登录时,脚本内部使用“初次 + 2 次”固定预算、间隔 3 秒重试完全相同的 logout;任一次确认已退出即继续,全部耗尽且仍登录才转 `AUTH_FLOW:LOGOUT_STILL_LOGGED_IN`。所有失败分支都不得执行 login。每个 auth 动作只允许产生一个最终 `AUTH_FLOW:*`,具体恢复 marker 已由错误处理器输出时,调用方不得追加 `AUTH_FLOW:FAILED`。
|
|
25
26
|
|
|
@@ -30,6 +30,7 @@ fi
|
|
|
30
30
|
source "${SCRIPT_DIR}/network_retry.sh"
|
|
31
31
|
source "${SCRIPT_DIR}/sign_status_parser.sh"
|
|
32
32
|
RENDERER="${SCRIPT_DIR}/../../../normal/scripts/render_customer_message.mjs"
|
|
33
|
+
AUTH_LOCAL_STATE_PERMISSION_EXIT_CODE="${ALIPAY_CLI_LOCAL_STATE_PERMISSION_EXIT_CODE:-77}"
|
|
33
34
|
|
|
34
35
|
require_command jq || exit 1
|
|
35
36
|
require_command alipay-cli || exit 1
|
|
@@ -336,8 +337,27 @@ extract_json_payload() {
|
|
|
336
337
|
printf '%s' "$analysis" | jq -ce '.value | select(type == "object")' 2>/dev/null
|
|
337
338
|
}
|
|
338
339
|
|
|
340
|
+
auth_has_local_state_permission_error() {
|
|
341
|
+
alipay_cli_has_local_state_permission_error "$1"
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
auth_local_state_permission_failure() {
|
|
345
|
+
emit_control "AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
auth_require_local_state_access() {
|
|
349
|
+
require_alipay_cli_local_state_access || {
|
|
350
|
+
auth_local_state_permission_failure
|
|
351
|
+
return 1
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
339
355
|
auth_cli_environment_failure() {
|
|
340
|
-
local action="$1"
|
|
356
|
+
local action="$1" failure_code="${2:-1}"
|
|
357
|
+
if [ "$failure_code" -eq "$AUTH_LOCAL_STATE_PERMISSION_EXIT_CODE" ]; then
|
|
358
|
+
auth_local_state_permission_failure
|
|
359
|
+
return
|
|
360
|
+
fi
|
|
341
361
|
echo "❌ ${action} 未能在当前 Agent 执行环境取得可确认结果,已停止。"
|
|
342
362
|
echo "📋 这通常表示当前执行环境缺少联网权限、CLI wrapper 混入输出,或 stdout/stderr 无法唯一解析。"
|
|
343
363
|
echo "📋 这不代表支付宝业务失败,也不能据此判断用户本机 logout/login 失败。"
|
|
@@ -352,7 +372,7 @@ handle_auth_cli_result() {
|
|
|
352
372
|
return 0
|
|
353
373
|
fi
|
|
354
374
|
case "$error_type" in
|
|
355
|
-
MCP_AUTH_ERROR|AUTH_MISMATCH)
|
|
375
|
+
MCP_AUTH_ERROR|AUTH_MISMATCH|CLI_LOCAL_FS_PERMISSION)
|
|
356
376
|
# error_handler.sh already emitted the unique recovery marker.
|
|
357
377
|
;;
|
|
358
378
|
MCP_SERVICE_ERROR|SERVICE_UNSTABLE)
|
|
@@ -379,7 +399,7 @@ wait_for_effective_whoami() {
|
|
|
379
399
|
|
|
380
400
|
while [ "$attempt" -le "$max_attempts" ]; do
|
|
381
401
|
AUTH_WHOAMI_RESULT=$(run_json_command "alipay-cli whoami --json" alipay-cli whoami --json) || {
|
|
382
|
-
auth_cli_environment_failure "$action"
|
|
402
|
+
auth_cli_environment_failure "$action" "$?"
|
|
383
403
|
return 1
|
|
384
404
|
}
|
|
385
405
|
handle_auth_cli_result "$AUTH_WHOAMI_RESULT" || return 1
|
|
@@ -412,6 +432,10 @@ run_json_command() {
|
|
|
412
432
|
stderr_output=$(cat "$stderr_file")
|
|
413
433
|
|
|
414
434
|
combined_output=$(printf '%s\n%s' "$stdout" "$stderr_output")
|
|
435
|
+
if auth_has_local_state_permission_error "$combined_output"; then
|
|
436
|
+
rm -f "$stderr_file"
|
|
437
|
+
return "$AUTH_LOCAL_STATE_PERMISSION_EXIT_CODE"
|
|
438
|
+
fi
|
|
415
439
|
if json_payload=$(extract_json_payload "$combined_output"); then
|
|
416
440
|
rm -f "$stderr_file"
|
|
417
441
|
printf '%s' "$json_payload"
|
|
@@ -442,7 +466,7 @@ validate_current_authorization() {
|
|
|
442
466
|
|
|
443
467
|
if [ -z "$whoami_result" ]; then
|
|
444
468
|
whoami_result=$(run_json_command "alipay-cli whoami --json" alipay-cli whoami --json) || {
|
|
445
|
-
auth_cli_environment_failure "登录状态复核"
|
|
469
|
+
auth_cli_environment_failure "登录状态复核" "$?"
|
|
446
470
|
return 1
|
|
447
471
|
}
|
|
448
472
|
fi
|
|
@@ -598,7 +622,7 @@ auth_init() {
|
|
|
598
622
|
|
|
599
623
|
# Step 1: 检查登录状态
|
|
600
624
|
CHECK_RESULT=$(run_json_command "alipay-cli whoami --json" alipay-cli whoami --json) || {
|
|
601
|
-
auth_cli_environment_failure "登录状态检查"
|
|
625
|
+
auth_cli_environment_failure "登录状态检查" "$?"
|
|
602
626
|
return 1
|
|
603
627
|
}
|
|
604
628
|
handle_auth_cli_result "$CHECK_RESULT" || return 1
|
|
@@ -627,8 +651,9 @@ auth_init() {
|
|
|
627
651
|
fi
|
|
628
652
|
|
|
629
653
|
# Step 2: 执行登录
|
|
654
|
+
auth_require_local_state_access || return 1
|
|
630
655
|
LOGIN_RESULT=$(run_json_command "alipay-cli login --non-interactive --scope" alipay-cli login --non-interactive --scope "$SCOPE" --json) || {
|
|
631
|
-
auth_cli_environment_failure "授权登录发起"
|
|
656
|
+
auth_cli_environment_failure "授权登录发起" "$?"
|
|
632
657
|
return 1
|
|
633
658
|
}
|
|
634
659
|
handle_auth_cli_result "$LOGIN_RESULT" || return 1
|
|
@@ -741,8 +766,9 @@ auth_confirm() {
|
|
|
741
766
|
fi
|
|
742
767
|
|
|
743
768
|
# Step 1: 执行授权确认
|
|
769
|
+
auth_require_local_state_access || return 1
|
|
744
770
|
LOGIN_COMPLETE_RESULT=$(run_json_command "alipay-cli login --complete --json" alipay-cli login --complete --json) || {
|
|
745
|
-
auth_cli_environment_failure "授权完成确认"
|
|
771
|
+
auth_cli_environment_failure "授权完成确认" "$?"
|
|
746
772
|
return 1
|
|
747
773
|
}
|
|
748
774
|
|
|
@@ -871,6 +897,7 @@ auth_wait() {
|
|
|
871
897
|
|
|
872
898
|
# ─── auth mismatch: 授权范围不满足 → logout → 重新授权 ──────────────────────
|
|
873
899
|
auth_mismatch() {
|
|
900
|
+
local mismatch_message=""
|
|
874
901
|
if [ "${1:-}" = "--defer-open" ]; then
|
|
875
902
|
shift
|
|
876
903
|
else
|
|
@@ -895,7 +922,8 @@ auth_mismatch() {
|
|
|
895
922
|
fi
|
|
896
923
|
|
|
897
924
|
# Step 2: mismatch 是授权不匹配恢复路径中唯一执行 logout 的入口。
|
|
898
|
-
|
|
925
|
+
auth_require_local_state_access || return 1
|
|
926
|
+
if ! mismatch_message=$(printf '%s' '{}' | ALIPAY_AIPAY_RENDERER_MANAGED_CALLER=auth.sh node "$RENDERER" auth.mismatch --variant DEFAULT); then
|
|
899
927
|
emit_control "AUTH_FLOW:FAILED"
|
|
900
928
|
return 1
|
|
901
929
|
fi
|
|
@@ -908,12 +936,17 @@ auth_mismatch() {
|
|
|
908
936
|
emit_control "AUTH_FLOW:LOGOUT_STILL_LOGGED_IN"
|
|
909
937
|
return 1
|
|
910
938
|
;;
|
|
939
|
+
LOCAL_FS_PERMISSION)
|
|
940
|
+
auth_local_state_permission_failure
|
|
941
|
+
return 1
|
|
942
|
+
;;
|
|
911
943
|
*)
|
|
912
944
|
render_logout_unconfirmed || return 1
|
|
913
945
|
emit_control "AUTH_FLOW:RETRY_WITH_NETWORK"
|
|
914
946
|
return 1
|
|
915
947
|
;;
|
|
916
948
|
esac
|
|
949
|
+
printf '%s\n' "$mismatch_message"
|
|
917
950
|
|
|
918
951
|
# Step 3: 调用 auth init 执行登录 + 构建授权链接 + 输出唯一授权消息。
|
|
919
952
|
# DEV_TOOL_NAME 已 export,子进程可继承。
|
|
@@ -322,7 +322,7 @@ extract_checked_errors() {
|
|
|
322
322
|
|
|
323
323
|
# ─── 统一错误检测 ──────────────────────────────────────────────────────────
|
|
324
324
|
# 参数: $1 - CLI 执行结果文本(原始输出,含信封或不含)
|
|
325
|
-
# 返回: MCP_AUTH_ERROR | MCP_SERVICE_ERROR | AUTH_MISMATCH | SERVICE_UNSTABLE | ERROR:xxx | CLI_ERROR:xxx | SUCCESS
|
|
325
|
+
# 返回: MCP_AUTH_ERROR | MCP_SERVICE_ERROR | AUTH_MISMATCH | SERVICE_UNSTABLE | CLI_LOCAL_FS_PERMISSION | ERROR:xxx | CLI_ERROR:xxx | SUCCESS
|
|
326
326
|
detect_error() {
|
|
327
327
|
local CLI_RESULT="$1"
|
|
328
328
|
|
|
@@ -332,6 +332,11 @@ detect_error() {
|
|
|
332
332
|
return
|
|
333
333
|
fi
|
|
334
334
|
|
|
335
|
+
if alipay_cli_has_local_state_permission_error "$CLI_RESULT"; then
|
|
336
|
+
echo "CLI_LOCAL_FS_PERMISSION"
|
|
337
|
+
return
|
|
338
|
+
fi
|
|
339
|
+
|
|
335
340
|
# 先解包 MCP 信封,再进行错误检测
|
|
336
341
|
local UNWRAPPED=$(unwrap_mcp "$CLI_RESULT")
|
|
337
342
|
|
|
@@ -404,6 +409,11 @@ run_alipay_cli_json_capture() {
|
|
|
404
409
|
rm -f "$stderr_file"
|
|
405
410
|
|
|
406
411
|
combined_output=$(printf '%s\n%s' "$stdout" "$stderr_output")
|
|
412
|
+
if type auth_has_local_state_permission_error >/dev/null 2>&1 &&
|
|
413
|
+
auth_has_local_state_permission_error "$combined_output"; then
|
|
414
|
+
ALIPAY_CLI_JSON_CAPTURE=""
|
|
415
|
+
return "${AUTH_LOCAL_STATE_PERMISSION_EXIT_CODE:-77}"
|
|
416
|
+
fi
|
|
407
417
|
if ALIPAY_CLI_JSON_CAPTURE=$(extract_captured_json "$combined_output"); then
|
|
408
418
|
return 0
|
|
409
419
|
fi
|
|
@@ -414,7 +424,7 @@ run_alipay_cli_json_capture() {
|
|
|
414
424
|
|
|
415
425
|
confirm_logout_postcondition() {
|
|
416
426
|
local logout_error_type whoami_error_type whoami_state
|
|
417
|
-
local logout_result_state attempt=1
|
|
427
|
+
local logout_result_state logout_capture_rc whoami_capture_rc attempt=1
|
|
418
428
|
local max_attempts=3
|
|
419
429
|
local interval_seconds=3
|
|
420
430
|
|
|
@@ -427,7 +437,9 @@ confirm_logout_postcondition() {
|
|
|
427
437
|
|
|
428
438
|
while [ "$attempt" -le "$max_attempts" ]; do
|
|
429
439
|
logout_result_state="UNCONFIRMED"
|
|
430
|
-
|
|
440
|
+
run_alipay_cli_json_capture alipay-cli logout --json
|
|
441
|
+
logout_capture_rc=$?
|
|
442
|
+
if [ "$logout_capture_rc" -eq 0 ]; then
|
|
431
443
|
logout_error_type=$(detect_error "$ALIPAY_CLI_JSON_CAPTURE")
|
|
432
444
|
if [ "$ALIPAY_CLI_JSON_EXIT_CODE" -eq 0 ] && [ "$logout_error_type" = "SUCCESS" ]; then
|
|
433
445
|
ALIPAY_LOGOUT_POSTCONDITION="COMMAND_CONFIRMED_SUCCESS"
|
|
@@ -446,11 +458,20 @@ confirm_logout_postcondition() {
|
|
|
446
458
|
logout_result_state="EXPLICIT_FAILURE"
|
|
447
459
|
;;
|
|
448
460
|
esac
|
|
461
|
+
elif [ "$logout_capture_rc" -eq "${AUTH_LOCAL_STATE_PERMISSION_EXIT_CODE:-77}" ]; then
|
|
462
|
+
ALIPAY_LOGOUT_POSTCONDITION="LOCAL_FS_PERMISSION"
|
|
463
|
+
return 1
|
|
449
464
|
else
|
|
450
465
|
ALIPAY_LOGOUT_ERROR_MESSAGE="退出命令未返回可唯一解析结果"
|
|
451
466
|
fi
|
|
452
467
|
|
|
453
|
-
|
|
468
|
+
run_alipay_cli_json_capture alipay-cli whoami --json
|
|
469
|
+
whoami_capture_rc=$?
|
|
470
|
+
if [ "$whoami_capture_rc" -eq "${AUTH_LOCAL_STATE_PERMISSION_EXIT_CODE:-77}" ]; then
|
|
471
|
+
ALIPAY_LOGOUT_POSTCONDITION="LOCAL_FS_PERMISSION"
|
|
472
|
+
return 1
|
|
473
|
+
fi
|
|
474
|
+
if [ "$whoami_capture_rc" -ne 0 ]; then
|
|
454
475
|
ALIPAY_LOGOUT_POSTCONDITION="UNCONFIRMED"
|
|
455
476
|
return 1
|
|
456
477
|
fi
|
|
@@ -525,6 +546,13 @@ handle_mcp_auth_error() {
|
|
|
525
546
|
}
|
|
526
547
|
emit_control "AUTH_FLOW:LOGOUT_STILL_LOGGED_IN"
|
|
527
548
|
;;
|
|
549
|
+
LOCAL_FS_PERMISSION)
|
|
550
|
+
if type auth_local_state_permission_failure >/dev/null 2>&1; then
|
|
551
|
+
auth_local_state_permission_failure
|
|
552
|
+
else
|
|
553
|
+
emit_control "AUTH_FLOW:RETRY_WITH_NETWORK"
|
|
554
|
+
fi
|
|
555
|
+
;;
|
|
528
556
|
*)
|
|
529
557
|
render_logout_unconfirmed || {
|
|
530
558
|
emit_control "AUTH_FLOW:FAILED"
|
|
@@ -639,6 +667,16 @@ handle_error() {
|
|
|
639
667
|
"SERVICE_UNSTABLE")
|
|
640
668
|
handle_service_unstable
|
|
641
669
|
;;
|
|
670
|
+
"CLI_LOCAL_FS_PERMISSION")
|
|
671
|
+
if type auth_local_state_permission_failure >/dev/null 2>&1; then
|
|
672
|
+
auth_local_state_permission_failure
|
|
673
|
+
else
|
|
674
|
+
MESSAGE_INPUT=$(jq -cn \
|
|
675
|
+
--arg errorMessage "alipay-cli 本地状态目录权限不足" \
|
|
676
|
+
'{errorMessage:$errorMessage,bizTips:"",checkedErrors:[]}')
|
|
677
|
+
render_error_message error.cli DEFAULT "$MESSAGE_INPUT"
|
|
678
|
+
fi
|
|
679
|
+
;;
|
|
642
680
|
"ERROR:"*)
|
|
643
681
|
local CODE="${ERROR_TYPE#ERROR:}"
|
|
644
682
|
handle_backend_error "$CLI_RESULT" "$CODE"
|