@alipay/alipay-aipay 1.6.0-beta.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alipay/alipay-aipay",
3
- "version": "1.6.0-beta.3",
3
+ "version": "1.6.0",
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.6.0-beta.3
1
+ 1.6.0
@@ -447,7 +447,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message a2m
447
447
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message a2m-execution-guard --project-path "$PROJECT_PATH" --service-url "$SERVICE_URL" --http-method POST --request-body-file "$POST_BODY_FILE" [--prior-receipt "$A2M_EXECUTION_RECEIPT"]
448
448
  ```
449
449
 
450
- 只接受唯一 `ALIPAY_AIPAY_INTERNAL:A2M_EXECUTION=<json>`。`decision=RUN` 时保存新 receipt 并继续;`REUSE_PASSED` 复用同一项目和输入的本轮通过证据,不重复联调;`BLOCK_UNCHANGED` 表示失败后代码、配置和输入均未变化,禁止重跑,将本轮 A2M 联调记录为失败并继续步骤 7/8;`UNKNOWN_PREVIOUS_EXECUTION` 表示上次命令可能已发出但未登记终态,当前没有登记的结果查询入口,禁止自动重跑或临时探测,固定记录联调结果未知并继续步骤 7/8。项目、服务 URL、方法或 POST body 变化时 runner 才会产生新的 `RUN` receipt。receipt 只保留在当前会话,不写跨会话业务进度。
450
+ 只接受唯一 `ALIPAY_AIPAY_INTERNAL:A2M_EXECUTION=<json>`。`decision=RUN` 时保存新 receipt 并继续;`REUSE_PASSED` 复用同一项目和输入的本轮通过证据,不重复联调;`BLOCK_UNCHANGED` 表示失败后代码、配置和输入均未变化,禁止重跑,将本轮 A2M 联调记录为失败并继续步骤 7/8;`UNKNOWN_PREVIOUS_EXECUTION` 表示上次命令可能已发出但未登记终态,当前没有登记的结果查询入口,禁止自动重跑或临时探测,固定记录联调结果未知并继续步骤 7/8。项目代码或配置的实际内容、服务 URL、方法或 POST body 变化时 runner 才会产生新的 `RUN` receipt;仅文件时间戳变化或同内容重写不属于输入变化。receipt 只保留在当前会话,不写跨会话业务进度。
451
451
 
452
452
  4. 仅 `decision=RUN` 时执行下列固定 runner 命令,输出固定联调说明后立即继续,不等待用户确认;禁止另写开始话术。服务地址和 HTTP 方法只用于后续实际命令,不在本消息中展示:
453
453
 
@@ -106,7 +106,7 @@ Windows 使用 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" a2m`;
106
106
 
107
107
  **⚠️ 脚本的收银接口地址和付款链接前缀已硬编码在脚本中(`PAY_ENDPOINT`、`PAY_URL_PREFIX`),执行时无需额外指定。**
108
108
 
109
- 先按统一 runtime 的 `integration-message a2m-execution-guard` 当前会话 receipt 契约校验项目快照、服务 URL、HTTP 方法和可选 POST body。只有 `decision=RUN` 才使用 `../../../normal/json/customer-messages.json` 的 `a2m.test.start` 渲染固定联调说明并立即运行脚本;`REUSE_PASSED|BLOCK_UNCHANGED|UNKNOWN_PREVIOUS_EXECUTION` 均不得重复发起完整联调。服务地址和 HTTP 方法只用于实际命令,不在开始消息中展示。
109
+ 先按统一 runtime 的 `integration-message a2m-execution-guard` 当前会话 receipt 契约校验项目快照、服务 URL、HTTP 方法和可选 POST body。项目快照按代码和配置的实际内容计算,仅文件时间戳变化或同内容重写不产生新的执行机会;实际内容变化时才允许生成新的 `RUN` receipt。只有 `decision=RUN` 才使用 `../../../normal/json/customer-messages.json` 的 `a2m.test.start` 渲染固定联调说明并立即运行脚本;`REUSE_PASSED|BLOCK_UNCHANGED|UNKNOWN_PREVIOUS_EXECUTION` 均不得重复发起完整联调。服务地址和 HTTP 方法只用于实际命令,不在开始消息中展示。
110
110
 
111
111
  ```bash
112
112
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message a2m-test-start
@@ -76,11 +76,6 @@ const aipayPaymentValidationMarker = 'Payment-Validation';
76
76
  const aipayPaymentVerifyMarker = 'alipay\\.aipay\\.agent\\.payment\\.verify|AlipayAipayAgentPaymentVerify(Request|Model|Response)|alipay_aipay_agent_payment_verify_response';
77
77
  const aipayFulfillmentConfirmMarker = 'alipay\\.aipay\\.agent\\.fulfillment\\.confirm|AlipayAipayAgentFulfillmentConfirm(Request|Model|Response)|alipay_aipay_agent_fulfillment_confirm_response';
78
78
  const aipayMarker = `${aipayPaymentNeededMarker}|${aipayPaymentProofMarker}|${aipayPaymentVerifyMarker}|${aipayFulfillmentConfirmMarker}`;
79
- const aipayAmountComparisonPattern = [
80
- '(?:amounts?Equal|amounts?_equal|compareAmounts?|amounts?Match|amounts?_match)\\s*\\([^)]{0,320}amount[^)]{0,320},[^)]{0,320}amount[^)]{0,320}\\)',
81
- '(?:normalizeAmount|normalize_amount)\\s*\\([^)]{0,200}amount[^)]{0,200}\\)\\s*(?:===|==|\\.equals\\s*\\()[\\s\\S]{0,240}(?:normalizeAmount|normalize_amount)\\s*\\([^)]{0,200}amount[^)]{0,200}\\)',
82
- '(?:normalized|expected|order|stored|local)[\\w$]*amount\\s*(?:===|==|\\.equals\\s*\\()[\\s\\S]{0,200}(?:normalized|verified|verify|returned|actual|response)[\\w$]*amount'
83
- ].join('|');
84
79
  const internalPrefix = 'ALIPAY_AIPAY_INTERNAL:';
85
80
  const receiptKinds = Object.freeze({
86
81
  checklist: 'integration-checklist-scope',
@@ -504,12 +499,8 @@ function projectSnapshotFingerprint(projectPath) {
504
499
  const stat = fs.statSync(file);
505
500
  const relative = path.relative(canonicalPath, file);
506
501
  hash.update(`${relative}\0${stat.size}\0`);
507
- if (path.basename(file) === '.alipay-sandbox.json') {
508
- hash.update(`${stat.mtimeMs}\n`);
509
- } else {
510
- hash.update(fs.readFileSync(file));
511
- hash.update('\n');
512
- }
502
+ hash.update(fs.readFileSync(file));
503
+ hash.update('\n');
513
504
  }
514
505
  return hash.digest('hex');
515
506
  }
@@ -597,20 +588,6 @@ function withoutCommentOnlyLines(content) {
597
588
  .join('\n');
598
589
  }
599
590
 
600
- function firstCodeContentPatternMatch(files, pattern) {
601
- for (const file of files) {
602
- let content;
603
- try {
604
- content = fs.readFileSync(file, 'utf8');
605
- } catch {
606
- continue;
607
- }
608
- const match = firstContentPatternMatch(file, withoutCommentOnlyLines(content), pattern);
609
- if (match) return match;
610
- }
611
- return null;
612
- }
613
-
614
591
  function auditFinding(projectPath, code, message, match = null) {
615
592
  const finding = { code, message };
616
593
  if (match) {
@@ -665,9 +642,6 @@ export function inspectImplementation(variant, projectPath) {
665
642
  findings.push(auditFinding(canonicalPath, code, message));
666
643
  }
667
644
  }
668
- if (variant === 'AIPAY' && !firstCodeContentPatternMatch(files, aipayAmountComparisonPattern)) {
669
- findings.push(auditFinding(canonicalPath, 'AIPAY_AMOUNT_CHECK_MISSING', '缺少验付金额与本地订单金额的实际比较'));
670
- }
671
645
 
672
646
  const commonTradeRelevance = [tradeQueryMarker, tradeRefundMarker, tradeRefundQueryMarker, tradeCloseMarker, tradeNotifyMarker].join('|');
673
647
  const targetRelevancePattern = variant === 'AIPAY'
@@ -36,6 +36,7 @@ const nodeEntrypoints = Object.freeze({
36
36
 
37
37
  export const runtimeDomains = Object.freeze([
38
38
  'self-update',
39
+ 'integration-bootstrap',
39
40
  'onboarding-bootstrap',
40
41
  'onboarding-execute-ready',
41
42
  ...Object.keys(nodeEntrypoints),
@@ -125,15 +126,29 @@ function assertEnumOption(options, name, allowedValues, { required = true } = {}
125
126
  return value;
126
127
  }
127
128
 
129
+ async function startTelemetryRun(rootIntent, productType) {
130
+ const telemetryArgs = ['start-run', '--root-intent', rootIntent];
131
+ if (productType) telemetryArgs.push('--product-type', productType);
132
+ const { runTelemetryCli } = await import('./telemetry.mjs');
133
+ await runTelemetryCli(cliArgv(telemetryArgs));
134
+ }
135
+
136
+ async function runIntegrationBootstrap(args) {
137
+ const options = parseRuntimeArgs(args);
138
+ assertOnlyOptions(options, ['root-intent', 'product-type']);
139
+ const rootIntent = assertEnumOption(options, 'root-intent', ['integration_only']);
140
+ const productType = assertEnumOption(options, 'product-type', ['aipay', 'webpay', 'apppay'], { required: false });
141
+ await startTelemetryRun(rootIntent, productType);
142
+ const { runFlowCli } = await import('./flow_loader.mjs');
143
+ runFlowCli(cliArgv(['integration', 'entry']));
144
+ }
145
+
128
146
  async function runOnboardingBootstrap(args) {
129
147
  const options = parseRuntimeArgs(args);
130
148
  assertOnlyOptions(options, ['root-intent', 'product-type']);
131
149
  const rootIntent = assertEnumOption(options, 'root-intent', ['onboarding_only']);
132
150
  const productType = assertEnumOption(options, 'product-type', ['aipay', 'webpay', 'apppay'], { required: false });
133
- const telemetryArgs = ['start-run', '--root-intent', rootIntent];
134
- if (productType) telemetryArgs.push('--product-type', productType);
135
- const { runTelemetryCli } = await import('./telemetry.mjs');
136
- await runTelemetryCli(cliArgv(telemetryArgs));
151
+ await startTelemetryRun(rootIntent, productType);
137
152
  const { runOnboardingMessageCli } = await import('./onboarding_message_runner.mjs');
138
153
  await runOnboardingMessageCli(cliArgv(['platform-entry']));
139
154
  const { isWindowsPlatform } = await import('./platform_compat.mjs');
@@ -152,6 +167,7 @@ async function runOnboardingExecuteReady(args) {
152
167
  }
153
168
 
154
169
  async function dispatch(domain, args) {
170
+ if (domain === 'integration-bootstrap') return runIntegrationBootstrap(args);
155
171
  if (domain === 'onboarding-bootstrap') return runOnboardingBootstrap(args);
156
172
  if (domain === 'onboarding-execute-ready') return runOnboardingExecuteReady(args);
157
173
  if (domain === 'auth') {
@@ -40,13 +40,13 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" render <messageId> --va
40
40
 
41
41
  | 意图 | 判定 | 入口 | 后续按需加载 |
42
42
  |---|---|---|---|
43
- | `integration_only` | 只要求代码开发、支付集成或集成排障,未同时要求产品开通 | 执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow integration entry` | 当前阶段、产品和语言的契约、示例与脚本 |
43
+ | `integration_only` | 只要求代码开发、支付集成或集成排障,未同时要求产品开通 | 执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-bootstrap --root-intent integration_only` | 当前阶段、产品和语言的契约、示例与脚本 |
44
44
  | `onboarding_only` | 只要求签约、入驻或产品开通,未同时要求代码开发 | 执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-bootstrap --root-intent onboarding_only` | 当前阶段的授权、查询或写分支模块 |
45
45
  | `full_process` | 明确要求完整接入、一站式,或同一请求同时要求代码开发和产品开通 | `normal/full-process-routing.md` | 先 Integration,满足衔接条件后 Onboarding |
46
46
 
47
- `onboarding_only` 正常入口使用 `onboarding-bootstrap --root-intent onboarding_only`,该组合动作只串行执行 `telemetry start-run`、`onboarding-message platform-entry` 和 `flow onboarding entry` 三个既有无业务写入动作;Windows 只发送登记引导并停止 Skill 内产品开通,且引导 URL 的 `platform_id` 由 runner 读取本次已创建的同一 `run_id` 后编码生成,禁止 Agent 传入或拼接;非 Windows 继续返回 entry 执行契约。执行该组合动作后不得再单独重复执行这三条原子命令。`full_process` 衔接 Onboarding 时已存在同一根流程 run,不使用带 `start-run` 的 bootstrap;仍先执行 flow 登记的 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message platform-entry`,再按需加载 Onboarding entry,避免重复 `run.intent_detected`。
47
+ `integration_only` 的 `integration-bootstrap` 只在同一 Node 进程串行执行 `telemetry start-run` 与 `flow integration entry`。`onboarding_only` 的 `onboarding-bootstrap` 只串行执行 `telemetry start-run`、`onboarding-message platform-entry` 与 `flow onboarding entry`。两者均为既有无业务写入动作,执行后不得重复原子命令。Windows Onboarding 仅发送登记引导并停止,URL `platform_id` 取本次 `run_id`,禁止 Agent 传入或拼接;非 Windows 返回 entry 契约。`full_process` 不使用 `integration-bootstrap`;衔接 Onboarding 也不使用带 `start-run` 的 bootstrap,仍执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message platform-entry` 后按需加载 entry,避免重复 `run.intent_detected`。
48
48
 
49
- 识别根意图后立即执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" telemetry start-run --root-intent <integration_only|onboarding_only|full_process>`;产品已唯一确定时追加 `--product-type <aipay|webpay|apppay>`。唯一例外是 `onboarding_only` 已按上表执行 `onboarding-bootstrap --root-intent onboarding_only` 时,bootstrap 已包含同一次 `start-run`,不得重复执行本条 telemetry。命令创建/复用当前流程 `run_id`,并在遥测开启时记录 `run.intent_detected`:同一意图和产品继续复用,`UNKNOWN` 补全产品仍复用同一 `run_id`;明确换产品、换根意图或既有 run 已终态才重建。第三方平台项目 ID 仍优先固定为 `run_id`,不得被显式 run ID 或本地生成值覆盖。业务 stage 只由登记 runner/script 异步记录。
49
+ `full_process` 识别根意图后立即执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" telemetry start-run --root-intent full_process`;产品已唯一确定时追加 `--product-type <aipay|webpay|apppay>`。`integration_only` 和 `onboarding_only` 已由上表各自 bootstrap 包含同一次 `start-run`,不得重复执行本条 telemetry。命令创建/复用当前流程 `run_id`,并在遥测开启时记录 `run.intent_detected`:同一意图和产品继续复用,`UNKNOWN` 补全产品仍复用同一 `run_id`;明确换产品、换根意图或既有 run 已终态才重建。第三方平台项目 ID 仍优先固定为 `run_id`,不得被显式 run ID 或本地生成值覆盖。业务 stage 只由登记 runner/script 异步记录。
50
50
 
51
51
  遥测默认开启,`ALIPAY_AIPAY_TELEMETRY=0|false|off|no` 可关闭 `METRIC_EVENT`、outbox、上传和 flush;私有流程 run context 仍用于 `PLATFORM_ID` 和终态生命周期。落盘/网络/上传/flush 失败静默,不改变业务、消息或确认,stdout 为空且 stderr 内部行不对客。`integration_only` 由 checklist 终态结束 run,其他意图由 Onboarding closeout 结束。脚本始终以当前流程 `run_id` 为 `PLATFORM_ID`,Agent 不手写环境前缀或改 MCP payload;维护诊断、outbox、上传和 flush 细节只在 `normal/telemetry.md` 按需读取。
52
52