@alipay/alipay-aipay 1.2.2 → 1.4.9

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 (98) 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 +6 -5
  25. package/skill/SKILL.md +15 -169
  26. package/skill/VERSION +1 -1
  27. package/skill/references/integration/flow.md +321 -292
  28. package/skill/references/integration/modules/alipay-sdk-reminder.md +5 -3
  29. package/skill/references/integration/modules/checklist.md +41 -27
  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 +53 -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 +37 -72
  56. package/skill/references/integration/modules/product-decision.md +10 -27
  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 +357 -147
  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 +80 -0
  65. package/skill/references/normal/json/customer-messages.json +937 -0
  66. package/skill/references/normal/json/policy-rules.json +179 -0
  67. package/skill/references/normal/rejection-guide.md +11 -6
  68. package/skill/references/normal/scripts/alipay_cli_env.mjs +29 -0
  69. package/skill/references/normal/scripts/alipay_cli_env.sh +21 -0
  70. package/skill/references/normal/scripts/common.sh +87 -0
  71. package/skill/references/normal/scripts/detect_dev_tool.sh +5 -1
  72. package/skill/references/normal/scripts/integration_message_runner.mjs +801 -0
  73. package/skill/references/normal/scripts/onboarding_message_runner.mjs +436 -0
  74. package/skill/references/normal/scripts/open_official_url.sh +82 -0
  75. package/skill/references/normal/scripts/platform_compat.mjs +39 -0
  76. package/skill/references/normal/scripts/project_route_inspector.sh +132 -0
  77. package/skill/references/normal/scripts/python_script_runner.mjs +56 -0
  78. package/skill/references/normal/scripts/render_customer_message.mjs +1263 -0
  79. package/skill/references/normal/scripts/self_update.mjs +160 -0
  80. package/skill/references/normal/scripts/telemetry.mjs +1278 -0
  81. package/skill/references/normal/self-update.md +18 -51
  82. package/skill/references/onboarding/flow.md +381 -283
  83. package/skill/references/onboarding/modules/app-release.md +132 -179
  84. package/skill/references/onboarding/modules/authorization.md +53 -64
  85. package/skill/references/onboarding/modules/error-handling.md +31 -34
  86. package/skill/references/onboarding/modules/product-sign.md +62 -66
  87. package/skill/references/onboarding/modules/scripts/app.sh +397 -158
  88. package/skill/references/onboarding/modules/scripts/ar_sign_apply.sh +38 -22
  89. package/skill/references/onboarding/modules/scripts/auth.sh +479 -167
  90. package/skill/references/onboarding/modules/scripts/download_key_tool.sh +157 -0
  91. package/skill/references/onboarding/modules/scripts/error_handler.sh +100 -130
  92. package/skill/references/onboarding/modules/scripts/network_retry.sh +96 -0
  93. package/skill/references/onboarding/modules/scripts/query_sign_status.sh +17 -70
  94. package/skill/references/onboarding/modules/scripts/service.sh +153 -89
  95. package/skill/references/onboarding/modules/scripts/sign_status_parser.sh +58 -0
  96. package/skill/references/onboarding/modules/scripts/upload_screenshots.sh +16 -14
  97. package/skill/references/onboarding/modules/service-registration.md +67 -72
  98. package/skill/references/runtime-entry.md +62 -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
10
  # 按量付费: FLOW:AI_PAY_NOT_SIGNED | FLOW:AI_PAY_SIGNED
11
11
  # 网站支付: FLOW:PC_WEB_NOT_SIGNED | FLOW:PC_WEB_SIGNED
12
- # APP支付: FLOW:APP_NOT_SIGNED | FLOW:APP_SIGNED
12
+ # APP 支付: 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,16 @@ 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
- }
88
-
89
74
  # 查询签约状态
90
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call ar-query.queryArInfosBySalesProd \
75
+ export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
76
+ run_network_retry RESULT read query_sign_status -- alipay-cli mcp call ar-query.queryArInfosBySalesProd \
91
77
  -d "{\"request\":{\"salesProductCodes\":[\"${SALES_CODE}\"]},\"ctx\":{}}" \
92
- --json 2>/dev/null)
78
+ --json
79
+ RETRY_RC=$?
80
+ if [ "$RETRY_RC" -ne 0 ]; then
81
+ echo "❌ 签约状态查询因网络或服务异常在自动重试两次后仍未恢复"
82
+ exit 1
83
+ fi
93
84
 
94
85
  # 错误检测
95
86
  if ! handle_error "$RESULT"; then
@@ -99,54 +90,10 @@ fi
99
90
  # 解包 MCP 信封后解析业务字段
100
91
  BUSINESS=$(unwrap_mcp "$RESULT")
101
92
 
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
93
+ # 只有明确返回数组才可判断签约状态;缺少字段必须阻断,避免误判为未签约。
94
+ if ! SIGN_STATUS_OUTPUT=$(emit_sign_status_from_business "$BUSINESS" "$SALES_CODE"); then
111
95
  echo "❌ 签约状态返回结构异常,无法解析 arInfoList"
112
96
  exit 1
113
97
  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
98
+ printf '%s\n' "$SIGN_STATUS_OUTPUT" \
99
+ | 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,66 @@ 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
+
34
+ SERVICE_LIST_PAGE_LIMIT=10
35
+ SERVICE_CREATE_LIMIT=10
36
+
37
+ normalize_service_pricing() {
38
+ local raw="$1"
39
+ local pricing_pattern='^ *([0-9]+([.][0-9]+)?) *(元/次)? *$'
40
+ SERVICE_PRICING_NORMALIZED=""
41
+ case "$raw" in *$'\n'*|*$'\r'*|*$'\t'*) return 1 ;; esac
42
+ if [[ "$raw" =~ $pricing_pattern ]]; then
43
+ SERVICE_PRICING_NORMALIZED="${BASH_REMATCH[1]}"
44
+ return 0
45
+ fi
46
+ return 1
47
+ }
48
+
49
+ validate_service_fields() {
50
+ # 1. 服务名称:长度 1-50 字符
51
+ if [ -z "$SERVICE_NAME" ] || [ ${#SERVICE_NAME} -gt 50 ]; then
52
+ echo "❌ 服务名称长度需在 1-50 字符之间(当前长度: ${#SERVICE_NAME})"
53
+ exit 1
54
+ fi
55
+
56
+ # 2. 服务描述:长度 1-500 字符
57
+ if [ -z "$SERVICE_DESC" ] || [ ${#SERVICE_DESC} -gt 500 ]; then
58
+ echo "❌ 服务描述长度需在 1-500 字符之间(当前长度: ${#SERVICE_DESC})"
59
+ exit 1
60
+ fi
61
+
62
+ # 3. 服务地址:有效 URL
63
+ if [ -z "$RESOURCE_URL" ] || ! [[ "$RESOURCE_URL" =~ ^https?:// ]]; then
64
+ echo "❌ 请提供有效的 URL 地址(以 http:// 或 https:// 开头)"
65
+ exit 1
66
+ fi
67
+
68
+ # 4. 服务单价:提交值统一规范化为纯数字,模板负责追加“元/次”。
69
+ if [ -z "$PRICING" ] || ! normalize_service_pricing "$PRICING"; then
70
+ echo "❌ 服务单价格式不正确,请输入数字金额(如 0.01、1.00);模板会追加“元/次”单位"
71
+ exit 1
72
+ fi
73
+ PRICING="$SERVICE_PRICING_NORMALIZED"
74
+ PRICING_VALID=$(awk -v p="$PRICING" 'BEGIN { if (p + 0 >= 0.01) print "true"; else print "false" }')
75
+ if [ "$PRICING_VALID" = "false" ]; then
76
+ echo "❌ 服务单价最低为 0.01 元"
77
+ exit 1
78
+ fi
79
+
80
+ # 5. schemaUrl 在本流程中承载序列化后的 JSON 请求示例,不是 URL。
81
+ # CLI 接收原始 JSON;save 分支通过 jq --arg 将其安全写入字符串字段。
82
+ if [ -z "$SCHEMA_URL" ] || ! echo "$SCHEMA_URL" | jq . >/dev/null 2>&1; then
83
+ echo "❌ 请提供有效的 JSON 格式请求示例"
84
+ exit 1
85
+ fi
86
+ }
30
87
 
31
88
  # ─── service list: 查询已有服务 ──────────────────────────────────────────────
32
89
  fetch_service_page() {
@@ -39,9 +96,15 @@ fetch_service_page() {
39
96
  --argjson offset "$OFFSET" \
40
97
  '{request:{limit:$limit,offset:$offset}}')
41
98
 
42
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.discoverBazaarServicesForMcp \
99
+ export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
100
+ run_network_retry RESULT read service_list_page -- alipay-cli mcp call a2a-pay-service.discoverBazaarServicesForMcp \
43
101
  -d "$REQUEST_JSON" \
44
- --json 2>/dev/null)
102
+ --json
103
+ RETRY_RC=$?
104
+ if [ "$RETRY_RC" -ne 0 ]; then
105
+ echo "❌ 服务列表当前分页因网络或服务异常在自动重试两次后仍未恢复"
106
+ return 1
107
+ fi
45
108
 
46
109
  if ! handle_error "$RESULT"; then
47
110
  return 1
@@ -54,6 +117,7 @@ fetch_service_page() {
54
117
  BUSINESS_MESSAGE=$(echo "$BUSINESS" | jq -r '
55
118
  .subMsg // .data.subMsg // .msg // .data.msg // "未知错误"
56
119
  ' 2>/dev/null)
120
+ BUSINESS_MESSAGE=$(sanitize_customer_error_text "$BUSINESS_MESSAGE")
57
121
  echo "❌ 查询服务列表失败: ${BUSINESS_CODE} / ${BUSINESS_MESSAGE}"
58
122
  return 1
59
123
  fi
@@ -103,7 +167,7 @@ fetch_service_page() {
103
167
  }
104
168
 
105
169
  fetch_service_list() {
106
- local LIMIT=20
170
+ local LIMIT="$SERVICE_LIST_PAGE_LIMIT"
107
171
  local OFFSET=0
108
172
  local EXPECTED_TOTAL=""
109
173
  local PAGE_COUNT
@@ -155,9 +219,13 @@ fetch_service_list() {
155
219
  done
156
220
 
157
221
  if ! echo "$SERVICE_LIST" | jq -e '
158
- all(.[]; ((.serviceId | type) == "string") and (.serviceId | length > 0))
222
+ all(.[];
223
+ ((.serviceId | type) == "string") and
224
+ (.serviceId | length > 0) and
225
+ ((.serviceId | test("[\u0000-\u001f\u007f]") | not))
226
+ )
159
227
  ' >/dev/null 2>&1; then
160
- echo "❌ 服务列表返回结构异常:存在缺少 serviceId 的候选服务"
228
+ echo "❌ 服务列表返回结构异常:候选 serviceId 缺失或包含控制字符"
161
229
  return 1
162
230
  fi
163
231
 
@@ -169,40 +237,31 @@ service_list() {
169
237
  exit 1
170
238
  fi
171
239
 
240
+ SERVICE_CANDIDATES=$(echo "$SERVICE_LIST" | jq -c '[.[] | {
241
+ serviceId: .serviceId,
242
+ serviceName: ((.serviceName // "未知") | tostring),
243
+ serviceDesc: ((.serviceDesc // "无描述") | tostring),
244
+ pricing: ((.metadata.pricing // .pricing // "未知") | tostring),
245
+ serviceStatus: ((.serviceStatus // .status // "未知") | tostring),
246
+ resourceUrl: ((.resourceUrl // "未知") | tostring)
247
+ }]')
248
+ if ! printf '%s' "$SERVICE_CANDIDATES" | node "$CANDIDATE_RUNNER" service-candidates >/dev/null 2>&1; then
249
+ echo "❌ 服务候选事实安全校验失败"
250
+ emit_control "FLOW:ERROR"
251
+ exit 1
252
+ fi
253
+ if ! emit_control_field "SERVICE_CANDIDATES_JSON" "$SERVICE_CANDIDATES"; then
254
+ echo "❌ 服务候选事实包含非法控制字符"
255
+ emit_control "FLOW:ERROR"
256
+ exit 1
257
+ fi
258
+
172
259
  if [ "$SERVICE_COUNT" -eq 0 ] || [ "$SERVICE_LIST" = "[]" ] || [ -z "$SERVICE_LIST" ]; then
173
- echo "📋 暂无已有服务;记录新建候选分支,等待 Step 4 统一决策"
174
- echo "FLOW:CREATE_NEW"
260
+ emit_control "FLOW:CREATE_NEW"
175
261
  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"
262
+ echo "$SERVICE_LIST" | jq -r '.[] | "SERVICE_CANDIDATE_ID=" + .serviceId' \
263
+ | while IFS= read -r marker; do emit_control "$marker"; done
264
+ emit_control "FLOW:SELECT"
206
265
  fi
207
266
  }
208
267
 
@@ -245,14 +304,19 @@ service_save() {
245
304
  echo "用法(修改): bash service.sh save --service-id <id> --name <name> --desc <desc> --url <url> --pricing <pricing> --schema <json>"
246
305
  exit 1
247
306
  fi
307
+ if [ -n "$SERVICE_ID" ] && ! validate_control_value "$SERVICE_ID"; then
308
+ echo "❌ serviceId 包含非法控制字符"
309
+ exit 1
310
+ fi
311
+ validate_service_fields
248
312
 
249
313
  if [ -z "$SERVICE_ID" ]; then
250
314
  # 创建新服务(不传 serviceId)
251
315
  if ! fetch_service_list; then
252
316
  exit 1
253
317
  fi
254
- if [ "$SERVICE_COUNT" -ge 20 ]; then
255
- echo "❌ 已达到服务数量上限(20个),无法创建新服务"
318
+ if [ "$SERVICE_COUNT" -ge "$SERVICE_CREATE_LIMIT" ]; then
319
+ echo "❌ 已达到服务数量上限(${SERVICE_CREATE_LIMIT}个),无法创建新服务"
256
320
  echo "📋 您当前已有 $SERVICE_COUNT 个服务,请选择复用已有服务或修改已有服务"
257
321
  exit 1
258
322
  fi
@@ -265,9 +329,6 @@ service_save() {
265
329
  --arg schemaUrl "$SCHEMA_URL" \
266
330
  '{request:{serviceName:$serviceName,serviceDesc:$serviceDesc,resourceUrl:$resourceUrl,pricing:$pricing,schemaUrl:$schemaUrl}}')
267
331
 
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
332
  else
272
333
  # 修改已有服务(必须传入 serviceId + 所有字段)
273
334
  REQUEST_JSON=$(jq -n \
@@ -279,9 +340,43 @@ service_save() {
279
340
  --arg schemaUrl "$SCHEMA_URL" \
280
341
  '{request:{serviceId:$serviceId,serviceName:$serviceName,serviceDesc:$serviceDesc,resourceUrl:$resourceUrl,pricing:$pricing,schemaUrl:$schemaUrl}}')
281
342
 
282
- RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.saveBazaarServiceForMcp \
283
- -d "$REQUEST_JSON" \
284
- --json 2>/dev/null)
343
+ fi
344
+
345
+ export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
346
+ run_network_retry RESULT write service_save -- alipay-cli mcp call a2a-pay-service.saveBazaarServiceForMcp \
347
+ -d "$REQUEST_JSON" \
348
+ --json
349
+ RETRY_RC=$?
350
+ if [ "$RETRY_RC" -eq 75 ]; then
351
+ if [ -z "$SERVICE_ID" ]; then
352
+ echo "❌ 服务创建响应不明;现有查询无法把同名候选唯一归属于本次创建,结果标记为 UNKNOWN,禁止自动重复创建"
353
+ exit 1
354
+ fi
355
+ if fetch_service_list; then
356
+ 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" '
357
+ [.[] | select(
358
+ .serviceId == $id and .serviceName == $name and .serviceDesc == $desc and
359
+ .resourceUrl == $url and
360
+ ((.metadata.pricing // .pricing) | tostring) == $pricing and
361
+ (.metadata.schema_url // .schemaUrl) == $schema
362
+ )] | length
363
+ ')
364
+ if [ "$MATCH_COUNT" -eq 1 ]; then
365
+ emit_control "✅ 服务修改已由列表查询核验成功"
366
+ emit_control "📋 服务ID: $SERVICE_ID"
367
+ emit_control_field "SERVICE_ID" "$SERVICE_ID" || return 1
368
+ return 0
369
+ fi
370
+ fi
371
+ echo "❌ 服务修改响应不明且现有列表无法排除传播延迟,结果标记为 UNKNOWN,禁止自动重复修改"
372
+ exit 1
373
+ elif [ "$RETRY_RC" -ne 0 ]; then
374
+ if [ -z "$SERVICE_ID" ]; then
375
+ echo "❌ 服务创建因明确未发送的网络异常在自动重试两次后仍未恢复"
376
+ else
377
+ echo "❌ 服务修改因明确未发送的网络异常在自动重试两次后仍未恢复"
378
+ fi
379
+ exit 1
285
380
  fi
286
381
 
287
382
  # 错误检测
@@ -320,12 +415,13 @@ service_save() {
320
415
  ')
321
416
  fi
322
417
 
323
- if [ -z "$NEW_SERVICE_ID" ]; then
418
+ if ! validate_control_value "$NEW_SERVICE_ID"; then
324
419
  echo "❌ 服务创建返回成功,但未解析到 serviceId,禁止继续后续流程"
325
420
  exit 1
326
421
  fi
327
- echo "✅ 服务${OPERATION}成功"
328
- echo "📋 服务ID: $NEW_SERVICE_ID"
422
+ emit_control "✅ 服务${OPERATION}成功"
423
+ emit_control "📋 服务ID: $NEW_SERVICE_ID"
424
+ emit_control_field "SERVICE_ID" "$NEW_SERVICE_ID" || exit 1
329
425
  else
330
426
  OPERATION="创建"
331
427
  if [ -n "$SERVICE_ID" ]; then
@@ -338,7 +434,8 @@ service_save() {
338
434
  .data.subMsg // .data.msg // .subMsg // .msg //
339
435
  .error.message // .errorMessage // "未知错误"
340
436
  ' 2>/dev/null)
341
- echo "❌ 服务${OPERATION}失败: ${BUSINESS_CODE} / ${ERROR_MSG:-未知错误}"
437
+ ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
438
+ echo "❌ 服务${OPERATION}失败: ${BUSINESS_CODE} / ${ERROR_MSG}"
342
439
  else
343
440
  echo "❌ 服务${OPERATION}返回结构异常,无法确认操作结果"
344
441
  fi
@@ -375,43 +472,10 @@ service_validate() {
375
472
  esac
376
473
  done
377
474
 
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
475
+ validate_service_fields
413
476
 
414
- echo "✅ 服务信息校验通过"
477
+ emit_control "✅ 服务信息校验通过"
478
+ emit_control_field "SERVICE_PRICING" "$PRICING" || exit 1
415
479
  }
416
480
 
417
481
  # ─── 入口分发 ────────────────────────────────────────────────────────────────
@@ -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个文件路径
5
+ # 调用位置: Step 4 签约材料类别
6
+ # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME/PLATFORM_ID;需传入3个文件路径
7
7
  # 用法: bash upload_screenshots.sh "$HOME_IMG" "$SHOP_IMG" "$PAY_IMG"
8
- # 返回值: 输出上传结果和图片引用值
8
+ # 返回值: stdout 仅输出上传结果;stderr 输出图片引用值控制信号
9
9
  #=============================================================================
10
10
 
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -31,7 +31,7 @@ if [ -z "$HOME_IMG" ] || [ -z "$SHOP_IMG" ] || [ -z "$PAY_IMG" ]; then
31
31
  echo "❌ 请提供 3 个截图文件路径"
32
32
  echo "用法: bash upload_screenshots.sh <首页截图> <商品页截图> <支付页截图>"
33
33
  echo " 网站支付:传入网站首页、商品页、支付页截图"
34
- echo " APP支付:传入APP首页、商品页、支付页截图"
34
+ echo " APP 支付:传入 APP 首页、商品页、支付页截图"
35
35
  exit 1
36
36
  fi
37
37
 
@@ -62,10 +62,10 @@ cleanup_upload_tmp() {
62
62
  }
63
63
  trap cleanup_upload_tmp EXIT
64
64
 
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" &
65
+ # 并行上传 3 张截图。PLATFORM_ID 由 common.sh 从当前 telemetry run 派生,缺失不阻断上传。
66
+ PLATFORM="${DEV_TOOL_NAME:-unknown}" PLATFORM_ID="${PLATFORM_ID:-}" alipay-cli file upload "$HOME_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_HOME" &
67
+ PLATFORM="${DEV_TOOL_NAME:-unknown}" PLATFORM_ID="${PLATFORM_ID:-}" alipay-cli file upload "$SHOP_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_SHOP" &
68
+ PLATFORM="${DEV_TOOL_NAME:-unknown}" PLATFORM_ID="${PLATFORM_ID:-}" alipay-cli file upload "$PAY_IMG" -s payMerchantcodeSkill --json 2>/dev/null > "$TMP_PAY" &
69
69
  wait
70
70
 
71
71
  # 解析图片引用值(兼容 file upload 返回 fileKey 或 URL 字段)
@@ -143,10 +143,12 @@ if [ -n "$ERRORS" ]; then
143
143
  exit 1
144
144
  fi
145
145
 
146
+ if ! validate_control_value "$HOME_REF" || ! validate_control_value "$SHOP_REF" || ! validate_control_value "$PAY_REF"; then
147
+ echo "❌ 截图上传返回的图片引用包含非法控制字符"
148
+ exit 1
149
+ fi
150
+
146
151
  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\"]}"
152
+ emit_control_field "SCREENSHOT_HOME_REF" "$HOME_REF" || exit 1
153
+ emit_control_field "SCREENSHOT_SHOP_REF" "$SHOP_REF" || exit 1
154
+ emit_control_field "SCREENSHOT_PAY_REF" "$PAY_REF" || exit 1