@alipay/alipay-aipay 1.7.7 → 1.7.9
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/README.md +2 -2
- package/package.json +3 -3
- package/skill/VERSION +1 -1
- package/skill/references/normal/json/policy-rules.json +1 -1
- package/skill/references/normal/scripts/open_official_url.sh +4 -2
- package/skill/references/normal/scripts/render_customer_message.mjs +4 -2
- package/skill/references/normal/scripts/self_update.mjs +6 -7
- package/skill/references/normal/scripts/windows/bootstrap-node.ps1 +0 -2
- package/skill-pre/VERSION +1 -1
- package/skill-pre/references/integration/flow.md +3 -3
- package/skill-pre/references/integration/modules/checklist.md +2 -2
- package/skill-pre/references/integration/modules/sandbox/a2m-sandbox-test.md +2 -2
- package/skill-pre/references/integration/modules/sandbox/sandbox-setup-guide.md +7 -7
- package/skill-pre/references/integration/modules/scripts/sandbox_config.sh +4 -10
- package/skill-pre/references/normal/conversation-telemetry.md +1 -1
- package/skill-pre/references/normal/full-process-routing.md +2 -1
- package/skill-pre/references/normal/scripts/runtime.mjs +6 -6
- package/skill-pre/references/normal/scripts/self_update.mjs +6 -7
- package/skill-pre/references/normal/scripts/telemetry.mjs +4 -4
- package/skill-pre/references/normal/scripts/windows/access-native.mjs +3 -0
- package/skill-pre/references/normal/scripts/windows/architecture.mjs +2 -30
- package/skill-pre/references/normal/scripts/windows/bootstrap-node.ps1 +1 -3
- package/skill-pre/references/normal/scripts/windows/git-discovery.mjs +7 -3
- package/skill-pre/references/normal/scripts/windows/git-install.mjs +3 -4
- package/skill-pre/references/normal/scripts/windows/host.mjs +31 -0
- package/skill-pre/references/normal/scripts/windows/preflight.mjs +27 -18
- package/skill-pre/references/normal/scripts/windows/prepare.mjs +3 -3
- package/skill-pre/references/normal/scripts/windows/python-execution.mjs +6 -6
- package/skill-pre/references/normal/scripts/windows/python-runtime.mjs +4 -4
- package/skill-pre/references/normal/scripts/windows/routing.mjs +11 -7
- package/skill-pre/references/normal/scripts/windows/shell_helpers.sh +2 -2
- package/skill-pre/references/normal/scripts/windows/winget.mjs +1 -1
- package/skill-pre/references/normal/windows-environment.md +15 -15
- package/skill-pre/references/onboarding/modules/authorization.md +1 -1
- package/skill-pre/references/onboarding/modules/scripts/app.sh +5 -5
- package/skill-pre/references/onboarding/modules/scripts/ar_sign_apply.sh +1 -1
- package/skill-pre/references/onboarding/modules/scripts/auth.sh +5 -5
- package/skill-pre/references/runtime-entry.md +1 -1
- package/skill-pre/references/normal/scripts/windows/acl-native.mjs +0 -3
- package/skill-pre/references/normal/scripts/windows/acl.mjs +0 -41
- package/skill-pre/references/normal/scripts/windows/architecture.ps1 +0 -55
package/README.md
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
# 正式版(默认)
|
|
11
11
|
npx -y @alipay/alipay-aipay@latest install
|
|
12
12
|
|
|
13
|
-
#
|
|
13
|
+
# 内测版
|
|
14
14
|
npx -y @alipay/alipay-aipay@latest install --channel pre
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
两份 Skill 可并存:正式版安装到 Agent 的 `skills/alipay-aipay
|
|
17
|
+
两份 Skill 可并存:正式版安装到 Agent 的 `skills/alipay-aipay/`,内测版安装到 `skills/alipay-aipay-pre/`。内测版使用独立名称 `alipay-aipay-pre`,在对话中明确点名或选择内测版使用。`--target` 的 Agent 目标选择规则不变。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alipay/alipay-aipay",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"description": "支付宝 AI 付接入 Skill 安装包 - 优先安装 Agent Skill,并在 macOS/Linux 后台准备用户级 CLI 工具",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"typescript": "^5.3.3"
|
|
56
56
|
},
|
|
57
57
|
"alipayAipayChannels": {
|
|
58
|
-
"stable": "1.7.
|
|
59
|
-
"pre": "1.7.
|
|
58
|
+
"stable": "1.7.5",
|
|
59
|
+
"pre": "1.7.8-pre"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/skill/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.7.
|
|
1
|
+
1.7.5
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schemaVersion":1,"rules":[{"policyId":"P-MCP-CONTRACT-FROZEN","scope":"all","severity":"critical","text":"只用当前 Skill 已验证的 MCP 脚本契约;禁止推断、改名或尝试近似方法。","runtimeText":"仅用已验证脚本;禁推断或尝试近似方法。"},{"policyId":"P-AUTH-BEFORE-ONBOARDING","scope":"onboarding","severity":"critical","text":"登录、scope 和 MCC 校验通过前,禁止 onboarding 查询或写入。","runtimeText":"登录/scope/MCC 未通过前禁查询和写入。"},{"policyId":"P-SIGNING-WRITE","scope":"onboarding.signing","severity":"critical","text":"签约材料校验通过后直接提交,不增加确认;缺失或非法时禁止提交。"},{"policyId":"P-SERVICE-WRITE","scope":"onboarding.service","severity":"critical","text":"服务创建摘要送达后直接创建;服务修改须取得绑定当前脱敏摘要的明确确认。"},{"policyId":"P-APPLICATION-WRITE","scope":"onboarding.application","severity":"critical","text":"完整新建材料或非空候选后的明确“新建”已构成创建确认;快照未变时不追加确认,公钥确认后直接提审。"},{"policyId":"P-WRITE-UNKNOWN","scope":"onboarding.write","severity":"critical","text":"非幂等写入结果不明时只读核验;仍无法确认则进入 UNKNOWN,禁止重试写入。"},{"policyId":"P-PARTIAL-RESULT","scope":"onboarding","severity":"critical","text":"签约、服务、应用分支独立记录,失败不回滚或覆盖其他成功结果。"},{"policyId":"P-MATERIAL-CATEGORY","scope":"onboarding.materials","severity":"required","text":"每轮只展示一个材料类别;同类一次收齐,已提供材料不得重复索取。"},{"policyId":"P-KEY-NO-PRIVATE","scope":"onboarding.application","severity":"critical","text":"禁止请求、处理、保存或输出生产私钥,也不提供密钥生成命令。"},{"policyId":"P-KEY-PUBLIC-USER","scope":"onboarding.application","severity":"critical","text":"应用公钥只能由用户提供;缺少时禁止 createKeyConfirmPage,也不得补全、改写或添加 PEM 头尾。"},{"policyId":"P-AUTH-URL","scope":"onboarding.authorization","severity":"critical","text":"授权链接只由 auth.sh 构造并校验固定域名、路径和参数;禁用 verification_url。"},{"policyId":"P-KEY-URL","scope":"onboarding.application","severity":"critical","text":"公钥确认只展示 createKeyConfirmPage 返回并校验的裸 URL;禁止二维码链接和 alipays://。"},{"policyId":"P-AUTH-URL-AUTO-OPEN","scope":"onboarding.authorization","severity":"critical","text":"授权 URL 交付后调用受控 opener;失败时保留同一裸 URL 和复制兜底。"},{"policyId":"P-KEY-URL-AUTO-OPEN","scope":"onboarding.application","severity":"critical","text":"公钥 URL 交付后调用受控 opener;失败时保留同一裸 URL 和复制兜底。"},{"policyId":"P-KEY-TOOL-DOWNLOAD","scope":"onboarding.application","severity":"critical","text":"新建 WEBAPP 或 MOBILEAPP IOS|ANDROID|ALL 在首次等待或写入前必须展示 https://opendocs.alipay.com/isv/02kipk;HarmonyOS 除外。仅空候选且缺公钥时自动下载,非空候选只在用户要求时下载;只下载,不安装、启动或生成密钥。"},{"policyId":"P-A2M-SANDBOX","scope":"integration.aipay","severity":"critical","text":"AI 按量付费沙箱 serviceId 固定为 api_mock_service_id,SDK 使用沙箱网关;生产网关和真实 serviceId 只用于正式配置。","runtimeText":"A2M 沙箱固定 api_mock_service_id 与沙箱网关;生产值仅用于正式配置。"},{"policyId":"P-A2M-SUCCESS","scope":"integration.aipay","severity":"critical","text":"自动联调只有在 HTTP 200、非空可归属资源、无明确业务失败且适用 Payment-Validation 有效时通过。","runtimeText":"联调仅在 HTTP 200、资源可归属、无业务失败且适用回执有效时通过。"},{"policyId":"P-SANDBOX-CREDENTIAL-EXCEPTION","scope":"integration.sandbox","severity":"critical","text":"Unix/macOS/Linux 只允许快速沙箱实际返回且已校验的买家登录/支付密码在沙箱摘要和付款体验中经 stdin 临时渲染。Windows 手工沙箱允许用户在 sandbox.windows.manual_setup 后提供当前沙箱应用的 APPID、支付宝公钥、应用公钥、与当前开发语言匹配的应用私钥和沙箱账号信息;Agent 只能将其用于已确认目标项目的受保护配置,不得在回复、摘要、普通日志或业务状态中复述或另存原文。两类例外均不得扩展到生产环境账号、应用私钥或密码。","runtimeText":"仅登记且已校验的快速沙箱或 Windows 手工沙箱资料可按 flow 用于受保护项目;禁复述、另存或扩展到生产值。"},{"policyId":"P-SENSITIVE-STATE","scope":"all","severity":"critical","text":"用户公钥仅用于当前 app key/verify-key/verify-key-and-audit 调用,禁止在回复、摘要、普通日志、跨会话状态或宽权限临时文件中复述或保存;除登记的沙箱例外外,私钥、token、Payment-Proof、签名串、完整支付表单和未脱敏响应同样不得进入这些位置;临时 URL 仅可由登记动作校验后在该动作正文展示。","runtimeText":"公钥限当前 app 调用且禁复述/保存;敏感值禁入回复/摘要/日志/状态/宽权限文件;临时 URL 仅由登记动作展示。"},{"policyId":"P-PROJECT-PROTECT","scope":"integration","severity":"critical","text":"不得清空、覆盖或删除用户既有项目;只在已确认目标路径和范围内做必要修改。","runtimeText":"禁清空/覆盖/删除既有项目;仅改已确认路径和范围。"},{"policyId":"P-CUSTOMER-OUTPUT-EXCLUSIVE","scope":"all","severity":"critical","text":"登记 runner/script 的 stdout 是唯一对客正文,禁止增删改写;阻塞消息送达后立即等待用户。","runtimeText":"登记 stdout 原文是唯一正文;阻塞送达后立即等待。"},{"policyId":"P-ONBOARDING-CONTROL-CHANNEL","scope":"onboarding","severity":"critical","text":"剔除 ALIPAY_AIPAY_INTERNAL 内部行后再处理 stdout;内部行禁止对客,正文为空时直接转移。","runtimeText":"内部行禁对客;正文为空按唯一终态转移。"},{"policyId":"P-AUTH-PAGE-DELIVERY-BARRIER","scope":"onboarding.authorization","severity":"critical","text":"`auth.page` stdout 必须先独立送达,再 opener 和有限轮询;不得合并 pending 或收口,也不等待确认。"},{"policyId":"P-KEY-PAGE-DELIVERY-BARRIER","scope":"onboarding.application","severity":"critical","text":"`application.key.page` stdout 必须先独立送达,再 opener 和有限轮询;不得合并 pending 或收口,也不等待确认。"},{"policyId":"P-DETERMINISTIC-HANDOFF","scope":"all","severity":"critical","text":"只执行 flow 动作处登记命令并按唯一终态立即转移;禁止追加命令重复解析,失败只走登记恢复。","runtimeText":"仅执行登记命令并按唯一终态转移;禁追加解析;失败只走登记恢复。"}],"officialUrls":{"aipaySite":"https://aipay.alipay.com/","aipaySkillSite":"https://aipay.alipay.com/?from=alipay-aipay-skill","merchantPlatform":"https://b.alipay.com/page/portal/home","openPlatform":"https://open.alipay.com/","openPlatformHome":"https://open.alipay.com","technicalSupport":"https://opensupport.alipay.com/support/intelligent-services?form=payskill","keyToolManual":"https://opendocs.alipay.com/isv/02kipk","keyToolMac":"https://ideservice.alipay.com/ide/getPluginUrl.htm?clientType=assistant&platform=mac&channelType=WEB","keyToolWindows":"https://ideservice.alipay.com/ide/getPluginUrl.htm?clientType=assistant&platform=win&channelType=WEB","androidSandboxAlipay":"https://mdn.alipayobjects.com/sandboxsys/afts/img/_itHRrdOD9oAAAAAAAAAAAAADgSLAQBr/original","sandboxToolFallback":"https://open.alipay.com/develop/sandbox/tool","sandboxGateway":"https://openapi-sandbox.dl.alipaydev.com/gateway.do","productionGateway":"https://openapi.alipay.com/gateway.do","openPlatformPaySkill":"https://open.alipay.com?form=payskill","traditionalPaymentSkill":"https://github.com/alipay/ai/tree/main/skills","dingtalkSupportGroupQr":"https://mdn.alipayobjects.com/huamei_5fajmi/afts/img/MlFpRKmYyLIAAAAARJAAAAgADlahAQFr/original","wecomCommunityGroupQr":"https://mdn.alipayobjects.com/huamei_5fajmi/afts/img/Cz0TTZVO7_4AAAAAQDAAAAgADlahAQFr/fmt.webp"},"authorizationProducts":[{"productName":"AI 按量付费","salesCode":"I1080300001000160457","scope":"app:all,machine_pay:write,agmnt:write"},{"productName":"AI 网页应用收款","salesCode":"I1080300001000041203","scope":"app:all,fast_instant_trade_pay:write"},{"productName":"AI 移动应用收款","salesCode":"I1080300001000041313","scope":"app:all,auth_alipay_apppay:write"}],"temporaryUrlAllowlist":{"authorization":{"host":"aipay.alipay.com","path":"/cli-auth","requiredQueryParams":["deviceCode","productCode","mccCode"],"optionalQueryParams":["platform"]},"publicKeyConfirmation":{"host":"aipay.alipay.com","path":"/public-key-confirm","requiredQueryParams":["keyConfirmToken"],"optionalQueryParams":[]},"windowsOnboardingRedirect":{"host":"aipay.alipay.com","path":"/","requiredQueryParams":["from","reason","platform_id"],"optionalQueryParams":[]}}}
|
|
1
|
+
{"schemaVersion":1,"rules":[{"policyId":"P-MCP-CONTRACT-FROZEN","scope":"all","severity":"critical","text":"只用当前 Skill 已验证的 MCP 脚本契约;禁止推断、改名或尝试近似方法。","runtimeText":"仅用已验证脚本;禁推断或尝试近似方法。"},{"policyId":"P-AUTH-BEFORE-ONBOARDING","scope":"onboarding","severity":"critical","text":"登录、scope 和 MCC 校验通过前,禁止 onboarding 查询或写入。","runtimeText":"登录/scope/MCC 未通过前禁查询和写入。"},{"policyId":"P-SIGNING-WRITE","scope":"onboarding.signing","severity":"critical","text":"签约材料校验通过后直接提交,不增加确认;缺失或非法时禁止提交。"},{"policyId":"P-SERVICE-WRITE","scope":"onboarding.service","severity":"critical","text":"服务创建摘要送达后直接创建;服务修改须取得绑定当前脱敏摘要的明确确认。"},{"policyId":"P-APPLICATION-WRITE","scope":"onboarding.application","severity":"critical","text":"完整新建材料或非空候选后的明确“新建”已构成创建确认;快照未变时不追加确认,公钥确认后直接提审。"},{"policyId":"P-WRITE-UNKNOWN","scope":"onboarding.write","severity":"critical","text":"非幂等写入结果不明时只读核验;仍无法确认则进入 UNKNOWN,禁止重试写入。"},{"policyId":"P-PARTIAL-RESULT","scope":"onboarding","severity":"critical","text":"签约、服务、应用分支独立记录,失败不回滚或覆盖其他成功结果。"},{"policyId":"P-MATERIAL-CATEGORY","scope":"onboarding.materials","severity":"required","text":"每轮只展示一个材料类别;同类一次收齐,已提供材料不得重复索取。"},{"policyId":"P-KEY-NO-PRIVATE","scope":"onboarding.application","severity":"critical","text":"禁止请求、处理、保存或输出生产私钥,也不提供密钥生成命令。"},{"policyId":"P-KEY-PUBLIC-USER","scope":"onboarding.application","severity":"critical","text":"应用公钥只能由用户提供;缺少时禁止 createKeyConfirmPage,也不得补全、改写或添加 PEM 头尾。"},{"policyId":"P-AUTH-URL","scope":"onboarding.authorization","severity":"critical","text":"授权链接只由 auth.sh 构造并校验固定域名、路径和参数;禁用 verification_url。"},{"policyId":"P-KEY-URL","scope":"onboarding.application","severity":"critical","text":"公钥确认只展示 createKeyConfirmPage 返回并校验的裸 URL;禁止二维码链接和 alipays://。"},{"policyId":"P-AUTH-URL-AUTO-OPEN","scope":"onboarding.authorization","severity":"critical","text":"授权 URL 交付后调用受控 opener;失败时保留同一裸 URL 和复制兜底。"},{"policyId":"P-KEY-URL-AUTO-OPEN","scope":"onboarding.application","severity":"critical","text":"公钥 URL 交付后调用受控 opener;失败时保留同一裸 URL 和复制兜底。"},{"policyId":"P-KEY-TOOL-DOWNLOAD","scope":"onboarding.application","severity":"critical","text":"新建 WEBAPP 或 MOBILEAPP IOS|ANDROID|ALL 在首次等待或写入前必须展示 https://opendocs.alipay.com/isv/02kipk;HarmonyOS 除外。仅空候选且缺公钥时自动下载,非空候选只在用户要求时下载;只下载,不安装、启动或生成密钥。"},{"policyId":"P-A2M-SANDBOX","scope":"integration.aipay","severity":"critical","text":"AI 按量付费沙箱 serviceId 固定为 api_mock_service_id,SDK 使用沙箱网关;生产网关和真实 serviceId 只用于正式配置。","runtimeText":"A2M 沙箱固定 api_mock_service_id 与沙箱网关;生产值仅用于正式配置。"},{"policyId":"P-A2M-SUCCESS","scope":"integration.aipay","severity":"critical","text":"自动联调只有在 HTTP 200、非空可归属资源、无明确业务失败且适用 Payment-Validation 有效时通过。","runtimeText":"联调仅在 HTTP 200、资源可归属、无业务失败且适用回执有效时通过。"},{"policyId":"P-SANDBOX-CREDENTIAL-EXCEPTION","scope":"integration.sandbox","severity":"critical","text":"Unix/macOS/Linux 只允许快速沙箱实际返回且已校验的买家登录/支付密码在沙箱摘要和付款体验中经 stdin 临时渲染。Windows 手工沙箱允许用户在 sandbox.windows.manual_setup 后提供当前沙箱应用的 APPID、支付宝公钥、应用公钥、与当前开发语言匹配的应用私钥和沙箱账号信息;Agent 只能将其用于已确认目标项目的受保护配置,不得在回复、摘要、普通日志或业务状态中复述或另存原文。两类例外均不得扩展到生产环境账号、应用私钥或密码。","runtimeText":"仅登记且已校验的快速沙箱或 Windows 手工沙箱资料可按 flow 用于受保护项目;禁复述、另存或扩展到生产值。"},{"policyId":"P-SENSITIVE-STATE","scope":"all","severity":"critical","text":"用户公钥仅用于当前 app key/verify-key/verify-key-and-audit 调用,禁止在回复、摘要、普通日志、跨会话状态或宽权限临时文件中复述或保存;除登记的沙箱例外外,私钥、token、Payment-Proof、签名串、完整支付表单和未脱敏响应同样不得进入这些位置;临时 URL 仅可由登记动作校验后在该动作正文展示。","runtimeText":"公钥限当前 app 调用且禁复述/保存;敏感值禁入回复/摘要/日志/状态/宽权限文件;临时 URL 仅由登记动作展示。"},{"policyId":"P-PROJECT-PROTECT","scope":"integration","severity":"critical","text":"不得清空、覆盖或删除用户既有项目;只在已确认目标路径和范围内做必要修改。","runtimeText":"禁清空/覆盖/删除既有项目;仅改已确认路径和范围。"},{"policyId":"P-CUSTOMER-OUTPUT-EXCLUSIVE","scope":"all","severity":"critical","text":"登记 runner/script 的 stdout 是唯一对客正文,禁止增删改写;阻塞消息送达后立即等待用户。","runtimeText":"登记 stdout 原文是唯一正文;阻塞送达后立即等待。"},{"policyId":"P-ONBOARDING-CONTROL-CHANNEL","scope":"onboarding","severity":"critical","text":"剔除 ALIPAY_AIPAY_INTERNAL 内部行后再处理 stdout;内部行禁止对客,正文为空时直接转移。","runtimeText":"内部行禁对客;正文为空按唯一终态转移。"},{"policyId":"P-AUTH-PAGE-DELIVERY-BARRIER","scope":"onboarding.authorization","severity":"critical","text":"`auth.page` stdout 必须先独立送达,再 opener 和有限轮询;不得合并 pending 或收口,也不等待确认。"},{"policyId":"P-KEY-PAGE-DELIVERY-BARRIER","scope":"onboarding.application","severity":"critical","text":"`application.key.page` stdout 必须先独立送达,再 opener 和有限轮询;不得合并 pending 或收口,也不等待确认。"},{"policyId":"P-DETERMINISTIC-HANDOFF","scope":"all","severity":"critical","text":"只执行 flow 动作处登记命令并按唯一终态立即转移;禁止追加命令重复解析,失败只走登记恢复。","runtimeText":"仅执行登记命令并按唯一终态转移;禁追加解析;失败只走登记恢复。"}],"officialUrls":{"aipaySite":"https://aipay.alipay.com/","aipaySkillSite":"https://aipay.alipay.com/?from=alipay-aipay-skill","merchantPlatform":"https://b.alipay.com/page/portal/home","openPlatform":"https://open.alipay.com/","openPlatformHome":"https://open.alipay.com","technicalSupport":"https://opensupport.alipay.com/support/intelligent-services?form=payskill","keyToolManual":"https://opendocs.alipay.com/isv/02kipk","keyToolMac":"https://ideservice.alipay.com/ide/getPluginUrl.htm?clientType=assistant&platform=mac&channelType=WEB","keyToolWindows":"https://ideservice.alipay.com/ide/getPluginUrl.htm?clientType=assistant&platform=win&channelType=WEB","androidSandboxAlipay":"https://mdn.alipayobjects.com/sandboxsys/afts/img/_itHRrdOD9oAAAAAAAAAAAAADgSLAQBr/original","sandboxToolFallback":"https://open.alipay.com/develop/sandbox/tool","sandboxGateway":"https://openapi-sandbox.dl.alipaydev.com/gateway.do","productionGateway":"https://openapi.alipay.com/gateway.do","openPlatformPaySkill":"https://open.alipay.com?form=payskill","traditionalPaymentSkill":"https://github.com/alipay/ai/tree/main/skills","dingtalkSupportGroupQr":"https://mdn.alipayobjects.com/huamei_5fajmi/afts/img/MlFpRKmYyLIAAAAARJAAAAgADlahAQFr/original","wecomCommunityGroupQr":"https://mdn.alipayobjects.com/huamei_5fajmi/afts/img/Cz0TTZVO7_4AAAAAQDAAAAgADlahAQFr/fmt.webp"},"authorizationProducts":[{"productName":"AI 按量付费","salesCode":"I1080300001000160457","scope":"app:all,machine_pay:write,agmnt:write"},{"productName":"AI 网页应用收款","salesCode":"I1080300001000041203","scope":"app:all,fast_instant_trade_pay:write"},{"productName":"AI 移动应用收款","salesCode":"I1080300001000041313","scope":"app:all,auth_alipay_apppay:write"}],"temporaryUrlAllowlist":{"authorization":{"host":"aipay.alipay.com","path":"/cli-auth","requiredQueryParams":["deviceCode","productCode","mccCode"],"optionalQueryParams":["platform"]},"publicKeyConfirmation":[{"host":"aipay.alipay.com","path":"/public-key-confirm","requiredQueryParams":["keyConfirmToken"],"optionalQueryParams":[]},{"host":"open.alipay.com","path":"/ai/ai-resource-center/public-key-confirm","requiredQueryParams":["keyConfirmToken"],"optionalQueryParams":[]}],"windowsOnboardingRedirect":{"host":"aipay.alipay.com","path":"/","requiredQueryParams":["from","reason","platform_id"],"optionalQueryParams":[]}}}
|
|
@@ -18,8 +18,10 @@ const policy = JSON.parse(fs.readFileSync(policyFile, "utf8"));
|
|
|
18
18
|
if (/[\u0000-\u0020\u007f`()\[\]<>|]/.test(raw)) process.exit(1);
|
|
19
19
|
let url;
|
|
20
20
|
try { url = new URL(raw); } catch { process.exit(1); }
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const entries = policy.temporaryUrlAllowlist[kind === "authorization" ? "authorization" : "publicKeyConfirmation"];
|
|
22
|
+
const allowed = (Array.isArray(entries) ? entries : [entries]).find((entry) =>
|
|
23
|
+
entry && url.hostname === entry.host && url.pathname === entry.path);
|
|
24
|
+
if (!allowed || url.protocol !== "https:" || url.username || url.password || url.port || url.hash) process.exit(1);
|
|
23
25
|
if (kind === "authorization") {
|
|
24
26
|
const required = allowed.requiredQueryParams;
|
|
25
27
|
const optional = allowed.optionalQueryParams;
|
|
@@ -343,8 +343,10 @@ function validateUrl(value, policy, urlKind, expected = {}) {
|
|
|
343
343
|
} catch {
|
|
344
344
|
throw new Error('officialTemporaryUrl 不是合法 URL');
|
|
345
345
|
}
|
|
346
|
-
const
|
|
347
|
-
|
|
346
|
+
const entries = policy.temporaryUrlAllowlist[urlKind];
|
|
347
|
+
const allowed = (Array.isArray(entries) ? entries : [entries]).find((entry) =>
|
|
348
|
+
entry && parsed.hostname === entry.host && parsed.pathname === entry.path);
|
|
349
|
+
if (!allowed || parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.port || parsed.hash) {
|
|
348
350
|
throw new Error(`officialTemporaryUrl 不符合 ${urlKind} allowlist`);
|
|
349
351
|
}
|
|
350
352
|
if (urlKind === 'authorization') {
|
|
@@ -307,17 +307,14 @@ function removeTransactionPath(target) {
|
|
|
307
307
|
|
|
308
308
|
function reconcileInstallTransaction(skillDir, transactionId, channel) {
|
|
309
309
|
const artifacts = transactionArtifacts(skillDir, transactionId, channel);
|
|
310
|
-
|
|
311
|
-
if (!current && isRecoverableSkillRoot(artifacts.backup)) {
|
|
310
|
+
if (isRecoverableSkillRoot(artifacts.backup)) {
|
|
312
311
|
try {
|
|
313
312
|
removeTransactionPath(skillDir);
|
|
314
313
|
fs.renameSync(artifacts.backup, skillDir);
|
|
315
314
|
} catch {}
|
|
316
|
-
current = readLocalVersion(skillDir);
|
|
317
315
|
}
|
|
318
316
|
removeTransactionPath(artifacts.staging);
|
|
319
|
-
|
|
320
|
-
return current;
|
|
317
|
+
return { version: readLocalVersion(skillDir), backupPresent: fs.existsSync(artifacts.backup) };
|
|
321
318
|
}
|
|
322
319
|
|
|
323
320
|
async function installVersion(skillDir, packageVersion, channel) {
|
|
@@ -351,10 +348,11 @@ async function installVersion(skillDir, packageVersion, channel) {
|
|
|
351
348
|
} catch { /* An invalid receipt never permits a session switch. */ }
|
|
352
349
|
}
|
|
353
350
|
}
|
|
351
|
+
const reconciled = reconcileInstallTransaction(skillDir, transactionId, channel);
|
|
354
352
|
return {
|
|
355
353
|
ok: result.status === 0 && !result.error,
|
|
356
354
|
reason: result.status === 0 && !result.error ? 'ok' : packageManagerFailureKind(result),
|
|
357
|
-
|
|
355
|
+
...reconciled,
|
|
358
356
|
session,
|
|
359
357
|
};
|
|
360
358
|
}
|
|
@@ -395,8 +393,9 @@ export async function runSelfUpdateCli(argv = process.argv) {
|
|
|
395
393
|
if (installed.session && installed.session.version===latest.raw) {
|
|
396
394
|
return {kind:'SESSION_READY',version:latest,skillDir:installed.session.skillDir};
|
|
397
395
|
}
|
|
396
|
+
if (installed.backupPresent) return { kind: 'INSTALL_FAILED' };
|
|
398
397
|
const updated = installed.version || readLocalVersion(skillDir);
|
|
399
|
-
if (updated && readChannel(skillDir) === channel && compareVersions(updated, latest) >= 0) return { kind: 'UPDATED', version: updated };
|
|
398
|
+
if (installed.ok && updated && readChannel(skillDir) === channel && compareVersions(updated, latest) >= 0) return { kind: 'UPDATED', version: updated };
|
|
400
399
|
if (installed.reason === 'network') return { kind: 'RETRY_WITH_NETWORK' };
|
|
401
400
|
if (installed.reason === 'local') return { kind: 'CHECK_FAILED' };
|
|
402
401
|
return { kind: installed.ok ? 'VERIFY_FAILED' : 'INSTALL_FAILED' };
|
|
@@ -158,8 +158,6 @@ function Invoke-NodeBootstrap([string]$Action, [string]$Root) {
|
|
|
158
158
|
if ($MyInvocation.InvocationName -ne '.') {
|
|
159
159
|
$ErrorActionPreference = 'Stop'
|
|
160
160
|
try {
|
|
161
|
-
. (Join-Path $PSScriptRoot 'architecture.ps1')
|
|
162
|
-
if ((Get-AipayNativeArchitecture) -ne 'x64') { throw 'UNSUPPORTED_PLATFORM' }
|
|
163
161
|
$localData = $env:LOCALAPPDATA
|
|
164
162
|
if (-not $localData) { $localData = [Environment]::GetFolderPath('LocalApplicationData') }
|
|
165
163
|
if (-not $localData -or -not [IO.Path]::IsPathRooted($localData)) { throw 'STORAGE_FAILED' }
|
package/skill-pre/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.7.
|
|
1
|
+
1.7.8-pre
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- ALIPAY_AIPAY_FLOW:INTEGRATION_CORE:START -->
|
|
2
2
|
# 支付产品-代码开发流程
|
|
3
3
|
|
|
4
|
-
本 flow 的 Windows READY/LEGACY/CODE_ONLY 指根入口的唯一兼容环境分流事实,或 Windows 环境文档明确修复后唯一、根意图匹配的新 READY 事实;BLOCKED 停在环境恢复点,不进入本 flow。后续命令附加当前有效的 `--windows-route`。Windows READY 通过 Git Bash 执行登记的快速沙箱脚本;Windows LEGACY/CODE_ONLY 保留原 Node 独立开发和手工沙箱分支。三者都由当前 Agent 串行执行,不启用 Integration Worker。Windows
|
|
4
|
+
本 flow 的 Windows READY/LEGACY/CODE_ONLY 指根入口的唯一兼容环境分流事实,或 Windows 环境文档明确修复后唯一、根意图匹配的新 READY 事实;BLOCKED 停在环境恢复点,不进入本 flow。后续命令附加当前有效的 `--windows-route`。Windows READY 通过 Git Bash 执行登记的快速沙箱脚本;Windows LEGACY/CODE_ONLY 保留原 Node 独立开发和手工沙箱分支。三者都由当前 Agent 串行执行,不启用 Integration Worker。Windows 沙箱项目配置不要求精确 NTFS ACL 白名单;仍校验字段、项目实际加载路径及防误提交。登录凭据与生产配置沿各自动作的保护规则处理。CODE_ONLY 允许 `integration_only/full_process` 在可选工具故障时继续代码开发,沙箱保持 `VERIFY_PENDING`;完整接入完成代码部分后停在开通前,不把 CODE_ONLY 用于 Onboarding。根意图变化必须重跑 Windows 入口。
|
|
5
5
|
|
|
6
6
|
> ⚠️ **前置声明**:本 flow 仅支持 **AI 网页应用收款、AI 移动应用收款、AI 按量付费**三种产品的集成。原有“网站支付”“APP 支付”“按量付费”仍作为输入别名和资源目录名。**其他产品(当面付、订单码支付、JSAPI支付、预授权支付、商家扣款等)暂不支持**,如需集成请前往[支付宝开放平台](https://open.alipay.com/)查阅相关文档。
|
|
7
7
|
|
|
@@ -156,7 +156,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message loc
|
|
|
156
156
|
node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" sandbox ensure "<规范化项目路径>" "<已确认服务端语言>" [--telemetry-run-id "$RUN_ID" --telemetry-history-count "$HISTORY_COUNT"] --agent-platform "<AGENT_PLATFORM>" --session-id "<SESSION_ID>"
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
4. Windows LEGACY/CODE_ONLY 不调用快速沙箱脚本。普通代码开发或完整接入请求没有明确要求当前配置沙箱时,不展示申领消息、不补问,直接记录 `sandboxConfigState=VERIFY_PENDING` 并继续步骤 2
|
|
159
|
+
4. Windows LEGACY/CODE_ONLY 不调用快速沙箱脚本。普通代码开发或完整接入请求没有明确要求当前配置沙箱时,不展示申领消息、不补问,直接记录 `sandboxConfigState=VERIFY_PENDING` 并继续步骤 2。只有用户明确要求现在配置/恢复沙箱时才执行下列既有标准消息 `sandbox.windows.manual_setup`;该消息使用自由资料回复,不要求用户输入 `1` 或自行执行脚本。随后只处理用户针对本轮该消息提供的资料:完整有效时写入目标项目实际使用的本机配置并记录 `READY`,部分或错误时使用既有受控失败分支补问实际缺失/错误字段:
|
|
160
160
|
|
|
161
161
|
```bash
|
|
162
162
|
node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message windows-sandbox-setup --agent-platform "<AGENT_PLATFORM>" --session-id "<SESSION_ID>"
|
|
@@ -328,7 +328,7 @@ curl -sL "<当前契约 sourceUrl 中的官方页面>"
|
|
|
328
328
|
|
|
329
329
|
开始执行代码自检、语法/静态检查或支付配置后置校验前,进入本 flow 的 `verification` 阶段;该阶段不再单独记录 telemetry 开始态,只由最终收口阶段记录结果。
|
|
330
330
|
|
|
331
|
-
**支付配置接入与后置校验**:`sandboxConfigState=READY` 时,Unix/macOS/Linux 或 Windows READY 快速沙箱由商家服务端代码使用当前语言的标准 JSON 解析器,在运行时读取步骤 1/3 已验证的 `.alipay-sandbox.json`,并从 `appIds[0]` 映射 `appId`、`alipayPublicKey` 和当前语言私钥字段;不得先用 `jq`、`cat` 或临时脚本把字段原文打印到工具输出、复制到源码或重复写入 `.env`。项目已有配置抽象时在其服务端加载边界接入该 JSON,不改变字段原值。Windows LEGACY/CODE_ONLY 从步骤 1 由 Agent
|
|
331
|
+
**支付配置接入与后置校验**:`sandboxConfigState=READY` 时,Unix/macOS/Linux 或 Windows READY 快速沙箱由商家服务端代码使用当前语言的标准 JSON 解析器,在运行时读取步骤 1/3 已验证的 `.alipay-sandbox.json`,并从 `appIds[0]` 映射 `appId`、`alipayPublicKey` 和当前语言私钥字段;不得先用 `jq`、`cat` 或临时脚本把字段原文打印到工具输出、复制到源码或重复写入 `.env`。项目已有配置抽象时在其服务端加载边界接入该 JSON,不改变字段原值。Windows LEGACY/CODE_ONLY 从步骤 1 由 Agent 写入并校验的本机沙箱配置读取。后置校验必须检查实际加载路径、字段选择、SDK 初始化和版本控制保护;Java 使用 `appPrivateKey`,其他四种语言使用 `appPrivatePkcsKey`。A2M 的 `seller_signature` 使用原生密码库时,只在调用边界按库要求解析密钥。失败时修正加载器或 SDK 配置,禁止猜测、转换格式或改写原始值。
|
|
332
332
|
|
|
333
333
|
`sandboxConfigState=CREATE_PENDING|VERIFY_PENDING` 时仍完整实现当前产品全部适用接口、安全校验和配置加载边界,但不得读取当前无效配置、写入占位 appId/密钥、把示例值当作运行配置或声称 `INT.CODE.CONFIG_VERIFIED` 通过。加载器在配置缺失或无效时必须明确失败并阻止真实 SDK 调用;本轮所有依赖沙箱值的运行验证保持未完成。
|
|
334
334
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
| 私钥仓库安全 | 私钥不得上传公共仓库 | 私钥泄露将导致应用和支付宝交互的安全性完全丧失 |
|
|
15
15
|
| 沙箱配置后置校验 | 沙箱 appId、应用私钥、支付宝公钥接入项目后必须完成配置准确性校验 | `sandboxConfigState=READY` 时,Unix/macOS/Linux 或 Windows READY 必须确认商家服务端加载器直接读取已验证的 `.alipay-sandbox.json`,从同一 `appIds[0]` 选择当前语言字段且不在源码、普通日志或额外 `.env` 留下密钥副本;Windows LEGACY/CODE_ONLY 必须确认项目实际读取值属于本次手工申领和密钥配置的同一沙箱应用。待配置时本项直接不通过,代码只能保留会在配置缺失时明确失败的加载边界,禁止占位符、示例值或其他来源密钥 |
|
|
16
16
|
| 用户项目文件保护 | 既有项目结构、文件和无关支付能力均保留;新项目只创建在尚不存在或为空的目录 | 检查本轮变更不存在未经独立二次确认的既有文件删除、既有文件整体覆盖,或与已确认目标产品无关的修改;新建文件不属于既有文件整体覆盖。发现违规立即判定不通过并停止后续流程 |
|
|
17
|
-
| 沙箱配置防提交 | Unix/macOS/Linux 或 Windows READY 快速沙箱:配置未被 Git 跟踪,项目根目录 `.gitignore` 包含精确规则 `/.alipay-sandbox.json`,Unix 配置权限为 `0600
|
|
17
|
+
| 沙箱配置防提交 | Unix/macOS/Linux 或 Windows READY 快速沙箱:配置未被 Git 跟踪,项目根目录 `.gitignore` 包含精确规则 `/.alipay-sandbox.json`,Unix 配置权限为 `0600`;Windows LEGACY/CODE_ONLY 手工沙箱:实际沙箱配置未被 Git 跟踪并具有对应忽略保护。Windows 沙箱配置不要求精确 NTFS ACL 白名单 | 避免沙箱配置随项目进入 Git 暂存区或公共仓库;缺少适用防提交保护时判定不通过 |
|
|
18
18
|
| 沙箱配置稳定定位 | Unix/macOS/Linux 或 Windows READY 项目代码从已确认的规范化项目根定位 `.alipay-sandbox.json` | 禁止依赖 `cwd`、`getcwd()`、`Directory.GetCurrentDirectory()`、`user.dir` 或 Agent 启动目录 |
|
|
19
19
|
| SDK 公钥/证书模式一致 | 公钥模式使用普通执行 API;证书执行 API 只在应用公钥证书、支付宝公钥证书和支付宝根证书均已配置时使用 | 禁止公钥配置模式误用证书执行 API |
|
|
20
20
|
| 支付校验无旁路 | 生产源码中不存在 Mock、测试或沙箱开关可触达的跳过验签、固定成功或支付校验旁路 | 沙箱与生产必须共用相同验证控制流 |
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
| 幂等履约 | 同一订单重复携带 `Payment-Proof` 时不得重复发放资源 | 应返回历史履约结果或可重试确认结果 |
|
|
85
85
|
| 履约确认 | 资源生成后必须调用 `alipay.aipay.agent.fulfillment.confirm` | 确认成功后再标记订单 `FULFILLED` 并返回成功交付 |
|
|
86
86
|
| 自动联调成功证据 | 必须同时具备 HTTP 200、非空 `resource_id` / `resourceId`、非空 `content`、无明确业务失败,以及当前五语言示例有效的 `Payment-Validation` | 204、空体、空对象、`VERIFY_FAILED`、履约失败或异常响应头均不得判为通过 |
|
|
87
|
-
| 敏感过程产物 |
|
|
87
|
+
| 敏感过程产物 | 单次联调仅使用本次临时目录,Unix/macOS/Linux 的目录/文件权限不得宽于 `0700/0600`;Windows 检查实际可写和非符号链接,不以 ACL 白名单为完成条件;命令结束时立即清理 | 禁止打印 Payment-Proof 或 Payment-Validation 原始值;失败后重新执行完整联调 |
|
|
88
88
|
| 沙箱 serviceId | 沙箱联调的 `serviceId` 固定为 `api_mock_service_id` | 不向用户索要正式 `serviceId`,不使用其他占位符 |
|
|
89
89
|
| 沙箱空字段边界 | 沙箱联调中字段为空可用于排查定位,生产环境关键字段为空必须按异常处理 | 不得把沙箱容错逻辑直接迁移成生产跳过校验 |
|
|
90
90
|
| 生产实现完整性 | 订单持久化、本地订单匹配、金额一致性、资源防串、幂等履约、待确认状态和确认失败重试均已实际实现 | 任一关键控制仍为 TODO、注释、内存演示或伪代码时只能判定沙箱演示可测试,不得判定生产就绪 |
|
|
@@ -192,7 +192,7 @@ Payment-Proof 参考结构:
|
|
|
192
192
|
|
|
193
193
|
> 当前 `serviceId=api_mock_service_id` 仅用于沙箱联调。正式上线前,必须替换为支付宝服务市场注册或复用服务后实际返回的真实 `serviceId`。
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
脚本在单次临时目录传递敏感中间值;Unix/macOS/Linux 校验目录/文件模式位不宽于 `0700/0600`,Windows 在启动 Python 前确认目录实际可写,不将其解释为 ACL 已安全配置。命令退出前清理,该目录不用于用户进度或后续恢复;Agent 不向用户索要、展示或复用其中的 Payment-Proof。
|
|
196
196
|
|
|
197
197
|
**沙箱支付宝下载红线(Agent 内部约束,不要作为用户提示逐字输出):**
|
|
198
198
|
- 默认只提供上方沙箱支付宝安装直链,复制到网页浏览器打开,并使用支付宝客户端扫码下载。
|
|
@@ -207,7 +207,7 @@ Payment-Proof 参考结构:
|
|
|
207
207
|
|
|
208
208
|
1. **沙箱收银接口**:脚本默认使用 `http://aicashier.dl.alipaydev.com/openclawpay/agent/v1/pay`,此地址已硬编码在脚本中
|
|
209
209
|
2. **付款链接**:前缀为 `https://render.alipay.com/p/yuyan/180020010001290755/pay.html?schema=`,通过 URL 编码的 `payScheme` 拼接
|
|
210
|
-
3.
|
|
210
|
+
3. **过程产物**:只在当前命令的系统临时专用目录中短时存在;Unix/macOS/Linux 校验目录/文件 `0700/0600`,Windows 校验实际可写和非符号链接,不验证 ACL 白名单;命令成功、失败或异常退出都执行清理,不提供自定义目录和跨轮恢复
|
|
211
211
|
4. **买家签名**:默认占位值 `-`,无需修改
|
|
212
212
|
5. **沙箱化 Agent 网络权限**:脚本内 `fetch_payment_needed` 使用 curl,且收银测试会访问沙箱接口;沙箱化 Agent 环境首次执行即申请可联网权限
|
|
213
213
|
6. **沙箱支付宝安装包**:沙箱支付宝当前仅支持安卓系统;默认引导用户复制 `https://mdn.alipayobjects.com/sandboxsys/afts/img/_itHRrdOD9oAAAAAAAAAAAAADgSLAQBr/original` 到网页浏览器打开,并使用支付宝客户端扫码下载。若用户明确反馈该直链、页面二维码无法打开或无法下载,只能引导用户前往支付宝开放平台沙箱工具页 `https://open.alipay.com/develop/sandbox/tool`,按页面指引安装沙箱版支付宝。严禁引导用户使用 iOS 沙箱支付宝、应用市场搜索、`https://sandbox.alipay.com` 或其他自编下载 URL。
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
- ✅ **安全隔离**:测试环境不涉及真实资金,可放心调试
|
|
13
13
|
|
|
14
14
|
### 1.2 Windows LEGACY/CODE_ONLY 用户注意事项
|
|
15
|
-
Windows READY 通过兼容层执行 flow 登记的快速沙箱;下述手工分支适用于 Windows LEGACY/CODE_ONLY;CODE_ONLY
|
|
15
|
+
Windows READY 通过兼容层执行 flow 登记的快速沙箱;下述手工分支适用于 Windows LEGACY/CODE_ONLY;CODE_ONLY 只放行代码开发,不代表站点开通选择。Windows 沙箱项目配置不要求精确 NTFS ACL 白名单,配置是否可用仍由字段校验、实际项目加载路径和防误提交检查决定。
|
|
16
16
|
|
|
17
|
-
Windows LEGACY/CODE_ONLY 普通代码开发或完整接入请求未明确要求当前配置沙箱时,记录 `sandboxConfigState=VERIFY_PENDING` 并继续代码实现,不展示资料收集消息。只有用户明确要求现在配置或恢复 Windows LEGACY/CODE_ONLY 沙箱时,才使用 `../../../normal/json/customer-messages.json` 的既有 `sandbox.windows.manual_setup`,引导用户前往支付宝 AI 付站点的“选择产品 → 一站式接入 → 技术集成”页面获取当前沙箱的 APPID
|
|
17
|
+
Windows LEGACY/CODE_ONLY 普通代码开发或完整接入请求未明确要求当前配置沙箱时,记录 `sandboxConfigState=VERIFY_PENDING` 并继续代码实现,不展示资料收集消息。只有用户明确要求现在配置或恢复 Windows LEGACY/CODE_ONLY 沙箱时,才使用 `../../../normal/json/customer-messages.json` 的既有 `sandbox.windows.manual_setup`,引导用户前往支付宝 AI 付站点的“选择产品 → 一站式接入 → 技术集成”页面获取当前沙箱的 APPID、公私钥和账号信息;随后只处理用户针对本轮该消息提供的资料,完整时校验并写入目标项目实际使用的本地沙箱配置,部分或错误时只补问对应字段。不得要求用户自行配置、理解 `sandbox_config.sh`、执行 Bash 或手工拼接 Skill 的规范化 JSON。该资料输入例外只适用于沙箱,生产环境应用私钥和密码禁止提供给 Agent;Agent 不得在回复、摘要或普通日志中复述收到的值。
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message windows-sandbox-setup --agent-platform "<AGENT_PLATFORM>" --session-id "<SESSION_ID>"
|
|
@@ -57,7 +57,7 @@ Unix/macOS/Linux 或 Windows READY 快速沙箱由 `sandbox_config.sh` 在内部
|
|
|
57
57
|
1. 提取候选 `data`。
|
|
58
58
|
2. 按第 4 节逐项校验必含字段。
|
|
59
59
|
3. 校验通过后,将候选 `data` 按原始 JSON 结构写入正式本地配置文件。
|
|
60
|
-
4. 确认配置未被 Git 跟踪、项目根目录 `.gitignore` 已包含 `/.alipay-sandbox.json
|
|
60
|
+
4. 确认配置未被 Git 跟踪、项目根目录 `.gitignore` 已包含 `/.alipay-sandbox.json`;Unix/macOS/Linux 确认权限为 `0600`,Windows 确认文件实际可访问且不是符号链接。创建阶段只通过带 `ALIPAY_AIPAY_INTERNAL:` 前缀的 stderr 内部事实返回机器标记和实际配置文件路径,不对客展示关键字段摘要。
|
|
61
61
|
5. 后续由商家服务端代码使用当前语言标准 JSON 解析器在运行时读取该文件并映射到 SDK;Agent 不通过 shell 输出字段原文,也不把沙箱密钥复制到源码或重复写入 `.env`。
|
|
62
62
|
6. 代码开发完成且配置后置校验通过后,再使用第 5.2 节的摘要输出入口对客展示沙箱环境配置。
|
|
63
63
|
|
|
@@ -65,8 +65,8 @@ Windows LEGACY/CODE_ONLY 手工沙箱:
|
|
|
65
65
|
|
|
66
66
|
1. 没有资料且没有明确配置请求时记录 `VERIFY_PENDING` 并继续代码实现,不渲染消息、不探测猜测配置。
|
|
67
67
|
2. 用户明确要求配置且尚未提供资料时,才使用标准消息一次收集当前沙箱应用的 APPID、支付宝公钥、应用公钥、与已确认语言匹配的应用私钥和沙箱账号信息;缺失或校验失败时只补问对应字段。
|
|
68
|
-
3. 按第 4 节校验资料,随后由 Agent
|
|
69
|
-
4.
|
|
68
|
+
3. 按第 4 节校验资料,随后由 Agent 写入目标项目实际使用的本地沙箱配置;不要求采用快速沙箱 `data` 的嵌套结构,不把值复制到源码或普通日志。
|
|
69
|
+
4. 检查沙箱配置未被 Git 跟踪,并已有适用于实际路径的版本控制忽略保护;不因项目目录继承额外 Windows ACL 权限而阻断沙箱配置。
|
|
70
70
|
5. 只有 `READY` 时才输出第 5 节规定的摘要和 Windows LEGACY/CODE_ONLY 提醒并从实际本机配置映射到 SDK;Agent 不得在回复或摘要中复述用户提供的沙箱密钥和密码,生产环境应用私钥和密码禁止提供给 Agent。
|
|
71
71
|
|
|
72
72
|
Unix/macOS/Linux 或 Windows READY 快速沙箱的流程准备必须使用 integration flow 登记的 `sandbox_config.sh ensure` 入口:配置缺失时脚本内部创建,已存在时脚本内部复核;步骤 3 仅在首次准备为 `READY` 时执行 `reverify`,待配置时直接继续代码开发;代码开发完成且配置仍为 `READY` 后才使用 `summary` 展示摘要。`ensure|reverify` 会把既定重试耗尽转换为受控 `CREATE_PENDING|VERIFY_PENDING`,直接渲染统一消息并返回终态标记;Agent 不得直接选择创建分支、重复检查文件存在性或权限、读取字段结构、拼接沙箱 JSON、另写解析逻辑或自制摘要表。Windows LEGACY/CODE_ONLY 手工申领分支检查目标项目实际读取的本地配置,不把平台字段擅自改造成快速沙箱返回结构。
|
|
@@ -128,8 +128,8 @@ Unix/macOS/Linux 或 Windows READY 快速沙箱:
|
|
|
128
128
|
Windows LEGACY/CODE_ONLY 手工沙箱:
|
|
129
129
|
|
|
130
130
|
- 由 Agent 根据目标项目实际结构选择并写入本机敏感配置路径,不要求用户创建 `.alipay-sandbox.json` 或自行配置项目。
|
|
131
|
-
- 配置必须未被 Git
|
|
132
|
-
- 只有实际检查到的字段才能进入后续 SDK
|
|
131
|
+
- 配置必须未被 Git 跟踪,并建立适用于该实际路径的忽略保护;Windows 不以 POSIX `0600` 或精确 NTFS ACL 白名单作为沙箱完成条件。
|
|
132
|
+
- 只有实际检查到的字段才能进入后续 SDK 映射;无法自动核验的平台页面信息标记为人工待验证,项目继承的额外 Windows ACL 权限不构成缺口。
|
|
133
133
|
|
|
134
134
|
Unix/macOS/Linux 或 Windows READY 创建阶段把实际本机配置路径和 `FLOW:SANDBOX_CONFIG_READY` 作为带 `ALIPAY_AIPAY_INTERNAL:` 前缀的 stderr 内部事实,stdout 为空;不展示账号、密码、公钥或摘要。Windows LEGACY/CODE_ONLY 手工分支完成后只在内部保留实际本机配置路径。两条分支在代码开发完成且配置后置校验通过后,才进入摘要展示。
|
|
135
135
|
|
|
@@ -80,11 +80,6 @@ if [ "$MODE" = "summary" ]; then
|
|
|
80
80
|
fi
|
|
81
81
|
case "$PROJECT_PATH" in /*) ;; *) echo "SANDBOX_ERROR:项目路径必须为绝对路径" >&2; exit 2 ;; esac
|
|
82
82
|
[ -d "$PROJECT_PATH" ] && [ ! -L "$PROJECT_PATH" ] || { echo "SANDBOX_ERROR:项目目录不可访问或不安全" >&2; exit 2; }
|
|
83
|
-
if declare -F windows_protect >/dev/null; then
|
|
84
|
-
windows_probe=$(mktemp "${PROJECT_PATH}/.windows-acl-probe.XXXXXX") || exit 78
|
|
85
|
-
windows_protect "$windows_probe" || { rm -f "$windows_probe"; exit 78; }
|
|
86
|
-
rm -f "$windows_probe" || exit 78
|
|
87
|
-
fi
|
|
88
83
|
detected=()
|
|
89
84
|
find "$PROJECT_PATH" -maxdepth 4 -type f \( -name pom.xml -o -name build.gradle -o -name build.gradle.kts \) -print -quit | grep -q . && detected+=(Java)
|
|
90
85
|
find "$PROJECT_PATH" -maxdepth 4 -type f -name package.json -print -quit | grep -q . && detected+=(Node.js)
|
|
@@ -199,7 +194,7 @@ ensure_config_not_tracked() {
|
|
|
199
194
|
}
|
|
200
195
|
|
|
201
196
|
ensure_config_permissions() {
|
|
202
|
-
if declare -F
|
|
197
|
+
if declare -F windows_check_access >/dev/null; then windows_check_access "$CONFIG_PATH"; return $?; fi
|
|
203
198
|
local mode
|
|
204
199
|
chmod 600 "$CONFIG_PATH" 2>/dev/null || return 1
|
|
205
200
|
if mode=$(stat -f '%Lp' "$CONFIG_PATH" 2>/dev/null); then
|
|
@@ -321,24 +316,23 @@ if [ "$MODE" = "create" ]; then
|
|
|
321
316
|
validate_data "$data" || { echo "SANDBOX_ERROR:候选 data 缺少当前语言或测试账号必含字段" >&2; exit 1; }
|
|
322
317
|
temp=$(mktemp "${PROJECT_PATH}/.alipay-sandbox.XXXXXX") || exit 1
|
|
323
318
|
chmod 600 "$temp" 2>/dev/null || true
|
|
324
|
-
if declare -F windows_protect >/dev/null; then windows_protect "$temp" || { rm -f "$temp"; exit 78; }; fi
|
|
325
319
|
printf '%s\n' "$data" >"$temp" || { rm -f "$temp"; exit 1; }
|
|
326
320
|
mv "$temp" "$CONFIG_PATH" || { rm -f "$temp"; exit 1; }
|
|
327
|
-
ensure_config_permissions || { echo "SANDBOX_ERROR
|
|
321
|
+
ensure_config_permissions || { echo "SANDBOX_ERROR:沙箱配置文件不可访问或权限不符合当前系统要求" >&2; exit 1; }
|
|
328
322
|
elif [ "$MODE" = "verify" ]; then
|
|
329
323
|
[ -f "$CONFIG_PATH" ] && [ ! -L "$CONFIG_PATH" ] || { echo "SANDBOX_ERROR:配置文件不存在或不安全" >&2; exit 1; }
|
|
330
324
|
ensure_config_not_tracked || { echo "SANDBOX_ERROR:沙箱配置已被 Git 跟踪,必须先从版本控制中移除" >&2; exit 1; }
|
|
331
325
|
ensure_gitignore_protection || { echo "SANDBOX_ERROR:无法为沙箱配置建立 Git 忽略保护" >&2; exit 1; }
|
|
332
326
|
data=$(jq -c . "$CONFIG_PATH" 2>/dev/null) || { echo "SANDBOX_ERROR:配置不是合法 JSON" >&2; exit 1; }
|
|
333
327
|
validate_data "$data" || { echo "SANDBOX_ERROR:配置缺少当前语言或测试账号必含字段" >&2; exit 1; }
|
|
334
|
-
ensure_config_permissions || { echo "SANDBOX_ERROR
|
|
328
|
+
ensure_config_permissions || { echo "SANDBOX_ERROR:沙箱配置文件不可访问或权限不符合当前系统要求" >&2; exit 1; }
|
|
335
329
|
elif [ "$MODE" = "summary" ]; then
|
|
336
330
|
[ -f "$CONFIG_PATH" ] && [ ! -L "$CONFIG_PATH" ] || { echo "SANDBOX_ERROR:配置文件不存在或不安全" >&2; exit 1; }
|
|
337
331
|
ensure_config_not_tracked || { echo "SANDBOX_ERROR:沙箱配置已被 Git 跟踪,必须先从版本控制中移除" >&2; exit 1; }
|
|
338
332
|
ensure_gitignore_protection || { echo "SANDBOX_ERROR:无法为沙箱配置建立 Git 忽略保护" >&2; exit 1; }
|
|
339
333
|
data=$(jq -c . "$CONFIG_PATH" 2>/dev/null) || { echo "SANDBOX_ERROR:配置不是合法 JSON" >&2; exit 1; }
|
|
340
334
|
validate_data "$data" || { echo "SANDBOX_ERROR:配置缺少当前语言或测试账号必含字段" >&2; exit 1; }
|
|
341
|
-
ensure_config_permissions || { echo "SANDBOX_ERROR
|
|
335
|
+
ensure_config_permissions || { echo "SANDBOX_ERROR:沙箱配置文件不可访问或权限不符合当前系统要求" >&2; exit 1; }
|
|
342
336
|
else
|
|
343
337
|
echo "SANDBOX_ERROR:用法 sandbox_config.sh <ensure|reverify|create|verify> <projectPath> <language> 或 sandbox_config.sh summary <productType> <projectPath> <language>" >&2
|
|
344
338
|
exit 2
|
|
@@ -94,7 +94,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" telemetry end-conversat
|
|
|
94
94
|
|
|
95
95
|
采集脱敏后的完整正文,不主动截断或摘要。
|
|
96
96
|
|
|
97
|
-
独立 conversation state 只保存随机 ID、会话 hash、去重 hash、消息序号、创建时授权 ID 和 ACTIVE/CLOSED
|
|
97
|
+
独立 conversation state 只保存随机 ID、会话 hash、去重 hash、消息序号、创建时授权 ID 和 ACTIVE/CLOSED 状态;正文仅进入当前用户的 outbox。Unix/macOS/Linux 使用 `0600` 文件模式,Windows 仅检查目录实际可写,不声称已经配置 ACL。对话事件使用 .conversation 后缀保存 JSON,让只识别 .json 的旧版 worker 跳过。对话正文和解析错误不进入 stdout/stderr。code 入队时固定,后续改配置不重标旧事件。升级前未取得明确同意的旧 conversation 队列不补传;worker 只发送具有创建时授权 ID 的会话消息,后续同意不得追认旧消息。
|
|
98
98
|
|
|
99
99
|
对话上报请求不设置脚本级网络超时(timeout=0)。采集命令完成本地状态记录和入队后,尝试启动 detached 后台 worker 并立即返回,不在前台等待网络结果。后台发送也负责失败补传;若网络一直不返回结果,仅后台请求等待,不拖住 Skill 的后续命令。前台 flush-outbox 跳过对话记录,把它们留给后台 worker,避免补传重新引入前台等待。后台 worker 启动失败时保留队列,Skill 继续;后续触发时再尝试启动,不保证最终送达。操作系统、宿主和服务端仍可能中止连接;明确失败时继续按原机制保留记录补传。本地状态写入和入队仍需要少量执行时间,不能把“不等待网络”描述为完全零耗时。
|
|
100
100
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 完整接入编排
|
|
2
2
|
|
|
3
|
-
本文件是 `full_process` 唯一入口。Windows 复用根入口的 READY/LEGACY 分流,或明确修复后唯一、根意图匹配的新 READY 事实;BLOCKED
|
|
3
|
+
本文件是 `full_process` 唯一入口。Windows 复用根入口的 READY/LEGACY/CODE_ONLY 分流,或明确修复后唯一、根意图匹配的新 READY 事实;BLOCKED 先恢复环境,不进入本流程。CODE_ONLY 只完成独立代码开发,沙箱保持 `VERIFY_PENDING`,最终如实列出未完成项并停在 Onboarding 前;不得登录、开通或宣称完整接入完成。从仅开发切换为完整接入时必须先用 `full_process` 重新执行 Windows 入口。命令携带当前有效的 `--windows-route`。READY 执行 Integration 快速沙箱及 Onboarding 本地流程,LEGACY 仅在不支持的平台映射或用户明确选站点时先完成可独立开发内容,再在原衔接点输出站点引导。三者都不重新安装、不创建 Integration Worker。启动方案送达前只复用 Integration 步骤 1 的项目、语言、当前系统分支环境和沙箱准备;不得开发代码、进入 Onboarding 或读取开通信息。
|
|
4
4
|
|
|
5
5
|
目标项目和技术栈确定后执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow integration entry --agent-platform "<AGENT_PLATFORM>" --session-id "<SESSION_ID>"`,只加载当前入口阶段并按步骤 1/2 准备及展示方案;代码开发满足衔接条件后执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow onboarding entry --agent-platform "<AGENT_PLATFORM>" --session-id "<SESSION_ID>"`。禁止整读两个 flow。所有 Skill 自有运行时动作只用当前 Skill 绝对路径下的统一入口单命令执行,不前置 `cd`、不拼接管道;用户项目命令仍以已确认项目根为 workdir。
|
|
6
6
|
|
|
@@ -86,6 +86,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" integration-message sta
|
|
|
86
86
|
|
|
87
87
|
- 启动方案送达后先完成上述 Worker 分流,再由确定的执行者进入 Integration 步骤 3;用户中断后若项目、产品、语言或框架变化,重新澄清和扫描并输出当前方案。
|
|
88
88
|
- Integration 先完整执行和校验。只有沙箱待配置,或 READY 且仅剩非阻塞人工待验证项时,保持“部分通过”进入 Onboarding;其他代码、安全或依据缺口停在 Integration,不提前登录或收集开通材料。
|
|
89
|
+
- Windows CODE_ONLY 时,即使沙箱待配置是代码部分的唯一缺口,也在 Integration 最终检查后停止;恢复可选工具并按 `full_process` 复检得到 READY,才按实际项目状态恢复沙箱和 Onboarding。
|
|
89
90
|
- 阶段间只复用有效的产品、Integration 结果、沙箱状态、人工待验证项和剩余待办,不再询问是否进入 Onboarding;Onboarding 只保留非阻塞方案展示。
|
|
90
91
|
- 授权后分别查询签约、应用和适用服务;分支独立,单分支失败不回滚其他成功,认证/授权不匹配或主体变化全局阻断。一次只收集一个类别,提前材料直接校验且不重复索取。
|
|
91
92
|
- 签约材料通过后直接提交;服务创建摘要后直创、修改仍确认;空应用候选材料完整或非空候选明确新建,重查未变即创建,以用户公钥生成官方确认页,校验成功后直接提审。均不增加额外确认点;按量付费沙箱测试仍属 Integration 默认动作。
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawnSync as nativeSpawn } from 'node:child_process';
|
|
4
|
-
const { spawnSync } = process.platform === 'win32'
|
|
5
|
-
? await import('./windows/execution.mjs')
|
|
6
|
-
: { spawnSync: nativeSpawn };
|
|
7
4
|
import path from 'node:path';
|
|
8
5
|
import process from 'node:process';
|
|
9
6
|
import { fileURLToPath } from 'node:url';
|
|
@@ -69,7 +66,10 @@ function cliArgv(args) {
|
|
|
69
66
|
return [process.execPath, fileURLToPath(import.meta.url), ...args];
|
|
70
67
|
}
|
|
71
68
|
|
|
72
|
-
function runShell(script, cwd, args) {
|
|
69
|
+
async function runShell(script, cwd, args) {
|
|
70
|
+
const spawnSync = process.platform === 'win32'
|
|
71
|
+
? (await import('./windows/execution.mjs')).spawnSync
|
|
72
|
+
: nativeSpawn;
|
|
73
73
|
const captureWindowsSandbox = process.platform === 'win32' && path.basename(script) === 'sandbox_config.sh';
|
|
74
74
|
const result = spawnSync('bash', [script, ...args], {
|
|
75
75
|
cwd,
|
|
@@ -227,14 +227,14 @@ async function dispatch(domain, args) {
|
|
|
227
227
|
if (domain === 'windows-entry') return windowsRouting.runWindowsEntry(args);
|
|
228
228
|
if (process.env.ALIPAY_AIPAY_WINDOWS_ROUTE === 'CODE_ONLY' &&
|
|
229
229
|
(domain.startsWith('onboarding-') || (domain === 'flow' && args[0] !== 'integration') ||
|
|
230
|
-
(args.includes('--root-intent') && args[args.indexOf('--root-intent') + 1]
|
|
230
|
+
(args.includes('--root-intent') && args[args.indexOf('--root-intent') + 1] === 'onboarding_only'))) {
|
|
231
231
|
windowsRouting.requireBusinessEnvironment();
|
|
232
232
|
}
|
|
233
233
|
if (process.env.ALIPAY_AIPAY_WINDOWS_ROUTE === 'BLOCKED' &&
|
|
234
234
|
['integration-bootstrap','onboarding-bootstrap','flow'].includes(domain)) windowsRouting.requireBusinessEnvironment();
|
|
235
235
|
if (['sandbox', 'mcc', 'auth', 'screenshots', 'special-license', 'sign', 'service', 'app',
|
|
236
236
|
'onboarding-discovery', 'onboarding-recovery', 'onboarding-execute-ready'].includes(domain)) {
|
|
237
|
-
windowsRouting.requireBusinessEnvironment();
|
|
237
|
+
windowsRouting.requireBusinessEnvironment({credentials: domain !== 'sandbox'});
|
|
238
238
|
}
|
|
239
239
|
if (domain === 'env' && ['prepare', 'prepare-jq', 'retry'].includes(args[0])) {
|
|
240
240
|
const { runEnvironment } = await import('./windows/prepare.mjs');
|
|
@@ -307,17 +307,14 @@ function removeTransactionPath(target) {
|
|
|
307
307
|
|
|
308
308
|
function reconcileInstallTransaction(skillDir, transactionId, channel) {
|
|
309
309
|
const artifacts = transactionArtifacts(skillDir, transactionId, channel);
|
|
310
|
-
|
|
311
|
-
if (!current && isRecoverableSkillRoot(artifacts.backup)) {
|
|
310
|
+
if (isRecoverableSkillRoot(artifacts.backup)) {
|
|
312
311
|
try {
|
|
313
312
|
removeTransactionPath(skillDir);
|
|
314
313
|
fs.renameSync(artifacts.backup, skillDir);
|
|
315
314
|
} catch {}
|
|
316
|
-
current = readLocalVersion(skillDir);
|
|
317
315
|
}
|
|
318
316
|
removeTransactionPath(artifacts.staging);
|
|
319
|
-
|
|
320
|
-
return current;
|
|
317
|
+
return { version: readLocalVersion(skillDir), backupPresent: fs.existsSync(artifacts.backup) };
|
|
321
318
|
}
|
|
322
319
|
|
|
323
320
|
async function installVersion(skillDir, packageVersion, channel) {
|
|
@@ -351,10 +348,11 @@ async function installVersion(skillDir, packageVersion, channel) {
|
|
|
351
348
|
} catch { /* An invalid receipt never permits a session switch. */ }
|
|
352
349
|
}
|
|
353
350
|
}
|
|
351
|
+
const reconciled = reconcileInstallTransaction(skillDir, transactionId, channel);
|
|
354
352
|
return {
|
|
355
353
|
ok: result.status === 0 && !result.error,
|
|
356
354
|
reason: result.status === 0 && !result.error ? 'ok' : packageManagerFailureKind(result),
|
|
357
|
-
|
|
355
|
+
...reconciled,
|
|
358
356
|
session,
|
|
359
357
|
};
|
|
360
358
|
}
|
|
@@ -395,8 +393,9 @@ export async function runSelfUpdateCli(argv = process.argv) {
|
|
|
395
393
|
if (installed.session && installed.session.version===latest.raw) {
|
|
396
394
|
return {kind:'SESSION_READY',version:latest,skillDir:installed.session.skillDir};
|
|
397
395
|
}
|
|
396
|
+
if (installed.backupPresent) return { kind: 'INSTALL_FAILED' };
|
|
398
397
|
const updated = installed.version || readLocalVersion(skillDir);
|
|
399
|
-
if (updated && readChannel(skillDir) === channel && compareVersions(updated, latest) >= 0) return { kind: 'UPDATED', version: updated };
|
|
398
|
+
if (installed.ok && updated && readChannel(skillDir) === channel && compareVersions(updated, latest) >= 0) return { kind: 'UPDATED', version: updated };
|
|
400
399
|
if (installed.reason === 'network') return { kind: 'RETRY_WITH_NETWORK' };
|
|
401
400
|
if (installed.reason === 'local') return { kind: 'CHECK_FAILED' };
|
|
402
401
|
return { kind: installed.ok ? 'VERIFY_FAILED' : 'INSTALL_FAILED' };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
const
|
|
3
|
-
? (await import('./windows/
|
|
2
|
+
const windowsCheckWritable = process.platform === 'win32'
|
|
3
|
+
? (await import('./windows/host.mjs')).checkWritable
|
|
4
4
|
: null;
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import fs from 'node:fs';
|
|
@@ -368,9 +368,9 @@ export function telemetryStoragePaths(env = process.env) {
|
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
function ensurePrivateDir(dir) {
|
|
371
|
-
if (
|
|
371
|
+
if (windowsCheckWritable) {
|
|
372
372
|
fs.mkdirSync(dir, { recursive: true });
|
|
373
|
-
|
|
373
|
+
windowsCheckWritable(dir);
|
|
374
374
|
return;
|
|
375
375
|
}
|
|
376
376
|
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import {checkWritable} from './host.mjs';
|
|
2
|
+
try { if(process.argv.length!==3)throw new Error('Writable target required');checkWritable(process.argv[2]); }
|
|
3
|
+
catch(e){process.stderr.write('ALIPAY_AIPAY_INTERNAL:WINDOWS_STORAGE_ERROR='+(e.reason||'STORAGE_FAILED')+'\n');process.exitCode=78;}
|
|
@@ -1,34 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {fail, run, powershell, psEnv} from './acl.mjs';
|
|
1
|
+
import {fail} from './host.mjs';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
// or environment override can select the probe. No ExecutionPolicy changes.
|
|
6
|
-
const probe = fs.readFileSync(new URL('./architecture.ps1', import.meta.url), 'utf8');
|
|
7
|
-
export const architectureCommand = `$ErrorActionPreference = 'Stop'\n${probe}\nGet-AipayNativeArchitecture`;
|
|
8
|
-
let nativeArchitecture;
|
|
9
|
-
|
|
10
|
-
function readNativeArchitecture() {
|
|
11
|
-
if (nativeArchitecture) return nativeArchitecture;
|
|
12
|
-
let result;
|
|
13
|
-
try {
|
|
14
|
-
result = run(powershell(), ['-NoProfile', '-NonInteractive', '-Command', architectureCommand],
|
|
15
|
-
{env: psEnv(), timeout: 10000});
|
|
16
|
-
} catch { fail('ARCHITECTURE_CHECK_FAILED', 'system architecture'); }
|
|
17
|
-
const value = result.stdout?.trim();
|
|
18
|
-
if (result.error || result.status !== 0 || !['x64', 'arm64', 'ia32', 'arm', 'ia64'].includes(value)) {
|
|
19
|
-
fail('ARCHITECTURE_CHECK_FAILED', 'system architecture');
|
|
20
|
-
}
|
|
21
|
-
nativeArchitecture = value;
|
|
22
|
-
return value;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function requireNativeX64({platform = process.platform, arch = process.arch,
|
|
26
|
-
readArchitecture = readNativeArchitecture} = {}) {
|
|
3
|
+
export function requireWindowsX64Node({platform = process.platform, arch = process.arch} = {}) {
|
|
27
4
|
if (platform !== 'win32') fail('WINDOWS_ADAPTER_REQUIRES_WINDOWS');
|
|
28
5
|
if (arch !== 'x64') fail('NO_COMPATIBLE_EXECUTION_MAPPING', arch);
|
|
29
|
-
let native;
|
|
30
|
-
try { native = readArchitecture(); }
|
|
31
|
-
catch { fail('ARCHITECTURE_CHECK_FAILED', 'system architecture'); }
|
|
32
|
-
if (!['x64', 'arm64', 'ia32', 'arm', 'ia64'].includes(native)) fail('ARCHITECTURE_CHECK_FAILED', 'system architecture');
|
|
33
|
-
if (native !== 'x64') fail('NO_COMPATIBLE_EXECUTION_MAPPING', native);
|
|
34
6
|
}
|
|
@@ -158,15 +158,13 @@ function Invoke-NodeBootstrap([string]$Action, [string]$Root) {
|
|
|
158
158
|
if ($MyInvocation.InvocationName -ne '.') {
|
|
159
159
|
$ErrorActionPreference = 'Stop'
|
|
160
160
|
try {
|
|
161
|
-
. (Join-Path $PSScriptRoot 'architecture.ps1')
|
|
162
|
-
if ((Get-AipayNativeArchitecture) -ne 'x64') { throw 'UNSUPPORTED_PLATFORM' }
|
|
163
161
|
$localData = $env:LOCALAPPDATA
|
|
164
162
|
if (-not $localData) { $localData = [Environment]::GetFolderPath('LocalApplicationData') }
|
|
165
163
|
if (-not $localData -or -not [IO.Path]::IsPathRooted($localData)) { throw 'STORAGE_FAILED' }
|
|
166
164
|
$result = Invoke-NodeBootstrap $Mode (Join-Path $localData 'alipay-aipay-pre/bootstrap')
|
|
167
165
|
} catch {
|
|
168
166
|
$reason = [string]$_.Exception.Message
|
|
169
|
-
if ($reason -notmatch '^(DOWNLOAD_FAILED|NO_LTS_ASSET|INTEGRITY_FAILED|VERIFY_FAILED|UNSAFE_DIRECTORY|ENVIRONMENT_BUSY|ENVIRONMENT_STATE_INVALID|RETRY_BUDGET_EXHAUSTED|
|
|
167
|
+
if ($reason -notmatch '^(DOWNLOAD_FAILED|NO_LTS_ASSET|INTEGRITY_FAILED|VERIFY_FAILED|UNSAFE_DIRECTORY|ENVIRONMENT_BUSY|ENVIRONMENT_STATE_INVALID|RETRY_BUDGET_EXHAUSTED|STORAGE_FAILED)$') { $reason = 'SETUP_FAILED' }
|
|
170
168
|
$result = @{status='BLOCKED'; reason=$reason}
|
|
171
169
|
}
|
|
172
170
|
[Console]::Error.WriteLine('ALIPAY_AIPAY_INTERNAL:NODE_BOOTSTRAP=' + ($result | ConvertTo-Json -Compress))
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {run, fail} from './
|
|
4
|
-
|
|
3
|
+
import {run, fail} from './host.mjs';
|
|
4
|
+
function managedGitVersion() {
|
|
5
|
+
try { return JSON.parse(fs.readFileSync(new URL('./policy.json',import.meta.url),'utf8')).git.version; }
|
|
6
|
+
catch { return ''; }
|
|
7
|
+
}
|
|
5
8
|
|
|
6
9
|
export function gitCandidates(env = process.env) {
|
|
7
10
|
if (env.ALIPAY_GIT_BASH) return [env.ALIPAY_GIT_BASH];
|
|
11
|
+
const managedVersion = env.LOCALAPPDATA ? managedGitVersion() : '';
|
|
8
12
|
const candidates = [
|
|
9
13
|
path.win32.join(env.ProgramFiles || 'C:/Program Files', 'Git/bin/bash.exe'),
|
|
10
14
|
...(env.LOCALAPPDATA ? [path.win32.join(env.LOCALAPPDATA, 'Programs/Git/bin/bash.exe'),
|
|
11
|
-
path.win32.join(env.LOCALAPPDATA, `Programs/Git-Aipay-${
|
|
15
|
+
...(managedVersion ? [path.win32.join(env.LOCALAPPDATA, `Programs/Git-Aipay-${managedVersion}/bin/bash.exe`)] : [])] : [])
|
|
12
16
|
];
|
|
13
17
|
const search = Object.entries(env).find(([key]) => key.toLowerCase() === 'path')?.[1] || '';
|
|
14
18
|
for (const directory of search.split(';').filter(p => path.win32.isAbsolute(p))) {
|