@alipay/alipay-aipay 1.5.0 → 1.5.1
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 +7 -14
- package/skill/references/integration/modules/checklist.md +2 -7
- package/skill/references/integration/modules/code-examples/php/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.php +330 -30
- package/skill/references/integration/modules/sandbox/a2m-sandbox-test.md +1 -1
- package/skill/references/integration/modules/sandbox/sandbox-setup-guide.md +1 -1
- package/skill/references/normal/rejection-guide.md +1 -2
- package/skill/references/normal/scripts/integration_message_runner.mjs +19 -1
- package/skill/references/normal/scripts/onboarding_message_runner.mjs +204 -12
- package/skill/references/normal/scripts/render_customer_message.mjs +68 -8
- package/skill/references/normal/scripts/telemetry.mjs +5 -3
- package/skill/references/onboarding/flow.md +31 -99
- package/skill/references/onboarding/modules/app-release.md +4 -4
- package/skill/references/onboarding/modules/service-registration.md +2 -2
- package/skill/references/runtime-entry.md +4 -4
|
@@ -131,6 +131,32 @@ function runPlatformEntry() {
|
|
|
131
131
|
: '';
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
function optional(args, name) {
|
|
135
|
+
const value = args[name];
|
|
136
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function parseJsonArg(args, name, label) {
|
|
140
|
+
const raw = required(args, name);
|
|
141
|
+
try {
|
|
142
|
+
return JSON.parse(raw);
|
|
143
|
+
} catch {
|
|
144
|
+
throw new Error(`${label} 必须是合法 JSON`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function runProductClarify() {
|
|
149
|
+
return renderMessage('product.clarify', 'DEFAULT', {});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function runEnterpriseUnsupported(args) {
|
|
153
|
+
const variant = required(args, 'variant');
|
|
154
|
+
if (!['ONBOARDING_ONLY', 'FULL_PROCESS'].includes(variant)) {
|
|
155
|
+
throw new Error('variant 非法,仅支持 ONBOARDING_ONLY、FULL_PROCESS');
|
|
156
|
+
}
|
|
157
|
+
return renderMessage('onboarding.enterprise.unsupported', variant, {});
|
|
158
|
+
}
|
|
159
|
+
|
|
134
160
|
async function runMccClarify(args) {
|
|
135
161
|
const productType = required(args, 'product-type');
|
|
136
162
|
const product = productFor({ ...args, 'product-type': productType });
|
|
@@ -212,13 +238,34 @@ async function runMccCandidates(args) {
|
|
|
212
238
|
}, { productType });
|
|
213
239
|
}
|
|
214
240
|
|
|
215
|
-
|
|
241
|
+
function renderPlanConfirm(productType, mccCandidate) {
|
|
242
|
+
const product = productFor({ 'product-type': productType });
|
|
243
|
+
return renderMessage('onboarding.plan.confirm', product.variant, {
|
|
244
|
+
mccCode: mccCandidate.mccCode,
|
|
245
|
+
mccName: mccCandidate.mccName,
|
|
246
|
+
mccQualification: mccCandidate.qualification
|
|
247
|
+
}, { productType });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function runPlanConfirm(args) {
|
|
251
|
+
const productType = required(args, 'product-type');
|
|
252
|
+
productFor({ ...args, 'product-type': productType });
|
|
253
|
+
return renderPlanConfirm(productType, {
|
|
254
|
+
mccCode: required(args, 'mcc-code'),
|
|
255
|
+
mccName: required(args, 'mcc-name'),
|
|
256
|
+
qualification: required(args, 'mcc-qualification')
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function runMccResolve(args, { renderPlan = false } = {}) {
|
|
216
261
|
const productType = required(args, 'product-type');
|
|
217
262
|
productFor({ ...args, 'product-type': productType });
|
|
218
263
|
emitStageMetricAsync('onboarding.mcc_prepare.start', { productType });
|
|
219
264
|
const result = mccSearchResult(required(args, 'query'));
|
|
220
265
|
process.stderr.write(`ALIPAY_AIPAY_INTERNAL:MCC_RESOLUTION=${JSON.stringify(result)}\n`);
|
|
221
|
-
if (result.matchType === 'UNIQUE')
|
|
266
|
+
if (result.matchType === 'UNIQUE') {
|
|
267
|
+
return renderPlan ? renderPlanConfirm(productType, result.candidates[0]) : '';
|
|
268
|
+
}
|
|
222
269
|
if (result.matchType === 'NONE') {
|
|
223
270
|
return renderMessage('onboarding.mcc.no_match', 'DEFAULT', {}, { productType });
|
|
224
271
|
}
|
|
@@ -294,7 +341,9 @@ async function runMaterialCollect(args) {
|
|
|
294
341
|
}, { productType });
|
|
295
342
|
}
|
|
296
343
|
|
|
297
|
-
const input =
|
|
344
|
+
const input = optional(args, 'missing-fields') !== undefined
|
|
345
|
+
? { missingFields: args['missing-fields'] }
|
|
346
|
+
: await readStdin();
|
|
298
347
|
return renderMessage('materials.category.collect', stateRule.variant, {
|
|
299
348
|
categoryName,
|
|
300
349
|
currentStatus: stateRule.currentStatus,
|
|
@@ -305,7 +354,9 @@ async function runMaterialCollect(args) {
|
|
|
305
354
|
async function runApplicationCandidates(args) {
|
|
306
355
|
const applicationType = required(args, 'application-type');
|
|
307
356
|
if (!['WEBAPP', 'MOBILEAPP'].includes(applicationType)) throw new Error('application-type 非法,仅支持 WEBAPP、MOBILEAPP');
|
|
308
|
-
const applicationCandidates =
|
|
357
|
+
const applicationCandidates = optional(args, 'candidates-json') !== undefined
|
|
358
|
+
? parseJsonArg(args, 'candidates-json', '应用候选输入')
|
|
359
|
+
: await readStdin();
|
|
309
360
|
if (!Array.isArray(applicationCandidates)) throw new Error('应用候选输入必须是 JSON 数组');
|
|
310
361
|
const onlineCount = applicationCandidates.filter((candidate) => candidate?.status === 'ON_LINE').length;
|
|
311
362
|
const variant = applicationCandidates.length === 0
|
|
@@ -320,8 +371,10 @@ async function runApplicationCandidates(args) {
|
|
|
320
371
|
return `${facts}\n\n${selection}`;
|
|
321
372
|
}
|
|
322
373
|
|
|
323
|
-
async function runServiceCandidates() {
|
|
324
|
-
const serviceCandidates =
|
|
374
|
+
async function runServiceCandidates(args) {
|
|
375
|
+
const serviceCandidates = optional(args, 'candidates-json') !== undefined
|
|
376
|
+
? parseJsonArg(args, 'candidates-json', '服务候选输入')
|
|
377
|
+
: await readStdin();
|
|
325
378
|
if (!Array.isArray(serviceCandidates)) throw new Error('服务候选输入必须是 JSON 数组');
|
|
326
379
|
const variant = serviceCandidates.length === 0 ? 'EMPTY' : 'DEFAULT';
|
|
327
380
|
const facts = renderMessage('service.candidates.facts', variant, { serviceCandidates });
|
|
@@ -341,7 +394,12 @@ function canonicalCandidates(candidates) {
|
|
|
341
394
|
async function runApplicationRecheck(args) {
|
|
342
395
|
const applicationType = required(args, 'application-type');
|
|
343
396
|
if (!['WEBAPP', 'MOBILEAPP'].includes(applicationType)) throw new Error('application-type 非法,仅支持 WEBAPP、MOBILEAPP');
|
|
344
|
-
const input =
|
|
397
|
+
const input = optional(args, 'previous-candidates-json') !== undefined || optional(args, 'current-candidates-json') !== undefined
|
|
398
|
+
? {
|
|
399
|
+
previousCandidates: parseJsonArg(args, 'previous-candidates-json', '上一轮应用候选快照'),
|
|
400
|
+
currentCandidates: parseJsonArg(args, 'current-candidates-json', '当前应用候选快照')
|
|
401
|
+
}
|
|
402
|
+
: await readStdin();
|
|
345
403
|
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('应用候选重查输入必须是 JSON 对象');
|
|
346
404
|
if (canonicalCandidates(input.previousCandidates) === canonicalCandidates(input.currentCandidates)) return '';
|
|
347
405
|
const applicationCandidates = input.currentCandidates;
|
|
@@ -388,13 +446,102 @@ function normalizeCloseoutInput(input) {
|
|
|
388
446
|
return variables;
|
|
389
447
|
}
|
|
390
448
|
|
|
391
|
-
|
|
392
|
-
|
|
449
|
+
function closeoutInputFromArgs(args) {
|
|
450
|
+
if (optional(args, 'input-json') !== undefined) return parseJsonArg(args, 'input-json', 'closeout 输入');
|
|
451
|
+
const mapping = {
|
|
452
|
+
'product-name': 'productName',
|
|
453
|
+
'process-result-title': 'processResultTitle',
|
|
454
|
+
'integration-result': 'integrationResult',
|
|
455
|
+
'sandbox-config-state': 'sandboxConfigState',
|
|
456
|
+
'signing-result': 'signingResult',
|
|
457
|
+
'service-result': 'serviceResult',
|
|
458
|
+
'application-result': 'applicationResult',
|
|
459
|
+
'remaining-actions': 'remainingActions',
|
|
460
|
+
'manual-verification-items': 'manualVerificationItems',
|
|
461
|
+
'application-operation-app-id': 'applicationOperationAppId',
|
|
462
|
+
'application-operation-actual-status': 'applicationOperationActualStatus',
|
|
463
|
+
'application-operation-next-action': 'applicationOperationNextAction',
|
|
464
|
+
'next-flow-reminder': 'nextFlowReminder'
|
|
465
|
+
};
|
|
466
|
+
const hasTypedInput = Object.keys(mapping).some((name) => Object.prototype.hasOwnProperty.call(args, name));
|
|
467
|
+
if (!hasTypedInput) return null;
|
|
468
|
+
const input = {};
|
|
469
|
+
for (const [argName, fieldName] of Object.entries(mapping)) {
|
|
470
|
+
if (Object.prototype.hasOwnProperty.call(args, argName)) input[fieldName] = args[argName];
|
|
471
|
+
}
|
|
472
|
+
for (const name of ['product-name', 'process-result-title', 'integration-result', 'signing-result', 'service-result', 'application-result', 'remaining-actions', 'next-flow-reminder']) {
|
|
473
|
+
required(args, name);
|
|
474
|
+
}
|
|
475
|
+
return input;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async function runCloseout(args) {
|
|
479
|
+
const variables = normalizeCloseoutInput(closeoutInputFromArgs(args) || await readStdin());
|
|
393
480
|
const rendered = renderMessage('process.partial_result', 'DEFAULT', variables);
|
|
394
481
|
emitTerminalMetric({ productName: variables.productName });
|
|
395
482
|
return rendered;
|
|
396
483
|
}
|
|
397
484
|
|
|
485
|
+
function runServiceCreateSummary(args) {
|
|
486
|
+
return renderMessage('service.create.summary', 'DEFAULT', {
|
|
487
|
+
serviceName: required(args, 'service-name'),
|
|
488
|
+
serviceDescription: required(args, 'service-description'),
|
|
489
|
+
serviceUrl: required(args, 'service-url'),
|
|
490
|
+
servicePricing: required(args, 'service-pricing'),
|
|
491
|
+
serviceSchema: required(args, 'service-schema')
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function runServiceUpdateConfirm(args) {
|
|
496
|
+
return renderMessage('onboarding.write.confirm', 'SERVICE_UPDATE_ONLY', {
|
|
497
|
+
sessionSummary: required(args, 'session-summary'),
|
|
498
|
+
subjectSummary: required(args, 'subject-summary'),
|
|
499
|
+
productName: 'AI 按量付费',
|
|
500
|
+
actionTypes: '服务修改',
|
|
501
|
+
serviceId: required(args, 'service-id'),
|
|
502
|
+
serviceName: required(args, 'service-name'),
|
|
503
|
+
serviceDescription: required(args, 'service-description'),
|
|
504
|
+
serviceUrl: required(args, 'service-url'),
|
|
505
|
+
servicePricing: required(args, 'service-pricing'),
|
|
506
|
+
serviceSchema: required(args, 'service-schema')
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function runHarmonyManualCreate() {
|
|
511
|
+
return renderMessage('application.harmony.manual_create', 'DEFAULT', {});
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function runApplicationReuseNoKey(args) {
|
|
515
|
+
return renderMessage('application.reuse.no_key', 'DEFAULT', {
|
|
516
|
+
appId: required(args, 'app-id')
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function runSigningResult(args) {
|
|
521
|
+
const variables = {
|
|
522
|
+
actualStatus: required(args, 'actual-status'),
|
|
523
|
+
nextAction: required(args, 'next-action')
|
|
524
|
+
};
|
|
525
|
+
const feeDisplay = optional(args, 'fee-display');
|
|
526
|
+
if (feeDisplay !== undefined) variables.feeDisplay = feeDisplay;
|
|
527
|
+
return renderMessage('signing.operation.result', feeDisplay === undefined ? 'WITHOUT_FEE' : 'WITH_FEE', variables);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function runServiceResult(args) {
|
|
531
|
+
return renderMessage('service.operation.result', 'DEFAULT', {
|
|
532
|
+
serviceId: required(args, 'service-id'),
|
|
533
|
+
actualResult: required(args, 'actual-result')
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function runApplicationResult(args) {
|
|
538
|
+
return renderMessage('application.operation.result', 'DEFAULT', {
|
|
539
|
+
appId: required(args, 'app-id'),
|
|
540
|
+
actualStatus: required(args, 'actual-status'),
|
|
541
|
+
nextAction: required(args, 'next-action')
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
398
545
|
async function main() {
|
|
399
546
|
const { command, args } = parseArgs(process.argv);
|
|
400
547
|
if (command === 'platform-entry') {
|
|
@@ -402,6 +549,14 @@ async function main() {
|
|
|
402
549
|
if (message) console.log(message);
|
|
403
550
|
return;
|
|
404
551
|
}
|
|
552
|
+
if (command === 'product-clarify') {
|
|
553
|
+
console.log(runProductClarify());
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (command === 'enterprise-unsupported') {
|
|
557
|
+
console.log(runEnterpriseUnsupported(args));
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
405
560
|
if (command === 'mcc-clarify') {
|
|
406
561
|
console.log(await runMccClarify(args));
|
|
407
562
|
return;
|
|
@@ -419,6 +574,15 @@ async function main() {
|
|
|
419
574
|
if (message) console.log(message);
|
|
420
575
|
return;
|
|
421
576
|
}
|
|
577
|
+
if (command === 'mcc-resolve-plan') {
|
|
578
|
+
const message = await runMccResolve(args, { renderPlan: true });
|
|
579
|
+
if (message) console.log(message);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (command === 'plan-confirm') {
|
|
583
|
+
console.log(await runPlanConfirm(args));
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
422
586
|
if (command === 'material-collect') {
|
|
423
587
|
console.log(await runMaterialCollect(args));
|
|
424
588
|
return;
|
|
@@ -428,7 +592,7 @@ async function main() {
|
|
|
428
592
|
return;
|
|
429
593
|
}
|
|
430
594
|
if (command === 'service-candidates') {
|
|
431
|
-
console.log(await runServiceCandidates());
|
|
595
|
+
console.log(await runServiceCandidates(args));
|
|
432
596
|
return;
|
|
433
597
|
}
|
|
434
598
|
if (command === 'application-recheck') {
|
|
@@ -437,10 +601,38 @@ async function main() {
|
|
|
437
601
|
return;
|
|
438
602
|
}
|
|
439
603
|
if (command === 'closeout') {
|
|
440
|
-
console.log(await runCloseout());
|
|
604
|
+
console.log(await runCloseout(args));
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (command === 'service-create-summary') {
|
|
608
|
+
console.log(runServiceCreateSummary(args));
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (command === 'service-update-confirm') {
|
|
612
|
+
console.log(runServiceUpdateConfirm(args));
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
if (command === 'application-harmony-manual-create') {
|
|
616
|
+
console.log(runHarmonyManualCreate());
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (command === 'application-reuse-no-key') {
|
|
620
|
+
console.log(runApplicationReuseNoKey(args));
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
if (command === 'signing-result') {
|
|
624
|
+
console.log(runSigningResult(args));
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (command === 'service-result') {
|
|
628
|
+
console.log(runServiceResult(args));
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (command === 'application-result') {
|
|
632
|
+
console.log(runApplicationResult(args));
|
|
441
633
|
return;
|
|
442
634
|
}
|
|
443
|
-
throw new Error('用法: onboarding_message_runner.mjs <platform-entry|mcc-resolve|mcc-search|mcc-clarify|mcc-candidates|material-collect|application-candidates|service-candidates|application-recheck|closeout> ...');
|
|
635
|
+
throw new Error('用法: onboarding_message_runner.mjs <platform-entry|product-clarify|enterprise-unsupported|mcc-resolve|mcc-resolve-plan|plan-confirm|mcc-search|mcc-clarify|mcc-candidates|material-collect|application-candidates|service-candidates|application-recheck|closeout|service-create-summary|service-update-confirm|application-harmony-manual-create|application-reuse-no-key|signing-result|service-result|application-result> ...');
|
|
444
636
|
}
|
|
445
637
|
|
|
446
638
|
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
@@ -553,6 +553,18 @@ function validateVariantInputShape(messageId, variantName, variables) {
|
|
|
553
553
|
}
|
|
554
554
|
|
|
555
555
|
const managedEntrypoints = {
|
|
556
|
+
'product.unsupported': {
|
|
557
|
+
command: 'node scripts/integration_message_runner.mjs product-unsupported --product-name <产品名>',
|
|
558
|
+
reason: '不支持产品拒绝引导必须由 runner 接收产品名后托管输出,禁止 jq/printf 管道直调 renderer。'
|
|
559
|
+
},
|
|
560
|
+
'product.clarify': {
|
|
561
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs product-clarify,或代码开发上下文执行 node ../normal/scripts/integration_message_runner.mjs product-clarify',
|
|
562
|
+
reason: '产品澄清属于通用托管消息,禁止用 printf/renderer 管道直接输出。'
|
|
563
|
+
},
|
|
564
|
+
'onboarding.enterprise.unsupported': {
|
|
565
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs enterprise-unsupported --variant <ONBOARDING_ONLY|FULL_PROCESS>',
|
|
566
|
+
reason: '企业账号停止分支必须由 Onboarding runner 输出,禁止空 JSON 管道直调 renderer。'
|
|
567
|
+
},
|
|
556
568
|
'onboarding.windows.redirect': {
|
|
557
569
|
command: 'node ../normal/scripts/onboarding_message_runner.mjs platform-entry',
|
|
558
570
|
reason: 'Windows 产品开通入口必须由 runner 根据真实运行平台确定;非 Windows 不得输出该消息。'
|
|
@@ -562,7 +574,7 @@ const managedEntrypoints = {
|
|
|
562
574
|
reason: '代码开发启动确认必须绑定 runner 同一次项目扫描的项目来源、代码状态和其他支付产品,禁止手写项目扫描事实。'
|
|
563
575
|
},
|
|
564
576
|
'integration.checklist.result': {
|
|
565
|
-
command: 'node ../normal/scripts/integration_message_runner.mjs checklist-result --variant <AIPAY|WEBPAY|APPPAY>',
|
|
577
|
+
command: 'node ../normal/scripts/integration_message_runner.mjs checklist-result --variant <AIPAY|WEBPAY|APPPAY> --project-path <absPath> --scope-receipt <receipt> --overall-result <result> --failed-items <items> --manual-items <items> ...',
|
|
566
578
|
reason: '最终 checklist 结论必须由 runner 统一接收最终证据并调用 renderer,同一次代码开发只输出一次。'
|
|
567
579
|
},
|
|
568
580
|
'integration.project_candidates.select': {
|
|
@@ -585,30 +597,66 @@ const managedEntrypoints = {
|
|
|
585
597
|
command: 'node ../normal/scripts/onboarding_discovery_runner.mjs run --product-type <aipay|webpay|apppay> --sales-code <SALES_CODE>',
|
|
586
598
|
reason: '该 runner 执行本轮适用查询、校验原始脚本事实、输出唯一 DISCOVERY_RESULT envelope,并在同一次 stdout 生成摘要;禁止单独重放摘要。'
|
|
587
599
|
},
|
|
600
|
+
'onboarding.plan.confirm': {
|
|
601
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs mcc-resolve-plan --query <经营描述|MCC编码|MCC名称> --product-type <aipay|webpay|apppay>,或已持有唯一 MCC 事实时执行 plan-confirm --product-type <...> --mcc-code <...> --mcc-name <...> --mcc-qualification <...>',
|
|
602
|
+
reason: '方案确认必须由 runner 绑定本轮唯一 MCC 事实和产品变体生成,避免 Agent 用 jq/printf/管道手写 renderer 输入。'
|
|
603
|
+
},
|
|
588
604
|
'materials.category.collect': {
|
|
589
|
-
command: 'node ../normal/scripts/onboarding_message_runner.mjs material-collect --category <signing|service|application> --state <INITIAL|PARTIAL|INVALID|APP_MOBILE_INITIAL> --product-type <aipay|webpay|apppay>',
|
|
605
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs material-collect --category <signing|service|application> --state <INITIAL|PARTIAL|INVALID|APP_MOBILE_INITIAL> --product-type <aipay|webpay|apppay> [--missing-fields <字段列表>]',
|
|
590
606
|
reason: '运行时禁止手写 categoryName/currentStatus/missingFields;runner 会归一化“签约资料”“AI 网页应用收款签约截图”“mobilePlatform”等常见别名后再调用 renderer。'
|
|
591
607
|
},
|
|
608
|
+
'service.create.summary': {
|
|
609
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-create-summary --service-name <name> --service-description <desc> --service-url <url> --service-pricing <amount> --service-schema <json>',
|
|
610
|
+
reason: '服务创建摘要必须由 runner 接收已校验五项资料后托管输出,禁止 jq/printf 管道直调 renderer。'
|
|
611
|
+
},
|
|
612
|
+
'onboarding.write.confirm': {
|
|
613
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-update-confirm --session-summary <summary> --subject-summary <summary> --service-id <id> --service-name <name> --service-description <desc> --service-url <url> --service-pricing <amount> --service-schema <json>',
|
|
614
|
+
reason: '服务修改确认必须由 runner 固定产品和动作,只绑定当前服务修改摘要,禁止 Agent 自行拼 actionTypes。'
|
|
615
|
+
},
|
|
616
|
+
'signing.operation.result': {
|
|
617
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs signing-result --actual-status <status> [--fee-display <fee>] --next-action <action>',
|
|
618
|
+
reason: '签约分支结果必须由 Onboarding runner 输出,避免直调 renderer 或手写状态。'
|
|
619
|
+
},
|
|
620
|
+
'service.operation.result': {
|
|
621
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-result --service-id <id> --actual-result <result>',
|
|
622
|
+
reason: '服务分支结果必须由 Onboarding runner 输出,避免直调 renderer 或手写状态。'
|
|
623
|
+
},
|
|
624
|
+
'application.harmony.manual_create': {
|
|
625
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-harmony-manual-create',
|
|
626
|
+
reason: 'HarmonyOS 移动应用边界必须由 Onboarding runner 输出,禁止空 JSON 管道直调 renderer。'
|
|
627
|
+
},
|
|
628
|
+
'application.reuse.no_key': {
|
|
629
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-reuse-no-key --app-id <appId>',
|
|
630
|
+
reason: '复用应用缺公钥提示必须由 runner 绑定当前完整 appId 后输出。'
|
|
631
|
+
},
|
|
632
|
+
'application.operation.result': {
|
|
633
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-result --app-id <id> --actual-status <status> --next-action <action>',
|
|
634
|
+
reason: '应用分支结果必须由 Onboarding runner 输出,避免直调 renderer 或手写状态。'
|
|
635
|
+
},
|
|
592
636
|
'application.candidates.facts': {
|
|
593
|
-
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-candidates --application-type <WEBAPP|MOBILEAPP>',
|
|
637
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-candidates --application-type <WEBAPP|MOBILEAPP> --candidates-json <APP_CANDIDATES_JSON>',
|
|
594
638
|
reason: '应用候选事实和适用选择提示必须由 runner 接收结构化候选数组并统一生成,禁止脚本或 Agent 拼接 Markdown 行。'
|
|
595
639
|
},
|
|
596
640
|
'application.candidate.select': {
|
|
597
|
-
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-candidates --application-type <WEBAPP|MOBILEAPP>',
|
|
641
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs application-candidates --application-type <WEBAPP|MOBILEAPP> --candidates-json <APP_CANDIDATES_JSON>',
|
|
598
642
|
reason: '应用候选选择必须由 runner 绑定同一份结构化候选快照生成,禁止脚本或 Agent 单独调用。'
|
|
599
643
|
},
|
|
600
644
|
'service.candidates.facts': {
|
|
601
|
-
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-candidates',
|
|
645
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-candidates --candidates-json <SERVICE_CANDIDATES_JSON>',
|
|
602
646
|
reason: '服务候选事实和适用选择提示必须由 runner 接收结构化候选数组并统一生成,禁止脚本或 Agent 拼接 Markdown 行。'
|
|
603
647
|
},
|
|
604
648
|
'service.candidate.select': {
|
|
605
|
-
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-candidates',
|
|
649
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs service-candidates --candidates-json <SERVICE_CANDIDATES_JSON>',
|
|
606
650
|
reason: '服务候选选择必须由 runner 绑定同一份结构化候选快照生成,禁止脚本或 Agent 单独调用。'
|
|
607
651
|
},
|
|
608
652
|
'process.partial_result': {
|
|
609
|
-
command: 'node ../normal/scripts/onboarding_message_runner.mjs closeout',
|
|
653
|
+
command: 'node ../normal/scripts/onboarding_message_runner.mjs closeout --product-name <name> --process-result-title <title> --integration-result <result> --signing-result <result> --service-result <result> --application-result <result> --remaining-actions <actions> --next-flow-reminder <reminder>',
|
|
610
654
|
reason: '产品开通 Step 6 最终收口必须由 runner 统一合并代码开发状态、产品开通分支状态、最近应用分支结果和上线前关键点;禁止 Agent 手写、缩写或删减 AI 网页应用收款限制引导。'
|
|
611
655
|
},
|
|
656
|
+
'sandbox.android.client': {
|
|
657
|
+
command: 'node ../normal/scripts/integration_message_runner.mjs sandbox-android-client',
|
|
658
|
+
reason: '沙箱支付宝 Android 下载说明必须由 Integration runner 输出,避免 Agent 为静态消息直调 renderer 或追加 shell 过滤。'
|
|
659
|
+
},
|
|
612
660
|
'auth.page': {
|
|
613
661
|
command: 'bash modules/scripts/auth.sh init --defer-open --scope <scope> --sales-code <code> --mcc-code <code> --product-name <name> --mcc-name <name>,页面 stdout 独立送达后执行 bash modules/scripts/auth.sh open ...',
|
|
614
662
|
reason: '授权页必须由 auth.sh 绑定本次 CLI deviceCode、固定产品/MCC 上下文和 URL 白名单;受控 opener 必须在页面消息独立送达后执行,后续 auth.pending 不得合并到同一条对客回复。',
|
|
@@ -1245,6 +1293,18 @@ async function readStdin() {
|
|
|
1245
1293
|
return input.trim() ? JSON.parse(input) : {};
|
|
1246
1294
|
}
|
|
1247
1295
|
|
|
1296
|
+
function inputJsonArg() {
|
|
1297
|
+
const index = process.argv.indexOf('--input-json');
|
|
1298
|
+
if (index < 0) return null;
|
|
1299
|
+
const value = process.argv[index + 1];
|
|
1300
|
+
if (value === undefined || value.startsWith('--')) throw new Error('参数 --input-json 缺少取值');
|
|
1301
|
+
try {
|
|
1302
|
+
return JSON.parse(value);
|
|
1303
|
+
} catch {
|
|
1304
|
+
throw new Error('--input-json 必须是合法 JSON 对象');
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1248
1308
|
async function main() {
|
|
1249
1309
|
if (process.argv.includes('--check-catalog')) {
|
|
1250
1310
|
const errors = validateCatalog();
|
|
@@ -1275,7 +1335,7 @@ async function main() {
|
|
|
1275
1335
|
const variant = variantIndex >= 0 ? process.argv[variantIndex + 1] : 'DEFAULT';
|
|
1276
1336
|
if (!messageId) throw new Error('用法: render_customer_message.mjs <messageId> [--variant NAME]');
|
|
1277
1337
|
assertManagedCliAllowed(messageId);
|
|
1278
|
-
const variables = await readStdin();
|
|
1338
|
+
const variables = inputJsonArg() ?? await readStdin();
|
|
1279
1339
|
console.log(renderMessageWithFallback(messageId, variant, variables));
|
|
1280
1340
|
}
|
|
1281
1341
|
|
|
@@ -396,7 +396,9 @@ export function messageMetricEvent(messageId, variantName, variables = {}, conte
|
|
|
396
396
|
|
|
397
397
|
export function emitMetricEvent(event, { env = process.env, stream = process.stderr, upload = true } = {}) {
|
|
398
398
|
if (!telemetryEnabled(env) || !event) return false;
|
|
399
|
-
stream.write
|
|
399
|
+
if (stream && typeof stream.write === 'function') {
|
|
400
|
+
stream.write(`${internalPrefix}METRIC_EVENT=${JSON.stringify(event)}\n`);
|
|
401
|
+
}
|
|
400
402
|
if (upload) scheduleSyncLogUpload(event, env);
|
|
401
403
|
return true;
|
|
402
404
|
}
|
|
@@ -448,7 +450,7 @@ export function emitMessageMetric(messageId, variantName, variables = {}, contex
|
|
|
448
450
|
try {
|
|
449
451
|
const event = messageMetricEvent(messageId, variantName, variables, context);
|
|
450
452
|
if (event?.stage === 'run.terminal' && telemetryEnabled()) updateExistingRunStateFromEvent(event);
|
|
451
|
-
return emitMetricEvent(event);
|
|
453
|
+
return emitMetricEvent(event, { stream: null });
|
|
452
454
|
} catch {
|
|
453
455
|
return false;
|
|
454
456
|
}
|
|
@@ -460,7 +462,7 @@ export function emitTerminalMetric(context = {}) {
|
|
|
460
462
|
const event = stageMetricEvent('run.terminal', context);
|
|
461
463
|
if (!event) return false;
|
|
462
464
|
updateExistingRunStateFromEvent(event);
|
|
463
|
-
return emitMetricEvent(event);
|
|
465
|
+
return emitMetricEvent(event, { stream: null });
|
|
464
466
|
} catch {
|
|
465
467
|
return false;
|
|
466
468
|
}
|