@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 +1 -1
- package/skill/VERSION +1 -1
- package/skill/references/integration/flow.md +1 -1
- package/skill/references/integration/modules/sandbox/a2m-sandbox-test.md +1 -1
- package/skill/references/normal/scripts/integration_message_runner.mjs +2 -28
- package/skill/references/normal/scripts/runtime.mjs +20 -4
- package/skill/references/runtime-entry.md +3 -3
package/package.json
CHANGED
package/skill/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.6.0
|
|
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
|
|
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
|
-
|
|
508
|
-
|
|
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
|
-
|
|
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"
|
|
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
|
-
`
|
|
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
|
|
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
|
|