@alipay/alipay-aipay 1.2.2 → 1.5.0

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.
Files changed (104) hide show
  1. package/README.md +5 -0
  2. package/dist/commands/install.d.ts.map +1 -1
  3. package/dist/commands/install.js +13 -12
  4. package/dist/commands/install.js.map +1 -1
  5. package/dist/commands/uninstall.d.ts.map +1 -1
  6. package/dist/commands/uninstall.js +17 -9
  7. package/dist/commands/uninstall.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +5 -5
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/index.js +4 -4
  12. package/dist/index.js.map +1 -1
  13. package/dist/utils/config.d.ts +5 -3
  14. package/dist/utils/config.d.ts.map +1 -1
  15. package/dist/utils/config.js +34 -12
  16. package/dist/utils/config.js.map +1 -1
  17. package/dist/utils/file.d.ts +8 -0
  18. package/dist/utils/file.d.ts.map +1 -1
  19. package/dist/utils/file.js +161 -9
  20. package/dist/utils/file.js.map +1 -1
  21. package/dist/utils/jq.d.ts.map +1 -1
  22. package/dist/utils/jq.js +8 -0
  23. package/dist/utils/jq.js.map +1 -1
  24. package/package.json +9 -5
  25. package/skill/SKILL.md +15 -169
  26. package/skill/VERSION +1 -1
  27. package/skill/references/integration/flow.md +388 -291
  28. package/skill/references/integration/modules/alipay-sdk-reminder.md +5 -3
  29. package/skill/references/integration/modules/checklist.md +54 -32
  30. package/skill/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +199 -0
  31. package/skill/references/integration/modules/code-examples/csharp/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +8 -4
  32. package/skill/references/integration/modules/code-examples/csharp/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +6 -2
  33. package/skill/references/integration/modules/code-examples/csharp/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.cs +3 -1
  34. package/skill/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +184 -0
  35. package/skill/references/integration/modules/code-examples/java/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +4 -1
  36. package/skill/references/integration/modules/code-examples/java/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +5 -2
  37. package/skill/references/integration/modules/code-examples/java/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemoController.java +3 -1
  38. package/skill/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +135 -0
  39. package/skill/references/integration/modules/code-examples/nodejs/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +16 -10
  40. package/skill/references/integration/modules/code-examples/nodejs/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +10 -4
  41. package/skill/references/integration/modules/code-examples/nodejs/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.js +2 -1
  42. package/skill/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +157 -0
  43. package/skill/references/integration/modules/code-examples/php/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +4 -1
  44. package/skill/references/integration/modules/code-examples/php/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +5 -2
  45. package/skill/references/integration/modules/code-examples/php/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.php +2 -1
  46. package/skill/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +128 -0
  47. package/skill/references/integration/modules/code-examples/python/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +4 -1
  48. package/skill/references/integration/modules/code-examples/python/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +5 -1
  49. package/skill/references/integration/modules/code-examples/python/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.py +4 -2
  50. package/skill/references/integration/modules/interface-contract/aipay-interface-contract.md +52 -0
  51. package/skill/references/integration/modules/interface-contract/apppay-interface-contract.md +45 -0
  52. package/skill/references/integration/modules/interface-contract/common-trade-contract.md +42 -0
  53. package/skill/references/integration/modules/interface-contract/notify-url-contract.md +68 -0
  54. package/skill/references/integration/modules/interface-contract/webpay-interface-contract.md +44 -0
  55. package/skill/references/integration/modules/interface-guide.md +38 -71
  56. package/skill/references/integration/modules/product-decision.md +18 -35
  57. package/skill/references/integration/modules/sandbox/a2m-sandbox-test.md +62 -94
  58. package/skill/references/integration/modules/sandbox/alipay-sandbox-tool.md +43 -40
  59. package/skill/references/integration/modules/sandbox/sandbox-setup-guide.md +93 -114
  60. package/skill/references/integration/modules/scripts/local_402_sandbox_pay.py +358 -148
  61. package/skill/references/integration/modules/scripts/sandbox_config.sh +299 -0
  62. package/skill/references/integration/modules/troubleshooting-flow.md +28 -0
  63. package/skill/references/normal/alipay-cli-env.md +15 -5
  64. package/skill/references/normal/full-process-routing.md +82 -0
  65. package/skill/references/normal/json/customer-messages.json +942 -0
  66. package/skill/references/normal/json/policy-rules.json +179 -0
  67. package/skill/references/normal/rejection-guide.md +12 -7
  68. package/skill/references/normal/scripts/alipay_cli_env.mjs +33 -0
  69. package/skill/references/normal/scripts/alipay_cli_env.sh +55 -0
  70. package/skill/references/normal/scripts/common.sh +151 -0
  71. package/skill/references/normal/scripts/detect_dev_tool.sh +5 -1
  72. package/skill/references/normal/scripts/flow_loader.mjs +241 -0
  73. package/skill/references/normal/scripts/integration_context_runner.mjs +166 -0
  74. package/skill/references/normal/scripts/integration_message_runner.mjs +1023 -0
  75. package/skill/references/normal/scripts/interaction_reply.mjs +133 -0
  76. package/skill/references/normal/scripts/onboarding_discovery_runner.mjs +224 -0
  77. package/skill/references/normal/scripts/onboarding_message_runner.mjs +451 -0
  78. package/skill/references/normal/scripts/onboarding_recovery_runner.mjs +96 -0
  79. package/skill/references/normal/scripts/open_official_url.sh +82 -0
  80. package/skill/references/normal/scripts/platform_compat.mjs +39 -0
  81. package/skill/references/normal/scripts/project_route_inspector.sh +132 -0
  82. package/skill/references/normal/scripts/python_script_runner.mjs +56 -0
  83. package/skill/references/normal/scripts/render_customer_message.mjs +1288 -0
  84. package/skill/references/normal/scripts/self_update.mjs +160 -0
  85. package/skill/references/normal/scripts/telemetry.mjs +1327 -0
  86. package/skill/references/normal/self-update.md +18 -51
  87. package/skill/references/normal/telemetry.md +26 -0
  88. package/skill/references/onboarding/flow.md +421 -309
  89. package/skill/references/onboarding/modules/app-release.md +44 -438
  90. package/skill/references/onboarding/modules/authorization.md +25 -281
  91. package/skill/references/onboarding/modules/error-handling.md +31 -237
  92. package/skill/references/onboarding/modules/product-sign.md +25 -294
  93. package/skill/references/onboarding/modules/scripts/app.sh +445 -169
  94. package/skill/references/onboarding/modules/scripts/ar_sign_apply.sh +47 -28
  95. package/skill/references/onboarding/modules/scripts/auth.sh +484 -167
  96. package/skill/references/onboarding/modules/scripts/download_key_tool.sh +157 -0
  97. package/skill/references/onboarding/modules/scripts/error_handler.sh +101 -130
  98. package/skill/references/onboarding/modules/scripts/network_retry.sh +96 -0
  99. package/skill/references/onboarding/modules/scripts/query_sign_status.sh +20 -71
  100. package/skill/references/onboarding/modules/scripts/service.sh +154 -89
  101. package/skill/references/onboarding/modules/scripts/sign_status_parser.sh +58 -0
  102. package/skill/references/onboarding/modules/scripts/upload_screenshots.sh +34 -20
  103. package/skill/references/onboarding/modules/service-registration.md +20 -317
  104. package/skill/references/runtime-entry.md +63 -0
@@ -3,13 +3,13 @@
3
3
  # 脚本名称: query_sign_status.sh
4
4
  # 功能描述: 查询签约状态并根据结果判断后续流程
5
5
  # 调用位置: Step 3.1 状态与资源查询
6
- # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME;需传入 --sales-code,或兼容使用 SALES_CODE 环境变量
6
+ # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME/PLATFORM_ID;需传入 --sales-code,或兼容使用 SALES_CODE 环境变量
7
7
  # 用法: bash query_sign_status.sh --sales-code <code> [--product-type aipay|webpay|apppay]
8
- # 返回值: 输出签约状态判断结果和处理建议
8
+ # 返回值: 在 stderr 输出签约状态控制信号;stdout 只保留受控错误正文
9
9
  # SIGN_STATUS=NOT_SIGNED | SIGN_STATUS=SIGNED_EFFECTIVE | SIGN_STATUS=SIGN_SUBMITTED | SIGN_STATUS=OTHER_STATUS
10
- # 按量付费: FLOW:AI_PAY_NOT_SIGNED | FLOW:AI_PAY_SIGNED
11
- # 网站支付: FLOW:PC_WEB_NOT_SIGNED | FLOW:PC_WEB_SIGNED
12
- # APP支付: FLOW:APP_NOT_SIGNED | FLOW:APP_SIGNED
10
+ # AI 按量付费: FLOW:AI_PAY_NOT_SIGNED | FLOW:AI_PAY_SIGNED
11
+ # AI 网页应用收款: FLOW:PC_WEB_NOT_SIGNED | FLOW:PC_WEB_SIGNED
12
+ # AI 移动应用收款: FLOW:APP_NOT_SIGNED | FLOW:APP_SIGNED
13
13
  #=============================================================================
14
14
 
15
15
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -21,6 +21,8 @@ else
21
21
  echo "❌ 缺少错误处理脚本: ${SCRIPT_DIR}/error_handler.sh"
22
22
  exit 1
23
23
  fi
24
+ source "${SCRIPT_DIR}/network_retry.sh"
25
+ source "${SCRIPT_DIR}/sign_status_parser.sh"
24
26
 
25
27
  require_command jq || exit 1
26
28
  require_command alipay-cli || exit 1
@@ -69,27 +71,18 @@ if [ "$PRODUCT_TYPE" != "unknown" ] && [ "$PRODUCT_TYPE" != "$EXPECTED_PRODUCT_T
69
71
  exit 1
70
72
  fi
71
73
 
72
- emit_signed_flow() {
73
- case "$SALES_CODE" in
74
- "I1080300001000041203")
75
- echo "FLOW:PC_WEB_SIGNED"
76
- # 网站支付已生效或已提交:Step 4 只处理应用决策,Step 5 跳过签约提交
77
- ;;
78
- "I1080300001000041313")
79
- echo "FLOW:APP_SIGNED"
80
- # APP支付已生效或已提交:Step 4 只处理应用决策,Step 5 跳过签约提交
81
- ;;
82
- "I1080300001000160457")
83
- echo "FLOW:AI_PAY_SIGNED"
84
- # 按量付费已生效或已提交:Step 4 处理服务/应用决策,Step 5 跳过签约提交
85
- ;;
86
- esac
87
- }
74
+ init_alipay_cli_product "$EXPECTED_PRODUCT_TYPE" || exit 1
88
75
 
89
76
  # 查询签约状态
90
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call ar-query.queryArInfosBySalesProd \
77
+ export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
78
+ run_network_retry RESULT read query_sign_status -- alipay-cli mcp call ar-query.queryArInfosBySalesProd \
91
79
  -d "{\"request\":{\"salesProductCodes\":[\"${SALES_CODE}\"]},\"ctx\":{}}" \
92
- --json 2>/dev/null)
80
+ --json
81
+ RETRY_RC=$?
82
+ if [ "$RETRY_RC" -ne 0 ]; then
83
+ echo "❌ 签约状态查询因网络或服务异常在自动重试两次后仍未恢复"
84
+ exit 1
85
+ fi
93
86
 
94
87
  # 错误检测
95
88
  if ! handle_error "$RESULT"; then
@@ -99,54 +92,10 @@ fi
99
92
  # 解包 MCP 信封后解析业务字段
100
93
  BUSINESS=$(unwrap_mcp "$RESULT")
101
94
 
102
- # 只有明确返回数组才可判断签约状态;缺少字段必须阻断,避免误判为未签约
103
- AR_LIST=$(echo "$BUSINESS" | jq -c '
104
- if (.resultObj | type) == "object" and (.resultObj.arInfoList | type) == "array" then
105
- .resultObj.arInfoList
106
- else
107
- null
108
- end
109
- ' 2>/dev/null)
110
- if [ -z "$AR_LIST" ] || ! echo "$AR_LIST" | jq -e 'type == "array"' >/dev/null 2>&1; then
95
+ # 只有明确返回数组才可判断签约状态;缺少字段必须阻断,避免误判为未签约。
96
+ if ! SIGN_STATUS_OUTPUT=$(emit_sign_status_from_business "$BUSINESS" "$SALES_CODE"); then
111
97
  echo "❌ 签约状态返回结构异常,无法解析 arInfoList"
112
98
  exit 1
113
99
  fi
114
- AR_COUNT=$(echo "$AR_LIST" | jq 'length')
115
-
116
- if [ "$AR_COUNT" -eq 0 ]; then
117
- echo "📋 签约状态: 未签约 (NOT_SIGNED);继续 Step 4 一次性资料与资源决策"
118
- echo "SIGN_STATUS=NOT_SIGNED"
119
-
120
- case "$SALES_CODE" in
121
- "I1080300001000041203")
122
- echo "FLOW:PC_WEB_NOT_SIGNED"
123
- # 网站支付未签约:需先采集 3 张网站截图,再进入 Step 5 签约
124
- ;;
125
- "I1080300001000041313")
126
- echo "FLOW:APP_NOT_SIGNED"
127
- # APP支付未签约:需先采集 APP 名称和 3 张APP界面截图,再进入 Step 5 签约
128
- ;;
129
- "I1080300001000160457")
130
- echo "FLOW:AI_PAY_NOT_SIGNED"
131
- # 按量付费未签约:Step 4 无需页面图片,但仍完成服务/应用决策
132
- ;;
133
- esac
134
- else
135
- # AR_LIST 已在上方确认为数组
136
- HAS_EFFECTIVE=$(echo "$AR_LIST" | jq -r '[.[] | select(.arStatus == "02")] | length')
137
- HAS_SUBMITTED=$(echo "$AR_LIST" | jq -r '[.[] | select(.arStatus == "01")] | length')
138
-
139
- if [ "$HAS_EFFECTIVE" -gt 0 ]; then
140
- echo "✅ 签约已生效;无需签约材料,继续 Step 4 资源决策"
141
- echo "SIGN_STATUS=SIGNED_EFFECTIVE"
142
- emit_signed_flow
143
- elif [ "$HAS_SUBMITTED" -gt 0 ]; then
144
- echo "📋 已提交签约(待生效),无需重复提交签约,继续推进后续步骤"
145
- echo "SIGN_STATUS=SIGN_SUBMITTED"
146
- emit_signed_flow
147
- else
148
- echo "📋 其他签约状态;保留已取得的只读结果并将签约分支标记为待核验"
149
- echo "SIGN_STATUS=OTHER_STATUS"
150
- echo "FLOW:OTHER_STATUS"
151
- fi
152
- fi
100
+ printf '%s\n' "$SIGN_STATUS_OUTPUT" \
101
+ | while IFS= read -r marker; do emit_control "$marker"; done
@@ -3,18 +3,19 @@
3
3
  # 脚本名称: service.sh
4
4
  # 功能描述: 服务市场注册 - 查询已有服务 + 创建/修改服务
5
5
  # 调用位置: list 用于 Step 3.1 前置资源查询;save/validate 用于 Step 5.2 服务市场注册
6
- # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME;必要时可用 DEV_TOOL_NAME 环境变量覆盖
6
+ # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME/PLATFORM_ID;必要时可用 DEV_TOOL_NAME 环境变量覆盖
7
7
  # 用法:
8
8
  # service list - 查询已有服务列表
9
9
  # service save --name <n> --desc <d> --url <u> --pricing <p> --schema <json> [--service-id <id>]
10
10
  # service validate --name <n> --desc <d> --url <u> --pricing <p> --schema <json>
11
11
  # 返回值:
12
- # list: 输出服务列表 + FLOW:CREATE_NEW | FLOW:SELECT
13
- # save: 输出 ✅/❌ + serviceId(无 FLOW 标记,由 Agent 根据退出码判断)
14
- # validate: 输出 ✅/❌ + 校验详情(退出码 0=通过, 1=失败)
12
+ # list: stdout 成功时为空;stderr 输出带统一内部前缀的候选 JSON、SERVICE_CANDIDATE_ID 和 FLOW
13
+ # save: stderr 输出实际解析到的 SERVICE_ID(不接受 Agent 自填)
14
+ # validate: stderr 输出规范化结果(退出码 0=通过, 1=失败)
15
15
  #=============================================================================
16
16
 
17
17
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ CANDIDATE_RUNNER="${SCRIPT_DIR}/../../../normal/scripts/onboarding_message_runner.mjs"
18
19
 
19
20
  # 一次性 source error_handler(含 unwrap_mcp)
20
21
  if [ -f "${SCRIPT_DIR}/error_handler.sh" ]; then
@@ -23,10 +24,67 @@ else
23
24
  echo "❌ 缺少错误处理脚本: ${SCRIPT_DIR}/error_handler.sh"
24
25
  exit 1
25
26
  fi
27
+ source "${SCRIPT_DIR}/network_retry.sh"
26
28
 
27
29
  require_command jq || exit 1
28
30
  require_command alipay-cli || exit 1
29
31
  require_command awk || exit 1
32
+ require_command node || exit 1
33
+ init_alipay_cli_product aipay || exit 1
34
+
35
+ SERVICE_LIST_PAGE_LIMIT=10
36
+ SERVICE_CREATE_LIMIT=10
37
+
38
+ normalize_service_pricing() {
39
+ local raw="$1"
40
+ local pricing_pattern='^ *([0-9]+([.][0-9]+)?) *(元(/次)?)? *$'
41
+ SERVICE_PRICING_NORMALIZED=""
42
+ case "$raw" in *$'\n'*|*$'\r'*|*$'\t'*) return 1 ;; esac
43
+ if [[ "$raw" =~ $pricing_pattern ]]; then
44
+ SERVICE_PRICING_NORMALIZED="${BASH_REMATCH[1]}"
45
+ return 0
46
+ fi
47
+ return 1
48
+ }
49
+
50
+ validate_service_fields() {
51
+ # 1. 服务名称:长度 1-50 字符
52
+ if [ -z "$SERVICE_NAME" ] || [ ${#SERVICE_NAME} -gt 50 ]; then
53
+ echo "❌ 服务名称长度需在 1-50 字符之间(当前长度: ${#SERVICE_NAME})"
54
+ exit 1
55
+ fi
56
+
57
+ # 2. 服务描述:长度 1-500 字符
58
+ if [ -z "$SERVICE_DESC" ] || [ ${#SERVICE_DESC} -gt 500 ]; then
59
+ echo "❌ 服务描述长度需在 1-500 字符之间(当前长度: ${#SERVICE_DESC})"
60
+ exit 1
61
+ fi
62
+
63
+ # 3. 服务地址:有效 URL
64
+ if [ -z "$RESOURCE_URL" ] || ! [[ "$RESOURCE_URL" =~ ^https?:// ]]; then
65
+ echo "❌ 请提供有效的 URL 地址(以 http:// 或 https:// 开头)"
66
+ exit 1
67
+ fi
68
+
69
+ # 4. 服务单价:提交值统一规范化为纯数字,模板负责追加“元/次”。
70
+ if [ -z "$PRICING" ] || ! normalize_service_pricing "$PRICING"; then
71
+ echo "❌ 服务单价格式不正确,请输入金额(如 0.03、0.03元或 0.03 元/次)"
72
+ exit 1
73
+ fi
74
+ PRICING="$SERVICE_PRICING_NORMALIZED"
75
+ PRICING_VALID=$(awk -v p="$PRICING" 'BEGIN { if (p + 0 >= 0.01) print "true"; else print "false" }')
76
+ if [ "$PRICING_VALID" = "false" ]; then
77
+ echo "❌ 服务单价最低为 0.01 元"
78
+ exit 1
79
+ fi
80
+
81
+ # 5. schemaUrl 在本流程中承载序列化后的 JSON 请求示例,不是 URL。
82
+ # CLI 接收原始 JSON;save 分支通过 jq --arg 将其安全写入字符串字段。
83
+ if [ -z "$SCHEMA_URL" ] || ! echo "$SCHEMA_URL" | jq . >/dev/null 2>&1; then
84
+ echo "❌ 请提供有效的 JSON 格式请求示例"
85
+ exit 1
86
+ fi
87
+ }
30
88
 
31
89
  # ─── service list: 查询已有服务 ──────────────────────────────────────────────
32
90
  fetch_service_page() {
@@ -39,9 +97,15 @@ fetch_service_page() {
39
97
  --argjson offset "$OFFSET" \
40
98
  '{request:{limit:$limit,offset:$offset}}')
41
99
 
42
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.discoverBazaarServicesForMcp \
100
+ export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
101
+ run_network_retry RESULT read service_list_page -- alipay-cli mcp call a2a-pay-service.discoverBazaarServicesForMcp \
43
102
  -d "$REQUEST_JSON" \
44
- --json 2>/dev/null)
103
+ --json
104
+ RETRY_RC=$?
105
+ if [ "$RETRY_RC" -ne 0 ]; then
106
+ echo "❌ 服务列表当前分页因网络或服务异常在自动重试两次后仍未恢复"
107
+ return 1
108
+ fi
45
109
 
46
110
  if ! handle_error "$RESULT"; then
47
111
  return 1
@@ -54,6 +118,7 @@ fetch_service_page() {
54
118
  BUSINESS_MESSAGE=$(echo "$BUSINESS" | jq -r '
55
119
  .subMsg // .data.subMsg // .msg // .data.msg // "未知错误"
56
120
  ' 2>/dev/null)
121
+ BUSINESS_MESSAGE=$(sanitize_customer_error_text "$BUSINESS_MESSAGE")
57
122
  echo "❌ 查询服务列表失败: ${BUSINESS_CODE} / ${BUSINESS_MESSAGE}"
58
123
  return 1
59
124
  fi
@@ -103,7 +168,7 @@ fetch_service_page() {
103
168
  }
104
169
 
105
170
  fetch_service_list() {
106
- local LIMIT=20
171
+ local LIMIT="$SERVICE_LIST_PAGE_LIMIT"
107
172
  local OFFSET=0
108
173
  local EXPECTED_TOTAL=""
109
174
  local PAGE_COUNT
@@ -155,9 +220,13 @@ fetch_service_list() {
155
220
  done
156
221
 
157
222
  if ! echo "$SERVICE_LIST" | jq -e '
158
- all(.[]; ((.serviceId | type) == "string") and (.serviceId | length > 0))
223
+ all(.[];
224
+ ((.serviceId | type) == "string") and
225
+ (.serviceId | length > 0) and
226
+ ((.serviceId | test("[\u0000-\u001f\u007f]") | not))
227
+ )
159
228
  ' >/dev/null 2>&1; then
160
- echo "❌ 服务列表返回结构异常:存在缺少 serviceId 的候选服务"
229
+ echo "❌ 服务列表返回结构异常:候选 serviceId 缺失或包含控制字符"
161
230
  return 1
162
231
  fi
163
232
 
@@ -169,40 +238,31 @@ service_list() {
169
238
  exit 1
170
239
  fi
171
240
 
241
+ SERVICE_CANDIDATES=$(echo "$SERVICE_LIST" | jq -c '[.[] | {
242
+ serviceId: .serviceId,
243
+ serviceName: ((.serviceName // "未知") | tostring),
244
+ serviceDesc: ((.serviceDesc // "无描述") | tostring),
245
+ pricing: ((.metadata.pricing // .pricing // "未知") | tostring),
246
+ serviceStatus: ((.serviceStatus // .status // "未知") | tostring),
247
+ resourceUrl: ((.resourceUrl // "未知") | tostring)
248
+ }]')
249
+ if ! printf '%s' "$SERVICE_CANDIDATES" | node "$CANDIDATE_RUNNER" service-candidates >/dev/null 2>&1; then
250
+ echo "❌ 服务候选事实安全校验失败"
251
+ emit_control "FLOW:ERROR"
252
+ exit 1
253
+ fi
254
+ if ! emit_control_field "SERVICE_CANDIDATES_JSON" "$SERVICE_CANDIDATES"; then
255
+ echo "❌ 服务候选事实包含非法控制字符"
256
+ emit_control "FLOW:ERROR"
257
+ exit 1
258
+ fi
259
+
172
260
  if [ "$SERVICE_COUNT" -eq 0 ] || [ "$SERVICE_LIST" = "[]" ] || [ -z "$SERVICE_LIST" ]; then
173
- echo "📋 暂无已有服务;记录新建候选分支,等待 Step 4 统一决策"
174
- echo "FLOW:CREATE_NEW"
261
+ emit_control "FLOW:CREATE_NEW"
175
262
  else
176
- echo "📋 发现您已有以下服务:"
177
- echo ""
178
- echo "| 序号 | 服务ID | 服务名称 | 描述 | 价格 | 实际状态 | 服务地址 |"
179
- echo "|------|--------|----------|------|------|----------|----------|"
180
-
181
- for i in $(seq 0 $((SERVICE_COUNT-1))); do
182
- SERVICE=$(echo "$SERVICE_LIST" | jq ".[$i]")
183
- SERVICE_ID=$(echo "$SERVICE" | jq -r '.serviceId // "未知"')
184
- SERVICE_NAME=$(echo "$SERVICE" | jq -r '.serviceName // "未知"')
185
- SERVICE_DESC=$(echo "$SERVICE" | jq -r '.serviceDesc // "无描述"')
186
- PRICING=$(echo "$SERVICE" | jq -r '.pricing // "未知"')
187
- SERVICE_STATUS=$(echo "$SERVICE" | jq -r '.serviceStatus // .status // "未知"')
188
- RESOURCE_URL=$(echo "$SERVICE" | jq -r '.resourceUrl // "未知"')
189
-
190
- case "$SERVICE_STATUS" in
191
- "ACTIVE") STATUS_CN="已上线" ;;
192
- "PENDING") STATUS_CN="审核中" ;;
193
- "REJECTED") STATUS_CN="审核拒绝" ;;
194
- *) STATUS_CN="$SERVICE_STATUS" ;;
195
- esac
196
-
197
- echo "| $((i+1)) | $SERVICE_ID | $SERVICE_NAME | $SERVICE_DESC | ${PRICING}元/次 | $STATUS_CN | $RESOURCE_URL |"
198
- done
199
-
200
- echo ""
201
- echo "请选择:"
202
- echo " • 输入序号 (1-${SERVICE_COUNT}) 复用对应服务"
203
- echo " • 输入\"新建\"创建新服务"
204
- echo " • 输入\"修改 + serviceId\"修改已有服务"
205
- echo "FLOW:SELECT"
263
+ echo "$SERVICE_LIST" | jq -r '.[] | "SERVICE_CANDIDATE_ID=" + .serviceId' \
264
+ | while IFS= read -r marker; do emit_control "$marker"; done
265
+ emit_control "FLOW:SELECT"
206
266
  fi
207
267
  }
208
268
 
@@ -245,14 +305,19 @@ service_save() {
245
305
  echo "用法(修改): bash service.sh save --service-id <id> --name <name> --desc <desc> --url <url> --pricing <pricing> --schema <json>"
246
306
  exit 1
247
307
  fi
308
+ if [ -n "$SERVICE_ID" ] && ! validate_control_value "$SERVICE_ID"; then
309
+ echo "❌ serviceId 包含非法控制字符"
310
+ exit 1
311
+ fi
312
+ validate_service_fields
248
313
 
249
314
  if [ -z "$SERVICE_ID" ]; then
250
315
  # 创建新服务(不传 serviceId)
251
316
  if ! fetch_service_list; then
252
317
  exit 1
253
318
  fi
254
- if [ "$SERVICE_COUNT" -ge 20 ]; then
255
- echo "❌ 已达到服务数量上限(20个),无法创建新服务"
319
+ if [ "$SERVICE_COUNT" -ge "$SERVICE_CREATE_LIMIT" ]; then
320
+ echo "❌ 已达到服务数量上限(${SERVICE_CREATE_LIMIT}个),无法创建新服务"
256
321
  echo "📋 您当前已有 $SERVICE_COUNT 个服务,请选择复用已有服务或修改已有服务"
257
322
  exit 1
258
323
  fi
@@ -265,9 +330,6 @@ service_save() {
265
330
  --arg schemaUrl "$SCHEMA_URL" \
266
331
  '{request:{serviceName:$serviceName,serviceDesc:$serviceDesc,resourceUrl:$resourceUrl,pricing:$pricing,schemaUrl:$schemaUrl}}')
267
332
 
268
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.saveBazaarServiceForMcp \
269
- -d "$REQUEST_JSON" \
270
- --json 2>/dev/null)
271
333
  else
272
334
  # 修改已有服务(必须传入 serviceId + 所有字段)
273
335
  REQUEST_JSON=$(jq -n \
@@ -279,9 +341,43 @@ service_save() {
279
341
  --arg schemaUrl "$SCHEMA_URL" \
280
342
  '{request:{serviceId:$serviceId,serviceName:$serviceName,serviceDesc:$serviceDesc,resourceUrl:$resourceUrl,pricing:$pricing,schemaUrl:$schemaUrl}}')
281
343
 
282
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.saveBazaarServiceForMcp \
283
- -d "$REQUEST_JSON" \
284
- --json 2>/dev/null)
344
+ fi
345
+
346
+ export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
347
+ run_network_retry RESULT write service_save -- alipay-cli mcp call a2a-pay-service.saveBazaarServiceForMcp \
348
+ -d "$REQUEST_JSON" \
349
+ --json
350
+ RETRY_RC=$?
351
+ if [ "$RETRY_RC" -eq 75 ]; then
352
+ if [ -z "$SERVICE_ID" ]; then
353
+ echo "❌ 服务创建响应不明;现有查询无法把同名候选唯一归属于本次创建,结果标记为 UNKNOWN,禁止自动重复创建"
354
+ exit 1
355
+ fi
356
+ if fetch_service_list; then
357
+ MATCH_COUNT=$(echo "$SERVICE_LIST" | jq --arg id "$SERVICE_ID" --arg name "$SERVICE_NAME" --arg desc "$SERVICE_DESC" --arg url "$RESOURCE_URL" --arg pricing "$PRICING" --arg schema "$SCHEMA_URL" '
358
+ [.[] | select(
359
+ .serviceId == $id and .serviceName == $name and .serviceDesc == $desc and
360
+ .resourceUrl == $url and
361
+ ((.metadata.pricing // .pricing) | tostring) == $pricing and
362
+ (.metadata.schema_url // .schemaUrl) == $schema
363
+ )] | length
364
+ ')
365
+ if [ "$MATCH_COUNT" -eq 1 ]; then
366
+ emit_control "✅ 服务修改已由列表查询核验成功"
367
+ emit_control "📋 服务ID: $SERVICE_ID"
368
+ emit_control_field "SERVICE_ID" "$SERVICE_ID" || return 1
369
+ return 0
370
+ fi
371
+ fi
372
+ echo "❌ 服务修改响应不明且现有列表无法排除传播延迟,结果标记为 UNKNOWN,禁止自动重复修改"
373
+ exit 1
374
+ elif [ "$RETRY_RC" -ne 0 ]; then
375
+ if [ -z "$SERVICE_ID" ]; then
376
+ echo "❌ 服务创建因明确未发送的网络异常在自动重试两次后仍未恢复"
377
+ else
378
+ echo "❌ 服务修改因明确未发送的网络异常在自动重试两次后仍未恢复"
379
+ fi
380
+ exit 1
285
381
  fi
286
382
 
287
383
  # 错误检测
@@ -320,12 +416,13 @@ service_save() {
320
416
  ')
321
417
  fi
322
418
 
323
- if [ -z "$NEW_SERVICE_ID" ]; then
419
+ if ! validate_control_value "$NEW_SERVICE_ID"; then
324
420
  echo "❌ 服务创建返回成功,但未解析到 serviceId,禁止继续后续流程"
325
421
  exit 1
326
422
  fi
327
- echo "✅ 服务${OPERATION}成功"
328
- echo "📋 服务ID: $NEW_SERVICE_ID"
423
+ emit_control "✅ 服务${OPERATION}成功"
424
+ emit_control "📋 服务ID: $NEW_SERVICE_ID"
425
+ emit_control_field "SERVICE_ID" "$NEW_SERVICE_ID" || exit 1
329
426
  else
330
427
  OPERATION="创建"
331
428
  if [ -n "$SERVICE_ID" ]; then
@@ -338,7 +435,8 @@ service_save() {
338
435
  .data.subMsg // .data.msg // .subMsg // .msg //
339
436
  .error.message // .errorMessage // "未知错误"
340
437
  ' 2>/dev/null)
341
- echo "❌ 服务${OPERATION}失败: ${BUSINESS_CODE} / ${ERROR_MSG:-未知错误}"
438
+ ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
439
+ echo "❌ 服务${OPERATION}失败: ${BUSINESS_CODE} / ${ERROR_MSG}"
342
440
  else
343
441
  echo "❌ 服务${OPERATION}返回结构异常,无法确认操作结果"
344
442
  fi
@@ -375,43 +473,10 @@ service_validate() {
375
473
  esac
376
474
  done
377
475
 
378
- # 1. 服务名称:长度 1-50 字符
379
- if [ -z "$SERVICE_NAME" ] || [ ${#SERVICE_NAME} -gt 50 ]; then
380
- echo "❌ 服务名称长度需在 1-50 字符之间(当前长度: ${#SERVICE_NAME})"
381
- exit 1
382
- fi
383
-
384
- # 2. 服务描述:长度 1-500 字符
385
- if [ -z "$SERVICE_DESC" ] || [ ${#SERVICE_DESC} -gt 500 ]; then
386
- echo "❌ 服务描述长度需在 1-500 字符之间(当前长度: ${#SERVICE_DESC})"
387
- exit 1
388
- fi
389
-
390
- # 3. 服务地址:有效 URL
391
- if [ -z "$RESOURCE_URL" ] || ! [[ "$RESOURCE_URL" =~ ^https?:// ]]; then
392
- echo "❌ 请提供有效的 URL 地址(以 http:// 或 https:// 开头)"
393
- exit 1
394
- fi
395
-
396
- # 4. 服务单价:数字格式,>= 0.01
397
- if [ -z "$PRICING" ] || ! [[ "$PRICING" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
398
- echo "❌ 服务单价格式不正确,请输入数字(如 0.01、1.00)"
399
- exit 1
400
- fi
401
- PRICING_VALID=$(awk -v p="$PRICING" 'BEGIN { if (p + 0 >= 0.01) print "true"; else print "false" }')
402
- if [ "$PRICING_VALID" = "false" ]; then
403
- echo "❌ 服务单价最低为 0.01 元"
404
- exit 1
405
- fi
406
-
407
- # 5. schemaUrl 在本流程中承载序列化后的 JSON 请求示例,不是 URL。
408
- # CLI 接收原始 JSON;save 分支通过 jq --arg 将其安全写入字符串字段。
409
- if [ -z "$SCHEMA_URL" ] || ! echo "$SCHEMA_URL" | jq . >/dev/null 2>&1; then
410
- echo "❌ 请提供有效的 JSON 格式请求示例"
411
- exit 1
412
- fi
476
+ validate_service_fields
413
477
 
414
- echo "✅ 服务信息校验通过"
478
+ emit_control "✅ 服务信息校验通过"
479
+ emit_control_field "SERVICE_PRICING" "$PRICING" || exit 1
415
480
  }
416
481
 
417
482
  # ─── 入口分发 ────────────────────────────────────────────────────────────────
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+
3
+ emit_signed_flow() {
4
+ case "$1" in
5
+ "I1080300001000041203") echo "FLOW:PC_WEB_SIGNED" ;;
6
+ "I1080300001000041313") echo "FLOW:APP_SIGNED" ;;
7
+ "I1080300001000160457") echo "FLOW:AI_PAY_SIGNED" ;;
8
+ *) return 1 ;;
9
+ esac
10
+ }
11
+
12
+ emit_sign_status_from_business() {
13
+ local business="$1"
14
+ local sales_code="$2"
15
+ local ar_list ar_count has_effective has_submitted
16
+
17
+ case "$sales_code" in
18
+ "I1080300001000041203"|"I1080300001000041313"|"I1080300001000160457") ;;
19
+ *) return 1 ;;
20
+ esac
21
+
22
+ ar_list=$(printf '%s' "$business" | jq -c '
23
+ if (.resultObj | type) == "object" and (.resultObj.arInfoList | type) == "array" then
24
+ .resultObj.arInfoList
25
+ else
26
+ null
27
+ end
28
+ ' 2>/dev/null) || return 1
29
+ [ -n "$ar_list" ] && printf '%s' "$ar_list" | jq -e 'type == "array"' >/dev/null 2>&1 || return 1
30
+ ar_count=$(printf '%s' "$ar_list" | jq 'length') || return 1
31
+
32
+ if [ "$ar_count" -eq 0 ]; then
33
+ echo "📋 签约状态: 未签约 (NOT_SIGNED);进入 Step 4 签约材料类别"
34
+ echo "SIGN_STATUS=NOT_SIGNED"
35
+ case "$sales_code" in
36
+ "I1080300001000041203") echo "FLOW:PC_WEB_NOT_SIGNED" ;;
37
+ "I1080300001000041313") echo "FLOW:APP_NOT_SIGNED" ;;
38
+ "I1080300001000160457") echo "FLOW:AI_PAY_NOT_SIGNED" ;;
39
+ esac
40
+ return 0
41
+ fi
42
+
43
+ has_effective=$(printf '%s' "$ar_list" | jq -r '[.[] | select(.arStatus == "02")] | length') || return 1
44
+ has_submitted=$(printf '%s' "$ar_list" | jq -r '[.[] | select(.arStatus == "01")] | length') || return 1
45
+ if [ "$has_effective" -gt 0 ]; then
46
+ echo "✅ 签约已生效;无需签约材料,继续 Step 4 资源决策"
47
+ echo "SIGN_STATUS=SIGNED_EFFECTIVE"
48
+ emit_signed_flow "$sales_code"
49
+ elif [ "$has_submitted" -gt 0 ]; then
50
+ echo "📋 已提交签约(待生效),无需重复提交签约,继续推进后续步骤"
51
+ echo "SIGN_STATUS=SIGN_SUBMITTED"
52
+ emit_signed_flow "$sales_code"
53
+ else
54
+ echo "📋 其他签约状态;保留已取得的只读结果并将签约分支标记为待核验"
55
+ echo "SIGN_STATUS=OTHER_STATUS"
56
+ echo "FLOW:OTHER_STATUS"
57
+ fi
58
+ }
@@ -2,10 +2,10 @@
2
2
  #=============================================================================
3
3
  # 脚本名称: upload_screenshots.sh
4
4
  # 功能描述: 并行上传截图文件并解析可用于签约的图片引用值
5
- # 调用位置: Step 4 一次性资料与资源决策
6
- # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME;需传入3个文件路径
7
- # 用法: bash upload_screenshots.sh "$HOME_IMG" "$SHOP_IMG" "$PAY_IMG"
8
- # 返回值: 输出上传结果和图片引用值
5
+ # 调用位置: Step 4 签约材料类别
6
+ # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME/PLATFORM_ID;需传入产品类型和3个文件路径
7
+ # 用法: bash upload_screenshots.sh --product-type <webpay|apppay> "$HOME_IMG" "$SHOP_IMG" "$PAY_IMG"
8
+ # 返回值: stdout 仅输出上传结果;stderr 输出图片引用值控制信号
9
9
  #=============================================================================
10
10
 
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -22,16 +22,28 @@ require_command jq || exit 1
22
22
  require_command alipay-cli || exit 1
23
23
  require_command mktemp || exit 1
24
24
 
25
- HOME_IMG="$1"
26
- SHOP_IMG="$2"
27
- PAY_IMG="$3"
25
+ if [ "${1:-}" != "--product-type" ] || [ "$#" -lt 5 ]; then
26
+ echo "❌ 请先传入 --product-type webpay|apppay"
27
+ exit 1
28
+ fi
29
+ PRODUCT_TYPE="$2"
30
+ shift 2
31
+ case "$PRODUCT_TYPE" in
32
+ webpay|apppay) ;;
33
+ *) echo "❌ 截图上传仅支持 webpay|apppay"; exit 1 ;;
34
+ esac
35
+ init_alipay_cli_product "$PRODUCT_TYPE" || exit 1
36
+
37
+ HOME_IMG="${1:-}"
38
+ SHOP_IMG="${2:-}"
39
+ PAY_IMG="${3:-}"
28
40
 
29
41
  # 校验参数
30
42
  if [ -z "$HOME_IMG" ] || [ -z "$SHOP_IMG" ] || [ -z "$PAY_IMG" ]; then
31
43
  echo "❌ 请提供 3 个截图文件路径"
32
- echo "用法: bash upload_screenshots.sh <首页截图> <商品页截图> <支付页截图>"
33
- echo " 网站支付:传入网站首页、商品页、支付页截图"
34
- echo " APP支付:传入APP首页、商品页、支付页截图"
44
+ echo "用法: bash upload_screenshots.sh --product-type <webpay|apppay> <首页截图> <商品页截图> <支付页截图>"
45
+ echo " AI 网页应用收款:传入网站首页、商品页、支付页截图"
46
+ echo " AI 移动应用收款:传入 APP 首页、商品页、支付页截图"
35
47
  exit 1
36
48
  fi
37
49
 
@@ -62,10 +74,10 @@ cleanup_upload_tmp() {
62
74
  }
63
75
  trap cleanup_upload_tmp EXIT
64
76
 
65
- # 并行上传 3 张截图
66
- export PLATFORM=${DEV_TOOL_NAME} && alipay-cli file upload "$HOME_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_HOME" &
67
- export PLATFORM=${DEV_TOOL_NAME} && alipay-cli file upload "$SHOP_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_SHOP" &
68
- export PLATFORM=${DEV_TOOL_NAME} && alipay-cli file upload "$PAY_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_PAY" &
77
+ # 并行上传 3 张截图。PLATFORM_ID 与 PRODUCT 均由公共上下文初始化。
78
+ PLATFORM="${DEV_TOOL_NAME:-unknown}" PLATFORM_ID="${PLATFORM_ID:-}" PRODUCT="${PRODUCT:-}" alipay-cli file upload "$HOME_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_HOME" &
79
+ PLATFORM="${DEV_TOOL_NAME:-unknown}" PLATFORM_ID="${PLATFORM_ID:-}" PRODUCT="${PRODUCT:-}" alipay-cli file upload "$SHOP_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_SHOP" &
80
+ PLATFORM="${DEV_TOOL_NAME:-unknown}" PLATFORM_ID="${PLATFORM_ID:-}" PRODUCT="${PRODUCT:-}" alipay-cli file upload "$PAY_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_PAY" &
69
81
  wait
70
82
 
71
83
  # 解析图片引用值(兼容 file upload 返回 fileKey 或 URL 字段)
@@ -143,10 +155,12 @@ if [ -n "$ERRORS" ]; then
143
155
  exit 1
144
156
  fi
145
157
 
158
+ if ! validate_control_value "$HOME_REF" || ! validate_control_value "$SHOP_REF" || ! validate_control_value "$PAY_REF"; then
159
+ echo "❌ 截图上传返回的图片引用包含非法控制字符"
160
+ exit 1
161
+ fi
162
+
146
163
  echo "✅ 截图上传成功"
147
- echo " - 首页截图: $HOME_REF"
148
- echo " - 商品页截图: $SHOP_REF"
149
- echo " - 支付页截图: $PAY_REF"
150
- echo ""
151
- echo "# 更新对话上下文状态:"
152
- echo "# collect_information = {\"screenshot\":[\"$HOME_REF\",\"$SHOP_REF\",\"$PAY_REF\"]}"
164
+ emit_control_field "SCREENSHOT_HOME_REF" "$HOME_REF" || exit 1
165
+ emit_control_field "SCREENSHOT_SHOP_REF" "$SHOP_REF" || exit 1
166
+ emit_control_field "SCREENSHOT_PAY_REF" "$PAY_REF" || exit 1