@alipay/alipay-aipay 1.5.8-beta → 1.5.8-beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alipay/alipay-aipay",
3
- "version": "1.5.8-beta",
3
+ "version": "1.5.8-beta2",
4
4
  "description": "支付宝 AI 付 Skill 安装包 - 优先安装 Agent Skill,并在 macOS/Linux 后台准备用户级 CLI 工具",
5
5
  "type": "module",
6
6
  "bin": {
package/skill/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.8-beta
1
+ 1.5.8-beta2
@@ -197,7 +197,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message win
197
197
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message start-confirm --product-type "$PRODUCT_TYPE" --product-name "$PRODUCT_NAME" --project-path "$PROJECT_PATH" --project-selection "$PROJECT_SELECTION" --language "$SERVER_LANGUAGE" --framework "$FRAMEWORK" --framework-source "$FRAMEWORK_SOURCE"
198
198
  ```
199
199
 
200
- runner 失败时不得展示手写方案或进入步骤 3。成功时必须同时取得唯一 `ALIPAY_AIPAY_INTERNAL:PROJECT_CONFIRM_RECEIPT=<receipt>`;缺失、重复或不可解析都视为失败。stdout 是步骤 2 唯一对客消息;Agent 必须把 stdout 原文作为非阻塞消息发给用户,不能用命令面板里的 stdout、折叠输出或“已渲染/已展示”说明替代。禁止添加 `<...>` 标签、“已输出完整方案”“服务声明已打印”、重复摘要或任何前后缀。发送后不停止、不等待回复,立即执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow integration development --product-type "$PRODUCT_TYPE" --project-confirm-receipt "$PROJECT_CONFIRM_RECEIPT"`。loader 返回 `PROJECT_CONFIRMATION=VALID` 才能进入步骤 3;返回 `STALE` 时 stdout 已重新渲染当前标准方案并给出新 receipt,必须原文发送后使用新 receipt 立即重试一次;连续变化说明项目事实不稳定,停在步骤 2 核对,不要求用户输入确认口令。
200
+ runner 失败时不得展示手写方案或进入步骤 3。成功时必须同时取得唯一 `ALIPAY_AIPAY_INTERNAL:PROJECT_CONFIRM_RECEIPT=<receipt>` 和 `ALIPAY_AIPAY_INTERNAL:CUSTOMER_MESSAGE_DELIVERY_REQUIRED=integration.start.confirm`;缺失、重复或不可解析都视为失败。stdout 是步骤 2 唯一对客消息;Agent 必须把 stdout 原文作为非阻塞消息发给用户,且这是命令返回后的下一个动作;必须作为独立可见 assistant 消息送达,在此之前禁止继续调用工具。命令面板、折叠输出、内部思考或“已渲染/已展示”说明都不能替代交付;禁止添加 `<...>` 标签、“已输出完整方案”“服务声明已打印”、重复摘要或任何前后缀。发送后不停止、不等待回复,立即执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow integration development --product-type "$PRODUCT_TYPE" --project-confirm-receipt "$PROJECT_CONFIRM_RECEIPT"`。loader 返回 `PROJECT_CONFIRMATION=VALID` 才能进入步骤 3;返回 `STALE` 时 stdout 已重新渲染当前标准方案并给出新 receipt,必须先原文可见送达,再使用新 receipt 立即重试一次;连续变化说明项目事实不稳定,停在步骤 2 核对,不要求用户输入确认口令。
201
201
 
202
202
  - `full_process`:`../normal/full-process-routing.md` 已使用同一个 `integration.start.confirm`,在同一方案中绑定检查器产生的项目来源、代码状态和其他产品,以及产品、项目路径、语言/框架和服务声明;消息送达后已经直接通过 receipt 进入本步骤,禁止再次渲染或要求确认。该消息不展示步骤清单,也不缩减执行范围;后续仍必须按当前产品完成本 flow 的全部适用接口、完成条件和 checklist。任一方案字段变化时必须返回完整接入 router 重新扫描、渲染并自动校验新的单条方案。该方案仍禁止提前展示 MCC、授权范围、产品开通材料或 onboarding 待办。
203
203
 
@@ -60,15 +60,15 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message con
60
60
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message locate-projects --base-path "$USER_WORKSPACE_ROOT" --search-input "$SEARCH_INPUT" --format message
61
61
  ```
62
62
 
63
- 字段齐备后执行唯一 runner;禁止拆开执行项目扫描、`jq` 或 renderer,也不得附加解析。runner stdout 是本动作唯一对客消息,必须把 stdout 原文作为非阻塞消息发给用户;发送后不停止、不等待回复,立即使用同一次 runner 输出的 receipt 进入 development loader。方案事实变化时重新扫描并输出,不使用确认口令;静态扫描只决定进入验证,不证明完成。
63
+ 字段齐备后执行唯一 runner;禁止拆开执行项目扫描、`jq` 或 renderer,也不得附加解析。runner stdout 是本动作唯一对客消息;只有同时取得唯一 `CUSTOMER_MESSAGE_DELIVERY_REQUIRED=integration.start.confirm` 时,Agent 必须把 stdout 原文作为非阻塞消息发给用户,且这是命令返回后的下一个动作;必须作为独立可见 assistant 消息送达,在此之前禁止继续调用工具。发送后不停止、不等待回复,立即使用同一次 runner 输出的 receipt 进入 development loader。方案事实变化时重新扫描并输出,不使用确认口令;静态扫描只决定进入验证,不证明完成。
64
64
 
65
65
  ```bash
66
66
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message start-confirm --product-type "$PRODUCT_TYPE" --product-name "$PRODUCT_NAME" --project-path "$PROJECT_PATH" --project-selection "$PROJECT_SELECTION" --language "$SERVER_LANGUAGE" --framework "$FRAMEWORK" --framework-source "$FRAMEWORK_SOURCE"
67
67
  ```
68
68
 
69
- 上面命令失败时不得展示手写确认或进入子流程。成功时必须同时保存唯一 `ALIPAY_AIPAY_INTERNAL:PROJECT_CONFIRM_RECEIPT=<receipt>`;缺失、重复或不可解析视为失败。参数必须是当前确定值,禁止直接拼用户输入。runner 校验产品 variant 并固定服务声明;实际范围仍取当前 Integration flow 和 checklist。
69
+ 上面命令失败时不得展示手写确认或进入子流程。成功时必须同时保存唯一 `ALIPAY_AIPAY_INTERNAL:PROJECT_CONFIRM_RECEIPT=<receipt>` 和 `ALIPAY_AIPAY_INTERNAL:CUSTOMER_MESSAGE_DELIVERY_REQUIRED=integration.start.confirm`;缺失、重复或不可解析视为失败。参数必须是当前确定值,禁止直接拼用户输入。runner 校验产品 variant 并固定服务声明;实际范围仍取当前 Integration flow 和 checklist。
70
70
 
71
- 分流、展示和交接事实必须来自 runner 内同一次 `scan` 对象;禁止用描述、Agent 自报或历史分类代替。`evidence` 仅内部校验,不进 renderer;Onboarding Step 1 前禁止传/猜 `mccCode`。方案同时满足 `INT.START.PLAN_DELIVERED` 与 `INT.SERVICE_STATEMENT.DELIVERED` 后,执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow integration development --product-type "$PRODUCT_TYPE" --project-confirm-receipt "$PROJECT_CONFIRM_RECEIPT"`。只有内部 `PROJECT_CONFIRMATION=VALID` 才进入步骤 3;`STALE` 时 loader stdout 已重新渲染当前标准方案,必须原文发送并用新 receipt 立即重试一次,连续变化则停止核对。loader 在原位置记录兼容 stage 和预开发阅读 stage,禁止手工执行 telemetry;receipt 有效时禁止再次渲染 `integration.start.confirm`。
71
+ 分流、展示和交接事实必须来自 runner 内同一次 `scan` 对象;禁止用描述、Agent 自报或历史分类代替。`evidence` 仅内部校验,不进 renderer;Onboarding Step 1 前禁止传/猜 `mccCode`。只有方案 stdout 已按交付 marker 可见送达,才同时满足 `INT.START.PLAN_DELIVERED` 与 `INT.SERVICE_STATEMENT.DELIVERED`,随后执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow integration development --product-type "$PRODUCT_TYPE" --project-confirm-receipt "$PROJECT_CONFIRM_RECEIPT"`。只有内部 `PROJECT_CONFIRMATION=VALID` 才进入步骤 3;`STALE` 时 loader stdout 已重新渲染当前标准方案,必须先原文可见送达,再用新 receipt 立即重试一次,连续变化则停止核对。loader 在原位置记录兼容 stage 和预开发阅读 stage,禁止手工执行 telemetry;receipt 有效时禁止再次渲染 `integration.start.confirm`。
72
72
 
73
73
  合法组合必须确定产品、路径/来源、代码状态、语言/框架、服务声明和顺序;发现其他产品时保留。零散信息、`新建` 选择、未选候选或新项目未准备均不能替代完整机器校验。方案送达并通过 receipt 校验后仍完整执行 Integration 和 checklist。
74
74
 
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import process from 'node:process';
5
+
6
+ const internalPrefix = 'ALIPAY_AIPAY_INTERNAL:';
7
+ const autoMismatchFlows = new Set(['SCOPE_MISMATCH', 'MCC_MISMATCH']);
8
+
9
+ function runAuthScript(script, cwd, args, stdio) {
10
+ const result = spawnSync('bash', [script, ...args], {
11
+ cwd,
12
+ env: process.env,
13
+ encoding: stdio === 'pipe' ? 'utf8' : undefined,
14
+ stdio,
15
+ shell: false
16
+ });
17
+ if (result.error) throw result.error;
18
+ return result;
19
+ }
20
+
21
+ function authFlowValues(stderr) {
22
+ const prefix = `${internalPrefix}AUTH_FLOW:`;
23
+ return String(stderr || '')
24
+ .split(/\r?\n/u)
25
+ .filter((line) => line.startsWith(prefix))
26
+ .map((line) => line.slice(prefix.length));
27
+ }
28
+
29
+ function withoutIntermediateFlow(stderr, flow) {
30
+ const marker = `${internalPrefix}AUTH_FLOW:${flow}`;
31
+ const source = String(stderr || '');
32
+ return source.split(/\r?\n/u).filter((line) => line !== marker).join('\n');
33
+ }
34
+
35
+ export function runAuthRuntime(script, cwd, args) {
36
+ if (args[0] !== 'init') {
37
+ const result = runAuthScript(script, cwd, args, 'inherit');
38
+ return Number.isInteger(result.status) ? result.status : 1;
39
+ }
40
+
41
+ const initial = runAuthScript(script, cwd, args, 'pipe');
42
+ const initialStatus = Number.isInteger(initial.status) ? initial.status : 1;
43
+ const flows = authFlowValues(initial.stderr);
44
+ const flow = flows.length === 1 ? flows[0] : '';
45
+ const canAutoRecover = initialStatus === 1
46
+ && initial.signal === null
47
+ && autoMismatchFlows.has(flow)
48
+ && String(initial.stdout || '').trim() === '';
49
+
50
+ if (!canAutoRecover) {
51
+ process.stdout.write(initial.stdout || '');
52
+ process.stderr.write(initial.stderr || '');
53
+ return initialStatus;
54
+ }
55
+
56
+ process.stderr.write(withoutIntermediateFlow(initial.stderr, flow));
57
+ process.stderr.write(`${internalPrefix}AUTH_AUTO_MISMATCH=${flow}\n`);
58
+ const recovered = runAuthScript(script, cwd, ['mismatch', ...args.slice(1)], 'inherit');
59
+ return Number.isInteger(recovered.status) ? recovered.status : 1;
60
+ }
@@ -213,6 +213,7 @@ export function runFlowCli(argv = process.argv) {
213
213
  if (!validation.valid) {
214
214
  process.stderr.write('ALIPAY_AIPAY_INTERNAL:PROJECT_CONFIRMATION=STALE\n');
215
215
  process.stderr.write(`ALIPAY_AIPAY_INTERNAL:PROJECT_CONFIRM_RECEIPT=${validation.receipt}\n`);
216
+ process.stderr.write('ALIPAY_AIPAY_INTERNAL:CUSTOMER_MESSAGE_DELIVERY_REQUIRED=integration.start.confirm\n');
216
217
  process.stdout.write(`${validation.message}\n`);
217
218
  return;
218
219
  }
@@ -1142,6 +1142,7 @@ export async function runIntegrationMessageCli(argv = process.argv) {
1142
1142
  const result = createStartConfirmation(args);
1143
1143
  console.log(result.message);
1144
1144
  process.stderr.write(`${internalPrefix}PROJECT_CONFIRM_RECEIPT=${result.receipt}\n`);
1145
+ process.stderr.write(`${internalPrefix}CUSTOMER_MESSAGE_DELIVERY_REQUIRED=integration.start.confirm\n`);
1145
1146
  return;
1146
1147
  }
1147
1148
  if (command === 'framework-resolve') {
@@ -266,6 +266,11 @@ function hasAuthBlocker(result) {
266
266
  ].includes(line));
267
267
  }
268
268
 
269
+ function hasNetworkRecovery(result) {
270
+ return internalLines(result.stderr).some((line) =>
271
+ line.startsWith('NETWORK_RETRY_EXHAUSTED=') && line.endsWith(':RETRY_WITH_NETWORK'));
272
+ }
273
+
269
274
  function emitEnvelope(envelope) {
270
275
  process.stderr.write(`${internalPrefix}DISCOVERY_RESULT=${JSON.stringify(envelope)}\n`);
271
276
  }
@@ -295,6 +300,7 @@ async function runDiscovery(args) {
295
300
 
296
301
  const executedResults = [signingResult, serviceResult, applicationResult].filter(Boolean);
297
302
  const globalBlocker = executedResults.some(hasAuthBlocker) ? 'AUTHORIZATION_INVALID' : '';
303
+ const retryWithNetwork = !globalBlocker && executedResults.some(hasNetworkRecovery);
298
304
  const envelope = {
299
305
  schema_ver: 1,
300
306
  product_type: productType,
@@ -306,6 +312,9 @@ async function runDiscovery(args) {
306
312
  };
307
313
  if (globalBlocker) envelope.global_blocker = globalBlocker;
308
314
  emitEnvelope(envelope);
315
+ if (retryWithNetwork) {
316
+ process.stderr.write(`${internalPrefix}DISCOVERY_FLOW:RETRY_WITH_NETWORK\n`);
317
+ }
309
318
 
310
319
  const customerOutputResults = globalBlocker
311
320
  ? executedResults.filter(hasAuthBlocker)
@@ -323,7 +332,7 @@ async function runDiscovery(args) {
323
332
  }));
324
333
  }
325
334
  if (uniqueCustomerOutputs.length > 0) process.stdout.write(`${uniqueCustomerOutputs.join('\n\n')}\n`);
326
- return globalBlocker ? 2 : 0;
335
+ return globalBlocker || retryWithNetwork ? 2 : 0;
327
336
  }
328
337
 
329
338
  export async function runOnboardingDiscoveryCli(argv = process.argv) {
@@ -8,6 +8,7 @@ import { isWindowsPlatform } from './platform_compat.mjs';
8
8
  import { buildWindowsOnboardingRedirectUrl, loadMccRecords, renderMessage } from './render_customer_message.mjs';
9
9
  import { currentRunContext, emitStageMetricAsync, emitTerminalMetric } from './telemetry.mjs';
10
10
 
11
+ const internalPrefix = 'ALIPAY_AIPAY_INTERNAL:';
11
12
  const productTypes = {
12
13
  aipay: { variant: 'AIPAY', productName: 'AI 按量付费' },
13
14
  webpay: { variant: 'WEBPAY', productName: 'AI 网页应用收款' },
@@ -415,14 +416,19 @@ function renderPlanConfirm(productType, mccCandidate) {
415
416
  }, { productType });
416
417
  }
417
418
 
419
+ function requireCustomerMessageDelivery(messageId, message) {
420
+ process.stderr.write(`${internalPrefix}CUSTOMER_MESSAGE_DELIVERY_REQUIRED=${messageId}\n`);
421
+ return message;
422
+ }
423
+
418
424
  async function runPlanConfirm(args) {
419
425
  const productType = required(args, 'product-type');
420
426
  productFor({ ...args, 'product-type': productType });
421
- return renderPlanConfirm(productType, {
427
+ return requireCustomerMessageDelivery('onboarding.plan.confirm', renderPlanConfirm(productType, {
422
428
  mccCode: required(args, 'mcc-code'),
423
429
  mccName: required(args, 'mcc-name'),
424
430
  qualification: required(args, 'mcc-qualification')
425
- });
431
+ }));
426
432
  }
427
433
 
428
434
  async function runMccResolvePlan(args) {
@@ -444,7 +450,10 @@ async function runMccResolvePlan(args) {
444
450
  const { candidates: _internalCandidates, ...controlResult } = result;
445
451
  process.stderr.write(`ALIPAY_AIPAY_INTERNAL:MCC_RESOLUTION=${JSON.stringify(controlResult)}\n`);
446
452
  if (result.matchType === 'UNIQUE') {
447
- return renderPlanConfirm(productType, result.candidates[0]);
453
+ return requireCustomerMessageDelivery(
454
+ 'onboarding.plan.confirm',
455
+ renderPlanConfirm(productType, result.candidates[0])
456
+ );
448
457
  }
449
458
  if (result.matchType === 'NONE') {
450
459
  return renderMessage('onboarding.mcc.no_match', 'DEFAULT', {}, { productType });
@@ -154,6 +154,12 @@ async function runOnboardingExecuteReady(args) {
154
154
  async function dispatch(domain, args) {
155
155
  if (domain === 'onboarding-bootstrap') return runOnboardingBootstrap(args);
156
156
  if (domain === 'onboarding-execute-ready') return runOnboardingExecuteReady(args);
157
+ if (domain === 'auth') {
158
+ const [script, cwd] = shellPath(domain);
159
+ const { runAuthRuntime } = await import('./auth_runtime_runner.mjs');
160
+ process.exitCode = runAuthRuntime(script, cwd, args);
161
+ return;
162
+ }
157
163
  if (shellEntrypoints[domain]) {
158
164
  const [script, cwd] = shellPath(domain);
159
165
  return runShell(script, cwd, args);
@@ -136,7 +136,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-
136
136
 
137
137
  `AGENT_MCC_STATUS` 仅允许 `MATCHED|INSUFFICIENT|UNSUPPORTED`;`MATCHED` 必须提供 1 到 3 个用英文逗号分隔的完整编码,后两者不得提供编码。runner 会重新执行确定性召回并校验 Agent 编码确实存在于当前 MCC 表,名称、适用商家和特殊资质全部从同一表重建;非法、重复、超量、状态与候选数量矛盾或表外编码均为 Skill 契约错误,禁止降级为 Agent 自报结果。`MATCHED` 时按交集候选、确定性强命中、Agent 独立候选和确定性弱命中的顺序合并;`INSUFFICIENT|UNSUPPORTED` 不得否决确定性强命中,强命中仍可形成唯一或多候选结果,但确定性弱命中不得单独推进。确定性候选最多 5 个,最终合并候选最多 8 个。按次收费、支付渠道和目标产品只用于产品决策,不能改变 MCC 排名。
138
138
 
139
- 只接受唯一 `ALIPAY_AIPAY_INTERNAL:MCC_RESOLUTION=<json>`,其中必须包含 `semanticStatus`、`deterministicCandidateCodes`、`agentCandidateCodes`、`mergedCandidateCodes` 和 `mccTableSummary`:`matchType=UNIQUE` 时必须恰有一条候选,stdout 已直接渲染同一候选绑定的 `onboarding.plan.confirm`,必须原文发送但不停止、不等待回复,随后立即进入 `execute`;`MULTIPLE` 时 runner stdout 已直接渲染固定候选消息,必须原文发送并停止,等待用户回复序号、MCC 二级类目名称或编码;`NONE` 时 runner stdout 已直接渲染独立 `onboarding.mcc.no_match`,必须原文发送并停止。禁止再次调用旧的 `mcc-search`/`mcc-candidates` 组合、自由拼候选表、解释、示例或“是否继续”等近似问法。
139
+ 只接受唯一 `ALIPAY_AIPAY_INTERNAL:MCC_RESOLUTION=<json>`,其中必须包含 `semanticStatus`、`deterministicCandidateCodes`、`agentCandidateCodes`、`mergedCandidateCodes` 和 `mccTableSummary`:`matchType=UNIQUE` 时必须恰有一条候选,并同时取得唯一 `ALIPAY_AIPAY_INTERNAL:CUSTOMER_MESSAGE_DELIVERY_REQUIRED=onboarding.plan.confirm`;命令返回后的下一个 Agent 动作必须先把 stdout 作为独立可见 assistant 消息原文送达,在此之前禁止继续调用工具。送达后不停止、不等待回复,随后立即进入 `execute`。`MULTIPLE` 时 runner stdout 已直接渲染固定候选消息,必须原文发送并停止,等待用户回复序号、MCC 二级类目名称或编码;`NONE` 时 runner stdout 已直接渲染独立 `onboarding.mcc.no_match`,必须原文发送并停止。禁止再次调用旧的 `mcc-search`/`mcc-candidates` 组合、自由拼候选表、解释、示例或“是否继续”等近似问法。
140
140
 
141
141
  `MULTIPLE` 同时只接受唯一 `ALIPAY_AIPAY_INTERNAL:MCC_SELECTION_RECEIPT=<opaque>`。用户回复序号、当前候选表中的完整 MCC 名称或编码时,只能映射到该 receipt 绑定候选快照的对应行,并执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-resolve-plan --query "$MCC_SEARCH_QUERY" --product-type "$PRODUCT_TYPE" --select "$SELECTED_MCC_CODE" --selection-receipt "$MCC_SELECTION_RECEIPT"`;`MCC_SEARCH_QUERY` 仍使用产生该候选快照的原始经营描述,runner 必须校验产品、原始描述摘要、候选成员和当前 MCC 表摘要均未变化后生成唯一方案,不重新运行 Agent 泛化或扩大候选。候选、MCC 表摘要、产品或原始经营描述变化后旧 receipt 失效。用户提供新的经营描述时才开始新一轮双路召回。`UNIQUE` 直接输出非阻塞方案;`MULTIPLE|NONE` 继续使用 runner 本次真实 stdout。无需固定重试口令,不得猜测或追加近似候选。
142
142
 
@@ -156,11 +156,11 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-
156
156
  3. 当前产品在“未签约”或“需要新建应用”时可能需要的条件材料;不在状态查询前要求用户确认材料齐备状态。
157
157
  4. 固定展示企业账号暂不支持通过 Skill 完成产品开通,并引导前往支付宝商家平台;这只是边界预告,不新增账号类型问题。用户已经明确表示使用企业账号时不得继续展示可确认方案,改走入口处的停止分支。
158
158
 
159
- 方案必须由上方 `mcc-resolve-plan` 或已持有唯一 MCC 事实时的统一 runtime `onboarding-message plan-confirm` 动作生成;禁止直接调用 renderer 或用 `jq/printf` 拼输入。三个产品变体都固定展示企业账号边界和支付宝商家平台链接,不得删减或改写。MCC 名称、编码和特殊资质必须逐字来自 runner 唯一命中或 `mcc-reference.md` 的同一行,并通过 runner 内部 renderer 交叉校验;特殊资质为 `-` 时固定显示“当前类目参考表未列出”,不得解释为企业/个人资格结论。禁止自由补充主体资格、营业执照、审核规则或其他模板未列出的前提。用户明确表示企业账号要通过 Skill 完成产品开通时,改用 `enterprise-unsupported` 并停止产品开通,不得继续生成授权或收集材料。产品或 MCC 事实变化时重新校验并渲染完整方案。字段齐备后不得先输出产品判断、材料预告、企业账号提示或待办;runner stdout 是 Step 1 唯一对客消息,必须把 stdout 原文作为非阻塞消息发给用户,然后直接进入执行,不等待用户回复。
159
+ 方案必须由上方 `mcc-resolve-plan` 或已持有唯一 MCC 事实时的统一 runtime `onboarding-message plan-confirm` 动作生成;禁止直接调用 renderer 或用 `jq/printf` 拼输入。两个入口都必须产生唯一 `CUSTOMER_MESSAGE_DELIVERY_REQUIRED=onboarding.plan.confirm`。三个产品变体都固定展示企业账号边界和支付宝商家平台链接,不得删减或改写。MCC 名称、编码和特殊资质必须逐字来自 runner 唯一命中或 `mcc-reference.md` 的同一行,并通过 runner 内部 renderer 交叉校验;特殊资质为 `-` 时固定显示“当前类目参考表未列出”,不得解释为企业/个人资格结论。禁止自由补充主体资格、营业执照、审核规则或其他模板未列出的前提。用户明确表示企业账号要通过 Skill 完成产品开通时,改用 `enterprise-unsupported` 并停止产品开通,不得继续生成授权或收集材料。产品或 MCC 事实变化时重新校验并渲染完整方案。字段齐备后不得先输出产品判断、材料预告、企业账号提示或待办;runner stdout 是 Step 1 唯一对客消息,必须先原文可见送达,命令面板、折叠输出、内部思考或“已打印”都不能替代;然后直接进入执行,不等待用户回复。
160
160
 
161
161
  产品无法可靠识别时只使用上方 `product-clarify`;产品明确但尚无 MCC 检索输入时只使用一次 `mcc-clarify`;已有检索输入后统一使用 `mcc-resolve-plan`,由 runner 直接返回方案、候选或 `onboarding.mcc.no_match`。不得保留“先运行旧字符串搜索,无匹配后再临时让 Agent 猜”的两阶段对客流程;同一经营描述不得自动循环、重复加载完整 MCC 表或连续输出近似澄清消息。用户已经明确提供的信息不得重复询问;只有产品和唯一 MCC 事实都通过机器校验后才能执行 `login`。登录后必须先执行 Step 3.1 的只读查询,再根据实际结果收集签约、服务和应用分支的必要资料。
162
162
 
163
- **自动推进规则(执行约束,不是对客正文)**:只有产品、MCC 名称、MCC 编码、特殊资质和固定授权范围都由同一条唯一匹配事实交叉校验通过,才允许输出方案并立即执行统一 runtime 的 `onboarding-execute-ready --product-type "$PRODUCT_TYPE"`;原子 fallback 才拆为 `flow onboarding execute --product-type "$PRODUCT_TYPE"` 后接 `env check --product-type "$PRODUCT_TYPE"`。缺少实际入参、结果为多候选/无匹配、字段冲突或校验证据不足时必须停留在 Step 1 澄清,禁止靠默认值推进。产品或 MCC 在进入 loader 前发生变化时重新校验和渲染方案。execute loader 继续在相同转移位置记录兼容 stage `onboarding.user_confirmed`,该 stage 表示已基于完整确定事实进入执行,不表示收到额外确认回复;禁止手工上报或伪造用户回复。
163
+ **自动推进规则(执行约束,不是对客正文)**:只有产品、MCC 名称、MCC 编码、特殊资质和固定授权范围都由同一条唯一匹配事实交叉校验通过,并且方案的唯一交付 marker 已产生、stdout 已作为可见消息送达,才允许执行统一 runtime 的 `onboarding-execute-ready --product-type "$PRODUCT_TYPE"`;交付消息之前禁止发起该工具调用。原子 fallback 才拆为 `flow onboarding execute --product-type "$PRODUCT_TYPE"` 后接 `env check --product-type "$PRODUCT_TYPE"`。缺少实际入参、结果为多候选/无匹配、字段冲突或校验证据不足时必须停留在 Step 1 澄清,禁止靠默认值推进。产品或 MCC 在进入 loader 前发生变化时重新校验和渲染方案。execute loader 继续在相同转移位置记录兼容 stage `onboarding.user_confirmed`,该 stage 表示已基于完整确定事实进入执行,不表示收到额外确认回复;禁止手工上报或伪造用户回复。
164
164
 
165
165
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_ENTRY:END -->
166
166
 
@@ -202,10 +202,11 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
202
202
  ├─ AUTH_FLOW:SKIP → 进入 Step 3.1并复用合法签约查询事实
203
203
  ├─ AUTH_FLOW:READY_TO_OPEN → 输出非阻塞授权页,执行第 2 项
204
204
  │ └─ 若同时存在 AUTH_STATE:SAVE_FAILED:授权页 stdout 已送达,后续 open 仅可降级为 AUTH_OPEN:LINK_ONLY;wait/confirm 仍使用本条命令显式上下文继续,禁止重新生成授权页
205
- ├─ AUTH_FLOW:SCOPE_MISMATCH / MCC_MISMATCH → 执行第 4 项
205
+ ├─ 底层 init 命中 SCOPE_MISMATCH / MCC_MISMATCH → runtime 在同一命令内自动调用既有第 4 项,只透传 mismatch 的最终结果;唯一 AUTH_AUTO_MISMATCH 仅供内部诊断,不是终态
206
206
  ├─ AUTH_FLOW:RETRY_WITH_NETWORK → 取得联网权限后重试同一完整命令
207
207
  ├─ AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION → 取得 CLI 私有状态目录权限后原样重试本命令一次
208
- └─ AUTH_FLOW:FAILED → 停止并按错误输出恢复,禁止进入 Step 3.1
208
+ ├─ AUTH_FLOW:LOGOUT_STILL_LOGGED_IN → 自动 mismatch 的 logout 后置条件未成立,按第 4 项同名分支停止
209
+ └─ AUTH_FLOW:FAILED / 初始 mismatch 输出不满足唯一空 stdout 契约 → 停止并按错误输出恢复,禁止进入 Step 3.1
209
210
  2. 仅 AUTH_FLOW:READY_TO_OPEN:独立送达 init stdout,再执行 node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" auth open --scope "$SCOPE" --sales-code "$SALES_CODE" --mcc-code "$MCC_CODE" --product-name "$PRODUCT_NAME" --mcc-name "$MCC_NAME"。`OPENED` stdout 为空;`OPEN_FAILED|GUI_UNAVAILABLE|LINK_ONLY` 时,宿主有内置浏览器打开/导航能力则用它打开本次已校验、已交付的同一 `officialUrl` 一次,禁止搜索、改写、自动填写或代替扫码。无该能力或仍失败时,执行 node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" auth manual-open 并独立送达 stdout。随后无需回复,执行 node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" auth wait --scope "$SCOPE" --sales-code "$SALES_CODE" --mcc-code "$MCC_CODE" --product-name "$PRODUCT_NAME" --mcc-name "$MCC_NAME"
210
211
  ├─ open 返回 AUTH_FLOW:CONTEXT_MISMATCH → 不执行 wait;使用当前已确认的完整参数重新执行第 1 项
211
212
  ├─ open 返回 AUTH_FLOW:FAILED → 停止并按错误输出恢复,禁止执行 wait 或进入 Step 3.1
@@ -231,7 +232,7 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
231
232
 
232
233
  `mismatch` 中 logout 明确业务失败但 `whoami` 仍登录时,脚本内部以“初次 + 2 次”固定预算、间隔 3 秒重试完全相同的 logout。每次 logout 失败后只执行一次 `whoami` 后置核验;logout 明确成功时无需额外核验。任一次证明已退出即继续重新授权;预算耗尽且仍登录才输出 `AUTH_FLOW:LOGOUT_STILL_LOGGED_IN`。网络/服务异常、冲突输出或结果无法确认不消耗该业务重试预算,只转 `AUTH_FLOW:RETRY_WITH_NETWORK`。整个过程不增加用户确认或 Agent 命令,logout 未证明成功前禁止 login。
233
234
 
234
- `AUTH_FLOW:CONTEXT_MISMATCH` 适用于 `open|wait|confirm|mismatch` 的显式上下文与同一次 init 短时状态不一致;脚本必须在任何 `login --complete/logout` 前停止且不输出对客正文。Agent 不得忽略差异、改用旧状态继续或手工清理状态;必须立即用当前 Step 1 已确认的完整参数重新执行第 1 项。新的 init 先完成固定产品/MCC 机器校验,再安全替换旧短时状态;若 CLI 仍处于登录态,因为签约查询没有权威 MCC 字段,init 必须返回对应 `SCOPE_MISMATCH/MCC_MISMATCH` 并转第 4 项,不得返回 `SKIP`。CLI 未登录时直接生成当前上下文的新授权页。两种分支都不得复用旧 deviceCode 或新增用户确认。
235
+ `AUTH_FLOW:CONTEXT_MISMATCH` 适用于 `open|wait|confirm|mismatch` 的显式上下文与同一次 init 短时状态不一致;脚本必须在任何 `login --complete/logout` 前停止且不输出对客正文。Agent 不得忽略差异、改用旧状态继续或手工清理状态;必须立即用当前 Step 1 已确认的完整参数重新执行第 1 项。新的 init 先完成固定产品/MCC 机器校验,再安全替换旧短时状态;若 CLI 仍处于登录态,因为签约查询没有权威 MCC 字段,底层 init 必须返回对应 `SCOPE_MISMATCH/MCC_MISMATCH`,统一 runtime 随即在同一命令内调用既有 `auth.sh mismatch`,不得返回 `SKIP` 或要求 Agent 再发一条机械命令。CLI 未登录时直接生成当前上下文的新授权页。两种分支都不得复用旧 deviceCode 或新增用户确认。
235
236
 
236
237
  `auth.page` 非阻塞并追加“扫码完成后请回到 Agent 对话页面”;`auth.pending` 仅由 wait 耗尽或单次 confirm 的 PENDING 渲染,其他对客终态由脚本渲染对应消息。自动轮询期间即使 `login --complete` 已返回可复核状态,只要 `whoami` 尚未取得有效本机登录态,也继续按 PENDING 处理并消耗本次 wait 预算,不输出断头失败文案。剔除 `ALIPAY_AIPAY_INTERNAL:` 内部行后的 stdout 是当前动作唯一对客正文;禁止再次调用 renderer、另写近似话术、输出 stderr 或内部行、重复转述。授权脚本明确返回链接过期时必须重建,旧回复失效。
237
238
 
@@ -252,7 +253,9 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
252
253
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-discovery run --product-type "$PRODUCT_TYPE" --sales-code "$SALES_CODE" [--reuse-sign-receipt "$AUTH_SIGN_REUSE_RECEIPT"]
253
254
  ```
254
255
 
255
- 只接受唯一 `ALIPAY_AIPAY_INTERNAL:DISCOVERY_RESULT=<json>`。runner stdout 保留底层脚本已有的受控错误正文,并在没有全局授权阻断时追加原 `onboarding.discovery.summary` 标准正文;必须原文送达,不得手写、压缩或再次调用 `discovery-summary`。envelope 中每个分支只允许 `SUCCESS|QUERY_FAILED|NOT_APPLICABLE`:成功分支携带原脚本的确定状态和候选,失败不得伪装为空列表;存在 `global_blocker=AUTHORIZATION_INVALID` 时停止查询组,按 Step 3 重新授权,不进入 Step 4。
256
+ 只接受唯一 `ALIPAY_AIPAY_INTERNAL:DISCOVERY_RESULT=<json>`。runner stdout 保留底层脚本已有的受控错误正文,并在没有全局授权阻断时追加原 `onboarding.discovery.summary` 标准正文;必须原文送达,不得手写、压缩或再次调用 `discovery-summary`。envelope 中每个分支只允许 `SUCCESS|QUERY_FAILED|NOT_APPLICABLE`:成功分支携带原脚本的确定状态和候选,失败不得伪装为空列表;存在 `global_blocker=AUTHORIZATION_INVALID` 时停止查询组,按 Step 3 重新授权,不进入 Step 4。不存在授权阻断且底层重试耗尽具有 DNS、连接、timeout、socket/TLS、`fetch failed`、`network_error`、`网络连接失败` 或连接前沙箱禁网强证据时,runner 额外且至多输出一个 `ALIPAY_AIPAY_INTERNAL:DISCOVERY_FLOW:RETRY_WITH_NETWORK`;支付宝侧明确服务异常、业务错误、裸 `permission denied` 或结构异常不得触发该 marker。
257
+
258
+ 命中 `DISCOVERY_FLOW:RETRY_WITH_NETWORK` 时先暂存本次 stdout,不对客发送;宿主支持时申请联网权限,并以完全相同的产品、salesCode 和签约复用回执原样重试同一条 discovery 命令一次。重试成功只送达重试后的 stdout 并继续;权限被拒绝、宿主不支持时送达首次 stdout 一次;重试仍返回同一 marker 时只送达重试后的 stdout 一次并停止再次申请。该恢复不新增对客文案、确认点或 closeout 枚举。`AUTHORIZATION_INVALID` 优先,禁止同时进入网络恢复。
256
259
 
257
260
  不存在全局授权阻断时,执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow onboarding branch-summary` 加载 Step 4 和三个分支共用的 Step 5 约束;共用区块只加载一次,不得整份读取后续 flow。
258
261
 
@@ -269,6 +272,7 @@ Step 5 直接使用对应 phase 的完整命令;仅出现脚本异常、需要
269
272
  所有内部事实行都必须以 `ALIPAY_AIPAY_INTERNAL:` 开头;宿主合并 stdout/stderr 时也逐行剔除。无前缀的相似文本不得作为流程事实;唯一字段缺失、重复或冲突时按结构异常处理。
270
273
 
271
274
  - MCP 认证失败或产品/scope/MCC 授权不匹配:discovery runner 子查询只上报认证失效事实,不在并发子进程内 logout;立即停止查询组,不再处理剩余查询结果。授权不匹配时调用 Step 3 的 `auth.sh mismatch`,由该命令统一 logout 并重新授权。重新授权后仅恢复尚未执行的查询,保留重新授权前已经成功取得且主体未变化的结果。若无法确认仍为同一账号主体,则重新执行全部适用查询。
275
+ - 强网络证据且无授权阻断:只按上文 `DISCOVERY_FLOW:RETRY_WITH_NETWORK` 契约申请权限并原样重试 discovery 一次;连接前沙箱明确禁网不在子脚本内浪费两次固定间隔重试。远端服务异常仍使用既有分支失败和收口,不误报为本地联网权限。
272
276
  - 单个业务失败、响应结构错误或 MCP 服务失败,但当前会话仍有效:把该分支标记为查询失败,继续其他不依赖该结果的只读查询,最后一次性输出“已取得结果 + 失败分支”摘要。不得把失败视为空列表;应用查询失败时禁止应用复用/创建,服务查询失败时禁止服务复用/新建/修改。
273
277
  - 签约查询失败:只阻断签约分支;可继续应用/服务查询、候选展示、资源决策及其独立资料采集和写操作。不得推断签约状态,不得采集签约截图或签约所需 APP 名称,`signStatus` 和签约 `materialStatus` 保持未设置。签约查询恢复成功后,只有状态为 `NOT_SIGNED` 才进入签约材料类别。应用或服务查询失败也只阻断对应分支;认证失败、授权不匹配或无法确认登录主体一致时仍是全局阻断。
274
278
 
@@ -480,7 +484,23 @@ runner 从 `PRODUCT_TYPE` 唯一派生产品名,网站支付/APP 支付唯一
480
484
 
481
485
  renderer 还会按 `productName` 和分支完成条件自动派生上线前检查块。Agent 不传入、不改写该字段,也不得在模板外补第二份生产上线清单。该检查使用“【当前状态】/【上线前有以下关键点】/【提示】/【其他】”结构,不单列“相关站点”,也不在模板尾部追加第二个查询入口;必要 URL 只放在具体操作步骤中。完成态只能表述为代码开发和产品开通流程已完成,不得替用户确认生产配置已替换、产品真实可收款或应用页面状态;上线条件固定引导用户前往支付宝 AI 付站点,进入一站式接入 → 选择产品 → 密钥配置查看产品开通和应用上线情况;正式参数以生产 `appId`、应用公钥、应用私钥、支付宝公钥和生产网关为核心;AI 网页应用收款和 AI 移动应用收款必须完成公网 HTTPS `notify_url` 的验签、关键字段校验、幂等、`success` 回写和补偿查询;AI 按量付费必须把沙箱 `api_mock_service_id` 替换为服务市场真实 `serviceId`,A2M 示例中的 `sellerId` 来自商户 PID/2088,由商家自行在支付宝平台确认,不由 Agent 猜测、生成或代填。生产环境应用私钥、账号密码、支付凭证和未脱敏通知内容仍禁止提供给 Agent。分支未完成时,该派生块必须明确上表待办完成前不能正式收款。该提示只在消息目录维护,不增加用户确认点,Agent 不得在模板外重复输出或改写。
482
486
 
483
- 签约、服务和应用分别按本轮脚本实际结果表达:签约提交成功但未生效时,`signingResult` 固定使用“已提交,等待生效”;服务创建或修改成功且取得 `serviceId`、但未取得服务状态时,`serviceResult` 分别固定使用“创建成功,状态未取得”或“修改成功,状态未取得”;应用按消息目录的实际阶段枚举填写。任一分支失败或结果未知不清除其他分支成功,也不能概括为“全部失败”。
487
+ 签约、服务和应用分别按本轮脚本实际结果表达:签约提交成功但未生效时,`signingResult` 固定使用“已提交,等待生效”;服务创建或修改成功且取得 `serviceId`、但未取得服务状态时,`serviceResult` 分别固定使用“创建成功,状态未取得”或“修改成功,状态未取得”。任一分支失败或结果未知不清除其他分支成功,也不能概括为“全部失败”。`APPLICATION_RESULT` 只按下表从本轮实际 marker 选择,字面值必须与消息目录逐字一致:
488
+
489
+ <!-- APPLICATION_RESULT_MAP:START -->
490
+ | `APPLICATION_RESULT` | 本轮事实判据 |
491
+ |---|---|
492
+ | `待选择` | discovery 已取得应用候选,但用户尚未完成当前候选选择,或明确暂不新建 |
493
+ | `已创建,待设置公钥` | `APPLICATION_CREATE_RESULT=SUCCESS` 后尚未生成有效公钥页,或复用应用返回 `FLOW:REUSE_NO_KEY` |
494
+ | `公钥待确认` | 已取得 `KEY_PAGE_RESULT=READY_TO_OPEN`,但有限轮询或单次恢复返回 `FLOW:KEY_NOT_CONFIRMED` |
495
+ | `HarmonyOS 应用待平台侧创建、配置或上线` | 进入 `application.harmony.manual_create` 分支,尚未重新查询到可复用的 `ON_LINE` 应用 |
496
+ | `已提交审核,等待上线` | `APPLICATION_AUDIT_RESULT=SUBMITTED` / `FLOW:AUDIT_SUBMITTED`,但当前应用尚未满足完整上线条件 |
497
+ | `已上线且配置完整` | 当前应用已确认 `ON_LINE`、RSA2 应用公钥已生效且支付宝公钥已实际导出 |
498
+ | `需人工配置` | 权限恢复后最终仍取得 `ALIPAY_PUBLIC_KEY_EXPORT_STATUS=MANUAL_CONFIGURATION_REQUIRED` |
499
+ | `失败` | 应用创建、公钥页生成或应用提审取得明确 `FAILED`,且没有后续成功事实覆盖 |
500
+ | `结果未知` | 应用查询失败,或创建、公钥页、提审取得 `UNKNOWN` 且只读核验仍不能确认 |
501
+ <!-- APPLICATION_RESULT_MAP:END -->
502
+
503
+ `APP_FLOW:RETRY_WITH_LOCAL_CONFIG_PERMISSION` / `ALIPAY_PUBLIC_KEY_EXPORT_STATUS=RETRY_WITH_LOCAL_CONFIG_PERMISSION` 是恢复中间态,不得提前 closeout 为“需人工配置”;取得权限后只重试当前 app 命令一次,最终仍失败才按上表收口。
484
504
 
485
505
  只输出实际取得且有判断依据的费率、`serviceId`、`appId`、应用状态和公钥导出状态;没有取得的字段进入确定的下一步,不使用占位值、空值或推断值。只有签约为“已生效”、按量付费服务已复用或保存成功并取得实际 `serviceId`(消息值为“已复用”“创建成功,状态未取得”“修改成功,状态未取得”或“已完成”;网站支付和 APP 支付固定为“无需处理”)、应用为“已上线且配置完整”、剩余待办为“无”且没有人工待验证项时,runner 才派生“支付产品-产品开通已完成”;否则派生“流程进展”。“状态未取得”只表示保存响应未提供服务状态,不得改写为保存失败;renderer 会交叉校验这些条件,禁止在模板外另写相反结论。
486
506
 
@@ -21,7 +21,7 @@
21
21
  - `AUTH_STATE:SAVE_FAILED`:授权页 stdout 已经安全生成并交付,但本地短时状态文件未能保存;不得重新生成页面,后续 opener 只能降级为 `AUTH_OPEN:LINK_ONLY`,`wait|confirm` 仍使用 flow 登记命令的显式上下文。
22
22
  - `AUTH_FLOW:PENDING`:有限轮询耗尽或单次恢复查询尚未得到有效本机登录态;不等于失败,也不证明用户未扫码。
23
23
  - `AUTH_FLOW:EXPIRED`:当前页面实际返回过期,旧页面和旧回复失效,重新执行 flow 登记的 init。
24
- - `AUTH_FLOW:SCOPE_MISMATCH|MCC_MISMATCH`:只能走 `auth.sh mismatch`;logout 后置条件未成立前不得重授权;仍登录返回 `AUTH_FLOW:LOGOUT_STILL_LOGGED_IN`。
24
+ - `AUTH_FLOW:SCOPE_MISMATCH|MCC_MISMATCH`:只能走 `auth.sh mismatch`。统一 runtime 的 `auth init` 在底层 init 唯一返回 mismatch 且 stdout 为空时,会在同一命令内自动调用既有 `auth.sh mismatch`,抑制中间 mismatch 终态并只透传最终结果;`wait|confirm` 返回 mismatch 时仍按 flow 显式调用 mismatch。logout 后置条件未成立前不得重授权;仍登录返回 `AUTH_FLOW:LOGOUT_STILL_LOGGED_IN`。
25
25
  - `AUTH_FLOW:RETRY_WITH_NETWORK`:当前 Agent 环境无法确认结果,申请联网权限后原样重试同一命令;不得解释为用户本机登录失败。
26
26
  - `AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION`:授权状态命令 preflight 失败,或实际输出命中 CLI 私有状态写失败证据。可恢复阶段 stdout 为空;仅允许当前受控 runtime 命令访问 CLI 私有状态目录后原样重试一次;`wait|confirm` 保留短时授权状态,不重建授权页。Agent 禁止读取、列举、打印或复制已有凭据与日志;拒绝、不支持或重试仍命中同一 marker 时才输出最小失败说明。
27
27
 
@@ -9,6 +9,7 @@
9
9
  | `MCP_AUTH_ERROR` | HTTP 401、`Authorization is empty`、非法认证信息 | 停止查询组;logout 后置条件成立后重授权。仍登录则阻断;不可确认或无网络时只重试同一动作,不解释为用户本机或支付宝业务失败 |
10
10
  | `AUTH_MISMATCH` | `mccCode is not auth`、`salesProductCodes is not auth`、`scope is not auth` | 停止当前动作,只进 `auth.sh mismatch`;logout 后置条件未成立前禁重授权 |
11
11
  | `MCP_SERVICE_ERROR` / `SERVICE_UNSTABLE` | 已识别连接、网络或服务异常 | 按下方有限重试规则处理;耗尽后记录受影响分支,依赖允许时继续其他独立分支,最终统一收口 |
12
+ | `DISCOVERY_FLOW:RETRY_WITH_NETWORK` | discovery 子查询重试耗尽,且原始输出包含 DNS、连接、timeout、socket/TLS、`fetch failed`、`network_error`、`网络连接失败` 或连接前沙箱禁网强证据 | 只在无授权阻断时输出一次;暂存首次 stdout,申请联网权限后原样重试同一 discovery 命令一次。拒绝、不支持或再次命中时停止申请,只送达最新一次既有 stdout |
12
13
  | `CLI_LOCAL_FS_PERMISSION` | 授权状态命令 preflight 失败;或原始 stdout+stderr 命中私有状态写失败强证据,或私有状态路径与权限错误组合 | 仅用于 `auth.sh init|wait|confirm|mismatch` 的 `login/login --complete/logout` 链路;可恢复阶段 stdout 为空,只输出唯一 `AUTH_FLOW:RETRY_WITH_LOCAL_FS_PERMISSION`,取得 CLI 私有状态目录权限后原样重试一次,不改产品、scope、MCC 或授权页 |
13
14
  | `APP_LOCAL_CONFIG_PERMISSION` | 已取 RSA2 支付宝公钥但 config 探针失败 | stdout 空;输出两个本地权限 marker,取权后原样重试当前 app 命令一次,不重开公钥页 |
14
15
  | `OPEN_ERROR_KIND` | URL 已交付但 opener 失败 | 保留 URL 兜底;诊断不对客,不改写为业务、网络或授权失败 |
@@ -32,7 +33,8 @@ discovery runner 和截图上传这类并发/分组动作不得让每个子进
32
33
 
33
34
  ## 网络重试与写后核验
34
35
 
35
- - `MCP_SERVICE_ERROR`、`SERVICE_UNSTABLE` 和已识别本地网络错误:初次调用后最多重试 2 次,每次间隔 3 秒,始终复用完全相同的 argv、请求 JSON、业务请求号、资源名和动态字段。
36
+ - `MCP_SERVICE_ERROR`、`SERVICE_UNSTABLE` 和已识别本地网络错误:初次调用后最多重试 2 次,每次间隔 3 秒,始终复用完全相同的 argv、请求 JSON、业务请求号、资源名和动态字段。连接前沙箱明确拒绝联网时立即结束子脚本预算,由 discovery 的单次权限恢复处理,不额外等待两次 3 秒。
37
+ - discovery 只有强网络证据才输出 `DISCOVERY_FLOW:RETRY_WITH_NETWORK`;远端服务异常、业务错误、裸 `permission denied` 和响应结构异常仍保留既有失败分类。授权阻断优先且不得同时输出网络恢复 marker。
36
38
  - 认证、授权不匹配、参数、业务错误和结构歧义不进入通用网络重试。唯一例外是上述可验证最终状态的幂等 logout 恢复,它使用同一三次总预算且不经通用 `network_retry.sh`。stderr 不拼入待解析 JSON。
37
39
  - 只读调用可使用完整重试预算。非幂等写操作只有明确 `NOT_SENT` 才自动重试;DNS 失败、connection refused 或宿主在连接前明确拒绝网络访问可归为 `NOT_SENT`。
38
40
  - timeout、连接中断、发送阶段不明和 `SERVICE_UNSTABLE` 一律归为 `MAYBE_SENT`,停止写重试并使用现有只读能力核验;无法确认输出 `UNKNOWN`。
@@ -8,7 +8,7 @@ NETWORK_ATTEMPTS=0
8
8
 
9
9
  network_retry_is_local_transport_error() {
10
10
  printf '%s' "$1" | grep -Eqi \
11
- 'could not resolve host|name or service not known|nodename nor servname|connection refused|failed to connect|network access[^[:cntrl:]]*(denied|blocked)[^[:cntrl:]]*before connection'
11
+ 'network[ _]error|网络连接失败|could not resolve host|name or service not known|nodename nor servname|connection refused|failed to connect|fetch failed|socket hang up|econn(refused|reset)|enotfound|eai_again|etimedout|(^|[^[:alpha:]])timeout([^[:alpha:]]|$)|timed out|tls[^[:cntrl:]]*(error|failed|failure)|network access[^[:cntrl:]]*(denied|blocked)[^[:cntrl:]]*before connection'
12
12
  }
13
13
 
14
14
  network_retry_is_not_sent() {
@@ -16,6 +16,20 @@ network_retry_is_not_sent() {
16
16
  'could not resolve host|name or service not known|nodename nor servname|connection refused|network access[^[:cntrl:]]*(denied|blocked)[^[:cntrl:]]*before connection'
17
17
  }
18
18
 
19
+ network_retry_is_explicit_network_restriction() {
20
+ printf '%s' "$1" | grep -Eqi \
21
+ 'network access[^[:cntrl:]]*(denied|blocked)[^[:cntrl:]]*before connection'
22
+ }
23
+
24
+ network_retry_emit_exhausted() {
25
+ local action_name="$1" classification="$2" dispatch="$3" attempt="$4" evidence="$5"
26
+ local recovery="NONE"
27
+ if network_retry_is_local_transport_error "$evidence"; then
28
+ recovery="RETRY_WITH_NETWORK"
29
+ fi
30
+ echo "ALIPAY_AIPAY_INTERNAL:NETWORK_RETRY_EXHAUSTED=${action_name}:${classification}:${dispatch}:${attempt}:${recovery}" >&2
31
+ }
32
+
19
33
  run_network_retry() {
20
34
  local result_var="$1" operation="$2" action_name="$3"
21
35
  shift 3
@@ -87,8 +101,13 @@ run_network_retry() {
87
101
  return 75
88
102
  fi
89
103
 
104
+ if network_retry_is_explicit_network_restriction "$(printf '%s\n%s' "$stdout" "$stderr")"; then
105
+ network_retry_emit_exhausted "$action_name" "$classification" "$dispatch" "$attempt" "$(printf '%s\n%s' "$stdout" "$stderr")"
106
+ return 76
107
+ fi
108
+
90
109
  if [ "$attempt" -gt "$max_retries" ]; then
91
- echo "NETWORK_RETRY_EXHAUSTED:${action_name}:${classification}:${dispatch}:${attempt}" >&2
110
+ network_retry_emit_exhausted "$action_name" "$classification" "$dispatch" "$attempt" "$(printf '%s\n%s' "$stdout" "$stderr")"
92
111
  return 76
93
112
  fi
94
113
  sleep "$delay_seconds"
@@ -16,7 +16,7 @@ AI 网页应用收款覆盖 PC 网页和手机浏览器/H5,接口固定 `alipa
16
16
  7. **沙箱结论**:真实快速沙箱配置不得用占位值,唯一例外是 AI 按量付费沙箱 `service_id=api_mock_service_id`,且生产禁用。`CREATE_PENDING|VERIFY_PENDING` 只允许继续代码实现,阻止字段使用、摘要、后置校验、联调和付款体验。字段校验不等于支付测试;仅完整 402 链路满足 flow 才可称沙箱测试通过。
17
17
  8. **异步通知**:AI 网页应用收款/AI 移动应用收款必须实现通知。本地无公网 HTTPS `notify_url` 时可不传并以交易查询验收,公网通知联调列为人工待验证;生产上线前须恢复通知并完成验签、幂等、关键字段校验、`success` 回写和补偿查询,否则不宣称生产就绪。
18
18
  9. **受控页面**:授权链接仅由 `auth.sh` 按固定产品/MCC 生成,只允许 `https://aipay.alipay.com/cli-auth` 及登记参数,禁用 CLI `verification_url`;公钥页和系统 opener 只走登记脚本。失败后宿主内置浏览器只可打开已交付的同一 URL 一次;仍失败才提示手动打开,再有限轮询。禁止搜索、改写或自动操作;opener/config 写失败不算业务失败。
19
- 10. **对客输出**:指定 runner/renderer/脚本时,stdout 是唯一对客正文,须原文回复且不加旁白;工具输出记录、折叠面板或日志不等于已对客发送。展示命令只执行登记的单条命令,禁止追加 `2>&1`、管道、`grep/sed/awk/tee`、临时包装或拆回 `jq/printf/renderer`。除 `self_update.mjs` 的 `SELF_UPDATE:*` stderr 终态外,内部事实行均以 `ALIPAY_AIPAY_INTERNAL:` 开头;宿主合并输出时仍整行剔除,严禁对客。所有 `postRenderHintType=scanReturn` 的页面消息都是交付屏障(当前为 `auth.page`、`application.key.page`):先独立送达页面 stdout,再执行受控 opener 和有限轮询,不把后续待完成或收口消息合并发送;屏障不要求确认或新增操作。阻塞正文后等待;剔除内部行后正文为空则直接转移,不补话术。
19
+ 10. **对客输出**:指定 runner/renderer/脚本时,stdout 是唯一对客正文,须原文回复且不加旁白;工具输出记录、折叠面板或日志不等于已对客发送。展示命令只执行登记的单条命令,禁止追加 `2>&1`、管道、`grep/sed/awk/tee`、临时包装或拆回 `jq/printf/renderer`。除 `self_update.mjs` 的 `SELF_UPDATE:*` stderr 终态外,内部事实行均以 `ALIPAY_AIPAY_INTERNAL:` 开头;宿主合并输出时仍整行剔除,严禁对客。`integration.start.confirm` 和 `onboarding.plan.confirm` 成功时必须各自产生唯一 `ALIPAY_AIPAY_INTERNAL:CUSTOMER_MESSAGE_DELIVERY_REQUIRED=<messageId>`;命令返回后的下一个 Agent 动作必须先把剔除内部行后的 stdout 作为独立可见 assistant 消息原文送达,在该消息送达前禁止继续调用工具。工具面板、内部思考或声称“已展示”都不满足交付;送达后自动继续,不等待回复、不新增确认。所有 `postRenderHintType=scanReturn` 的页面消息都是交付屏障(当前为 `auth.page`、`application.key.page`):先独立送达页面 stdout,再执行受控 opener 和有限轮询,不把后续待完成或收口消息合并发送;屏障不要求确认或新增操作。阻塞正文后等待;剔除内部行后正文为空则直接转移,不补话术。
20
20
  11. **确定性转移**:固定脚本终态后立即转移;只执行动作处登记命令,禁止追加 `jq/cat/grep/curl` 或临时脚本重复解析。失败只走登记恢复;项目自检不绕过 Skill 脚本或打印敏感配置。
21
21
 
22
22
  ## 标准消息
@@ -54,7 +54,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" render <messageId> --va
54
54
 
55
55
  代码开发或完整接入缺项目位置/服务端语言时,执行 `integration.context.required` 或 `integration.project_path.required` 标准消息;框架缺失不触发补问。先区分新建与复用;`PROJECT_INPUT` 保留原话,明确新建项目/网站/商城/应用等产物时必须 `resolve-project --intent new`,不得因当前目录有项目改为复用。未知现有项目先轻量定位,所有路径再由 `resolve-project` 解析。路径和服务端语言明确后使用 `integration-message framework-resolve`:新项目按语言采用固定默认框架,现有项目优先从依赖推导,无法推导时沿用现有结构,用户明确框架始终优先;补齐前不初始化、装依赖或改文件。
56
56
 
57
- 每轮代码开发只渲染一次非阻塞 `integration.start.confirm`,两种意图复用同一次检查器事实并覆盖 Integration 步骤 1 至步骤8:代码开发校验;`full_process` 在方案展示前已完成步骤 1,方案送达且 receipt 有效后进入步骤 3。Onboarding 只保留一次非阻塞方案展示;方案送达且 MCC 唯一事实有效后,正常路径执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-execute-ready --product-type "$PRODUCT_TYPE"`,该组合动作只串行加载 `flow onboarding execute` 并执行既有 `env check`,不跨用户输入、授权页或任何写操作;执行后不得再重复单独加载 execute phase 或重复环境检查。服务修改仍保留绑定当前摘要的阻塞确认。签约材料完整后直接提交,服务创建摘要后直接创建,新建应用公钥校验成功后直接提审。
57
+ 每轮代码开发只渲染一次非阻塞 `integration.start.confirm`,两种意图复用同一次检查器事实并覆盖 Integration 步骤 1 至步骤8:代码开发校验;只有对应 `CUSTOMER_MESSAGE_DELIVERY_REQUIRED` marker 唯一且 stdout 已作为可见消息送达,才算方案送达,随后以 receipt 进入步骤 3。`full_process` 在方案展示前已完成步骤 1。Onboarding 只保留一次非阻塞方案展示;同样只有 marker 唯一且 stdout 已可见送达,才允许在 MCC 唯一事实有效后执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-execute-ready --product-type "$PRODUCT_TYPE"`。该组合动作只串行加载 `flow onboarding execute` 并执行既有 `env check`,不跨用户输入、授权页或任何写操作;执行后不得再重复单独加载 execute phase 或重复环境检查。两类方案送达后都自动继续,不等待回复。服务修改仍保留绑定当前摘要的阻塞确认。签约材料完整后直接提交,服务创建摘要后直接创建,新建应用公钥校验成功后直接提审。
58
58
 
59
59
  扫码页非阻塞:授权最多 12 次/间隔 5 秒,公钥最多 20 次/间隔 2 秒,成功即推进;耗尽后经统一回复判定只查一次,不重启轮询。
60
60