@voobase/cli 0.1.1-nonprod.2071 → 0.1.1-nonprod.2075

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.
@@ -2451,7 +2451,7 @@ Set-Acl -LiteralPath $credentialPath -AclObject $acl
2451
2451
  <p class="close-hint">\u8BF7\u91CD\u65B0\u5728\u7EC8\u7AEF\u6267\u884C platform login</p>
2452
2452
  </div>
2453
2453
  </body>
2454
- </html>`}function escapeHtml(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function discoverOidcEndpoints(issuer){let discoveryUrl=`${issuer.endsWith("/")?issuer.slice(0,-1):issuer}/.well-known/openid-configuration`,response=await fetch(discoveryUrl);if(!response.ok)throw new Error(`\u83B7\u53D6 OIDC discovery \u5931\u8D25: ${response.status}`);let document=await response.json();if(!document.authorization_endpoint||!document.token_endpoint)throw new Error("OIDC discovery \u7F3A\u5C11\u6388\u6743\u6216 token \u7AEF\u70B9");return{authorization_endpoint:document.authorization_endpoint,device_authorization_endpoint:document.device_authorization_endpoint,token_endpoint:document.token_endpoint}}function getCredentialPath(){return resolveCliStateFilePath("credentials.json")}function getCliContextPath(){return resolveCliStateFilePath("context.json")}function getCliStateDir(){return resolveCliStateDir()}var CliLegacyCredentialStore=class{platform;backend="file";constructor(platform){this.platform=platform}exists(){return existsSync10(getCredentialPath())}read(){return new FileCredentialStore(getCredentialPath(),{platform:this.platform}).read()}write(value){withCliStateFileWriteFallback({fileName:"credentials.json",operation:"\u5199\u5165",write:({filePath})=>new FileCredentialStore(filePath,{platform:this.platform}).write(value)})}delete(){new FileCredentialStore(getCredentialPath(),{platform:this.platform}).delete()}};function resolveCredentialStores(options={}){let stateDir=options.stateDir??getCliStateDir(),platform=options.platform??process.platform,profileName=options.profileName??getDistributionProfile().name,legacyStore=options.legacyStore??(options.stateDir?new FileCredentialStore(join6(stateDir,"credentials.json"),{platform}):new CliLegacyCredentialStore(platform)),hasInjectedStore=Object.prototype.hasOwnProperty.call(options,"secureStore")||Object.prototype.hasOwnProperty.call(options,"legacyStore"),backendPreference=options.backendPreference??(hasInjectedStore?{isFilePreferred:()=>!1,preferFile:()=>{},clear:()=>{}}:new FileCredentialBackendPreference(join6(stateDir,"credential-backend-preference.json")));if(Object.prototype.hasOwnProperty.call(options,"secureStore"))return{secureStore:options.secureStore??null,legacyStore,backendPreference};if(profileName==="developer"||profileName==="test-only")return{secureStore:null,legacyStore,backendPreference};let selectedStore=createCredentialStore({platform,stateDir,profileName});return{secureStore:selectedStore.backend==="file"?null:selectedStore,legacyStore,backendPreference}}function markCredentialOrigin(credentials,backend){return Object.defineProperty(credentials,credentialOriginBackend,{value:backend,enumerable:!1,configurable:!0}),credentials}function getCredentialOrigin(credentials){return credentials[credentialOriginBackend]}function emitCredentialStoreWarnings(warnings,backend){if(warnings.length===0&&backend!=="file"){let report2=inspectCredentialSecurity({credentialsPath:getCredentialPath(),credentialsExist:existsSync10(getCredentialPath()),backend,probeWindowsAcl:!1});emitCredentialSecurityWarnings(report2);return}let report=inspectCredentialSecurity({credentialsPath:getCredentialPath(),credentialsExist:existsSync10(getCredentialPath()),backend,probeWindowsAcl:!1}),existingCodes=new Set(report.findings.map(finding=>finding.code));for(let code2 of warnings){if(existingCodes.has(code2))continue;let detail=credentialStoreWarningDetail(code2);report.findings.push({code:code2,level:code2==="credential_store_corrupted"?"error":"warning",...detail})}report.status=report.findings.some(finding=>finding.level==="error")?"error":report.findings.length>0?"warning":"ok",report.code=report.findings[0]?.code??"credential_security_ok",emitCredentialSecurityWarnings(report)}function credentialStoreWarningDetail(code2){switch(code2){case"credential_migration_pending":return{message:"\u68C0\u6D4B\u5230\u65E7\u7248\u660E\u6587\u51ED\u636E\uFF0C\u5F53\u524D\u767B\u5F55\u6001\u4ECD\u53EF\u7EE7\u7EED\u4F7F\u7528\u3002",action:"\u8FD0\u884C `platform credentials migrate` \u8FC1\u79FB\u5230\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u3002"};case"credential_migration_failed":return{message:"\u51ED\u636E\u5B89\u5168\u8FC1\u79FB\u672A\u5B8C\u6210\uFF0C\u5DF2\u4FDD\u7559\u539F\u6709\u53EF\u7528\u767B\u5F55\u6001\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u72B6\u6001\u540E\u91CD\u8BD5\u8FC1\u79FB\u3002"};case"credential_store_corrupted":return{message:"\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u4E2D\u7684 CLI \u51ED\u636E\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u5DF2\u5C1D\u8BD5\u517C\u5BB9\u51ED\u636E\u3002",action:"\u5982\u65E0\u517C\u5BB9\u51ED\u636E\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`\u3002"};default:return{message:"\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u5F53\u524D\u4E0D\u53EF\u7528\uFF0C\u5DF2\u4F7F\u7528\u517C\u5BB9\u6587\u4EF6\u4E14\u672C\u6B21\u547D\u4EE4\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u72B6\u6001\u5E76\u5728\u6062\u590D\u540E\u91CD\u8BD5\u8FC1\u79FB\u3002"}}}function loadStoredCredentials(storageOptions={}){let stores=resolveCredentialStores(storageOptions),result=readCredentialsWithFallback(stores);return emitCredentialStoreWarnings(result.warnings,result.backend),result.credentials&&result.backend!=="none"?markCredentialOrigin(result.credentials,result.backend):null}function selectApiToken(credentials){return looksLikeJwt(credentials.access_token)?credentials.access_token:looksLikeJwt(credentials.id_token)?credentials.id_token:credentials.access_token}function loadStoredCliContext(){let cliContextPath=getCliContextPath();return existsSync10(cliContextPath)?JSON.parse(readFileSync9(cliContextPath,"utf8")):null}function persistCredentials(credentials,storageOptions={}){let stores=resolveCredentialStores(storageOptions),result=writeCredentialsWithFallback(credentials,stores);return markCredentialOrigin(credentials,result.backend),emitCredentialStoreWarnings(result.warnings,result.backend),result}function migrateStoredCredentials(storageOptions={}){let stores=resolveCredentialStores(storageOptions),result=migrateLegacyCredentials(stores);return emitCredentialStoreWarnings(result.warnings,result.backend),result}function inspectStoredCredentialSecurity(storageOptions={}){let stores=resolveCredentialStores(storageOptions),credentialsPath=getCredentialPath(),legacyExists=stores.legacyStore.exists?.()??existsSync10(credentialsPath),backend=legacyExists?"file":"none",secureWarning=null;if(stores.secureStore?.exists)try{stores.secureStore.exists()&&(backend=stores.secureStore.backend)}catch(error){secureWarning=error instanceof Error&&"code"in error&&error.code==="credential_store_corrupted"?"credential_store_corrupted":"credential_secure_store_unavailable"}let report=inspectCredentialSecurity({credentialsPath,credentialsExist:legacyExists,backend});return secureWarning&&!report.findings.some(finding=>finding.code===secureWarning)&&(report.findings.push({code:secureWarning,level:secureWarning==="credential_store_corrupted"?"error":"warning",...credentialStoreWarningDetail(secureWarning)}),report.status=secureWarning==="credential_store_corrupted"?"error":"warning",report.code=report.findings[0]?.code??secureWarning),report}function clearStoredAuthentication(storageOptions={}){let stateDir=storageOptions.stateDir??getCliStateDir(),stores=resolveCredentialStores({...storageOptions,stateDir}),cleared=[],failed=[],attempt=(target,operation)=>{try{operation(),cleared.push(target)}catch{failed.push({target})}};stores.secureStore&&attempt(stores.secureStore.backend,()=>stores.secureStore.delete()),attempt("legacy_file",()=>stores.legacyStore.delete()),attempt("account_context",()=>deleteFileIfPresent(join6(stateDir,"context.json"))),attempt("warning_state",()=>deleteFileIfPresent(join6(stateDir,"credential-warning-state.json"))),attempt("backend_preference",()=>deleteFileIfPresent(join6(stateDir,"credential-backend-preference.json")));try{let temporaryFailures=deleteCredentialTemporaryFiles(stateDir,storageOptions.temporaryFileDeleter??deleteFileIfPresent);temporaryFailures.length===0&&cleared.push("orphan_temporary_files"),failed.push(...temporaryFailures.map(name=>({target:`orphan_temporary_file:${name}`})))}catch{failed.push({target:"orphan_temporary_files"})}return{status:failed.length>0?"partial":"cleared",cleared,failed}}function deleteFileIfPresent(filePath){try{unlinkSync4(filePath)}catch(error){if(error.code!=="ENOENT")throw error}}function deleteCredentialTemporaryFiles(stateDir,deleter){let entries;try{entries=readdirSync2(stateDir,{withFileTypes:!0,encoding:"utf8"})}catch(error){if(error.code==="ENOENT")return[];throw error}let failed=[];for(let entry of entries)if(!(!entry.isFile()||!/^(?:credentials\.json|credentials\.dpapi|credential-warning-state\.json|credential-backend-preference\.json)\.tmp-[a-z0-9-]+$/iu.test(entry.name)))try{deleter(join6(stateDir,entry.name))}catch{failed.push(entry.name)}return failed}function persistRefreshedCredentials(nextCredentials,previousCredentials,storageOptions){let stores=resolveCredentialStores(storageOptions);if(getCredentialOrigin(previousCredentials)==="file"){stores.legacyStore.write(toFileFallbackCredentials(nextCredentials)),markCredentialOrigin(nextCredentials,"file");let result={backend:"file",warnings:[],legacyDeleted:!1};return emitCredentialStoreWarnings(result.warnings,result.backend),result}return persistCredentials(nextCredentials,{...storageOptions,...stores})}function resolveStoredClientId(credentials){return credentials.client_id?.trim()||readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS)||readAuthConfigValue(AUTH_TENANT_CLIENT_ID_KEYS)}function readJwtExpiryMs(token){if(!looksLikeJwt(token))return null;try{let[,payload]=token.split("."),decoded=JSON.parse(Buffer.from(payload,"base64url").toString("utf8"));return typeof decoded.exp=="number"&&Number.isFinite(decoded.exp)?decoded.exp*1e3:null}catch{return null}}function isCredentialExpired(credentials,now=Date.now()){if(typeof credentials.expires_in=="number"&&Number.isFinite(credentials.expires_in)){let issuedAt=Date.parse(credentials.issued_at);if(Number.isFinite(issuedAt))return issuedAt+credentials.expires_in*1e3-TOKEN_REFRESH_SKEW_MS<=now}let jwtExpiry=readJwtExpiryMs(credentials.access_token)??readJwtExpiryMs(credentials.id_token);return typeof jwtExpiry=="number"?jwtExpiry-TOKEN_REFRESH_SKEW_MS<=now:!1}function canUsePatExchange(credentials,now=Date.now()){if(credentials.credential_mode!=="pat_exchange"||!credentials.exchange_subject_token||!credentials.exchange_subject_token_type||!resolveStoredClientId(credentials)||!credentials.mode_expires_at)return!1;let expiresAt=Date.parse(credentials.mode_expires_at);return Number.isFinite(expiresAt)&&expiresAt>now}async function refreshCredentials(credentials,storageOptions){let issuer=process.env.OIDC_ISSUER?.trim()||getDistributionProfile().defaults?.OIDC_ISSUER?.trim();if(!issuer)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11 OIDC_ISSUER\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 CLI \u51ED\u636E\u3002");let clientId=resolveStoredClientId(credentials);if(!clientId)throw new Error("\u5F53\u524D\u51ED\u636E\u7F3A\u5C11 client_id\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 CLI \u51ED\u636E\u3002");if(!credentials.refresh_token)throw new Error("\u5F53\u524D\u51ED\u636E\u7F3A\u5C11 refresh_token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`\u3002");let endpoints=await discoverOidcEndpoints(issuer),body=new URLSearchParams;body.set("grant_type","refresh_token"),body.set("client_id",clientId),body.set("refresh_token",credentials.refresh_token),applyResource(body,process.env.OIDC_AUDIENCE?.trim()||getDistributionProfile().defaults?.OIDC_AUDIENCE?.trim());let response=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),payload=await response.json();if(!response.ok)throw mapTokenFailureToAuthError({error:payload.error,errorDescription:payload.error_description,fallback:"\u5237\u65B0 CLI token \u5931\u8D25"});if(typeof payload.access_token!="string"||payload.access_token.length===0)throw new Error("\u5237\u65B0\u540E\u7684 token \u54CD\u5E94\u7F3A\u5C11 access_token");let nextCredentials={access_token:payload.access_token,id_token:typeof payload.id_token=="string"?payload.id_token:credentials.id_token,refresh_token:typeof payload.refresh_token=="string"?payload.refresh_token:credentials.refresh_token,client_id:clientId,token_type:payload.token_type??credentials.token_type,expires_in:typeof payload.expires_in=="number"?payload.expires_in:credentials.expires_in,scope:payload.scope??credentials.scope,issued_at:new Date().toISOString(),credential_mode:credentials.credential_mode??"interactive",exchange_subject_token:credentials.exchange_subject_token,exchange_subject_token_type:credentials.exchange_subject_token_type,mode_expires_at:credentials.mode_expires_at};return persistRefreshedCredentials(nextCredentials,credentials,storageOptions),nextCredentials}async function exchangePatCredentials(credentials,storageOptions){let issuer=process.env.OIDC_ISSUER?.trim()||getDistributionProfile().defaults?.OIDC_ISSUER?.trim();if(!issuer)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11 OIDC_ISSUER\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 PAT \u51ED\u636E\u3002");let clientId=resolveStoredClientId(credentials);if(!clientId)throw new Error("\u5F53\u524D PAT \u51ED\u636E\u7F3A\u5C11 client_id\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0\u3002");if(!credentials.exchange_subject_token||!credentials.exchange_subject_token_type)throw new Error("\u5F53\u524D PAT \u51ED\u636E\u7F3A\u5C11 subject_token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login --pat <token>`\u3002");if(credentials.mode_expires_at){let hardExpiry=Date.parse(credentials.mode_expires_at);if(Number.isFinite(hardExpiry)&&hardExpiry<=Date.now())throw new Error("\u5F53\u524D PAT \u767B\u5F55\u5DF2\u8D85\u8FC7 7 \u5929\u6709\u6548\u671F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login --pat <token>`\u3002")}let endpoints=await discoverOidcEndpoints(issuer),body=new URLSearchParams;body.set("grant_type","urn:ietf:params:oauth:grant-type:token-exchange"),body.set("client_id",clientId),body.set("subject_token",credentials.exchange_subject_token),body.set("subject_token_type",credentials.exchange_subject_token_type),body.set("requested_token_type","urn:ietf:params:oauth:token-type:access_token"),credentials.scope?.trim()&&body.set("scope",credentials.scope.trim()),applyResource(body,process.env.OIDC_AUDIENCE?.trim()||getDistributionProfile().defaults?.OIDC_AUDIENCE?.trim());let response=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),payload=await response.json();if(!response.ok)throw mapTokenFailureToAuthError({error:payload.error,errorDescription:payload.error_description,fallback:"PAT \u4EA4\u6362 access token \u5931\u8D25"});if(typeof payload.access_token!="string"||payload.access_token.length===0)throw new Error("PAT \u4EA4\u6362\u540E\u7684 token \u54CD\u5E94\u7F3A\u5C11 access_token");let nextCredentials={access_token:payload.access_token,id_token:typeof payload.id_token=="string"?payload.id_token:credentials.id_token,client_id:clientId,token_type:payload.token_type??credentials.token_type,expires_in:typeof payload.expires_in=="number"?payload.expires_in:credentials.expires_in,scope:payload.scope??credentials.scope,issued_at:new Date().toISOString(),credential_mode:"pat_exchange",exchange_subject_token:credentials.exchange_subject_token,exchange_subject_token_type:credentials.exchange_subject_token_type,mode_expires_at:credentials.mode_expires_at};return persistRefreshedCredentials(nextCredentials,credentials,storageOptions),nextCredentials}async function loadStoredCredentialsEnsuringFresh(options={}){let storageOptions=options.storage??{},credentials=loadStoredCredentials(storageOptions);if(!credentials)return null;let expired=isCredentialExpired(credentials);if(!options.forceRefresh&&!expired)return credentials;if(credentials.refresh_token)try{return refreshCredentials(credentials,storageOptions)}catch(error){maybeWrapCredentialRefreshError(error)}if(canUsePatExchange(credentials))try{return exchangePatCredentials(credentials,storageOptions)}catch(error){maybeWrapCredentialRefreshError(error)}if(expired)throw new Error("\u5F53\u524D\u51ED\u636E\u5DF2\u8FC7\u671F\u4E14\u4E0D\u652F\u6301\u81EA\u52A8\u5237\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login` \u6216 `platform login --pat <token>`\u3002");return credentials}function persistCliContext(context){withCliStateFileWriteFallback({fileName:"context.json",operation:"\u5199\u5165",write:({filePath,stateDir})=>{mkdirSync5(stateDir,{recursive:!0}),writeFileSync5(filePath,`${JSON.stringify({...context,updated_at:new Date().toISOString()},null,2)}
2454
+ </html>`}function escapeHtml(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function discoverOidcEndpoints(issuer){let discoveryUrl=`${issuer.endsWith("/")?issuer.slice(0,-1):issuer}/.well-known/openid-configuration`,response=await fetch(discoveryUrl);if(!response.ok)throw new Error(`\u83B7\u53D6 OIDC discovery \u5931\u8D25: ${response.status}`);let document=await response.json();if(!document.authorization_endpoint||!document.token_endpoint)throw new Error("OIDC discovery \u7F3A\u5C11\u6388\u6743\u6216 token \u7AEF\u70B9");return{authorization_endpoint:document.authorization_endpoint,device_authorization_endpoint:document.device_authorization_endpoint,token_endpoint:document.token_endpoint}}function getCredentialPath(){return resolveCliStateFilePath("credentials.json")}function getCliContextPath(){return resolveCliStateFilePath("context.json")}function getCliStateDir(){return resolveCliStateDir()}var CliLegacyCredentialStore=class{platform;backend="file";constructor(platform){this.platform=platform}exists(){return existsSync10(getCredentialPath())}read(){return new FileCredentialStore(getCredentialPath(),{platform:this.platform}).read()}write(value){withCliStateFileWriteFallback({fileName:"credentials.json",operation:"\u5199\u5165",write:({filePath})=>new FileCredentialStore(filePath,{platform:this.platform}).write(value)})}delete(){new FileCredentialStore(getCredentialPath(),{platform:this.platform}).delete()}};function resolveCredentialStores(options={}){let stateDir=options.stateDir??getCliStateDir(),platform=options.platform??process.platform,profileName=options.profileName??getDistributionProfile().name,legacyStore=options.legacyStore??(options.stateDir?new FileCredentialStore(join6(stateDir,"credentials.json"),{platform}):new CliLegacyCredentialStore(platform)),hasInjectedStore=Object.prototype.hasOwnProperty.call(options,"secureStore")||Object.prototype.hasOwnProperty.call(options,"legacyStore"),backendPreference=options.backendPreference??(hasInjectedStore?{isFilePreferred:()=>!1,preferFile:()=>{},clear:()=>{}}:new FileCredentialBackendPreference(join6(stateDir,"credential-backend-preference.json")));if(Object.prototype.hasOwnProperty.call(options,"secureStore"))return{secureStore:options.secureStore??null,legacyStore,backendPreference};if(profileName==="developer"||profileName==="test-only")return{secureStore:null,legacyStore,backendPreference};let selectedStore=createCredentialStore({platform,stateDir,profileName});return{secureStore:selectedStore.backend==="file"?null:selectedStore,legacyStore,backendPreference}}function markCredentialOrigin(credentials,backend){return Object.defineProperty(credentials,credentialOriginBackend,{value:backend,enumerable:!1,configurable:!0}),credentials}function getCredentialOrigin(credentials){return credentials[credentialOriginBackend]}function emitCredentialStoreWarnings(warnings,backend){if(warnings.length===0&&backend!=="file"){let report2=inspectCredentialSecurity({credentialsPath:getCredentialPath(),credentialsExist:existsSync10(getCredentialPath()),backend,probeWindowsAcl:!1});emitCredentialSecurityWarnings(report2);return}let report=inspectCredentialSecurity({credentialsPath:getCredentialPath(),credentialsExist:existsSync10(getCredentialPath()),backend,probeWindowsAcl:!1}),existingCodes=new Set(report.findings.map(finding=>finding.code));for(let code2 of warnings){if(existingCodes.has(code2))continue;let detail=credentialStoreWarningDetail(code2);report.findings.push({code:code2,level:code2==="credential_store_corrupted"?"error":"warning",...detail})}report.status=report.findings.some(finding=>finding.level==="error")?"error":report.findings.length>0?"warning":"ok",report.code=report.findings[0]?.code??"credential_security_ok",emitCredentialSecurityWarnings(report)}function credentialStoreWarningDetail(code2){switch(code2){case"credential_migration_pending":return{message:"\u68C0\u6D4B\u5230\u65E7\u7248\u660E\u6587\u51ED\u636E\uFF0C\u5F53\u524D\u767B\u5F55\u6001\u4ECD\u53EF\u7EE7\u7EED\u4F7F\u7528\u3002",action:"\u8FD0\u884C `platform credentials migrate` \u5B8C\u6210\u5F53\u524D\u5E73\u53F0\u7684\u51ED\u636E\u8FC1\u79FB\u6216\u654F\u611F\u5B57\u6BB5\u51C0\u5316\u3002"};case"credential_migration_failed":return{message:"\u51ED\u636E\u5B89\u5168\u8FC1\u79FB\u672A\u5B8C\u6210\uFF0C\u5DF2\u4FDD\u7559\u539F\u6709\u53EF\u7528\u767B\u5F55\u6001\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u72B6\u6001\u540E\u91CD\u8BD5\u8FC1\u79FB\u3002"};case"credential_store_corrupted":return{message:"\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u4E2D\u7684 CLI \u51ED\u636E\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u5DF2\u5C1D\u8BD5\u517C\u5BB9\u51ED\u636E\u3002",action:"\u5982\u65E0\u517C\u5BB9\u51ED\u636E\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`\u3002"};default:return{message:"\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u5F53\u524D\u4E0D\u53EF\u7528\uFF0C\u5DF2\u4F7F\u7528\u517C\u5BB9\u6587\u4EF6\u4E14\u672C\u6B21\u547D\u4EE4\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u72B6\u6001\u5E76\u5728\u6062\u590D\u540E\u91CD\u8BD5\u8FC1\u79FB\u3002"}}}function loadStoredCredentials(storageOptions={}){let stores=resolveCredentialStores(storageOptions),result=readCredentialsWithFallback(stores);return emitCredentialStoreWarnings(result.warnings,result.backend),result.credentials&&result.backend!=="none"?markCredentialOrigin(result.credentials,result.backend):null}function selectApiToken(credentials){return looksLikeJwt(credentials.access_token)?credentials.access_token:looksLikeJwt(credentials.id_token)?credentials.id_token:credentials.access_token}function loadStoredCliContext(){let cliContextPath=getCliContextPath();return existsSync10(cliContextPath)?JSON.parse(readFileSync9(cliContextPath,"utf8")):null}function persistCredentials(credentials,storageOptions={}){let stores=resolveCredentialStores(storageOptions),result=writeCredentialsWithFallback(credentials,stores);return markCredentialOrigin(credentials,result.backend),emitCredentialStoreWarnings(result.warnings,result.backend),result}function migrateStoredCredentials(storageOptions={}){let stores=resolveCredentialStores(storageOptions),result=migrateLegacyCredentials(stores);return emitCredentialStoreWarnings(result.warnings,result.backend),result}function inspectStoredCredentialSecurity(storageOptions={}){let stores=resolveCredentialStores(storageOptions),credentialsPath=getCredentialPath(),legacyExists=stores.legacyStore.exists?.()??existsSync10(credentialsPath),backend=legacyExists?"file":"none",secureWarning=null;if(stores.secureStore?.exists)try{stores.secureStore.exists()&&(backend=stores.secureStore.backend)}catch(error){secureWarning=error instanceof Error&&"code"in error&&error.code==="credential_store_corrupted"?"credential_store_corrupted":"credential_secure_store_unavailable"}let report=inspectCredentialSecurity({credentialsPath,credentialsExist:legacyExists,backend});return secureWarning&&!report.findings.some(finding=>finding.code===secureWarning)&&(report.findings.push({code:secureWarning,level:secureWarning==="credential_store_corrupted"?"error":"warning",...credentialStoreWarningDetail(secureWarning)}),report.status=secureWarning==="credential_store_corrupted"?"error":"warning",report.code=report.findings[0]?.code??secureWarning),report}function clearStoredAuthentication(storageOptions={}){let stateDir=storageOptions.stateDir??getCliStateDir(),stores=resolveCredentialStores({...storageOptions,stateDir}),cleared=[],failed=[],attempt=(target,operation)=>{try{operation(),cleared.push(target)}catch{failed.push({target})}};stores.secureStore&&attempt(stores.secureStore.backend,()=>stores.secureStore.delete()),attempt("legacy_file",()=>stores.legacyStore.delete()),attempt("account_context",()=>deleteFileIfPresent(join6(stateDir,"context.json"))),attempt("warning_state",()=>deleteFileIfPresent(join6(stateDir,"credential-warning-state.json"))),attempt("backend_preference",()=>deleteFileIfPresent(join6(stateDir,"credential-backend-preference.json")));try{let temporaryFailures=deleteCredentialTemporaryFiles(stateDir,storageOptions.temporaryFileDeleter??deleteFileIfPresent);temporaryFailures.length===0&&cleared.push("orphan_temporary_files"),failed.push(...temporaryFailures.map(name=>({target:`orphan_temporary_file:${name}`})))}catch{failed.push({target:"orphan_temporary_files"})}return{status:failed.length>0?"partial":"cleared",cleared,failed}}function deleteFileIfPresent(filePath){try{unlinkSync4(filePath)}catch(error){if(error.code!=="ENOENT")throw error}}function deleteCredentialTemporaryFiles(stateDir,deleter){let entries;try{entries=readdirSync2(stateDir,{withFileTypes:!0,encoding:"utf8"})}catch(error){if(error.code==="ENOENT")return[];throw error}let failed=[];for(let entry of entries)if(!(!entry.isFile()||!/^(?:credentials\.json|credentials\.dpapi|credential-warning-state\.json|credential-backend-preference\.json)\.tmp-[a-z0-9-]+$/iu.test(entry.name)))try{deleter(join6(stateDir,entry.name))}catch{failed.push(entry.name)}return failed}function persistRefreshedCredentials(nextCredentials,previousCredentials,storageOptions){let stores=resolveCredentialStores(storageOptions);if(getCredentialOrigin(previousCredentials)==="file"){stores.legacyStore.write(toFileFallbackCredentials(nextCredentials)),markCredentialOrigin(nextCredentials,"file");let result={backend:"file",warnings:[],legacyDeleted:!1};return emitCredentialStoreWarnings(result.warnings,result.backend),result}return persistCredentials(nextCredentials,{...storageOptions,...stores})}function resolveStoredClientId(credentials){return credentials.client_id?.trim()||readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS)||readAuthConfigValue(AUTH_TENANT_CLIENT_ID_KEYS)}function readJwtExpiryMs(token){if(!looksLikeJwt(token))return null;try{let[,payload]=token.split("."),decoded=JSON.parse(Buffer.from(payload,"base64url").toString("utf8"));return typeof decoded.exp=="number"&&Number.isFinite(decoded.exp)?decoded.exp*1e3:null}catch{return null}}function isCredentialExpired(credentials,now=Date.now()){if(typeof credentials.expires_in=="number"&&Number.isFinite(credentials.expires_in)){let issuedAt=Date.parse(credentials.issued_at);if(Number.isFinite(issuedAt))return issuedAt+credentials.expires_in*1e3-TOKEN_REFRESH_SKEW_MS<=now}let jwtExpiry=readJwtExpiryMs(credentials.access_token)??readJwtExpiryMs(credentials.id_token);return typeof jwtExpiry=="number"?jwtExpiry-TOKEN_REFRESH_SKEW_MS<=now:!1}function canUsePatExchange(credentials,now=Date.now()){if(credentials.credential_mode!=="pat_exchange"||!credentials.exchange_subject_token||!credentials.exchange_subject_token_type||!resolveStoredClientId(credentials)||!credentials.mode_expires_at)return!1;let expiresAt=Date.parse(credentials.mode_expires_at);return Number.isFinite(expiresAt)&&expiresAt>now}async function refreshCredentials(credentials,storageOptions){let issuer=process.env.OIDC_ISSUER?.trim()||getDistributionProfile().defaults?.OIDC_ISSUER?.trim();if(!issuer)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11 OIDC_ISSUER\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 CLI \u51ED\u636E\u3002");let clientId=resolveStoredClientId(credentials);if(!clientId)throw new Error("\u5F53\u524D\u51ED\u636E\u7F3A\u5C11 client_id\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 CLI \u51ED\u636E\u3002");if(!credentials.refresh_token)throw new Error("\u5F53\u524D\u51ED\u636E\u7F3A\u5C11 refresh_token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`\u3002");let endpoints=await discoverOidcEndpoints(issuer),body=new URLSearchParams;body.set("grant_type","refresh_token"),body.set("client_id",clientId),body.set("refresh_token",credentials.refresh_token),applyResource(body,process.env.OIDC_AUDIENCE?.trim()||getDistributionProfile().defaults?.OIDC_AUDIENCE?.trim());let response=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),payload=await response.json();if(!response.ok)throw mapTokenFailureToAuthError({error:payload.error,errorDescription:payload.error_description,fallback:"\u5237\u65B0 CLI token \u5931\u8D25"});if(typeof payload.access_token!="string"||payload.access_token.length===0)throw new Error("\u5237\u65B0\u540E\u7684 token \u54CD\u5E94\u7F3A\u5C11 access_token");let nextCredentials={access_token:payload.access_token,id_token:typeof payload.id_token=="string"?payload.id_token:credentials.id_token,refresh_token:typeof payload.refresh_token=="string"?payload.refresh_token:credentials.refresh_token,client_id:clientId,token_type:payload.token_type??credentials.token_type,expires_in:typeof payload.expires_in=="number"?payload.expires_in:credentials.expires_in,scope:payload.scope??credentials.scope,issued_at:new Date().toISOString(),credential_mode:credentials.credential_mode??"interactive",exchange_subject_token:credentials.exchange_subject_token,exchange_subject_token_type:credentials.exchange_subject_token_type,mode_expires_at:credentials.mode_expires_at};return persistRefreshedCredentials(nextCredentials,credentials,storageOptions),nextCredentials}async function exchangePatCredentials(credentials,storageOptions){let issuer=process.env.OIDC_ISSUER?.trim()||getDistributionProfile().defaults?.OIDC_ISSUER?.trim();if(!issuer)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11 OIDC_ISSUER\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 PAT \u51ED\u636E\u3002");let clientId=resolveStoredClientId(credentials);if(!clientId)throw new Error("\u5F53\u524D PAT \u51ED\u636E\u7F3A\u5C11 client_id\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0\u3002");if(!credentials.exchange_subject_token||!credentials.exchange_subject_token_type)throw new Error("\u5F53\u524D PAT \u51ED\u636E\u7F3A\u5C11 subject_token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login --pat <token>`\u3002");if(credentials.mode_expires_at){let hardExpiry=Date.parse(credentials.mode_expires_at);if(Number.isFinite(hardExpiry)&&hardExpiry<=Date.now())throw new Error("\u5F53\u524D PAT \u767B\u5F55\u5DF2\u8D85\u8FC7 7 \u5929\u6709\u6548\u671F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login --pat <token>`\u3002")}let endpoints=await discoverOidcEndpoints(issuer),body=new URLSearchParams;body.set("grant_type","urn:ietf:params:oauth:grant-type:token-exchange"),body.set("client_id",clientId),body.set("subject_token",credentials.exchange_subject_token),body.set("subject_token_type",credentials.exchange_subject_token_type),body.set("requested_token_type","urn:ietf:params:oauth:token-type:access_token"),credentials.scope?.trim()&&body.set("scope",credentials.scope.trim()),applyResource(body,process.env.OIDC_AUDIENCE?.trim()||getDistributionProfile().defaults?.OIDC_AUDIENCE?.trim());let response=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),payload=await response.json();if(!response.ok)throw mapTokenFailureToAuthError({error:payload.error,errorDescription:payload.error_description,fallback:"PAT \u4EA4\u6362 access token \u5931\u8D25"});if(typeof payload.access_token!="string"||payload.access_token.length===0)throw new Error("PAT \u4EA4\u6362\u540E\u7684 token \u54CD\u5E94\u7F3A\u5C11 access_token");let nextCredentials={access_token:payload.access_token,id_token:typeof payload.id_token=="string"?payload.id_token:credentials.id_token,client_id:clientId,token_type:payload.token_type??credentials.token_type,expires_in:typeof payload.expires_in=="number"?payload.expires_in:credentials.expires_in,scope:payload.scope??credentials.scope,issued_at:new Date().toISOString(),credential_mode:"pat_exchange",exchange_subject_token:credentials.exchange_subject_token,exchange_subject_token_type:credentials.exchange_subject_token_type,mode_expires_at:credentials.mode_expires_at};return persistRefreshedCredentials(nextCredentials,credentials,storageOptions),nextCredentials}async function loadStoredCredentialsEnsuringFresh(options={}){let storageOptions=options.storage??{},credentials=loadStoredCredentials(storageOptions);if(!credentials)return null;let expired=isCredentialExpired(credentials);if(!options.forceRefresh&&!expired)return credentials;if(credentials.refresh_token)try{return refreshCredentials(credentials,storageOptions)}catch(error){maybeWrapCredentialRefreshError(error)}if(canUsePatExchange(credentials))try{return exchangePatCredentials(credentials,storageOptions)}catch(error){maybeWrapCredentialRefreshError(error)}if(expired)throw new Error("\u5F53\u524D\u51ED\u636E\u5DF2\u8FC7\u671F\u4E14\u4E0D\u652F\u6301\u81EA\u52A8\u5237\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login` \u6216 `platform login --pat <token>`\u3002");return credentials}function persistCliContext(context){withCliStateFileWriteFallback({fileName:"context.json",operation:"\u5199\u5165",write:({filePath,stateDir})=>{mkdirSync5(stateDir,{recursive:!0}),writeFileSync5(filePath,`${JSON.stringify({...context,updated_at:new Date().toISOString()},null,2)}
2455
2455
  `,"utf8"),chmodSync3(filePath,384)}})}async function performDeviceCodeLogin(config2){let endpoints=await discoverOidcEndpoints(config2.issuer);if(!endpoints.device_authorization_endpoint)throw new Error("OIDC discovery \u7F3A\u5C11 Device Flow \u7AEF\u70B9");let authBody=new URLSearchParams;authBody.set("client_id",config2.clientId),authBody.set("scope",config2.scopes.join(" ")),applyResource(authBody,config2.audience);let deviceResponse=await fetch(endpoints.device_authorization_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:authBody}),devicePayload=await deviceResponse.json();if(!deviceResponse.ok)throw new Error(devicePayload.error_description??devicePayload.error??"\u7533\u8BF7 device_code \u5931\u8D25");await config2.onPrompt?.({verificationUri:devicePayload.verification_uri_complete??devicePayload.verification_uri??config2.issuer,userCode:devicePayload.user_code,expiresIn:devicePayload.expires_in});let intervalSeconds=Math.max(devicePayload.interval??5,1),deadline=Date.now()+devicePayload.expires_in*1e3;for(;Date.now()<deadline;){await sleep(intervalSeconds*1e3);let tokenBody=new URLSearchParams;tokenBody.set("grant_type","urn:ietf:params:oauth:grant-type:device_code"),tokenBody.set("device_code",devicePayload.device_code),tokenBody.set("client_id",config2.clientId);let tokenResponse=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:tokenBody}),tokenPayload=await tokenResponse.json();if(tokenResponse.ok)return{access_token:tokenPayload.access_token,id_token:tokenPayload.id_token,refresh_token:tokenPayload.refresh_token,client_id:config2.clientId,token_type:tokenPayload.token_type,expires_in:tokenPayload.expires_in,scope:tokenPayload.scope,issued_at:new Date().toISOString(),verificationUri:devicePayload.verification_uri_complete??devicePayload.verification_uri??config2.issuer,userCode:devicePayload.user_code};if(tokenPayload.error!=="authorization_pending"){if(tokenPayload.error==="slow_down"){await sleep(intervalSeconds*1e3);continue}throw new Error(tokenPayload.error_description??tokenPayload.error??"\u8F6E\u8BE2 token \u5931\u8D25")}}throw new Error("Device Code \u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`")}async function performAuthorizationCodeLogin(config2){let endpoints=await discoverOidcEndpoints(config2.issuer),redirectUrl=new URL(config2.redirectUri);if(redirectUrl.protocol!=="http:")throw new Error("CLI \u6D4F\u89C8\u5668\u6388\u6743\u4EC5\u652F\u6301 http \u56DE\u8C03\u5730\u5740");let state=randomBytes3(16).toString("base64url"),nonce=randomBytes3(16).toString("base64url"),codeVerifier=randomBytes3(32).toString("base64url"),codeChallenge=createHash5("sha256").update(codeVerifier).digest("base64url"),authorizationUrl=new URL(endpoints.authorization_endpoint);authorizationUrl.searchParams.set("client_id",config2.clientId),authorizationUrl.searchParams.set("redirect_uri",config2.redirectUri),authorizationUrl.searchParams.set("response_type","code"),authorizationUrl.searchParams.set("scope",config2.scopes.join(" ")),authorizationUrl.searchParams.set("state",state),authorizationUrl.searchParams.set("nonce",nonce),authorizationUrl.searchParams.set("code_challenge",codeChallenge),authorizationUrl.searchParams.set("code_challenge_method","S256");let normalizedPrompt=normalizeAuthorizationPrompt(config2.scopes,config2.prompt);normalizedPrompt&&authorizationUrl.searchParams.set("prompt",normalizedPrompt),applyResource(authorizationUrl.searchParams,config2.audience);let callbackResult=await new Promise((resolve20,reject)=>{let timeout=setTimeout(()=>{server.close(()=>{}),reject(new Error("\u6D4F\u89C8\u5668\u6388\u6743\u8D85\u65F6\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`"))},3e5),server=createServer((req,res)=>{let url=new URL(req.url??"/",config2.redirectUri);if(url.pathname!==redirectUrl.pathname){res.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),res.end("Not Found");return}let returnedState=url.searchParams.get("state"),error=url.searchParams.get("error"),code2=url.searchParams.get("code");if(error){clearTimeout(timeout);let errMsg=url.searchParams.get("error_description")??error;res.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),res.end(getLoginFailureHtml(errMsg)),server.close(()=>{}),reject(new Error(errMsg));return}if(!code2||returnedState!==state){clearTimeout(timeout),res.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),res.end(getLoginFailureHtml("\u6D4F\u89C8\u5668\u56DE\u8C03\u7F3A\u5C11\u6388\u6743\u7801\u6216 state \u4E0D\u5339\u914D\u3002")),server.close(()=>{}),reject(new Error("\u6D4F\u89C8\u5668\u56DE\u8C03\u7F3A\u5C11 code \u6216 state \u4E0D\u5339\u914D"));return}clearTimeout(timeout),res.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),res.end(getLoginSuccessHtml()),server.close(()=>{}),resolve20({code:code2})});server.on("error",error=>{clearTimeout(timeout),reject(error)}),server.listen(Number(redirectUrl.port||80),redirectUrl.hostname,async()=>{try{await config2.onPrompt?.({authorizationUrl:authorizationUrl.toString(),redirectUri:config2.redirectUri})}catch(error){clearTimeout(timeout),server.close(()=>{}),reject(error)}})}),tokenBody=new URLSearchParams;tokenBody.set("grant_type","authorization_code"),tokenBody.set("client_id",config2.clientId),tokenBody.set("code",callbackResult.code),tokenBody.set("redirect_uri",config2.redirectUri),tokenBody.set("code_verifier",codeVerifier),applyResource(tokenBody,config2.audience);let tokenResponse=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:tokenBody}),tokenPayload=await tokenResponse.json();if(!tokenResponse.ok)throw new Error(tokenPayload.error_description??tokenPayload.error??"\u6388\u6743\u7801\u6362\u53D6 token \u5931\u8D25");return{access_token:tokenPayload.access_token,id_token:tokenPayload.id_token,refresh_token:tokenPayload.refresh_token,client_id:config2.clientId,token_type:tokenPayload.token_type,expires_in:tokenPayload.expires_in,scope:tokenPayload.scope,issued_at:new Date().toISOString(),authorizationUrl:authorizationUrl.toString(),redirectUri:config2.redirectUri}}async function performPatTokenExchangeLogin(config2){let endpoints=await discoverOidcEndpoints(config2.issuer),body=new URLSearchParams;body.set("grant_type","urn:ietf:params:oauth:grant-type:token-exchange"),body.set("client_id",config2.clientId),body.set("subject_token",config2.subjectToken),body.set("subject_token_type",config2.subjectTokenType??"urn:logto:token-type:personal_access_token"),body.set("requested_token_type","urn:ietf:params:oauth:token-type:access_token"),config2.scopes.length>0&&body.set("scope",config2.scopes.join(" ")),applyResource(body,config2.audience);let tokenResponse=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),tokenPayload=await tokenResponse.json();if(!tokenResponse.ok)throw new Error(tokenPayload.error_description??tokenPayload.error??"PAT \u4EA4\u6362 token \u5931\u8D25");return{access_token:tokenPayload.access_token,id_token:typeof tokenPayload.id_token=="string"?tokenPayload.id_token:void 0,client_id:config2.clientId,token_type:tokenPayload.token_type,expires_in:tokenPayload.expires_in,scope:tokenPayload.scope??config2.scopes.join(" "),issued_at:new Date().toISOString(),credential_mode:"pat_exchange",exchange_subject_token:config2.subjectToken,exchange_subject_token_type:config2.subjectTokenType??"urn:logto:token-type:personal_access_token",mode_expires_at:new Date(Date.now()+PAT_LOGIN_VALIDITY_MS).toISOString()}}async function fetchWhoAmI(args){return createControlApiSdk({baseUrl:args.baseUrl,accessToken:args.accessToken,tenantId:args.tenantId,capability:"auth",requestClass:"control"}).getWhoAmI()}async function fetchTenantOverview(args){return createControlApiSdk({baseUrl:args.baseUrl,accessToken:args.accessToken,tenantId:args.tenantId,capability:"dashboard",requestClass:"control"}).getTenantOverview()}async function listTenantWorkspaces(args){return createControlApiSdk({baseUrl:args.baseUrl,accessToken:args.accessToken,capability:"auth",requestClass:"control"}).listTenantWorkspaces()}function looksLikeJwt(token){if(!token)return!1;let parts=token.split(".");return parts.length>=2&&parts.every(part=>part.length>0)}import{existsSync as existsSync11,mkdirSync as mkdirSync6,mkdtempSync as mkdtempSync2,readdirSync as readdirSync3,readFileSync as readFileSync10,renameSync as renameSync3,rmSync,statSync as statSync2,writeFileSync as writeFileSync6}from"node:fs";import{createServer as createNetServer}from"node:net";import{basename as basename3,dirname as dirname7,join as join7,relative as relative2,resolve as resolve7}from"node:path";import YAML from"yaml";var DEFAULT_APP_TEMPLATE_KEY="frontend-app-vite";function normalizeAppTemplateKey(value){if(typeof value>"u"||value.trim().length===0)return;let normalized=value.trim();if(normalized==="frontend-app-vite")return"frontend-app-vite";if(normalized==="backend-app-node")return"backend-app-node";throw new Error(`\u4E0D\u652F\u6301\u7684\u5E94\u7528\u6A21\u677F: ${normalized}\u3002\u5F53\u524D\u4EC5\u652F\u6301 \`frontend-app-vite\`\u3001\`backend-app-node\`\u3002\u65E7\u6A21\u677F\u5DF2\u4E0B\u7EBF\u3002`)}var PLATFORM_DIRECTORY=".platform",APP_MANIFEST_FILE="app.yaml",LEGACY_BINDING_FILE=join7(PLATFORM_DIRECTORY,"config.json"),SOURCE_CONTEXT_FILE=join7(PLATFORM_DIRECTORY,"source-context.json"),PLATFORM_BLOCKS_LOCKFILE=join7(PLATFORM_DIRECTORY,"platform-blocks.lock.json").replace(/\\/g,"/"),SOURCE_WORKSPACE_BYTES_LIMIT=50*1024*1024,SOURCE_WORKSPACE_ASSET_EXTENSIONS=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".ico",".bmp",".avif",".mp4",".mp3",".wav",".ogg",".pdf",".woff",".woff2",".ttf",".otf",".eot",".zip",".gz"]);function ensureDirectory(directory){mkdirSync6(directory,{recursive:!0})}function writeFileIfMissing(path3,content){if(existsSync11(path3))throw new Error(`\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6: ${path3}`);ensureDirectory(dirname7(path3)),writeFileSync6(path3,content,"utf8")}function listFilesRecursively(root,current=root){if(!existsSync11(current)||!statSync2(current).isDirectory())return[];let files=[];for(let entry of readdirSync3(current,{withFileTypes:!0})){let absolutePath=join7(current,entry.name);if(entry.isDirectory()){files.push(...listFilesRecursively(root,absolutePath));continue}entry.isFile()&&files.push(relative2(root,absolutePath))}return files.sort((left,right)=>left.localeCompare(right))}function seedRuntimeSdkVendor(targetDir){let workspaceRoot=findWorkspaceRoot(),runtimeSdkDistDir=join7(workspaceRoot,"packages","runtime-sdk","dist");if(!existsSync11(runtimeSdkDistDir)||!statSync2(runtimeSdkDistDir).isDirectory())throw new Error(`\u7F3A\u5C11\u6D4F\u89C8\u5668\u4FA7 runtime-sdk \u6784\u5EFA\u4EA7\u7269\uFF1A${runtimeSdkDistDir}\u3002\u8BF7\u5148\u6267\u884C \`pnpm --filter @platform/runtime-sdk build\`\uFF0C\u518D\u91CD\u65B0\u521D\u59CB\u5316\u8F7B\u5E94\u7528\u6A21\u677F\u3002`);let created=[];for(let relativePath of listFilesRecursively(runtimeSdkDistDir)){let sourcePath=join7(runtimeSdkDistDir,relativePath),outputPath=join7(targetDir,"vendor","runtime-sdk",relativePath);writeFileIfMissing(outputPath,readFileSync10(sourcePath,"utf8")),created.push(relative2(process.cwd(),outputPath))}return created}function normalizeAppManifest(input){let name=typeof input?.name=="string"&&input.name.trim().length>0?input.name.trim():"light-app",moduleName=typeof input?.module=="string"&&input.module.trim().length>0?input.module.trim():"light-app",templateKey=typeof input?.template_key=="string"&&input.template_key.trim().length>0?input.template_key.trim():DEFAULT_APP_TEMPLATE_KEY,normalizedEnvironments=Array.isArray(input?.environments)&&input.environments.length>0?input.environments.map(environment=>typeof environment?.name=="string"&&environment.name.trim().length>0?{name:environment.name.trim()}:null).filter(environment=>environment!==null):[];return{name,version:typeof input?.version=="string"&&input.version.trim().length>0?input.version.trim():"0.1.0",module:moduleName,template_key:templateKey,dev:{auto_restart:input?.dev?.auto_restart===!0},entry:{command:typeof input?.entry?.command=="string"&&input.entry.command.trim().length>0?input.entry.command.trim():"npm run dev",port:typeof input?.entry?.port=="number"&&Number.isFinite(input.entry.port)&&input.entry.port>0?input.entry.port:3e3,health_check:typeof input?.entry?.health_check=="string"&&input.entry.health_check.trim().length>0?input.entry.health_check.trim():"/healthz"},required_skills:Array.isArray(input?.required_skills)?input.required_skills.filter(Boolean):["db","auth"],permissions:Array.isArray(input?.permissions)?input.permissions.filter(Boolean):["app:read","app:write","app:publish"],env_vars:Array.isArray(input?.env_vars)?input.env_vars.filter(Boolean):["PORT","NODE_ENV","APP_ID","APP_ENV","TENANT_ID","DATABASE_URL","DATABASE_SCHEMA","CONTROL_API_BASE_URL"],runtime:{cpu:typeof input?.runtime?.cpu=="string"&&input.runtime.cpu.trim().length>0?input.runtime.cpu.trim():"250m",memory_mb:typeof input?.runtime?.memory_mb=="number"&&Number.isFinite(input.runtime.memory_mb)&&input.runtime.memory_mb>0?input.runtime.memory_mb:256},environments:normalizedEnvironments.length>0?normalizedEnvironments:[{name:"preview"},{name:"prod"}]}}function initProject(targetDir,_appName,templateKey=DEFAULT_APP_TEMPLATE_KEY){let absoluteTargetDir=resolve7(getInvocationCwd(),targetDir);ensureDirectory(absoluteTargetDir);let createdFiles=[],normalizedTemplateKey=normalizeAppTemplateKey(templateKey)??DEFAULT_APP_TEMPLATE_KEY,scaffoldFiles=normalizedTemplateKey==="frontend-app-vite"?assembleFrontendAppViteTemplate():normalizedTemplateKey==="backend-app-node"?assembleBackendAppNodeTemplate():assembleFrontendAppViteTemplate();for(let file of scaffoldFiles){let outputPath=join7(absoluteTargetDir,file.path);writeFileIfMissing(outputPath,file.content),createdFiles.push(relative2(getInvocationCwd(),outputPath))}let vendorCreated=scaffoldFiles.some(file=>file.path.startsWith("vendor/runtime-sdk/")||file.path.startsWith("src/vendor/runtime-sdk/"))?[]:seedRuntimeSdkVendor(absoluteTargetDir);return[...createdFiles,...vendorCreated]}function scaffoldAppDebugSurface(startDir,scaffold){let appRoot=findAppRoot(startDir),appJsPath=join7(appRoot,"src","app.js");if(!existsSync11(appJsPath))throw new Error(`\u672A\u627E\u5230\u5E94\u7528\u5165\u53E3\u6587\u4EF6: ${appJsPath}`);let spec=getAppDebugScaffoldSpec(scaffold),createdFiles=[],updatedFiles=[],targetFilePath=join7(appRoot,spec.filePath);existsSync11(targetFilePath)||(ensureDirectory(dirname7(targetFilePath)),writeFileSync6(targetFilePath,spec.source,"utf8"),createdFiles.push(relative2(appRoot,targetFilePath).replace(/\\/g,"/")));let appSource=readFileSync10(appJsPath,"utf8"),nextSource=injectDebugRouteIntoAppSource(appSource,spec);return nextSource!==appSource&&(writeFileSync6(appJsPath,nextSource,"utf8"),updatedFiles.push(relative2(appRoot,appJsPath).replace(/\\/g,"/"))),{appRoot,createdFiles,updatedFiles,routePath:spec.routePath}}function readAppManifest(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),manifestPath=join7(appRoot,APP_MANIFEST_FILE),raw=readFileSync10(manifestPath,"utf8"),manifest=normalizeAppManifest(YAML.parse(raw));if(!manifest||typeof manifest!="object")throw new Error(`\u65E0\u6548\u7684 app.yaml: ${manifestPath}`);return{directory:appRoot,path:manifestPath,manifest}}function readLegacyBinding(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),bindingPath=join7(appRoot,LEGACY_BINDING_FILE);if(!existsSync11(bindingPath))return null;let raw=JSON.parse(readFileSync10(bindingPath,"utf8")),binding={schema_version:typeof raw.schema_version=="number"?raw.schema_version:1,tenant_id:raw.tenant_id??"",app_id:raw.app_id??"",env:raw.env??"preview",linked_at:raw.linked_at??new Date(0).toISOString(),workspace_name:raw.workspace_name,app_name:raw.app_name,app_display_name:raw.app_display_name,validated_at:raw.validated_at};return{path:bindingPath,binding}}function readBinding(startDir=getInvocationCwd()){let sourceContext=readSourceContext(startDir);if(sourceContext?.sourceContext.tenant_id&&sourceContext.sourceContext.app_id){let context=sourceContext.sourceContext;return{path:sourceContext.path,binding:{schema_version:1,tenant_id:context.tenant_id,app_id:context.app_id,env:context.env||"preview",linked_at:context.linked_at??context.checked_out_at??context.updated_at,workspace_name:context.workspace_name,app_name:context.app_name,app_display_name:context.app_display_name,validated_at:context.validated_at}}}return readLegacyBinding(startDir)}function writeBinding(startDir,binding){let result=updateSourceContext(startDir,{tenant_id:binding.tenant_id,app_id:binding.app_id,env:binding.env,workspace_name:binding.workspace_name,app_name:binding.app_name,app_display_name:binding.app_display_name,validated_at:binding.validated_at,linked_at:new Date().toISOString()});return{appRoot:result.appRoot,path:result.path}}function readSourceContext(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),sourceContextPath=join7(appRoot,SOURCE_CONTEXT_FILE);if(!existsSync11(sourceContextPath))return null;let raw=JSON.parse(readFileSync10(sourceContextPath,"utf8")),sourceContext={schema_version:typeof raw.schema_version=="number"?raw.schema_version:1,tenant_id:raw.tenant_id??"",app_id:raw.app_id??"",env:raw.env??"preview",linked_at:raw.linked_at,validated_at:raw.validated_at,workspace_name:raw.workspace_name,app_name:raw.app_name,app_display_name:raw.app_display_name,template_key:raw.template_key,default_directory:raw.default_directory,generated_from_template:typeof raw.generated_from_template=="boolean"?raw.generated_from_template:void 0,base_source_version_id:raw.base_source_version_id,checked_out_at:raw.checked_out_at,last_submitted_source_version_id:raw.last_submitted_source_version_id,last_submitted_at:raw.last_submitted_at,last_preview_source_version_id:raw.last_preview_source_version_id,last_preview_build_id:raw.last_preview_build_id,last_preview_generated_at:raw.last_preview_generated_at,control_plane:raw.control_plane&&typeof raw.control_plane=="object"?raw.control_plane:void 0,updated_at:raw.updated_at??new Date(0).toISOString()};return{path:sourceContextPath,sourceContext}}function writeSourceContext(startDir,sourceContext){let appRoot=findAppRoot(startDir),path3=join7(appRoot,SOURCE_CONTEXT_FILE);return ensureDirectory(dirname7(path3)),writeFileSync6(path3,`${JSON.stringify({schema_version:1,...sourceContext,updated_at:new Date().toISOString()},null,2)}
2456
2456
  `,"utf8"),{appRoot,path:path3}}function updateSourceContext(startDir,patch){let appRoot=findAppRoot(startDir),existing=readSourceContext(appRoot)?.sourceContext,legacyBinding=readLegacyBinding(appRoot)?.binding;return writeSourceContext(appRoot,{tenant_id:patch.tenant_id??existing?.tenant_id??legacyBinding?.tenant_id??"",app_id:patch.app_id??existing?.app_id??legacyBinding?.app_id??"",env:patch.env??existing?.env??legacyBinding?.env??"preview",linked_at:patch.linked_at??existing?.linked_at??legacyBinding?.linked_at,validated_at:patch.validated_at??existing?.validated_at??legacyBinding?.validated_at,workspace_name:patch.workspace_name??existing?.workspace_name??legacyBinding?.workspace_name,app_name:patch.app_name??existing?.app_name??legacyBinding?.app_name,app_display_name:patch.app_display_name??existing?.app_display_name??legacyBinding?.app_display_name,template_key:patch.template_key??existing?.template_key,default_directory:patch.default_directory??existing?.default_directory,generated_from_template:typeof patch.generated_from_template=="boolean"?patch.generated_from_template:existing?.generated_from_template,base_source_version_id:patch.base_source_version_id??existing?.base_source_version_id,checked_out_at:patch.checked_out_at??existing?.checked_out_at,last_submitted_source_version_id:patch.last_submitted_source_version_id??existing?.last_submitted_source_version_id,last_submitted_at:patch.last_submitted_at??existing?.last_submitted_at,last_preview_source_version_id:patch.last_preview_source_version_id??existing?.last_preview_source_version_id,last_preview_build_id:patch.last_preview_build_id??existing?.last_preview_build_id,last_preview_generated_at:patch.last_preview_generated_at??existing?.last_preview_generated_at,control_plane:patch.control_plane??existing?.control_plane})}function checkoutSourceWorkspace(targetDir,files,sourceContext){let absoluteTargetDir=resolve7(getInvocationCwd(),targetDir);if(validatePortableWorkspacePaths(files),existsSync11(absoluteTargetDir))throw new Error(`\u76EE\u6807\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6\uFF08\u5305\u62EC\u7A7A\u76EE\u5F55\uFF09: ${absoluteTargetDir}`);let parentDir=dirname7(absoluteTargetDir);ensureDirectory(parentDir);let stagingDir=mkdtempSync2(join7(parentDir,`.${basename3(absoluteTargetDir)}.platform-checkout-`));try{for(let file of files){let normalizedPath=normalizePortableWorkspacePath(file.path);writeFileIfMissing(join7(stagingDir,normalizedPath),file.content)}let now=new Date().toISOString();if(writeFileIfMissing(join7(stagingDir,SOURCE_CONTEXT_FILE),`${JSON.stringify({schema_version:1,...sourceContext,linked_at:sourceContext.linked_at??now,updated_at:now},null,2)}
2457
2457
  `),existsSync11(absoluteTargetDir))throw new Error(`\u76EE\u6807\u76EE\u5F55\u5728\u68C0\u51FA\u8FC7\u7A0B\u4E2D\u88AB\u521B\u5EFA\uFF0C\u62D2\u7EDD\u8986\u76D6: ${absoluteTargetDir}`);renameSync3(stagingDir,absoluteTargetDir)}catch(error){throw rmSync(stagingDir,{recursive:!0,force:!0}),error}return files.map(file=>relative2(getInvocationCwd(),join7(absoluteTargetDir,normalizePortableWorkspacePath(file.path))))}function validatePortableWorkspacePaths(files){let canonicalPaths=new Map;for(let file of files){let normalizedPath=normalizePortableWorkspacePath(file.path);if(normalizedPath.toLowerCase()===SOURCE_CONTEXT_FILE.replace(/\\/gu,"/").toLowerCase())throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u975E\u6CD5\uFF08CLI \u4FDD\u7559\u8DEF\u5F84\uFF09: ${file.path}`);let canonicalPath=normalizedPath.normalize("NFC").toLowerCase(),collision=canonicalPaths.get(canonicalPath);if(collision)throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u51B2\u7A81: ${collision} <-> ${file.path}`);canonicalPaths.set(canonicalPath,file.path)}for(let[canonicalPath,originalPath]of canonicalPaths){let segments=canonicalPath.split("/");for(let index=1;index<segments.length;index+=1){let parentPath=segments.slice(0,index).join("/"),parentOriginalPath=canonicalPaths.get(parentPath);if(parentOriginalPath)throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u51B2\u7A81\uFF08\u6587\u4EF6\u4E0E\u76EE\u5F55\u91CD\u540D\uFF09: ${parentOriginalPath} <-> ${originalPath}`)}}}function normalizePortableWorkspacePath(inputPath){let normalizedSeparators=inputPath.replace(/\\/gu,"/");if(!normalizedSeparators||normalizedSeparators.startsWith("/")||/^[A-Za-z]:/u.test(normalizedSeparators))throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u975E\u6CD5: ${inputPath}`);let segments=normalizedSeparators.split("/");for(let segment of segments){if(!segment||segment==="."||segment==="..")throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u975E\u6CD5: ${inputPath}`);if(/[<>:"|?*\u0000-\u001F]/u.test(segment))throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u5305\u542B Windows \u975E\u6CD5\u5B57\u7B26: ${inputPath}`);if(/[. ]$/u.test(segment))throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u542B\u5C3E\u968F\u70B9\u6216\u7A7A\u683C: ${inputPath}`);let baseName=segment.split(".")[0]??segment;if(/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/iu.test(baseName))throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u4F7F\u7528 Windows \u4FDD\u7559\u540D: ${inputPath}`)}return segments.map(segment=>segment.normalize("NFC")).join("/")}function collectSourceWorkspaceFiles(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),files=walkSourceWorkspace(appRoot,appRoot);return{appRoot,files}}function assertSourceWorkspaceCloudUploadPolicy(appRoot,commandLabel){let stats=scanSourceWorkspaceUploadPolicy(appRoot,appRoot);if(stats.sourceBytes>SOURCE_WORKSPACE_BYTES_LIMIT)throw new Error(`\u5F53\u524D\u6E90\u7801\u5305\u4F53\u79EF ${stats.sourceBytes} bytes\uFF0C\u8D85\u8FC7\u4E91\u7AEF\u6E90\u7801\u4E0A\u4F20\u4E0A\u9650 ${SOURCE_WORKSPACE_BYTES_LIMIT} bytes\u3002`);if(stats.assetHits.length>0)throw new Error([`\u68C0\u6D4B\u5230\u672C\u5730\u7D20\u6750\u8D44\u6E90\uFF0C\u5F53\u524D \`${commandLabel}\` \u4E0D\u8D1F\u8D23\u7D20\u6750\u4E0A\u4F20\u56DE\u5199\u3002`,"Agent \u8BF7\u5148\u53C2\u8003 Skill \u6587\u6863 `design-import.md` \u6267\u884C\u8BBE\u8BA1\u6E90\u7801\u9884\u5904\u7406\uFF0C\u5C06\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u7D20\u6750\u5E93\u5E76\u628A\u6E90\u7801\u6539\u5199\u4E3A\u7D20\u6750\u5E93\u5F15\u7528\u540E\u518D\u8BD5\u3002",`\u793A\u4F8B\u547D\u4E2D: ${stats.assetHits.slice(0,10).join(", ")}`].join(`
@@ -2737,7 +2737,7 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
2737
2737
  `):process.stderr.write(`worker \u672A\u5B9E\u73B0: ${worker}
2738
2738
  \u5F53\u524D\u5DF2\u5B9E\u73B0: ${[...implementedWorkers].join(", ")}
2739
2739
  `),process.exitCode=1;return}await spawnControlApiWorker([worker,...serializeOptions(args.options)])}function printWorkerHelp(){process.stdout.write(["platform worker","","\u7528\u6CD5\uFF1A"," platform worker preview-retention [--once] [--dry-run] [--tenant <tenant-id>] [--app <app-id>] [--ttl-hours <n>] [--limit <n>] [--json]","","\u8BF4\u660E\uFF1A"," worker \u547D\u4EE4\u662F\u672C\u5730\u5F00\u53D1/\u8FD0\u7EF4\u5165\u53E3\uFF0C\u4F1A\u8F6C\u4EA4\u7ED9 @platform/control-api \u7684 worker \u5B9E\u73B0\u3002"," preview-retention \u9ED8\u8BA4\u4EE5\u524D\u53F0\u5E38\u9A7B worker \u8FD0\u884C\uFF1B\u52A0 --once \u65F6\u53EA\u6267\u884C\u4E00\u6B21\u3002",""].join(`
2740
- `))}function serializeOptions(options){let result=[];for(let[key,value]of Object.entries(options))key==="help"||key==="h"||(result.push(`--${key}`),typeof value=="string"&&result.push(value));return result}async function spawnControlApiWorker(args){await new Promise((resolve20,reject)=>{let child=spawn4("corepack",["pnpm","--silent","--filter","@platform/control-api","worker",...args],{stdio:"inherit"});child.on("error",reject),child.on("exit",(code2,signal)=>{if(signal){reject(new Error(`control-api worker exited by signal ${signal}`));return}code2&&code2!==0&&(process.exitCode=code2),resolve20()})})}applyStoredEnvironmentProfile();applyDistributionProfileDefaults();loadDotenvFiles();var distributionProfile=getDistributionProfile(),cliPackageVersion=getCliPackageVersion();function persistActiveTenantSelection(tenant){let currentContext=loadStoredCliContext();persistCliContext({active_tenant_id:tenant.tenant_id,active_tenant_name:tenant.name,selected_app_tenant_id:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_tenant_id,selected_app_id:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_id,selected_app_env:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_env,selected_app_name:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_name,selected_app_display_name:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_display_name})}function currentInvocationDir(){return getInvocationCwd()}function parseArgs5(argv){let[command="help",...rest]=argv,options={},positionals=[];for(let index=0;index<rest.length;index+=1){let current=rest[index];if(current==="--help"){options.help=!0;continue}if(current==="-h"){options.h=!0;continue}if(!current.startsWith("--")){positionals.push(current);continue}let[key,inlineValue]=current.slice(2).split("=",2);if(inlineValue!==void 0){options[key]=inlineValue;continue}let next=rest[index+1];if(next&&!next.startsWith("--")){options[key]=next,index+=1;continue}options[key]=!0}return{command,rest:positionals,options}}function printHelp(){let envCommandLines=distributionProfile.name!=="developer"?[]:[" env use <profile> \u5207\u6362 CLI \u73AF\u5883 profile\uFF08\u5982 local / test\uFF09"," env current \u67E5\u770B\u5F53\u524D CLI \u73AF\u5883 profile"," env list \u67E5\u770B\u53EF\u7528 CLI \u73AF\u5883 profile"];process7.stdout.write(["platform <command>","","Commands:"," login \u5168\u5C40\u767B\u5F55\u5E76\u4FDD\u5B58\u51ED\u636E"," logout \u6E05\u7406\u672C\u5730\u767B\u5F55\u51ED\u636E\u4E0E\u8D26\u53F7\u4E0A\u4E0B\u6587"," credentials migrate \u5C06\u65E7\u660E\u6587\u51ED\u636E\u8FC1\u79FB\u5230\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8"," version \u8F93\u51FA\u5F53\u524D CLI \u7248\u672C\u53F7"," app create \u5728\u4E91\u7AEF\u521B\u5EFA\u5E94\u7528\uFF0C\u5E76 checkout \u5230\u672C\u5730\u65B0\u76EE\u5F55"," app checkout \u4ECE\u4E91\u7AEF checkout \u5E94\u7528\u6E90\u7801\u526F\u672C\u5230\u672C\u5730\u65B0\u76EE\u5F55"," app submit \u5C06\u5F53\u524D\u672C\u5730\u6E90\u7801\u63D0\u4EA4\u4E3A\u65B0\u7684\u4E91\u7AEF\u6E90\u7801\u7248\u672C"," app version create \u5728\u5F53\u524D app \u4E0B\u57FA\u4E8E\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u65B0\u7684\u6E90\u7801\u7248\u672C\u9AA8\u67B6"," app version list \u67E5\u770B\u5E94\u7528\u7684\u6E90\u7801\u7248\u672C\u5217\u8868"," app versions \u67E5\u770B\u5E94\u7528\u7684\u6E90\u7801\u7248\u672C\u5217\u8868"," app status \u67E5\u770B\u5E94\u7528\u63A7\u5236\u9762\u603B\u89C8\uFF08\u542B Auth / DB / \u7248\u672C\u6982\u51B5\uFF09"," app diagnose \u67E5\u770B\u5E94\u7528\u662F\u5426\u5DF2 ready for runtime validation"," app preflight \u4E00\u6B21\u6027\u6267\u884C whoami / app current / app diagnose \u98CE\u683C\u68C0\u67E5"," app sync-platform-blocks \u540C\u6B65\u53CC\u6A21\u677F\u5E73\u53F0\u7EF4\u62A4\u533A\uFF08dry-run / adopt / apply / rollback --last\uFF09"," app import preprocess \u9884\u5904\u7406\u7B2C\u4E09\u65B9\u8BBE\u8BA1\u6E90\u7801\u5305\uFF0C\u751F\u6210 clean-source \u4E0E\u62A5\u544A"," app import stage \u628A clean-source \u4E0E\u62A5\u544A stage \u5230\u6A21\u677F\u5DE5\u4F5C\u533A"," app import merge \u628A\u4E0A\u6E38 src \u5B89\u5168\u5E76\u5165 src/imported-upstream/"," app scaffold \u6309\u9700\u6CE8\u5165\u672C\u5730 debug scaffold\uFF08auth/workflow/cms/db\uFF09"," app-library \u7BA1\u7406\u8F7B\u5E94\u7528\u8D44\u6E90\u5E93 example-app \u6761\u76EE"," app use \u517C\u5BB9\u8DEF\u5F84\uFF1A\u4E3A init/link/dev \u9009\u62E9\u76EE\u6807\u5E94\u7528"," app current \u67E5\u770B\u5F53\u524D\u5DF2\u9009\u5E94\u7528\u4E0A\u4E0B\u6587"," tenant use <id> \u8BBE\u7F6E\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587"," tenant current \u67E5\u770B\u5F53\u524D\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587",...envCommandLines," whoami \u8C03\u7528 Control API \u8F93\u51FA\u5F53\u524D\u4E3B\u4F53"," preview \u9ED8\u8BA4\u6253\u5F00\u5F53\u524D\u53EF\u7528 Preview\uFF1B\u751F\u6210\u8BF7\u7528 `platform preview generate`"," init [name] \u751F\u6210\u9879\u76EE\u9AA8\u67B6\uFF0C\u5E76\u81EA\u52A8\u5199\u5165\u5DF2\u9009\u5E94\u7528\u7ED1\u5B9A"," link \u7ED1\u5B9A tenant/app/env \u5230\u5F53\u524D\u5E94\u7528\u76EE\u5F55"," dev \u9ED8\u8BA4\u8F7B\u91CF\u5F00\u53D1\u5165\u53E3\uFF1A\u6CE8\u5165\u7ED1\u5B9A\u540E\u542F\u52A8\u672C\u5730\u5F00\u53D1\u6001"," dev push \u5C06\u5F53\u524D\u672C\u5730\u6E90\u7801\u8986\u76D6\u63A8\u9001\u5230\u4E91\u7AEF Dev Workspace"," dev preview generate \u57FA\u4E8E\u4E91\u7AEF Dev Workspace \u751F\u6210\u5DE5\u4F5C\u533A Preview"," auth \u7BA1\u7406 Auth \u57FA\u5EA7\u80FD\u529B\uFF08discover / configure / bind / inspect\uFF09"," cms \u7BA1\u7406 CMS \u57FA\u5EA7\u80FD\u529B\uFF08discover / configure / apply / inspect\uFF09"," asset \u7BA1\u7406\u79DF\u6237\u5171\u4EAB\u7D20\u6750\uFF08upload / list / folder / get / update / analyze / move / open / tag\uFF09"," blob \u7BA1\u7406 Object Storage Blob\uFF08upload / list / get / url\uFF09"," db \u67E5\u770B DB \u72B6\u6001\u3001\u8868\u7ED3\u6784\u4E0E\u53EA\u8BFB\u67E5\u8BE2"," data-form \u6821\u9A8C/\u7F16\u8BD1/apply/query Data Form schema \u4E0E\u8BB0\u5F55"," workflow \u7BA1\u7406 Workflow \u57FA\u5EA7\u80FD\u529B\uFF08template / definition / binding / runtime\uFF09"," notification \u7BA1\u7406 Notification \u57FA\u5EA7\u80FD\u529B\uFF08inbox / announce / delivery\uFF09"," publish \u7BA1\u7406\u5E94\u7528\u6B63\u5F0F\u53D1\u5E03\u72B6\u6001\u4E0E\u5F53\u524D\u90E8\u7F72\u7248\u672C"," resources \u6267\u884C\u8D44\u6E90 diff/apply/rollback"," logs \u67E5\u8BE2\u8FD0\u884C\u65F6\u65E5\u5FD7\uFF0C\u652F\u6301 --follow"," diagnostics \u5E73\u53F0\u672C\u5730\u8BCA\u65AD\uFF08control-api / credentials\uFF09"," worker \u542F\u52A8\u5E73\u53F0\u540E\u53F0 worker\uFF08preview-retention\uFF09","","Advanced commands:"," build \u9AD8\u7EA7\u8BCA\u65AD\u5165\u53E3\uFF1A\u53D1\u8D77\u548C\u67E5\u8BE2 build"," deploy \u8FC7\u6E21\u5165\u53E3\uFF1A\u9AD8\u7EA7\u53D1\u5E03\uFF08artifact / promote\uFF09"," rollback \u8FC7\u6E21\u5165\u53E3\uFF1A\u56DE\u6EDA\u5230\u76EE\u6807 release \u6216\u7248\u672C","","App commands:"," platform app create --tenant <tenant-id> --name <display-name> --dir <project-name> [--template frontend-app-vite|backend-app-node]"," platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>"," platform app checkout --tenant <tenant-id> --app <app-id> --source-version <srcver>",' platform app submit --message "local iteration"',' platform app version create --message "switch template" --template backend-app-node'," platform app versions --tenant <tenant-id> --app <app-id>"," platform app status [--tenant <tenant-id>] [--app <app-id>] [--env preview|prod]"," platform app sync-platform-blocks [--dry-run|--adopt|--apply|--rollback --last]"," platform app diagnose [--tenant <tenant-id>] [--app <app-id>] [--env preview|prod]"," platform app import preprocess [--dir <third-party-source-dir>] [--dry-run]"," platform app import stage --preprocess <source-dir|.design-preprocess|reports|import-manifest.json>"," platform app import merge [--workspace-dir <template-workspace-dir>]"," platform app scaffold <auth-debug|workflow-debug|cms-debug|db-debug>"," platform app-library list"," platform app-library config init"," platform app-library inspect entry-demo"," platform app-library checkout entry-demo --dir ./example-app-demo",' platform app-library create --name "Data Form Verify" --summary "\u672C\u5730\u9A8C\u8BC1\u540E\u7684\u793A\u4F8B\u5E94\u7528"'," platform app-library submit entry-demo"," platform app use --tenant <tenant-id> --app <app-id> --env preview"," platform app current","","DB commands:"," platform db status"," platform db history --limit 10"," platform db migrate [--dry-run]"," platform db tables",' platform db query --sql "SELECT ... LIMIT 5"'," platform db open","","Auth commands:"," platform auth discover [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth configure [--tenant <tenant-id>] [--app <app-id>] --enable [--template <template>] [--user-store-id <id>] [--enable-admin-password|--disable-admin-password] [--enable-phone-sms-otp|--disable-phone-sms-otp] [--json]"," platform auth bind [--tenant <tenant-id>] [--app <app-id>] [--action bind|rebind|disable] [--user-store-id <id>] [--json]"," platform auth inspect [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth role list [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth role create [--tenant <tenant-id>] [--app <app-id>] --key <role-key> --name <display-name> [--description <text>] [--status active|disabled] [--json]"," platform auth role inspect [--tenant <tenant-id>] [--app <app-id>] --role <role-key> [--json]"," platform auth role update [--tenant <tenant-id>] [--app <app-id>] --role <role-key> [--name <display-name>] [--description <text> | --clear-description] [--status active|disabled] [--json]"," platform auth user-role list [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> [--json]"," platform auth user-role assign [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --roles role-a,role-b [--json]"," platform auth user-role replace [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --roles role-a,role-b [--json]"," platform auth user-role remove [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --role <role-key> [--json]","","CMS commands:"," platform cms discover [--collection <name>] [--json]"," platform cms configure collection --file <spec.json> [--json]"," platform cms configure item --file <item.json> [--item-id <item-id>] [--json]"," platform cms configure category --collection <name> --name <name> --slug <slug> [--parent-id <id>] [--order <n>] [--json]"," platform cms import markdown <file> [--collection <name>] [--item-id <item-id> | --item-id-prefix <prefix>] [--tags <label,label>] [--category-path <segment/segment>] [--cover-asset-id <asset-id>] [--publish | --publish-status draft|published|archived] [--skip-existing] [--dry-run] [--json]"," platform cms import url <url> [--collection <name>] [--item-id <item-id>] [--tags <label,label>] [--category-path <segment/segment>] [--publish | --publish-status draft|published|archived] [--skip-existing] [--no-assetize-images] [--dry-run] [--json]"," platform cms attach asset --collection <name> --item-id <id> --field <field-name> --asset-id <id[,id]> [--replace] [--json]"," platform cms ensure category --collection <name> --path <segment/segment> [--json]"," platform cms list items --collection <name> [--page <n>] [--page-size <n>] [--status draft|published|archived] [--category-id <id>] [--q <keyword>] [--json]"," platform cms batch update --collection <name> --item-id <id[,id]> [--category-id <id> | --clear-category] [--add-tags <label,label>] [--status draft|published|archived] [--json]"," platform cms apply schema --collection <name> --version <n> [--json]"," platform cms apply publish --collection <name> --item-id <id> --status draft|published|archived [--json]"," platform cms inspect schema --collection <name> [--json]"," platform cms inspect item --collection <name> --id <id> [--json]"," platform cms inspect delivery list --collection <name> [--page <n>] [--page-size <n>] [--tag <tag>] [--category-id <id>] [--json]"," platform cms inspect delivery get --collection <name> (--slug <slug> | --id <id>) [--json]"," platform cms inspect delivery categories --collection <name> [--json]","","Asset commands:"," platform asset upload <file-path> [--title <title>] [--folder-id <folder-id>]"," platform asset list [--q <keyword>] [--media-type image|video] [--folder-id <folder-id>] [--page <n>] [--limit <n>]"," platform asset folder list"," platform asset folder create <name> [--parent-folder-id <folder-id>]"," platform asset folder rename <folder-id> --name <name> [--parent-folder-id <folder-id> | --root]"," platform asset get <asset-id>"," platform asset move <asset-id> [--folder-id <folder-id> | --root]"," platform asset update <asset-id> [--title <title>] [--folder-id <folder-id> | --root] [--tags <label,label>]"," platform asset analyze <asset-id> [--json]"," platform asset open <asset-id> [--output <path>]"," platform asset download <asset-id> --variant thumbnail|sm|md|lg|cover [--output <path>]"," platform asset tag list [--asset <asset-id>]"," platform asset tag add <asset-id> <label>"," platform asset tag remove <asset-id> <label>","","Preview commands:"," platform preview"," platform preview open [--source-version <srcver>]"," platform preview generate [--source-version <srcver>]"," platform preview generate --from-build <build-id>","","Publish commands:"," platform publish"," platform publish status"," platform publish set [--source-version <srcver>] [--status published|unpublished]"," platform publish rollback <srcver>","","Workflow commands:"," platform workflow template list"," platform workflow template inspect --template <key>"," platform workflow definition list [--status draft|active|inactive]"," platform workflow definition inspect --definition <key>"," platform workflow definition create --definition <key> --app <app-id> [--template <template-key> | --object-type <type> --schema <json>]"," platform workflow binding list [--app <app-id>] [--definition <key>]"," platform workflow binding inspect --definition <key> [--target-id <id>]"," platform workflow binding update --definition <key> [--target-id <id>] --file <override.json>"," platform workflow role bind --definition <key> --app <app-id> --file <bindings.json> # \u4F4E\u5C42\u9AD8\u7EA7\u5165\u53E3"," platform workflow diagnose [--app <app-id>]"," platform workflow start --definition <key> --object-type <type> --object-id <id>"," platform workflow action --instance <instance-id> --action <action-key>"," platform workflow tasks [--status pending]"," platform workflow instance <instance-id>","","Notification commands:"," platform notification inbox list [--app <app-id>] [--type task_projection|announcement|notification|alert] [--status unread|read|dismissed|archived] [--limit <n>]"," platform notification inbox update <item-id> --status unread|read|dismissed|archived"," platform notification announce platform --tenant <tenant-id> --title <text> [--body <text>] [--level info|success|warning|error]"," platform notification announce app --tenant <tenant-id> --app <app-id> --title <text> [--body <text>] [--level info|success|warning|error]"," platform notification delivery [--app <app-id>] [--status pending|running|succeeded|failed|dead]"," platform notification end-user users --app <app-id>"," platform notification end-user inbox --app <app-id> --end-user <app-user-id> [--type task_projection|announcement|notification|alert] [--status unread|read|dismissed|archived] [--limit <n>]"," platform notification end-user unread --app <app-id> --end-user <app-user-id>"," platform notification end-user publish --app <app-id> --end-user <app-user-id> --title <text> [--body <text>] [--kind notification|alert|announcement]"," platform notification end-user announcement --app <app-id> --end-user <app-user-id> --title <text> --body <text>"," platform notification end-user reminder --app <app-id> --end-user <app-user-id> --title <text> --remind-at <ISO datetime> [--body <text>]","","Advanced release commands:"," platform deploy [--source-version <srcver>] [--prod]"," platform rollback <release-id|version>","","Advanced build commands:"," platform build run --source-version <srcver>"," platform build get <build-id>"," platform build events <build-id>"," platform build validate --app <app-id> --source-version <srcver>"," platform logs --follow"," platform diagnostics control-api [--json]"," platform diagnostics credentials [--json] [--strict]"," platform worker preview-retention [--once] [--dry-run] [--json]","","Resource commands:"," platform resources diff --base-snapshot <rsnap-id>"," platform resources apply --base-snapshot <rsnap-id>"," platform resources rollback <rsnap-id> --approve-id <approve-id>","","Examples:"," platform login"," platform login --pat <personal-access-token>"," platform env use local"," platform env use test"," platform env current",' platform app create --tenant t-default --name "\u6D3B\u52A8\u9080\u8BF7\u51FD" --dir invite-frontend',' platform app create --tenant t-default --name "\u62A5\u540D\u52A9\u624B" --dir signup-runtime --template backend-app-node',' platform app create --tenant t-default --name "\u8425\u9500\u9875" --dir landing-page --template frontend-app-vite',' platform app create --tenant t-default --name "\u4E1A\u52A1\u540E\u53F0" --dir ops-console --template backend-app-node'," platform app checkout --tenant t-default --app app-demo --dir app-demo"," platform app checkout --tenant t-default --app app-demo --source-version srcver-123",' platform app submit --message "local iteration"'," platform dev push"," platform dev preview generate"," platform dev preview open",' platform asset upload ./logo.png --title "\u54C1\u724C Logo"'," platform asset folder create \u54C1\u724C\u7D20\u6750"," platform asset folder rename asset-folder-123 --name \u54C1\u724C\u89C6\u89C9 --root"," platform asset folder list"," platform asset list --q logo --tag-ids tag-1,tag-2 --page 2"," platform asset get asset-123"," platform asset move asset-123 --folder-id asset-folder-123",' platform asset update asset-123 --title "\u9996\u9875 Hero \u56FE" --scene outdoor --tags hero,homepage'," platform asset analyze asset-123"," platform asset open asset-123"," platform asset download asset-123 --variant md"," platform asset tag list --asset asset-123"," platform asset tag add asset-123 logo"," platform asset tag remove asset-123 logo"," platform app versions --tenant t-default --app app-demo"," platform whoami --tenant t-default"," platform build get build-123"," platform build events build-123"," platform build run --source-version srcver-123"," platform build validate --app app-demo --source-version srcver-123"," platform preview"," platform preview open --source-version srcver-123"," platform preview generate"," platform preview generate --source-version srcver-123"," platform publish"," platform publish status"," platform publish set --status unpublished"," platform publish set --source-version srcver-123 --status published"," platform publish rollback srcver-122"," cd signup-lite && platform dev"," cd signup-lite && platform dev push"," cd signup-lite && platform dev preview generate"," cd signup-lite && platform dev preview open"," platform deploy --source-version srcver-123"," platform deploy --prod"," platform rollback v0.2.0","","Other examples:"," platform app current"," platform tenant use t-default"," platform tenant current"," platform db status"," platform db history --limit 10"," platform db tables",' platform db query --sql "SELECT * FROM example_items LIMIT 5"'," platform auth discover --app app-demo"," platform auth configure --app app-demo --enable --template email_magic_link_only"," platform auth configure --app app-demo --enable --template phone_sms_otp_only"," platform auth configure --app app-demo --enable --template email_magic_link_and_phone_sms_otp"," platform auth configure --app app-demo --enable --enable-phone-sms-otp"," platform auth bind --app app-checkin --action bind --user-store-id us_xxx"," platform auth inspect --app app-demo --json"," platform cms discover"," platform cms discover --collection article"," platform cms configure collection --file ./cms/article.collection.json"," platform cms configure item --file ./cms/article.item.json"," platform cms import markdown ./docs/post.md --collection article --tags cms,agent --category-path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03 --cover-asset-id asset-123 --publish"," platform cms import url https://zhuanlan.zhihu.com/p/488185988 --collection article --tags cms,url --dry-run"," platform cms import url https://example.com/post --collection article --no-assetize-images"," platform cms import markdown ./docs/articles --collection article --recursive --item-id-prefix article-doc --skip-existing"," platform cms import markdown ./docs/post.md --collection article --category-path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03 --dry-run --json"," platform cms import markdown ./docs/post.md --collection article --skip-existing --publish"," platform cms attach asset --collection article --item-id cms-item-123 --field cover --asset-id asset-123"," platform cms ensure category --collection article --path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03"," platform cms list items --collection article --status draft"," platform cms batch update --collection article --item-id item-a,item-b --category-id cms-category-123 --add-tags cms,cli --status published"," platform cms apply schema --collection article --version 1"," platform cms inspect schema --collection article --json"," platform cms inspect item --collection article --id cms-item-123"," platform cms inspect delivery list --collection article --tag cms"," platform cms inspect delivery get --collection article --slug introducing-cms-base"," platform resources diff --base-snapshot rsnap-123"," platform resources apply --base-snapshot rsnap-123"," platform resources rollback rsnap-122 --approve-id approve-123"," platform logs --follow","","Compatible path examples:"," platform app use --tenant t-default --app app-demo --env preview"," platform init demo-app"," platform link --tenant t-default --app app-demo --env preview"," platform dev --target tenant-workbench"," platform dev --remote-bindings"," platform dev --remote-bindings=db",""].join(`
2740
+ `))}function serializeOptions(options){let result=[];for(let[key,value]of Object.entries(options))key==="help"||key==="h"||(result.push(`--${key}`),typeof value=="string"&&result.push(value));return result}async function spawnControlApiWorker(args){await new Promise((resolve20,reject)=>{let child=spawn4("corepack",["pnpm","--silent","--filter","@platform/control-api","worker",...args],{stdio:"inherit"});child.on("error",reject),child.on("exit",(code2,signal)=>{if(signal){reject(new Error(`control-api worker exited by signal ${signal}`));return}code2&&code2!==0&&(process.exitCode=code2),resolve20()})})}applyStoredEnvironmentProfile();applyDistributionProfileDefaults();loadDotenvFiles();var distributionProfile=getDistributionProfile(),cliPackageVersion=getCliPackageVersion();function persistActiveTenantSelection(tenant){let currentContext=loadStoredCliContext();persistCliContext({active_tenant_id:tenant.tenant_id,active_tenant_name:tenant.name,selected_app_tenant_id:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_tenant_id,selected_app_id:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_id,selected_app_env:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_env,selected_app_name:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_name,selected_app_display_name:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_display_name})}function currentInvocationDir(){return getInvocationCwd()}function parseArgs5(argv){let[command="help",...rest]=argv,options={},positionals=[];for(let index=0;index<rest.length;index+=1){let current=rest[index];if(current==="--help"){options.help=!0;continue}if(current==="-h"){options.h=!0;continue}if(!current.startsWith("--")){positionals.push(current);continue}let[key,inlineValue]=current.slice(2).split("=",2);if(inlineValue!==void 0){options[key]=inlineValue;continue}let next=rest[index+1];if(next&&!next.startsWith("--")){options[key]=next,index+=1;continue}options[key]=!0}return{command,rest:positionals,options}}function printHelp(){let envCommandLines=distributionProfile.name!=="developer"?[]:[" env use <profile> \u5207\u6362 CLI \u73AF\u5883 profile\uFF08\u5982 local / test\uFF09"," env current \u67E5\u770B\u5F53\u524D CLI \u73AF\u5883 profile"," env list \u67E5\u770B\u53EF\u7528 CLI \u73AF\u5883 profile"];process7.stdout.write(["platform <command>","","Commands:"," login \u5168\u5C40\u767B\u5F55\u5E76\u4FDD\u5B58\u51ED\u636E"," logout \u6E05\u7406\u672C\u5730\u767B\u5F55\u51ED\u636E\u4E0E\u8D26\u53F7\u4E0A\u4E0B\u6587"," credentials migrate \u8FC1\u79FB\u6216\u51C0\u5316\u65E7\u7248\u51ED\u636E"," version \u8F93\u51FA\u5F53\u524D CLI \u7248\u672C\u53F7"," app create \u5728\u4E91\u7AEF\u521B\u5EFA\u5E94\u7528\uFF0C\u5E76 checkout \u5230\u672C\u5730\u65B0\u76EE\u5F55"," app checkout \u4ECE\u4E91\u7AEF checkout \u5E94\u7528\u6E90\u7801\u526F\u672C\u5230\u672C\u5730\u65B0\u76EE\u5F55"," app submit \u5C06\u5F53\u524D\u672C\u5730\u6E90\u7801\u63D0\u4EA4\u4E3A\u65B0\u7684\u4E91\u7AEF\u6E90\u7801\u7248\u672C"," app version create \u5728\u5F53\u524D app \u4E0B\u57FA\u4E8E\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u65B0\u7684\u6E90\u7801\u7248\u672C\u9AA8\u67B6"," app version list \u67E5\u770B\u5E94\u7528\u7684\u6E90\u7801\u7248\u672C\u5217\u8868"," app versions \u67E5\u770B\u5E94\u7528\u7684\u6E90\u7801\u7248\u672C\u5217\u8868"," app status \u67E5\u770B\u5E94\u7528\u63A7\u5236\u9762\u603B\u89C8\uFF08\u542B Auth / DB / \u7248\u672C\u6982\u51B5\uFF09"," app diagnose \u67E5\u770B\u5E94\u7528\u662F\u5426\u5DF2 ready for runtime validation"," app preflight \u4E00\u6B21\u6027\u6267\u884C whoami / app current / app diagnose \u98CE\u683C\u68C0\u67E5"," app sync-platform-blocks \u540C\u6B65\u53CC\u6A21\u677F\u5E73\u53F0\u7EF4\u62A4\u533A\uFF08dry-run / adopt / apply / rollback --last\uFF09"," app import preprocess \u9884\u5904\u7406\u7B2C\u4E09\u65B9\u8BBE\u8BA1\u6E90\u7801\u5305\uFF0C\u751F\u6210 clean-source \u4E0E\u62A5\u544A"," app import stage \u628A clean-source \u4E0E\u62A5\u544A stage \u5230\u6A21\u677F\u5DE5\u4F5C\u533A"," app import merge \u628A\u4E0A\u6E38 src \u5B89\u5168\u5E76\u5165 src/imported-upstream/"," app scaffold \u6309\u9700\u6CE8\u5165\u672C\u5730 debug scaffold\uFF08auth/workflow/cms/db\uFF09"," app-library \u7BA1\u7406\u8F7B\u5E94\u7528\u8D44\u6E90\u5E93 example-app \u6761\u76EE"," app use \u517C\u5BB9\u8DEF\u5F84\uFF1A\u4E3A init/link/dev \u9009\u62E9\u76EE\u6807\u5E94\u7528"," app current \u67E5\u770B\u5F53\u524D\u5DF2\u9009\u5E94\u7528\u4E0A\u4E0B\u6587"," tenant use <id> \u8BBE\u7F6E\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587"," tenant current \u67E5\u770B\u5F53\u524D\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587",...envCommandLines," whoami \u8C03\u7528 Control API \u8F93\u51FA\u5F53\u524D\u4E3B\u4F53"," preview \u9ED8\u8BA4\u6253\u5F00\u5F53\u524D\u53EF\u7528 Preview\uFF1B\u751F\u6210\u8BF7\u7528 `platform preview generate`"," init [name] \u751F\u6210\u9879\u76EE\u9AA8\u67B6\uFF0C\u5E76\u81EA\u52A8\u5199\u5165\u5DF2\u9009\u5E94\u7528\u7ED1\u5B9A"," link \u7ED1\u5B9A tenant/app/env \u5230\u5F53\u524D\u5E94\u7528\u76EE\u5F55"," dev \u9ED8\u8BA4\u8F7B\u91CF\u5F00\u53D1\u5165\u53E3\uFF1A\u6CE8\u5165\u7ED1\u5B9A\u540E\u542F\u52A8\u672C\u5730\u5F00\u53D1\u6001"," dev push \u5C06\u5F53\u524D\u672C\u5730\u6E90\u7801\u8986\u76D6\u63A8\u9001\u5230\u4E91\u7AEF Dev Workspace"," dev preview generate \u57FA\u4E8E\u4E91\u7AEF Dev Workspace \u751F\u6210\u5DE5\u4F5C\u533A Preview"," auth \u7BA1\u7406 Auth \u57FA\u5EA7\u80FD\u529B\uFF08discover / configure / bind / inspect\uFF09"," cms \u7BA1\u7406 CMS \u57FA\u5EA7\u80FD\u529B\uFF08discover / configure / apply / inspect\uFF09"," asset \u7BA1\u7406\u79DF\u6237\u5171\u4EAB\u7D20\u6750\uFF08upload / list / folder / get / update / analyze / move / open / tag\uFF09"," blob \u7BA1\u7406 Object Storage Blob\uFF08upload / list / get / url\uFF09"," db \u67E5\u770B DB \u72B6\u6001\u3001\u8868\u7ED3\u6784\u4E0E\u53EA\u8BFB\u67E5\u8BE2"," data-form \u6821\u9A8C/\u7F16\u8BD1/apply/query Data Form schema \u4E0E\u8BB0\u5F55"," workflow \u7BA1\u7406 Workflow \u57FA\u5EA7\u80FD\u529B\uFF08template / definition / binding / runtime\uFF09"," notification \u7BA1\u7406 Notification \u57FA\u5EA7\u80FD\u529B\uFF08inbox / announce / delivery\uFF09"," publish \u7BA1\u7406\u5E94\u7528\u6B63\u5F0F\u53D1\u5E03\u72B6\u6001\u4E0E\u5F53\u524D\u90E8\u7F72\u7248\u672C"," resources \u6267\u884C\u8D44\u6E90 diff/apply/rollback"," logs \u67E5\u8BE2\u8FD0\u884C\u65F6\u65E5\u5FD7\uFF0C\u652F\u6301 --follow"," diagnostics \u5E73\u53F0\u672C\u5730\u8BCA\u65AD\uFF08control-api / credentials\uFF09"," worker \u542F\u52A8\u5E73\u53F0\u540E\u53F0 worker\uFF08preview-retention\uFF09","","Advanced commands:"," build \u9AD8\u7EA7\u8BCA\u65AD\u5165\u53E3\uFF1A\u53D1\u8D77\u548C\u67E5\u8BE2 build"," deploy \u8FC7\u6E21\u5165\u53E3\uFF1A\u9AD8\u7EA7\u53D1\u5E03\uFF08artifact / promote\uFF09"," rollback \u8FC7\u6E21\u5165\u53E3\uFF1A\u56DE\u6EDA\u5230\u76EE\u6807 release \u6216\u7248\u672C","","App commands:"," platform app create --tenant <tenant-id> --name <display-name> --dir <project-name> [--template frontend-app-vite|backend-app-node]"," platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>"," platform app checkout --tenant <tenant-id> --app <app-id> --source-version <srcver>",' platform app submit --message "local iteration"',' platform app version create --message "switch template" --template backend-app-node'," platform app versions --tenant <tenant-id> --app <app-id>"," platform app status [--tenant <tenant-id>] [--app <app-id>] [--env preview|prod]"," platform app sync-platform-blocks [--dry-run|--adopt|--apply|--rollback --last]"," platform app diagnose [--tenant <tenant-id>] [--app <app-id>] [--env preview|prod]"," platform app import preprocess [--dir <third-party-source-dir>] [--dry-run]"," platform app import stage --preprocess <source-dir|.design-preprocess|reports|import-manifest.json>"," platform app import merge [--workspace-dir <template-workspace-dir>]"," platform app scaffold <auth-debug|workflow-debug|cms-debug|db-debug>"," platform app-library list"," platform app-library config init"," platform app-library inspect entry-demo"," platform app-library checkout entry-demo --dir ./example-app-demo",' platform app-library create --name "Data Form Verify" --summary "\u672C\u5730\u9A8C\u8BC1\u540E\u7684\u793A\u4F8B\u5E94\u7528"'," platform app-library submit entry-demo"," platform app use --tenant <tenant-id> --app <app-id> --env preview"," platform app current","","DB commands:"," platform db status"," platform db history --limit 10"," platform db migrate [--dry-run]"," platform db tables",' platform db query --sql "SELECT ... LIMIT 5"'," platform db open","","Auth commands:"," platform auth discover [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth configure [--tenant <tenant-id>] [--app <app-id>] --enable [--template <template>] [--user-store-id <id>] [--enable-admin-password|--disable-admin-password] [--enable-phone-sms-otp|--disable-phone-sms-otp] [--json]"," platform auth bind [--tenant <tenant-id>] [--app <app-id>] [--action bind|rebind|disable] [--user-store-id <id>] [--json]"," platform auth inspect [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth role list [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth role create [--tenant <tenant-id>] [--app <app-id>] --key <role-key> --name <display-name> [--description <text>] [--status active|disabled] [--json]"," platform auth role inspect [--tenant <tenant-id>] [--app <app-id>] --role <role-key> [--json]"," platform auth role update [--tenant <tenant-id>] [--app <app-id>] --role <role-key> [--name <display-name>] [--description <text> | --clear-description] [--status active|disabled] [--json]"," platform auth user-role list [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> [--json]"," platform auth user-role assign [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --roles role-a,role-b [--json]"," platform auth user-role replace [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --roles role-a,role-b [--json]"," platform auth user-role remove [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --role <role-key> [--json]","","CMS commands:"," platform cms discover [--collection <name>] [--json]"," platform cms configure collection --file <spec.json> [--json]"," platform cms configure item --file <item.json> [--item-id <item-id>] [--json]"," platform cms configure category --collection <name> --name <name> --slug <slug> [--parent-id <id>] [--order <n>] [--json]"," platform cms import markdown <file> [--collection <name>] [--item-id <item-id> | --item-id-prefix <prefix>] [--tags <label,label>] [--category-path <segment/segment>] [--cover-asset-id <asset-id>] [--publish | --publish-status draft|published|archived] [--skip-existing] [--dry-run] [--json]"," platform cms import url <url> [--collection <name>] [--item-id <item-id>] [--tags <label,label>] [--category-path <segment/segment>] [--publish | --publish-status draft|published|archived] [--skip-existing] [--no-assetize-images] [--dry-run] [--json]"," platform cms attach asset --collection <name> --item-id <id> --field <field-name> --asset-id <id[,id]> [--replace] [--json]"," platform cms ensure category --collection <name> --path <segment/segment> [--json]"," platform cms list items --collection <name> [--page <n>] [--page-size <n>] [--status draft|published|archived] [--category-id <id>] [--q <keyword>] [--json]"," platform cms batch update --collection <name> --item-id <id[,id]> [--category-id <id> | --clear-category] [--add-tags <label,label>] [--status draft|published|archived] [--json]"," platform cms apply schema --collection <name> --version <n> [--json]"," platform cms apply publish --collection <name> --item-id <id> --status draft|published|archived [--json]"," platform cms inspect schema --collection <name> [--json]"," platform cms inspect item --collection <name> --id <id> [--json]"," platform cms inspect delivery list --collection <name> [--page <n>] [--page-size <n>] [--tag <tag>] [--category-id <id>] [--json]"," platform cms inspect delivery get --collection <name> (--slug <slug> | --id <id>) [--json]"," platform cms inspect delivery categories --collection <name> [--json]","","Asset commands:"," platform asset upload <file-path> [--title <title>] [--folder-id <folder-id>]"," platform asset list [--q <keyword>] [--media-type image|video] [--folder-id <folder-id>] [--page <n>] [--limit <n>]"," platform asset folder list"," platform asset folder create <name> [--parent-folder-id <folder-id>]"," platform asset folder rename <folder-id> --name <name> [--parent-folder-id <folder-id> | --root]"," platform asset get <asset-id>"," platform asset move <asset-id> [--folder-id <folder-id> | --root]"," platform asset update <asset-id> [--title <title>] [--folder-id <folder-id> | --root] [--tags <label,label>]"," platform asset analyze <asset-id> [--json]"," platform asset open <asset-id> [--output <path>]"," platform asset download <asset-id> --variant thumbnail|sm|md|lg|cover [--output <path>]"," platform asset tag list [--asset <asset-id>]"," platform asset tag add <asset-id> <label>"," platform asset tag remove <asset-id> <label>","","Preview commands:"," platform preview"," platform preview open [--source-version <srcver>]"," platform preview generate [--source-version <srcver>]"," platform preview generate --from-build <build-id>","","Publish commands:"," platform publish"," platform publish status"," platform publish set [--source-version <srcver>] [--status published|unpublished]"," platform publish rollback <srcver>","","Workflow commands:"," platform workflow template list"," platform workflow template inspect --template <key>"," platform workflow definition list [--status draft|active|inactive]"," platform workflow definition inspect --definition <key>"," platform workflow definition create --definition <key> --app <app-id> [--template <template-key> | --object-type <type> --schema <json>]"," platform workflow binding list [--app <app-id>] [--definition <key>]"," platform workflow binding inspect --definition <key> [--target-id <id>]"," platform workflow binding update --definition <key> [--target-id <id>] --file <override.json>"," platform workflow role bind --definition <key> --app <app-id> --file <bindings.json> # \u4F4E\u5C42\u9AD8\u7EA7\u5165\u53E3"," platform workflow diagnose [--app <app-id>]"," platform workflow start --definition <key> --object-type <type> --object-id <id>"," platform workflow action --instance <instance-id> --action <action-key>"," platform workflow tasks [--status pending]"," platform workflow instance <instance-id>","","Notification commands:"," platform notification inbox list [--app <app-id>] [--type task_projection|announcement|notification|alert] [--status unread|read|dismissed|archived] [--limit <n>]"," platform notification inbox update <item-id> --status unread|read|dismissed|archived"," platform notification announce platform --tenant <tenant-id> --title <text> [--body <text>] [--level info|success|warning|error]"," platform notification announce app --tenant <tenant-id> --app <app-id> --title <text> [--body <text>] [--level info|success|warning|error]"," platform notification delivery [--app <app-id>] [--status pending|running|succeeded|failed|dead]"," platform notification end-user users --app <app-id>"," platform notification end-user inbox --app <app-id> --end-user <app-user-id> [--type task_projection|announcement|notification|alert] [--status unread|read|dismissed|archived] [--limit <n>]"," platform notification end-user unread --app <app-id> --end-user <app-user-id>"," platform notification end-user publish --app <app-id> --end-user <app-user-id> --title <text> [--body <text>] [--kind notification|alert|announcement]"," platform notification end-user announcement --app <app-id> --end-user <app-user-id> --title <text> --body <text>"," platform notification end-user reminder --app <app-id> --end-user <app-user-id> --title <text> --remind-at <ISO datetime> [--body <text>]","","Advanced release commands:"," platform deploy [--source-version <srcver>] [--prod]"," platform rollback <release-id|version>","","Advanced build commands:"," platform build run --source-version <srcver>"," platform build get <build-id>"," platform build events <build-id>"," platform build validate --app <app-id> --source-version <srcver>"," platform logs --follow"," platform diagnostics control-api [--json]"," platform diagnostics credentials [--json] [--strict]"," platform worker preview-retention [--once] [--dry-run] [--json]","","Resource commands:"," platform resources diff --base-snapshot <rsnap-id>"," platform resources apply --base-snapshot <rsnap-id>"," platform resources rollback <rsnap-id> --approve-id <approve-id>","","Examples:"," platform login"," platform login --pat <personal-access-token>"," platform env use local"," platform env use test"," platform env current",' platform app create --tenant t-default --name "\u6D3B\u52A8\u9080\u8BF7\u51FD" --dir invite-frontend',' platform app create --tenant t-default --name "\u62A5\u540D\u52A9\u624B" --dir signup-runtime --template backend-app-node',' platform app create --tenant t-default --name "\u8425\u9500\u9875" --dir landing-page --template frontend-app-vite',' platform app create --tenant t-default --name "\u4E1A\u52A1\u540E\u53F0" --dir ops-console --template backend-app-node'," platform app checkout --tenant t-default --app app-demo --dir app-demo"," platform app checkout --tenant t-default --app app-demo --source-version srcver-123",' platform app submit --message "local iteration"'," platform dev push"," platform dev preview generate"," platform dev preview open",' platform asset upload ./logo.png --title "\u54C1\u724C Logo"'," platform asset folder create \u54C1\u724C\u7D20\u6750"," platform asset folder rename asset-folder-123 --name \u54C1\u724C\u89C6\u89C9 --root"," platform asset folder list"," platform asset list --q logo --tag-ids tag-1,tag-2 --page 2"," platform asset get asset-123"," platform asset move asset-123 --folder-id asset-folder-123",' platform asset update asset-123 --title "\u9996\u9875 Hero \u56FE" --scene outdoor --tags hero,homepage'," platform asset analyze asset-123"," platform asset open asset-123"," platform asset download asset-123 --variant md"," platform asset tag list --asset asset-123"," platform asset tag add asset-123 logo"," platform asset tag remove asset-123 logo"," platform app versions --tenant t-default --app app-demo"," platform whoami --tenant t-default"," platform build get build-123"," platform build events build-123"," platform build run --source-version srcver-123"," platform build validate --app app-demo --source-version srcver-123"," platform preview"," platform preview open --source-version srcver-123"," platform preview generate"," platform preview generate --source-version srcver-123"," platform publish"," platform publish status"," platform publish set --status unpublished"," platform publish set --source-version srcver-123 --status published"," platform publish rollback srcver-122"," cd signup-lite && platform dev"," cd signup-lite && platform dev push"," cd signup-lite && platform dev preview generate"," cd signup-lite && platform dev preview open"," platform deploy --source-version srcver-123"," platform deploy --prod"," platform rollback v0.2.0","","Other examples:"," platform app current"," platform tenant use t-default"," platform tenant current"," platform db status"," platform db history --limit 10"," platform db tables",' platform db query --sql "SELECT * FROM example_items LIMIT 5"'," platform auth discover --app app-demo"," platform auth configure --app app-demo --enable --template email_magic_link_only"," platform auth configure --app app-demo --enable --template phone_sms_otp_only"," platform auth configure --app app-demo --enable --template email_magic_link_and_phone_sms_otp"," platform auth configure --app app-demo --enable --enable-phone-sms-otp"," platform auth bind --app app-checkin --action bind --user-store-id us_xxx"," platform auth inspect --app app-demo --json"," platform cms discover"," platform cms discover --collection article"," platform cms configure collection --file ./cms/article.collection.json"," platform cms configure item --file ./cms/article.item.json"," platform cms import markdown ./docs/post.md --collection article --tags cms,agent --category-path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03 --cover-asset-id asset-123 --publish"," platform cms import url https://zhuanlan.zhihu.com/p/488185988 --collection article --tags cms,url --dry-run"," platform cms import url https://example.com/post --collection article --no-assetize-images"," platform cms import markdown ./docs/articles --collection article --recursive --item-id-prefix article-doc --skip-existing"," platform cms import markdown ./docs/post.md --collection article --category-path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03 --dry-run --json"," platform cms import markdown ./docs/post.md --collection article --skip-existing --publish"," platform cms attach asset --collection article --item-id cms-item-123 --field cover --asset-id asset-123"," platform cms ensure category --collection article --path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03"," platform cms list items --collection article --status draft"," platform cms batch update --collection article --item-id item-a,item-b --category-id cms-category-123 --add-tags cms,cli --status published"," platform cms apply schema --collection article --version 1"," platform cms inspect schema --collection article --json"," platform cms inspect item --collection article --id cms-item-123"," platform cms inspect delivery list --collection article --tag cms"," platform cms inspect delivery get --collection article --slug introducing-cms-base"," platform resources diff --base-snapshot rsnap-123"," platform resources apply --base-snapshot rsnap-123"," platform resources rollback rsnap-122 --approve-id approve-123"," platform logs --follow","","Compatible path examples:"," platform app use --tenant t-default --app app-demo --env preview"," platform init demo-app"," platform link --tenant t-default --app app-demo --env preview"," platform dev --target tenant-workbench"," platform dev --remote-bindings"," platform dev --remote-bindings=db",""].join(`
2741
2741
  `))}function printVersion(){process7.stdout.write(`v${cliPackageVersion}
2742
2742
  `)}function normalizeAppTemplateOption(value){return normalizeAppTemplateKey(value)}function readRequiredEnv(key){let value=process7.env[key];if(!value||value.trim().length===0)throw new Error(`\u7F3A\u5C11\u73AF\u5883\u53D8\u91CF: ${key}`);return value.trim()}function resolveBrowserLoginConfig(){let cliClientId=readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS),cliRedirectUri=readAuthConfigValue(AUTH_CLI_REDIRECT_URI_KEYS);if(cliClientId&&cliRedirectUri)return{clientId:cliClientId,redirectUri:cliRedirectUri,source:"cli-app"};let fallbackClientId=readAuthConfigValue(AUTH_TENANT_CLIENT_ID_KEYS),fallbackRedirectUri=readAuthConfigValue(AUTH_TENANT_REDIRECT_URI_KEYS);return!fallbackClientId||!fallbackRedirectUri?null:{clientId:fallbackClientId,redirectUri:fallbackRedirectUri,source:"workbench-fallback"}}function shouldFallbackToBrowserLogin(error){if(!(error instanceof Error))return!1;let message=error.message;return message.includes("OIDC discovery \u7F3A\u5C11 Device Flow \u7AEF\u70B9")||message.includes("device_code is not allowed for this client")||message.includes("grant-type:device_code is not allowed for this client")}function readOption2(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function hasFlag2(args,key){return args.options[key]===!0}function printDiagnosticsHelp(){process7.stdout.write(["platform diagnostics","","\u7528\u6CD5\uFF1A"," platform diagnostics control-api [--json]"," platform diagnostics credentials [--json] [--strict]","","\u8BF4\u660E\uFF1A"," \u8F93\u51FA control/runtime/public endpoint \u5206\u533A\u8BCA\u65AD\uFF0C\u4E0D\u6539\u53D8\u9ED8\u8BA4 URL\u3002"," runtime/public endpoint \u4EC5\u5728\u914D\u7F6E\u5B58\u5728\u4E14 capability allowlist \u547D\u4E2D\u65F6\u63A2\u6D4B\u3002"," credentials \u53EA\u8F93\u51FA\u5B58\u50A8\u540E\u7AEF\u3001state \u8DEF\u5F84\u548C\u6743\u9650\u5224\u65AD\uFF0C\u4E0D\u8BFB\u53D6\u6216\u8F93\u51FA token\u3002"," credentials warning \u9ED8\u8BA4\u9000\u51FA\u7801\u4E3A 0\uFF1B\u4EC5\u663E\u5F0F --strict \u8FD4\u56DE\u975E\u96F6\u3002","","\u73AF\u5883\u53D8\u91CF\uFF1A"," CONTROL_API_BASE_URL"," RUNTIME_API_BASE_URL"," PUBLIC_API_BASE_URL"," CONTROL_API_RUNTIME_ENDPOINT_CAPABILITIES",""].join(`
2743
2743
  `))}async function runDiagnostics(args){let subcommand=args.rest[0]??"help";if(hasFlag2(args,"help")||hasFlag2(args,"h")||subcommand==="help"){printDiagnosticsHelp();return}if(subcommand==="credentials"){let diagnostics2=inspectStoredCredentialSecurity();args.options.json===!0?process7.stdout.write(`${JSON.stringify(diagnostics2,null,2)}
@@ -2753,15 +2753,14 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
2753
2753
  `):process7.stdout.write(`\u51ED\u636E\u8FC1\u79FB\u672A\u5B8C\u6210\uFF0C\u539F\u6709\u53EF\u7528\u767B\u5F55\u6001\u5DF2\u4FDD\u7559\u3002
2754
2754
  \u5F53\u524D\u5B58\u50A8\u540E\u7AEF: ${result.backend}
2755
2755
  \u5EFA\u8BAE\uFF1A\u8FD0\u884C \`platform diagnostics credentials\` \u540E\u91CD\u8BD5\u3002
2756
- `),result.status==="failed"&&(process7.exitCode=2)}function printLogoutHelp(){process7.stdout.write(["platform logout","","\u7528\u6CD5\uFF1A"," platform logout [--json]","","\u8BF4\u660E\uFF1A"," \u6E05\u7406\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u3001\u517C\u5BB9\u51ED\u636E\u6587\u4EF6\u548C\u5168\u5C40 tenant/app \u9009\u62E9\u4E0A\u4E0B\u6587\u3002"," \u4FDD\u7559 environment profile \u548C\u9879\u76EE\u5185 .platform/source-context.json \u7ED1\u5B9A\u3002"," \u672C\u547D\u4EE4\u53EA\u6E05\u7406\u672C\u5730\u72B6\u6001\uFF0C\u4E0D\u64A4\u9500\u6D4F\u89C8\u5668 SSO \u6216\u670D\u52A1\u7AEF token\u3002",""].join(`
2756
+ `),result.status==="failed"&&(process7.exitCode=2)}function printLogoutHelp(){process7.stdout.write(["platform logout","","\u7528\u6CD5\uFF1A"," platform logout [--json]","","\u8BF4\u660E\uFF1A"," \u6E05\u7406\u672C\u5730\u51ED\u636E\u548C\u5168\u5C40 tenant/app \u9009\u62E9\u4E0A\u4E0B\u6587\u3002"," \u4FDD\u7559 environment profile \u548C\u9879\u76EE\u5185 .platform/source-context.json \u7ED1\u5B9A\u3002"," \u672C\u547D\u4EE4\u53EA\u6E05\u7406\u672C\u5730\u72B6\u6001\uFF0C\u4E0D\u64A4\u9500\u6D4F\u89C8\u5668 SSO \u6216\u670D\u52A1\u7AEF token\u3002",""].join(`
2757
2757
  `))}async function runLogout(args){if(hasFlag2(args,"help")||hasFlag2(args,"h")){printLogoutHelp();return}if(args.rest.length>0)throw printLogoutHelp(),new Error(`\u672A\u77E5 logout \u53C2\u6570: ${args.rest.join(" ")}`);let unsupportedOptions=Object.entries(args.options).filter(([key,value])=>!["help","h","json"].includes(key)||value!==!0);if(unsupportedOptions.length>0)throw new Error(`logout \u4E0D\u652F\u6301\u53C2\u6570: ${unsupportedOptions.map(([key])=>`--${key}`).join(", ")}\u3002\u672C\u6B21\u672A\u6267\u884C\u4EFB\u4F55\u6E05\u7406\uFF1B\u53EF\u8FD0\u884C \`platform logout --help\` \u67E5\u770B\u7528\u6CD5\u3002`);let result=clearStoredAuthentication(),stateDir=getCliStateDir(),output={status:result.status,state_dir:stateDir,cleared:result.cleared,failed:result.failed,preserved:["environment_profile","project_source_context"]};hasFlag2(args,"json")?process7.stdout.write(`${JSON.stringify(output,null,2)}
2758
2758
  `):process7.stdout.write([result.status==="cleared"?"\u672C\u5730 CLI \u767B\u5F55\u6001\u5DF2\u6E05\u7406\u3002":"\u672C\u5730 CLI \u767B\u5F55\u6001\u5DF2\u90E8\u5206\u6E05\u7406\u3002",`state \u76EE\u5F55: ${stateDir}`,"\u5DF2\u4FDD\u7559: environment profile\u3001\u9879\u76EE\u5185 .platform/source-context.json",...result.failed.length>0?[`\u672A\u6E05\u7406\u9879: ${result.failed.map(item=>item.target).join(", ")}`,"\u5EFA\u8BAE\uFF1A\u5173\u95ED\u5360\u7528\u7A0B\u5E8F\u6216\u89E3\u9501\u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u540E\u91CD\u8BD5 `platform logout`\u3002"]:[],""].join(`
2759
- `)),result.status==="partial"&&(process7.exitCode=2)}async function runLogin(args){let issuer=readRequiredEnv("OIDC_ISSUER"),audience=process7.env.OIDC_AUDIENCE?.trim(),scopes=(process7.env.LOGTO_CLI_SCOPES??"openid profile offline_access").split(/\s+/u).filter(Boolean),cliClientId=readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS),browserLoginConfig=resolveBrowserLoginConfig(),pat=readOption2(args,"pat")?.trim(),credentials;if(pat){if(!cliClientId)throw new Error("`platform login --pat` \u9700\u8981\u5DF2\u914D\u7F6E `AUTH_CLI_CLIENT_ID`\uFF08\u6216\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_APP_ID`\uFF09\u3002");credentials=await performPatTokenExchangeLogin({issuer,clientId:cliClientId,audience,scopes,subjectToken:pat});let persistence2=persistCredentials(credentials);process7.stdout.write(["PAT \u767B\u5F55\u5DF2\u5B8C\u6210\u3002",`\u51ED\u636E\u5B58\u50A8\u540E\u7AEF: ${persistence2.backend}`,...persistence2.backend==="file"?[`\u517C\u5BB9\u51ED\u636E\u6587\u4EF6: ${getCredentialPath()}`]:[],"\u8BF4\u660E: \u5F53\u524D\u4E3A\u673A\u5668\u51ED\u636E\u6A21\u5F0F\uFF0CCLI \u4F1A\u5728 7 \u5929\u7A97\u53E3\u5185\u81EA\u52A8\u91CD\u65B0\u4EA4\u6362 access token\u3002",...persistence2.backend==="file"?["\u6CE8\u610F: \u7CFB\u7EDF\u5B89\u5168\u5B58\u50A8\u4E0D\u53EF\u7528\uFF0C\u539F\u59CB PAT \u672A\u5199\u5165\u6587\u4EF6\uFF1B\u5F53\u524D access token \u5230\u671F\u540E\u9700\u91CD\u65B0\u767B\u5F55\u3002"]:[],"\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A"," 1. platform whoami"," 2. \u5982\u9700\u957F\u671F\u4EBA\u5DE5\u5F00\u53D1\uFF0C\u4F18\u5148\u6539\u7528 `platform login` \u6D4F\u89C8\u5668\u767B\u5F55",""].join(`
2759
+ `)),result.status==="partial"&&(process7.exitCode=2)}async function runLogin(args){let issuer=readRequiredEnv("OIDC_ISSUER"),audience=process7.env.OIDC_AUDIENCE?.trim(),scopes=(process7.env.LOGTO_CLI_SCOPES??"openid profile offline_access").split(/\s+/u).filter(Boolean),cliClientId=readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS),browserLoginConfig=resolveBrowserLoginConfig(),pat=readOption2(args,"pat")?.trim(),credentials;if(pat){if(!cliClientId)throw new Error("`platform login --pat` \u9700\u8981\u5DF2\u914D\u7F6E `AUTH_CLI_CLIENT_ID`\uFF08\u6216\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_APP_ID`\uFF09\u3002");credentials=await performPatTokenExchangeLogin({issuer,clientId:cliClientId,audience,scopes,subjectToken:pat});let persistence2=persistCredentials(credentials);process7.stdout.write(["PAT \u767B\u5F55\u5DF2\u5B8C\u6210\u3002",`\u51ED\u636E\u5B58\u50A8\u540E\u7AEF: ${persistence2.backend}`,...persistence2.backend==="file"?["\u6CE8\u610F: \u4E3A\u5B89\u5168\u8D77\u89C1\u4E0D\u4F1A\u4FDD\u5B58\u539F\u59CB PAT\uFF0C\u5F53\u524D access token \u5230\u671F\u540E\u9700\u91CD\u65B0\u767B\u5F55\u3002"]:["\u8BF4\u660E: \u5F53\u524D\u4E3A\u673A\u5668\u51ED\u636E\u6A21\u5F0F\uFF0CCLI \u4F1A\u5728 7 \u5929\u7A97\u53E3\u5185\u81EA\u52A8\u91CD\u65B0\u4EA4\u6362 access token\u3002"],"\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A"," 1. platform whoami"," 2. \u5982\u9700\u957F\u671F\u4EBA\u5DE5\u5F00\u53D1\uFF0C\u4F18\u5148\u6539\u7528 `platform login` \u6D4F\u89C8\u5668\u767B\u5F55",""].join(`
2760
2760
  `));return}if(cliClientId)try{credentials=await performDeviceCodeLogin({issuer,clientId:cliClientId,audience,scopes,onPrompt:async({verificationUri,userCode,expiresIn})=>{let{opened}=await openExternal(verificationUri);process7.stdout.write((opened?["\u5DF2\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u5B8C\u6210\u767B\u5F55\u6388\u6743\u3002",""]:["\u8BF7\u5728\u6D4F\u89C8\u5668\u5B8C\u6210\u767B\u5F55\u6388\u6743\u3002",`\u9A8C\u8BC1\u5730\u5740: ${verificationUri}`,`User Code: ${userCode}`,`\u6709\u6548\u671F: ${expiresIn} \u79D2`,""]).join(`
2761
- `))}})}catch(error){if(!shouldFallbackToBrowserLogin(error))throw error;if(process7.stdout.write(`\u5F53\u524D\u73AF\u5883\u4E0D\u53EF\u7528 Device Flow\uFF0C\u81EA\u52A8\u5207\u6362\u5230\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\u3002
2762
- `),!browserLoginConfig)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11\u53EF\u7528\u4E8E\u6D4F\u89C8\u5668\u767B\u5F55\u7684\u914D\u7F6E\uFF0C\u8BF7\u8865\u9F50 `AUTH_CLI_REDIRECT_URI`\uFF08\u6216\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_REDIRECT_URI`\uFF09\uFF0C\u6216\u63D0\u4F9B `AUTH_TENANT_CLIENT_ID / AUTH_TENANT_REDIRECT_URI`\uFF08\u65E7\u540D `LOGTO_TENANT_*`\uFF09\u4F5C\u4E3A\u56DE\u9000\u3002");credentials=await performAuthorizationCodeLogin({issuer,clientId:browserLoginConfig.clientId,redirectUri:browserLoginConfig.redirectUri,audience,scopes,prompt:"login",onPrompt:async({authorizationUrl,redirectUri})=>{let{opened}=await openExternal(authorizationUrl);process7.stdout.write(formatAuthorizationCodeLoginPrompt({opened,authorizationUrl,redirectUri,source:browserLoginConfig.source}))}})}else{if(!browserLoginConfig)throw new Error("\u7F3A\u5C11\u6D4F\u89C8\u5668\u767B\u5F55\u914D\u7F6E\uFF1A\u8BF7\u4F18\u5148\u8865\u9F50 `AUTH_CLI_CLIENT_ID / AUTH_CLI_REDIRECT_URI`\uFF08\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_*`\uFF09\uFF1B\u82E5\u6682\u65F6\u65E0\u6CD5\u63D0\u4F9B\uFF0C\u518D\u8865\u9F50 `AUTH_TENANT_CLIENT_ID / AUTH_TENANT_REDIRECT_URI`\uFF08\u517C\u5BB9\u65E7\u540D `LOGTO_TENANT_*`\uFF09\u4F5C\u4E3A\u56DE\u9000\u3002");process7.stdout.write(browserLoginConfig.source==="cli-app"?`\u5F53\u524D\u4F7F\u7528\u4E13\u7528 CLI App \u6267\u884C\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\uFF0C\u5E76\u81EA\u52A8\u9644\u5E26 consent \u4EE5\u6362\u53D6 refresh token\u3002
2761
+ `))}})}catch(error){if(!shouldFallbackToBrowserLogin(error))throw error;if(!browserLoginConfig)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11\u53EF\u7528\u4E8E\u6D4F\u89C8\u5668\u767B\u5F55\u7684\u914D\u7F6E\uFF0C\u8BF7\u8865\u9F50 `AUTH_CLI_REDIRECT_URI`\uFF08\u6216\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_REDIRECT_URI`\uFF09\uFF0C\u6216\u63D0\u4F9B `AUTH_TENANT_CLIENT_ID / AUTH_TENANT_REDIRECT_URI`\uFF08\u65E7\u540D `LOGTO_TENANT_*`\uFF09\u4F5C\u4E3A\u56DE\u9000\u3002");credentials=await performAuthorizationCodeLogin({issuer,clientId:browserLoginConfig.clientId,redirectUri:browserLoginConfig.redirectUri,audience,scopes,prompt:"login",onPrompt:async({authorizationUrl,redirectUri})=>{let{opened}=await openExternal(authorizationUrl);process7.stdout.write(formatAuthorizationCodeLoginPrompt({opened,authorizationUrl,redirectUri,source:browserLoginConfig.source}))}})}else{if(!browserLoginConfig)throw new Error("\u7F3A\u5C11\u6D4F\u89C8\u5668\u767B\u5F55\u914D\u7F6E\uFF1A\u8BF7\u4F18\u5148\u8865\u9F50 `AUTH_CLI_CLIENT_ID / AUTH_CLI_REDIRECT_URI`\uFF08\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_*`\uFF09\uFF1B\u82E5\u6682\u65F6\u65E0\u6CD5\u63D0\u4F9B\uFF0C\u518D\u8865\u9F50 `AUTH_TENANT_CLIENT_ID / AUTH_TENANT_REDIRECT_URI`\uFF08\u517C\u5BB9\u65E7\u540D `LOGTO_TENANT_*`\uFF09\u4F5C\u4E3A\u56DE\u9000\u3002");process7.stdout.write(browserLoginConfig.source==="cli-app"?`\u5F53\u524D\u4F7F\u7528\u4E13\u7528 CLI App \u6267\u884C\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\uFF0C\u5E76\u81EA\u52A8\u9644\u5E26 consent \u4EE5\u6362\u53D6 refresh token\u3002
2763
2762
  `:`\u672A\u914D\u7F6E\u5B8C\u6574\u4E13\u7528 CLI \u6D4F\u89C8\u5668\u767B\u5F55\u53C2\u6570\uFF0C\u81EA\u52A8\u56DE\u9000\u590D\u7528 workbench \u767B\u5F55\u914D\u7F6E\uFF0C\u5E76\u5F3A\u5236 prompt=login consent\u3002
2764
- `),credentials=await performAuthorizationCodeLogin({issuer,clientId:browserLoginConfig.clientId,redirectUri:browserLoginConfig.redirectUri,audience,scopes,prompt:"login",onPrompt:async({authorizationUrl,redirectUri})=>{let{opened}=await openExternal(authorizationUrl);process7.stdout.write(formatAuthorizationCodeLoginPrompt({opened,authorizationUrl,redirectUri,source:browserLoginConfig.source}))}})}let persistence=persistCredentials({...credentials,credential_mode:"interactive"}),autoSelectedTenant=null,autoSelectionNote=null;try{let workspaces=await listTenantWorkspaces({baseUrl:getControlApiBaseUrl(),accessToken:selectApiToken(credentials)});autoSelectedTenant=chooseDefaultTenantWorkspace(workspaces.items),autoSelectedTenant?persistActiveTenantSelection(autoSelectedTenant):workspaces.items.length>1&&(autoSelectionNote="\u68C0\u6D4B\u5230\u591A\u4E2A\u53EF\u7528\u79DF\u6237\uFF0C\u672A\u81EA\u52A8\u5207\u6362\u9ED8\u8BA4\u79DF\u6237\uFF1B\u8BF7\u6267\u884C `platform tenant use <tenant-id>`\u3002")}catch(error){autoSelectionNote=`\u9ED8\u8BA4\u79DF\u6237\u81EA\u52A8\u9009\u62E9\u5931\u8D25\uFF1A${error.message}`}process7.stdout.write(["\u767B\u5F55\u5DF2\u5B8C\u6210\u3002",`\u51ED\u636E\u5B58\u50A8\u540E\u7AEF: ${persistence.backend}`,...persistence.backend==="file"?[`\u517C\u5BB9\u51ED\u636E\u6587\u4EF6: ${getCredentialPath()}`]:[],...autoSelectedTenant?[`\u9ED8\u8BA4\u79DF\u6237\u5DF2\u81EA\u52A8\u8BBE\u7F6E: ${autoSelectedTenant.tenant_id} (${autoSelectedTenant.name})`,`\u4E0A\u4E0B\u6587\u5DF2\u5199\u5165: ${getCliContextPath()}`]:autoSelectionNote?[autoSelectionNote]:[],"\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A"," 1. platform whoami",' 2. \u65B0\u5EFA\u5E94\u7528\uFF1Aplatform app create --tenant <tenant-id> --name "<app-name>" --dir <project-name>'," 3. \u7F16\u8F91\u5DF2\u6709\u5E94\u7528\uFF1Aplatform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>"," 4. cd <project-name> && platform dev"," 5. \u9ED8\u8BA4\u5148\u8D70\u8F7B\u91CF\u5F00\u53D1\u6A21\u5F0F\uFF1B\u771F\u5B9E build / preview \u8054\u8C03\u5C5E\u4E8E\u9AD8\u7EA7\u8DEF\u5F84",""].join(`
2763
+ `),credentials=await performAuthorizationCodeLogin({issuer,clientId:browserLoginConfig.clientId,redirectUri:browserLoginConfig.redirectUri,audience,scopes,prompt:"login",onPrompt:async({authorizationUrl,redirectUri})=>{let{opened}=await openExternal(authorizationUrl);process7.stdout.write(formatAuthorizationCodeLoginPrompt({opened,authorizationUrl,redirectUri,source:browserLoginConfig.source}))}})}let persistence=persistCredentials({...credentials,credential_mode:"interactive"}),autoSelectedTenant=null,autoSelectionNote=null;try{let workspaces=await listTenantWorkspaces({baseUrl:getControlApiBaseUrl(),accessToken:selectApiToken(credentials)});autoSelectedTenant=chooseDefaultTenantWorkspace(workspaces.items),autoSelectedTenant?persistActiveTenantSelection(autoSelectedTenant):workspaces.items.length>1&&(autoSelectionNote="\u68C0\u6D4B\u5230\u591A\u4E2A\u53EF\u7528\u79DF\u6237\uFF0C\u672A\u81EA\u52A8\u5207\u6362\u9ED8\u8BA4\u79DF\u6237\uFF1B\u8BF7\u6267\u884C `platform tenant use <tenant-id>`\u3002")}catch(error){autoSelectionNote=`\u9ED8\u8BA4\u79DF\u6237\u81EA\u52A8\u9009\u62E9\u5931\u8D25\uFF1A${error.message}`}process7.stdout.write(["\u767B\u5F55\u5DF2\u5B8C\u6210\u3002",`\u51ED\u636E\u5B58\u50A8\u540E\u7AEF: ${persistence.backend}`,...autoSelectedTenant?[`\u9ED8\u8BA4\u79DF\u6237\u5DF2\u81EA\u52A8\u8BBE\u7F6E: ${autoSelectedTenant.tenant_id} (${autoSelectedTenant.name})`,`\u4E0A\u4E0B\u6587\u5DF2\u5199\u5165: ${getCliContextPath()}`]:autoSelectionNote?[autoSelectionNote]:[],"\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A"," 1. platform whoami",' 2. \u65B0\u5EFA\u5E94\u7528\uFF1Aplatform app create --tenant <tenant-id> --name "<app-name>" --dir <project-name>'," 3. \u7F16\u8F91\u5DF2\u6709\u5E94\u7528\uFF1Aplatform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>"," 4. cd <project-name> && platform dev"," 5. \u9ED8\u8BA4\u5148\u8D70\u8F7B\u91CF\u5F00\u53D1\u6A21\u5F0F\uFF1B\u771F\u5B9E build / preview \u8054\u8C03\u5C5E\u4E8E\u9AD8\u7EA7\u8DEF\u5F84",""].join(`
2765
2764
  `))}async function runWhoAmI(args){let credentials=await loadStoredCredentialsEnsuringFresh();if(!credentials)throw new Error("\u672A\u627E\u5230\u672C\u5730\u51ED\u636E\uFF0C\u8BF7\u5148\u6267\u884C `platform login`\u3002");let tenantId=resolveTenantContext(args),payload=await fetchWhoAmI({baseUrl:getControlApiBaseUrl(),accessToken:selectApiToken(credentials),tenantId});process7.stdout.write(`${JSON.stringify(payload,null,2)}
2766
2765
  `)}async function runTenant(args){let subcommand=args.rest[0]??"current";if(subcommand==="current"){let context=loadStoredCliContext();if(!context?.active_tenant_id){process7.stdout.write(`\u5F53\u524D\u672A\u8BBE\u7F6E\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587\u3002
2767
2766
  `);return}process7.stdout.write([`\u5F53\u524D\u9ED8\u8BA4\u79DF\u6237: ${context.active_tenant_id}`,`\u79DF\u6237\u540D\u79F0: ${context.active_tenant_name??"-"}`,`\u66F4\u65B0\u65F6\u95F4: ${context.updated_at}`,`\u4E0A\u4E0B\u6587\u6587\u4EF6: ${getCliContextPath()}`,""].join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voobase/cli",
3
- "version": "0.1.1-nonprod.2071",
3
+ "version": "0.1.1-nonprod.2075",
4
4
  "private": false,
5
5
  "platformDistributionProfile": {
6
6
  "name": "nonprod",
@@ -56,10 +56,10 @@
56
56
  "bundleDependencies": [],
57
57
  "platformDistributionBuild": {
58
58
  "channel": "nonprod",
59
- "version": "0.1.1-nonprod.2071",
60
- "sequence": 2071,
61
- "gitSha": "bb59d25",
62
- "fullGitSha": "bb59d255b7d15e1ef51163b175f78e60c27910bc",
63
- "buildId": "0.1.1-nonprod.2071+bb59d25"
59
+ "version": "0.1.1-nonprod.2075",
60
+ "sequence": 2075,
61
+ "gitSha": "d577d60",
62
+ "fullGitSha": "d577d60ab666bbba39ae7280d2eff011b224fa7b",
63
+ "buildId": "0.1.1-nonprod.2075+d577d60"
64
64
  }
65
65
  }