@alipay/alipay-aipay 1.1.0 → 1.2.2

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 (41) hide show
  1. package/dist/commands/install.js +1 -1
  2. package/dist/commands/install.js.map +1 -1
  3. package/dist/commands/update.js +1 -1
  4. package/dist/commands/update.js.map +1 -1
  5. package/dist/utils/alipay-cli.js +4 -4
  6. package/dist/utils/alipay-cli.js.map +1 -1
  7. package/package.json +3 -4
  8. package/skill/SKILL.md +75 -12
  9. package/skill/VERSION +1 -1
  10. package/skill/references/integration/flow.md +150 -108
  11. package/skill/references/integration/modules/alipay-sdk-reminder.md +29 -13
  12. package/skill/references/integration/modules/checklist.md +49 -19
  13. 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 +3 -3
  14. package/skill/references/integration/modules/code-examples/csharp/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.cs +27 -13
  15. 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 +3 -3
  16. package/skill/references/integration/modules/code-examples/java/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemoController.java +31 -12
  17. 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 +5 -4
  18. package/skill/references/integration/modules/code-examples/nodejs/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.js +69 -37
  19. 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 +3 -3
  20. package/skill/references/integration/modules/code-examples/php/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.php +38 -17
  21. 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 +3 -3
  22. package/skill/references/integration/modules/code-examples/python/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.py +31 -18
  23. package/skill/references/integration/modules/interface-guide.md +7 -3
  24. package/skill/references/integration/modules/sandbox/a2m-sandbox-test.md +76 -54
  25. package/skill/references/integration/modules/sandbox/alipay-sandbox-tool.md +3 -3
  26. package/skill/references/integration/modules/sandbox/sandbox-setup-guide.md +80 -24
  27. package/skill/references/integration/modules/scripts/local_402_sandbox_pay.py +35 -4
  28. package/skill/references/normal/alipay-cli-env.md +2 -2
  29. package/skill/references/normal/self-update.md +2 -2
  30. package/skill/references/onboarding/flow.md +193 -297
  31. package/skill/references/onboarding/modules/app-release.md +91 -35
  32. package/skill/references/onboarding/modules/authorization.md +19 -13
  33. package/skill/references/onboarding/modules/error-handling.md +19 -14
  34. package/skill/references/onboarding/modules/product-sign.md +22 -21
  35. package/skill/references/onboarding/modules/scripts/app.sh +139 -40
  36. package/skill/references/onboarding/modules/scripts/auth.sh +168 -99
  37. package/skill/references/onboarding/modules/scripts/error_handler.sh +148 -18
  38. package/skill/references/onboarding/modules/scripts/query_sign_status.sh +17 -11
  39. package/skill/references/onboarding/modules/scripts/service.sh +208 -37
  40. package/skill/references/onboarding/modules/scripts/upload_screenshots.sh +1 -1
  41. package/skill/references/onboarding/modules/service-registration.md +72 -29
@@ -2,14 +2,14 @@
2
2
  #=============================================================================
3
3
  # 脚本名称: service.sh
4
4
  # 功能描述: 服务市场注册 - 查询已有服务 + 创建/修改服务
5
- # 调用位置: Step 5.2 服务市场注册
5
+ # 调用位置: list 用于 Step 3.1 前置资源查询;save/validate 用于 Step 5.2 服务市场注册
6
6
  # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME;必要时可用 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
12
+ # list: 输出服务列表 + FLOW:CREATE_NEW | FLOW:SELECT
13
13
  # save: 输出 ✅/❌ + serviceId(无 FLOW 标记,由 Agent 根据退出码判断)
14
14
  # validate: 输出 ✅/❌ + 校验详情(退出码 0=通过, 1=失败)
15
15
  #=============================================================================
@@ -29,9 +29,18 @@ require_command alipay-cli || exit 1
29
29
  require_command awk || exit 1
30
30
 
31
31
  # ─── service list: 查询已有服务 ──────────────────────────────────────────────
32
- fetch_service_list() {
32
+ fetch_service_page() {
33
+ local OFFSET="$1"
34
+ local LIMIT="$2"
35
+ local REQUEST_JSON RESULT BUSINESS BUSINESS_CODE BUSINESS_MESSAGE
36
+
37
+ REQUEST_JSON=$(jq -n \
38
+ --argjson limit "$LIMIT" \
39
+ --argjson offset "$OFFSET" \
40
+ '{request:{limit:$limit,offset:$offset}}')
41
+
33
42
  RESULT=$(export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.discoverBazaarServicesForMcp \
34
- -d '{"request":{"serviceStatus":"ACTIVE"}}' \
43
+ -d "$REQUEST_JSON" \
35
44
  --json 2>/dev/null)
36
45
 
37
46
  if ! handle_error "$RESULT"; then
@@ -39,9 +48,116 @@ fetch_service_list() {
39
48
  fi
40
49
 
41
50
  BUSINESS=$(unwrap_mcp "$RESULT")
42
- SERVICE_LIST=$(echo "$BUSINESS" | jq -c '.resultObj.serviceList // []' 2>/dev/null)
43
- if [ -z "$SERVICE_LIST" ] || ! echo "$SERVICE_LIST" | jq -e 'type == "array"' >/dev/null 2>&1; then
44
- echo "❌ 服务列表返回结构异常,无法解析 serviceList"
51
+
52
+ BUSINESS_CODE=$(echo "$BUSINESS" | jq -r 'if has("code") then (.code | tostring) else "" end' 2>/dev/null)
53
+ if [ -n "$BUSINESS_CODE" ] && [ "$BUSINESS_CODE" != "10000" ]; then
54
+ BUSINESS_MESSAGE=$(echo "$BUSINESS" | jq -r '
55
+ .subMsg // .data.subMsg // .msg // .data.msg // "未知错误"
56
+ ' 2>/dev/null)
57
+ echo "❌ 查询服务列表失败: ${BUSINESS_CODE} / ${BUSINESS_MESSAGE}"
58
+ return 1
59
+ fi
60
+
61
+ PAGE_FORMAT=$(echo "$BUSINESS" | jq -r '
62
+ if ((.code | tostring) == "10000") and
63
+ ((.data | type) == "object") and
64
+ ((.data.items | type) == "array") and
65
+ ((.data.pagination | type) == "object") and
66
+ ((.data.pagination.total | type) == "number") and
67
+ (.data.pagination.total >= 0) and
68
+ ((.data.pagination.total | floor) == .data.pagination.total) and
69
+ ((.data.pagination.offset | type) == "number") and
70
+ (.data.pagination.offset >= 0) and
71
+ ((.data.pagination.offset | floor) == .data.pagination.offset) then
72
+ "current"
73
+ elif (.success == true) and
74
+ ((.resultObj | type) == "object") and
75
+ ((.resultObj.serviceList | type) == "array") then
76
+ "legacy"
77
+ else
78
+ "invalid"
79
+ end
80
+ ' 2>/dev/null)
81
+
82
+ case "$PAGE_FORMAT" in
83
+ current)
84
+ PAGE_ITEMS=$(echo "$BUSINESS" | jq -c '.data.items')
85
+ PAGE_TOTAL=$(echo "$BUSINESS" | jq -r '.data.pagination.total')
86
+ PAGE_OFFSET=$(echo "$BUSINESS" | jq -r '.data.pagination.offset')
87
+ ;;
88
+ legacy)
89
+ PAGE_ITEMS=$(echo "$BUSINESS" | jq -c '.resultObj.serviceList')
90
+ PAGE_TOTAL=$(echo "$PAGE_ITEMS" | jq 'length')
91
+ PAGE_OFFSET=0
92
+ ;;
93
+ *)
94
+ echo "❌ 服务列表返回结构异常,无法解析 data.items 或兼容的 resultObj.serviceList"
95
+ return 1
96
+ ;;
97
+ esac
98
+
99
+ if [ -z "$PAGE_ITEMS" ] || ! echo "$PAGE_ITEMS" | jq -e 'type == "array"' >/dev/null 2>&1; then
100
+ echo "❌ 服务列表返回结构异常,列表字段不是数组"
101
+ return 1
102
+ fi
103
+ }
104
+
105
+ fetch_service_list() {
106
+ local LIMIT=20
107
+ local OFFSET=0
108
+ local EXPECTED_TOTAL=""
109
+ local PAGE_COUNT
110
+
111
+ SERVICE_LIST='[]'
112
+
113
+ while true; do
114
+ if ! fetch_service_page "$OFFSET" "$LIMIT"; then
115
+ return 1
116
+ fi
117
+
118
+ if [ "$PAGE_FORMAT" = "legacy" ]; then
119
+ SERVICE_LIST="$PAGE_ITEMS"
120
+ break
121
+ fi
122
+
123
+ if [ "$PAGE_OFFSET" -ne "$OFFSET" ]; then
124
+ echo "❌ 服务列表分页返回异常:期望 offset=${OFFSET},实际 offset=${PAGE_OFFSET}"
125
+ return 1
126
+ fi
127
+
128
+ if [ -z "$EXPECTED_TOTAL" ]; then
129
+ EXPECTED_TOTAL="$PAGE_TOTAL"
130
+ elif [ "$PAGE_TOTAL" -ne "$EXPECTED_TOTAL" ]; then
131
+ echo "❌ 服务列表分页返回异常:分页过程中 total 发生变化"
132
+ return 1
133
+ fi
134
+
135
+ SERVICE_LIST=$(jq -cn \
136
+ --argjson existing "$SERVICE_LIST" \
137
+ --argjson page "$PAGE_ITEMS" \
138
+ '$existing + $page')
139
+ SERVICE_COUNT=$(echo "$SERVICE_LIST" | jq 'length')
140
+
141
+ if [ "$SERVICE_COUNT" -gt "$EXPECTED_TOTAL" ]; then
142
+ echo "❌ 服务列表分页返回异常:已返回数量超过 total"
143
+ return 1
144
+ fi
145
+ if [ "$SERVICE_COUNT" -eq "$EXPECTED_TOTAL" ]; then
146
+ break
147
+ fi
148
+
149
+ PAGE_COUNT=$(echo "$PAGE_ITEMS" | jq 'length')
150
+ if [ "$PAGE_COUNT" -eq 0 ]; then
151
+ echo "❌ 服务列表分页返回异常:尚有未返回数据但当前页为空"
152
+ return 1
153
+ fi
154
+ OFFSET="$SERVICE_COUNT"
155
+ done
156
+
157
+ if ! echo "$SERVICE_LIST" | jq -e '
158
+ all(.[]; ((.serviceId | type) == "string") and (.serviceId | length > 0))
159
+ ' >/dev/null 2>&1; then
160
+ echo "❌ 服务列表返回结构异常:存在缺少 serviceId 的候选服务"
45
161
  return 1
46
162
  fi
47
163
 
@@ -54,14 +170,13 @@ service_list() {
54
170
  fi
55
171
 
56
172
  if [ "$SERVICE_COUNT" -eq 0 ] || [ "$SERVICE_LIST" = "[]" ] || [ -z "$SERVICE_LIST" ]; then
57
- echo "📋 暂无服务上架,需要创建新服务"
173
+ echo "📋 暂无已有服务;记录新建候选分支,等待 Step 4 统一决策"
58
174
  echo "FLOW:CREATE_NEW"
59
175
  else
60
- # 输出服务列表
61
176
  echo "📋 发现您已有以下服务:"
62
177
  echo ""
63
- echo "| 序号 | 服务ID | 服务名称 | 描述 | 价格 | 状态 | 服务地址 |"
64
- echo "|------|--------|----------|------|------|------|----------|"
178
+ echo "| 序号 | 服务ID | 服务名称 | 描述 | 价格 | 实际状态 | 服务地址 |"
179
+ echo "|------|--------|----------|------|------|----------|----------|"
65
180
 
66
181
  for i in $(seq 0 $((SERVICE_COUNT-1))); do
67
182
  SERVICE=$(echo "$SERVICE_LIST" | jq ".[$i]")
@@ -69,11 +184,11 @@ service_list() {
69
184
  SERVICE_NAME=$(echo "$SERVICE" | jq -r '.serviceName // "未知"')
70
185
  SERVICE_DESC=$(echo "$SERVICE" | jq -r '.serviceDesc // "无描述"')
71
186
  PRICING=$(echo "$SERVICE" | jq -r '.pricing // "未知"')
72
- SERVICE_STATUS=$(echo "$SERVICE" | jq -r '.status // "未知"')
187
+ SERVICE_STATUS=$(echo "$SERVICE" | jq -r '.serviceStatus // .status // "未知"')
73
188
  RESOURCE_URL=$(echo "$SERVICE" | jq -r '.resourceUrl // "未知"')
74
189
 
75
190
  case "$SERVICE_STATUS" in
76
- "ONLINE") STATUS_CN="已上架" ;;
191
+ "ACTIVE") STATUS_CN="已上线" ;;
77
192
  "PENDING") STATUS_CN="审核中" ;;
78
193
  "REJECTED") STATUS_CN="审核拒绝" ;;
79
194
  *) STATUS_CN="$SERVICE_STATUS" ;;
@@ -84,9 +199,9 @@ service_list() {
84
199
 
85
200
  echo ""
86
201
  echo "请选择:"
87
- echo " • 输入序号(1-$SERVICE_COUNT)复用对应服务"
202
+ echo " • 输入序号 (1-${SERVICE_COUNT}) 复用对应服务"
88
203
  echo " • 输入\"新建\"创建新服务"
89
- echo " • 输入\"修改\"修改已有服务"
204
+ echo " • 输入\"修改 + serviceId\"修改已有服务"
90
205
  echo "FLOW:SELECT"
91
206
  fi
92
207
  }
@@ -102,12 +217,24 @@ service_save() {
102
217
 
103
218
  while [[ $# -gt 0 ]]; do
104
219
  case $1 in
105
- --service-id) SERVICE_ID="$2"; shift 2 ;;
106
- --name) SERVICE_NAME="$2"; shift 2 ;;
107
- --desc) SERVICE_DESC="$2"; shift 2 ;;
108
- --url) RESOURCE_URL="$2"; shift 2 ;;
109
- --pricing) PRICING="$2"; shift 2 ;;
110
- --schema) SCHEMA_URL="$2"; shift 2 ;;
220
+ --service-id)
221
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
222
+ SERVICE_ID="$2"; shift 2 ;;
223
+ --name)
224
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
225
+ SERVICE_NAME="$2"; shift 2 ;;
226
+ --desc)
227
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
228
+ SERVICE_DESC="$2"; shift 2 ;;
229
+ --url)
230
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
231
+ RESOURCE_URL="$2"; shift 2 ;;
232
+ --pricing)
233
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
234
+ PRICING="$2"; shift 2 ;;
235
+ --schema)
236
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
237
+ SCHEMA_URL="$2"; shift 2 ;;
111
238
  *) echo "❌ 未知参数: $1"; exit 1 ;;
112
239
  esac
113
240
  done
@@ -162,26 +289,59 @@ service_save() {
162
289
  exit 1
163
290
  fi
164
291
 
165
- # 解包 MCP 信封后解析业务字段
292
+ # 解包 MCP 信封后按当前协议解析,并兼容旧 success/resultObj 协议。
166
293
  BUSINESS=$(unwrap_mcp "$RESULT")
167
- SUCCESS=$(echo "$BUSINESS" | jq -r '.success // false')
168
-
169
- if [ "$SUCCESS" = "true" ]; then
170
- OPERATION="上架"
294
+ SAVE_FORMAT=$(echo "$BUSINESS" | jq -r '
295
+ if ((.code | tostring) == "10000") and
296
+ ((.data | type) == "object") and
297
+ (.data.success == true) then
298
+ "current"
299
+ elif (.success == true) and
300
+ ((.resultObj | type) == "object") then
301
+ "legacy"
302
+ else
303
+ "invalid"
304
+ end
305
+ ' 2>/dev/null)
306
+
307
+ if [ "$SAVE_FORMAT" = "current" ] || [ "$SAVE_FORMAT" = "legacy" ]; then
308
+ OPERATION="创建"
171
309
  if [ -n "$SERVICE_ID" ]; then
172
310
  OPERATION="修改"
173
311
  fi
174
- # 使用 --arg 安全拼接回退值
175
- NEW_SERVICE_ID=$(echo "$BUSINESS" | jq -r --arg fallback "${SERVICE_ID}" '.resultObj.serviceId // $fallback')
312
+
313
+ if [ "$SAVE_FORMAT" = "current" ]; then
314
+ NEW_SERVICE_ID=$(echo "$BUSINESS" | jq -r --arg fallback "${SERVICE_ID}" '
315
+ (.data.serviceId | select(type == "string" and length > 0)) // $fallback
316
+ ')
317
+ else
318
+ NEW_SERVICE_ID=$(echo "$BUSINESS" | jq -r --arg fallback "${SERVICE_ID}" '
319
+ (.resultObj.serviceId | select(type == "string" and length > 0)) // $fallback
320
+ ')
321
+ fi
322
+
323
+ if [ -z "$NEW_SERVICE_ID" ]; then
324
+ echo "❌ 服务创建返回成功,但未解析到 serviceId,禁止继续后续流程"
325
+ exit 1
326
+ fi
176
327
  echo "✅ 服务${OPERATION}成功"
177
328
  echo "📋 服务ID: $NEW_SERVICE_ID"
178
329
  else
179
- ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
180
- OPERATION="上架"
330
+ OPERATION="创建"
181
331
  if [ -n "$SERVICE_ID" ]; then
182
332
  OPERATION="修改"
183
333
  fi
184
- echo "❌ 服务${OPERATION}失败: $ERROR_MSG"
334
+
335
+ BUSINESS_CODE=$(echo "$BUSINESS" | jq -r 'if has("code") then (.code | tostring) else "" end' 2>/dev/null)
336
+ if [ -n "$BUSINESS_CODE" ] && [ "$BUSINESS_CODE" != "10000" ]; then
337
+ ERROR_MSG=$(echo "$BUSINESS" | jq -r '
338
+ .data.subMsg // .data.msg // .subMsg // .msg //
339
+ .error.message // .errorMessage // "未知错误"
340
+ ' 2>/dev/null)
341
+ echo "❌ 服务${OPERATION}失败: ${BUSINESS_CODE} / ${ERROR_MSG:-未知错误}"
342
+ else
343
+ echo "❌ 服务${OPERATION}返回结构异常,无法确认操作结果"
344
+ fi
185
345
  exit 1
186
346
  fi
187
347
  }
@@ -196,11 +356,21 @@ service_validate() {
196
356
 
197
357
  while [[ $# -gt 0 ]]; do
198
358
  case $1 in
199
- --name) SERVICE_NAME="$2"; shift 2 ;;
200
- --desc) SERVICE_DESC="$2"; shift 2 ;;
201
- --url) RESOURCE_URL="$2"; shift 2 ;;
202
- --pricing) PRICING="$2"; shift 2 ;;
203
- --schema) SCHEMA_URL="$2"; shift 2 ;;
359
+ --name)
360
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
361
+ SERVICE_NAME="$2"; shift 2 ;;
362
+ --desc)
363
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
364
+ SERVICE_DESC="$2"; shift 2 ;;
365
+ --url)
366
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
367
+ RESOURCE_URL="$2"; shift 2 ;;
368
+ --pricing)
369
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
370
+ PRICING="$2"; shift 2 ;;
371
+ --schema)
372
+ [ $# -ge 2 ] || { echo "❌ 缺少参数值: $1"; exit 1; }
373
+ SCHEMA_URL="$2"; shift 2 ;;
204
374
  *) echo "❌ 未知参数: $1"; exit 1 ;;
205
375
  esac
206
376
  done
@@ -234,7 +404,8 @@ service_validate() {
234
404
  exit 1
235
405
  fi
236
406
 
237
- # 5. 请求示例:有效 JSON(改用 jq 代替 python3,与脚本其他部分保持一致)
407
+ # 5. schemaUrl 在本流程中承载序列化后的 JSON 请求示例,不是 URL。
408
+ # CLI 接收原始 JSON;save 分支通过 jq --arg 将其安全写入字符串字段。
238
409
  if [ -z "$SCHEMA_URL" ] || ! echo "$SCHEMA_URL" | jq . >/dev/null 2>&1; then
239
410
  echo "❌ 请提供有效的 JSON 格式请求示例"
240
411
  exit 1
@@ -2,7 +2,7 @@
2
2
  #=============================================================================
3
3
  # 脚本名称: upload_screenshots.sh
4
4
  # 功能描述: 并行上传截图文件并解析可用于签约的图片引用值
5
- # 调用位置: Step 4 资料采集
5
+ # 调用位置: Step 4 一次性资料与资源决策
6
6
  # 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME;需传入3个文件路径
7
7
  # 用法: bash upload_screenshots.sh "$HOME_IMG" "$SHOP_IMG" "$PAY_IMG"
8
8
  # 返回值: 输出上传结果和图片引用值
@@ -1,7 +1,7 @@
1
1
  # 服务市场注册模块
2
2
 
3
3
  > 本文档定义按量付费产品的服务市场上架流程。**仅按量付费产品需要服务市场注册**。
4
- > 被引用文档:`SKILL.md` → Step 5 入驻推进 - 服务注册部分
4
+ > 被引用文档:`onboarding/flow.md` → Step 3.1 服务查询 + Step 5.2 服务注册
5
5
  > 本文档位于 `references/onboarding/modules/`,文中的 `scripts/...` 路径相对本目录;从技能包根目录执行时对应 `references/onboarding/modules/scripts/...`。
6
6
 
7
7
  ---
@@ -32,11 +32,11 @@
32
32
  │ └─ 调用 discoverBazaarServicesForMcp │
33
33
  │ │
34
34
  │ Step 2: 判断服务列表 │
35
- │ ├─ serviceList 为空 → 进入 Step 3 交互式收集服务信息 │
36
- │ └─ serviceList 不为空 → 进入 Step 3 让用户选择操作 │
35
+ │ ├─ data.items 为空 → 进入 Step 3 收集服务信息 │
36
+ │ └─ data.items 不为空 → 展示完整分页结果后进入 Step 3 决策 │
37
37
  │ │
38
38
  │ Step 3: 用户决策 │
39
- │ ├─ 选择序号(复用已有服务)→ 跳过创建,完成 │
39
+ │ ├─ 选择序号复用已有服务 → 跳过创建,完成 │
40
40
  │ ├─ 选择"新建" → ⚠️ 检查服务数量,若 ≥ 20 则禁止创建 │
41
41
  │ │ 若 < 20,收集 5 项服务信息,进入 Step 4 │
42
42
  │ └─ 选择"修改" → 输入服务ID,收集所有服务信息,进入 Step 4 │
@@ -72,7 +72,7 @@
72
72
 
73
73
  ## Step 2: 根据查询结果执行不同分支
74
74
 
75
- ### 场景 A:serviceList 为空(无已有服务)
75
+ ### 场景 A:服务列表为空(无已有服务)
76
76
 
77
77
  **此时必须进入 Step 3 收集服务信息并创建新服务。**
78
78
 
@@ -80,24 +80,24 @@
80
80
  >
81
81
  > ⚠️ 注意:服务数量上限为 20 个,`service.sh save` 在创建前会校验。
82
82
 
83
- ### 场景 B:serviceList 不为空(有已有服务)
83
+ ### 场景 B:服务列表不为空(有已有服务)
84
84
 
85
- **此时必须让用户选择是复用已有服务还是创建新服务。**
85
+ **此时必须按接口返回结果展示服务及其实际状态,让用户选择复用、创建或修改。Skill 不额外按状态过滤复用候选。**
86
86
 
87
87
  **输出格式:**
88
88
 
89
89
  ```markdown
90
90
  📋 发现您已有以下服务:
91
91
 
92
- | 序号 | 服务ID | 服务名称 | 描述 | 价格 | 状态 | 服务地址 |
93
- |------|--------|----------|------|------|------|----------|
94
- | 1 | SVC001 | 天气查询 | 提供全球天气查询 | 0.01元/次 | 已上架 | https://api.example.com/weather |
92
+ | 序号 | 服务ID | 服务名称 | 描述 | 价格 | 实际状态 | 服务地址 |
93
+ |------|--------|----------|------|------|----------|----------|
94
+ | 1 | SVC001 | 天气查询 | 提供全球天气查询 | 0.01元/次 | 已上线 | https://api.example.com/weather |
95
95
  | 2 | SVC002 | AI助手 | 智能对话服务 | 0.05元/次 | 审核中 | https://api.example.com/ai |
96
96
 
97
97
  请选择:
98
98
  • 输入序号(1/2)复用对应服务
99
99
  • 输入"新建"创建新服务
100
- • 输入"修改"修改已有服务
100
+ • 输入"修改 + serviceId"修改已有服务
101
101
  ```
102
102
 
103
103
  > 📎 表格渲染由 `scripts/service.sh list` 自动完成,无需手动拼接。Agent 直接展示脚本输出即可。
@@ -110,19 +110,21 @@ Agent 根据用户输入执行对应分支:
110
110
  |----------|----------|
111
111
  | 数字序号(1-$SERVICE_COUNT) | 复用对应服务 → 跳过创建,直接进入应用发布 |
112
112
  | "新建" | 进入 Step 3 收集服务信息 → `bash scripts/service.sh save`(创建前自动校验数量 < 20) |
113
- | "修改" | 引导用户输入服务ID → 进入 Step 3 收集**所有**字段 → `bash scripts/service.sh save --service-id <id>` |
113
+ | "修改 + serviceId" | 使用表格中展示的 serviceId → 进入 Step 3 收集**所有**字段 → `bash scripts/service.sh save --service-id <id>` |
114
114
 
115
115
  > ⚠️ 服务数量上限 20 个,由 `service.sh save` 在创建前自动校验。
116
116
 
117
+ 用户选择修改时可使用列表中展示的 `serviceId`。展示和记录接口返回的实际状态,不自行增加状态过滤、可用性结论或审核规则。
118
+
117
119
  ---
118
120
 
119
121
  ## Step 3: 收集服务信息(创建或修改服务时执行)
120
122
 
121
123
  **⚠️ 在以下情况需执行此步骤:**
122
124
  ```
123
- ✅ serviceList 为空(无已有服务)→ 创建新服务
125
+ ✅ 服务列表为空(无已有服务)→ 创建新服务
124
126
  ✅ 用户选择"新建" → 创建新服务
125
- ✅ 用户选择"修改" → 修改已有服务(需先输入服务ID)
127
+ ✅ 用户选择"修改" → 修改已有服务(提供表格中的 serviceId)
126
128
  ```
127
129
 
128
130
  **⚠️ 修改服务特别注意:**
@@ -141,11 +143,15 @@ Agent 根据用户输入执行对应分支:
141
143
  2. 服务描述(1-500 字符):简要描述服务功能
142
144
  3. 服务地址(URL):服务的 API 地址
143
145
  4. 服务单价(元,最低 0.01):用户每次调用的费用
144
- 5. 请求示例(JSON):API 请求参数示例
146
+ 5. 请求示例(JSON):API 请求参数示例,提交时作为 `schemaUrl` 字符串传入
145
147
 
146
- 请依次提供以上信息。
148
+ 请在一条回复中一次性提供以上全部信息。修改服务时请同时提供表格中的 serviceId,不再单独增加一轮询问。
147
149
  ```
148
150
 
151
+ 只补问缺失或校验失败的字段。已经通过校验的字段必须保留,不要求用户重新提交;修改服务仍必须最终获得全部五项字段,禁止只提交局部字段。
152
+
153
+ Agent 在当前任务中记录操作选择、serviceId 和五项服务资料。用户更正字段时只覆盖并重新校验该字段,其他未变化且已校验通过的字段继续复用;操作类型变化时清除不再适用的 serviceId 或创建资料。只补问缺失或校验失败字段,本模块的 `scripts/service.sh validate` 继续作为业务格式校验唯一来源。
154
+
149
155
  ### 入参校验规则
150
156
 
151
157
  | 字段 | 说明 | 验证规则 | 错误提示 |
@@ -154,7 +160,9 @@ Agent 根据用户输入执行对应分支:
154
160
  | `serviceDesc` | 服务描述 | 长度 1-500 字符 | 服务描述长度需在 1-500 字符之间 |
155
161
  | `resourceUrl` | 服务地址 | 有效的 URL 格式(以 http:// 或 https:// 开头) | 请提供有效的 URL 地址 |
156
162
  | `pricing` | 服务单价 | 必须 >= 0.01 元 | 服务单价最低为 0.01 元 |
157
- | `schemaUrl` | 请求示例 | 有效的 JSON 格式 | 请提供有效的 JSON 格式请求示例 |
163
+ | `schemaUrl` | 请求示例 | 有效的 JSON 格式;提交时序列化为字符串 | 请提供有效的 JSON 格式请求示例 |
164
+
165
+ > `schemaUrl` 是 MCP 入参字段名,本流程中承载的是序列化后的 JSON 请求示例,不是 URL。用户提供原始 JSON,例如 `{}`;`scripts/service.sh` 校验 JSON 后将其作为字符串写入 `request.schemaUrl`。禁止因为字段名含 `Url` 而要求用户提供网页地址。
158
166
 
159
167
  ### 校验脚本
160
168
 
@@ -186,20 +194,22 @@ bash scripts/service.sh validate --name "$SERVICE_NAME" --desc "$SERVICE_DES
186
194
  ### 成功输出格式
187
195
 
188
196
  ```markdown
189
- ✅ 服务上架成功
197
+ ✅ 服务创建成功
190
198
 
191
199
  | 项目 | 信息 |
192
200
  |------|------|
201
+ | 服务ID | API_xxx |
193
202
  | 服务名称 | 天气查询 |
194
203
  | 服务描述 | 提供全球天气查询服务 |
195
204
  | 服务地址 | https://api.example.com/weather |
196
205
  | 服务单价 | 0.01 元/次 |
197
- | 状态 | 审核中 |
198
206
  ```
199
207
 
208
+ `saveBazaarServiceForMcp` 的当前成功响应不包含服务状态。不得根据创建或修改成功推断为“审核中”“已上线”或其他状态。只有后续 `scripts/service.sh list` 只读查询成功并按 `serviceId` 匹配到该服务时,才能记录和展示实际状态;查询失败或尚未返回该服务时,将状态保留为“未取得”,不得因此重复执行 `save`。
209
+
200
210
  ### 按量付费集成产物
201
211
 
202
- 服务创建、修改或复用成功后,必须记录并向用户说明以下字段:
212
+ 服务创建、修改或复用成功后,必须记录并向用户说明以下已取得字段:
203
213
 
204
214
  | 字段 | 用途 |
205
215
  |------|------|
@@ -207,7 +217,7 @@ bash scripts/service.sh validate --name "$SERVICE_NAME" --desc "$SERVICE_DES
207
217
  | 服务名称 | 用于核对收银台展示和用户识别 |
208
218
  | 服务地址 `resourceUrl` | 应与实际提供 402 服务的资源地址一致 |
209
219
  | 服务单价 `pricing` | 应与 `Payment-Needed.protocol.amount` 的业务定价保持一致 |
210
- | 服务状态 | 判断是否可用于正式上架和后续排查 |
220
+ | 服务状态 | 仅在只读查询实际取得时记录,用于正式上线判断和后续排查 |
211
221
 
212
222
  如果服务注册成功但未解析到 `serviceId`,不要继续宣称按量付费入驻完成;应提示用户重新查询服务列表或根据服务名称定位服务。
213
223
 
@@ -230,9 +240,17 @@ bash scripts/service.sh validate --name "$SERVICE_NAME" --desc "$SERVICE_DES
230
240
 
231
241
  | 查询方式 | 参数 | 说明 |
232
242
  |----------|------|------|
233
- | 查询已上线服务列表 | `{"request":{"serviceStatus":"ACTIVE"}}` | 返回所有已上架的服务列表 |
243
+ | 查询服务列表 | `{"request":{"limit":20,"offset":0}}` | 返回接口可见的服务列表;脚本按 `pagination.total` 自动翻页并完整展示实际状态,不按状态过滤候选 |
234
244
  | 根据 serviceId 查询详情 | `{"request":{"keyword":"API_xxx"}}` | 返回指定服务的详细信息 |
235
245
 
246
+ **查询返回处理:**
247
+
248
+ - MCP 信封先通过共享 `unwrap_mcp` 解包 `content[0].text`。
249
+ - 当前成功协议以 `code="10000"` 判断,服务数组读取 `data.items`,分页读取 `data.pagination.limit/offset/total`。
250
+ - 当前服务状态字段读取 `serviceStatus`,兼容旧响应中的 `status`;`ACTIVE` 表示已上线,其他未定义映射的状态值原样展示,不推断业务含义。
251
+ - 脚本兼容旧成功协议中的 `success=true` 与 `resultObj.serviceList`,但不得用旧结构覆盖或猜测当前字段。
252
+ - 只有明确取得成功响应中的空数组,才能判定没有已有服务;业务失败、字段缺失、分页不完整或候选缺少 `serviceId` 均必须阻断,禁止输出 `FLOW:CREATE_NEW` 或 `FLOW:SELECT`。
253
+
236
254
  **⚠️ saveBazaarServiceForMcp 创建/修改服务参数说明:**
237
255
 
238
256
  | 场景 | 必传参数 | 说明 |
@@ -240,12 +258,35 @@ bash scripts/service.sh validate --name "$SERVICE_NAME" --desc "$SERVICE_DES
240
258
  | 创建新服务 | serviceName, serviceDesc, resourceUrl, pricing, schemaUrl | 无需传入 serviceId |
241
259
  | 修改已有服务 | **serviceId**, serviceName, serviceDesc, resourceUrl, pricing, schemaUrl | **必须传入 serviceId + 所有资料信息** |
242
260
 
261
+ **写入返回处理:**
262
+
263
+ - MCP 信封先通过共享 `unwrap_mcp` 解包 `content[0].text`。
264
+ - 当前成功协议必须同时满足 `code="10000"` 和 `data.success=true`,服务 ID 读取 `data.serviceId`。
265
+ - 脚本兼容旧成功协议中的 `success=true` 和 `resultObj.serviceId`;不得混用两套协议中的成功条件与服务 ID 路径。
266
+ - 创建成功但未解析到 `serviceId` 时必须阻断后续流程;修改成功未返回新 ID 时,继续使用本次请求中已经确认的原 `serviceId`。
267
+ - 业务失败优先展示 `data.subMsg` / `data.msg`,再读取顶层错误字段;响应结构不符合当前或兼容协议时不得宣称成功。
268
+ - 当前保存成功响应不包含服务状态;不得从 `success=true` 推断审核或上线状态。
269
+
270
+ 其中 `schemaUrl` 按本模块约定传入序列化后的 JSON 请求示例。例如空请求示例的实际入参为:
271
+
272
+ ```json
273
+ {
274
+ "request": {
275
+ "serviceName": "服务名称",
276
+ "serviceDesc": "服务描述",
277
+ "resourceUrl": "https://your-domain.com/callback",
278
+ "pricing": "0.6",
279
+ "schemaUrl": "{}"
280
+ }
281
+ }
282
+ ```
283
+
243
284
  ### 正确调用示例
244
285
 
245
286
  > 📎 所有 MCP 调用均有对应脚本:
246
287
 
247
288
  ```bash
248
- # ✅ 查询已上线服务列表 → scripts/service.sh list
289
+ # ✅ 查询服务列表 → scripts/service.sh list
249
290
  # ✅ 创建新服务 → scripts/service.sh save --name <name> --desc <desc> --url <url> --pricing <pricing> --schema <json>
250
291
  # ✅ 修改已有服务 → scripts/service.sh save --service-id <id> --name <name> --desc <desc> --url <url> --pricing <pricing> --schema <json>
251
292
  ```
@@ -270,12 +311,14 @@ export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.saveBaza
270
311
 
271
312
  ## 服务状态说明
272
313
 
314
+ 当前列表响应优先读取 `serviceStatus`,旧响应兼容读取 `status`。下表以外的实际状态值必须原样展示;没有已验证依据时不得自行翻译、归类或推断是否可用。
315
+
273
316
  | 状态 | 说明 | 处理方式 |
274
317
  |------|------|----------|
275
- | `DRAFT` | 草稿 | 可继续编辑或提交审核 |
276
- | `PENDING` | 审核中 | 等待审核结果,服务暂不可用 |
277
- | `ONLINE` | 已上架 | 服务可被调用,可直接复用 |
278
- | `REJECTED` | 审核拒绝 | 引导用户联系客服或重新提交 |
318
+ | `DRAFT` | 草稿 | 展示接口返回的实际状态,由用户决定后续操作 |
319
+ | `PENDING` | 审核中 | 展示接口返回的实际状态,由用户决定后续操作 |
320
+ | `ACTIVE` | 已上线 | 展示接口返回的实际状态,由用户决定后续操作 |
321
+ | `REJECTED` | 审核拒绝 | 展示接口返回的实际状态,由用户决定后续操作 |
279
322
 
280
323
  ---
281
324
 
@@ -283,8 +326,8 @@ export PLATFORM=${DEV_TOOL_NAME} && alipay-cli mcp call a2a-pay-service.saveBaza
283
326
 
284
327
  ```
285
328
  ❌ 禁止:未查询已有服务直接创建新服务
286
- ❌ 禁止:在 Step 4 资料采集阶段收集 按量付费 的服务信息(服务信息在服务市场模块交互式收集)
287
- ❌ 禁止:serviceList 不为空时直接创建新服务(必须让用户选择)
329
+ ❌ 禁止:未在 Step 3.1 成功查询已有服务就要求用户决定新建/修改或提供服务资料
330
+ ❌ 禁止:服务列表不为空时直接创建新服务(必须让用户选择)
288
331
  ❌ 禁止:用户选择复用已有服务后仍创建新服务
289
332
  ❌ 禁止:跳过服务信息校验直接提交
290
333
  ❌ 禁止:使用虚拟或自行推断的 MCP 方法