@transcend-io/cli 13.0.5 → 13.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-DQ5b5mys.mjs → app-CgHCDGve.mjs} +16 -16
- package/dist/{app-DQ5b5mys.mjs.map → app-CgHCDGve.mjs.map} +1 -1
- package/dist/{approvePrivacyRequests-O70eyhdH.mjs → approvePrivacyRequests-BrnJ-CVF.mjs} +2 -2
- package/dist/{approvePrivacyRequests-O70eyhdH.mjs.map → approvePrivacyRequests-BrnJ-CVF.mjs.map} +1 -1
- package/dist/bin/bash-complete.mjs +1 -1
- package/dist/bin/cli.mjs +1 -1
- package/dist/bin/deprecated-command.mjs +1 -1
- package/dist/{buildExamples-BsMXuFwm.mjs → buildExamples-CnR3Kr1g.mjs} +2 -2
- package/dist/{buildExamples-BsMXuFwm.mjs.map → buildExamples-CnR3Kr1g.mjs.map} +1 -1
- package/dist/{buildXdiSyncEndpoint-CRJSuwdq.mjs → buildXdiSyncEndpoint-C5d116vB.mjs} +2 -2
- package/dist/{buildXdiSyncEndpoint-CRJSuwdq.mjs.map → buildXdiSyncEndpoint-C5d116vB.mjs.map} +1 -1
- package/dist/{bulkRestartRequests-C9cHasoq.mjs → bulkRestartRequests-C3cbvO42.mjs} +2 -2
- package/dist/bulkRestartRequests-C3cbvO42.mjs.map +1 -0
- package/dist/{bulkRetryEnrichers-BLDtr5Ws.mjs → bulkRetryEnrichers-C0Z-5oAG.mjs} +2 -2
- package/dist/{bulkRetryEnrichers-BLDtr5Ws.mjs.map → bulkRetryEnrichers-C0Z-5oAG.mjs.map} +1 -1
- package/dist/{cancelPrivacyRequests-DSjAUS5b.mjs → cancelPrivacyRequests-i7HTC4_n.mjs} +2 -2
- package/dist/{cancelPrivacyRequests-DSjAUS5b.mjs.map → cancelPrivacyRequests-i7HTC4_n.mjs.map} +1 -1
- package/dist/{command-DB0ydG0y.mjs → command-hkvdh57O.mjs} +2 -2
- package/dist/{command-DB0ydG0y.mjs.map → command-hkvdh57O.mjs.map} +1 -1
- package/dist/{constants-ZX8RSZos.mjs → constants-CusZYsjT.mjs} +2 -2
- package/dist/{constants-ZX8RSZos.mjs.map → constants-CusZYsjT.mjs.map} +1 -1
- package/dist/{createPoolingCommandUi-Bj6pO1t7.mjs → createPoolingCommandUi-C6uf3bzG.mjs} +2 -2
- package/dist/{createPoolingCommandUi-Bj6pO1t7.mjs.map → createPoolingCommandUi-C6uf3bzG.mjs.map} +1 -1
- package/dist/{downloadPrivacyRequestFiles-DKRfQoAo.mjs → downloadPrivacyRequestFiles-Do8cKTNC.mjs} +2 -2
- package/dist/downloadPrivacyRequestFiles-Do8cKTNC.mjs.map +1 -0
- package/dist/extractClientError-BQgmnp3e.mjs.map +1 -1
- package/dist/{generateCrossAccountApiKeys-BnUQ_wCI.mjs → generateCrossAccountApiKeys-D3EzSJV7.mjs} +2 -2
- package/dist/{generateCrossAccountApiKeys-BnUQ_wCI.mjs.map → generateCrossAccountApiKeys-D3EzSJV7.mjs.map} +1 -1
- package/dist/{impl-DpLBWRCJ.mjs → impl-8kZN8w0q.mjs} +2 -2
- package/dist/{impl-DpLBWRCJ.mjs.map → impl-8kZN8w0q.mjs.map} +1 -1
- package/dist/{impl-DgMukyER.mjs → impl-B5CqfbCN.mjs} +2 -2
- package/dist/{impl-DgMukyER.mjs.map → impl-B5CqfbCN.mjs.map} +1 -1
- package/dist/{impl-IQy1_4me.mjs → impl-B964vhTe.mjs} +2 -2
- package/dist/{impl-IQy1_4me.mjs.map → impl-B964vhTe.mjs.map} +1 -1
- package/dist/{impl-CWykfeDx.mjs → impl-BUbwefXr.mjs} +2 -2
- package/dist/{impl-CWykfeDx.mjs.map → impl-BUbwefXr.mjs.map} +1 -1
- package/dist/{impl-CihGggtZ.mjs → impl-BY1HzPeX.mjs} +2 -2
- package/dist/{impl-CihGggtZ.mjs.map → impl-BY1HzPeX.mjs.map} +1 -1
- package/dist/{impl-COz--q8S.mjs → impl-BiQ9lDze.mjs} +2 -2
- package/dist/{impl-COz--q8S.mjs.map → impl-BiQ9lDze.mjs.map} +1 -1
- package/dist/{impl-CDB2WA0G.mjs → impl-C7iC7S5D.mjs} +2 -2
- package/dist/{impl-CDB2WA0G.mjs.map → impl-C7iC7S5D.mjs.map} +1 -1
- package/dist/{impl-DEK7xark.mjs → impl-C9JlWA7i.mjs} +2 -2
- package/dist/{impl-DEK7xark.mjs.map → impl-C9JlWA7i.mjs.map} +1 -1
- package/dist/{impl-CaPpiEL2.mjs → impl-CALzjhEc.mjs} +2 -2
- package/dist/{impl-CaPpiEL2.mjs.map → impl-CALzjhEc.mjs.map} +1 -1
- package/dist/{impl-DHq2UBl4.mjs → impl-CBLQwa8E.mjs} +2 -2
- package/dist/{impl-DHq2UBl4.mjs.map → impl-CBLQwa8E.mjs.map} +1 -1
- package/dist/{impl-BUMhJG9i.mjs → impl-CFPN8z3c.mjs} +2 -2
- package/dist/{impl-BUMhJG9i.mjs.map → impl-CFPN8z3c.mjs.map} +1 -1
- package/dist/{impl-BLX_G5bC.mjs → impl-COD03bOu.mjs} +2 -2
- package/dist/{impl-BLX_G5bC.mjs.map → impl-COD03bOu.mjs.map} +1 -1
- package/dist/{impl-BOVkmW_l.mjs → impl-COpuW67i.mjs} +2 -2
- package/dist/{impl-BOVkmW_l.mjs.map → impl-COpuW67i.mjs.map} +1 -1
- package/dist/{impl-B8sKYzjF2.mjs → impl-CVjaQ_-Y2.mjs} +2 -2
- package/dist/{impl-B8sKYzjF2.mjs.map → impl-CVjaQ_-Y2.mjs.map} +1 -1
- package/dist/{impl-bWws4YDq.mjs → impl-Cm_hCZ5h.mjs} +2 -2
- package/dist/{impl-bWws4YDq.mjs.map → impl-Cm_hCZ5h.mjs.map} +1 -1
- package/dist/impl-CoqCyj7e.mjs.map +1 -1
- package/dist/{impl-CFza6vNy.mjs → impl-CuII9KiJ.mjs} +2 -2
- package/dist/{impl-CFza6vNy.mjs.map → impl-CuII9KiJ.mjs.map} +1 -1
- package/dist/{impl-t0qVrVte.mjs → impl-D-1QAfLV.mjs} +2 -2
- package/dist/{impl-t0qVrVte.mjs.map → impl-D-1QAfLV.mjs.map} +1 -1
- package/dist/{impl-CeR4wR2T.mjs → impl-D8KUHOU8.mjs} +2 -2
- package/dist/{impl-CeR4wR2T.mjs.map → impl-D8KUHOU8.mjs.map} +1 -1
- package/dist/{impl-fmS5PIlk.mjs → impl-DAlYoIsj.mjs} +2 -2
- package/dist/{impl-fmS5PIlk.mjs.map → impl-DAlYoIsj.mjs.map} +1 -1
- package/dist/{impl-BAd2ga54.mjs → impl-DHTAxvp8.mjs} +2 -2
- package/dist/{impl-BAd2ga54.mjs.map → impl-DHTAxvp8.mjs.map} +1 -1
- package/dist/{impl-C7oKqTBj.mjs → impl-DLaSUiZ7.mjs} +2 -2
- package/dist/{impl-C7oKqTBj.mjs.map → impl-DLaSUiZ7.mjs.map} +1 -1
- package/dist/{impl-77sXwCIh.mjs → impl-DQbP4dBX.mjs} +2 -2
- package/dist/{impl-77sXwCIh.mjs.map → impl-DQbP4dBX.mjs.map} +1 -1
- package/dist/{impl-BUziAyU5.mjs → impl-DWmQ_15Y.mjs} +2 -2
- package/dist/{impl-BUziAyU5.mjs.map → impl-DWmQ_15Y.mjs.map} +1 -1
- package/dist/{impl-Bizz-Eku.mjs → impl-D_03KeBQ.mjs} +2 -2
- package/dist/{impl-Bizz-Eku.mjs.map → impl-D_03KeBQ.mjs.map} +1 -1
- package/dist/{impl-CHq5HbuZ2.mjs → impl-DbTZmp_W2.mjs} +2 -2
- package/dist/{impl-CHq5HbuZ2.mjs.map → impl-DbTZmp_W2.mjs.map} +1 -1
- package/dist/{impl-XbrQy_Ti2.mjs → impl-Dd60oodD2.mjs} +2 -2
- package/dist/{impl-XbrQy_Ti2.mjs.map → impl-Dd60oodD2.mjs.map} +1 -1
- package/dist/{impl-B1TF4tzM2.mjs → impl-De1JItpM2.mjs} +2 -2
- package/dist/{impl-B1TF4tzM2.mjs.map → impl-De1JItpM2.mjs.map} +1 -1
- package/dist/{impl-DJ5kJ80R.mjs → impl-DnPaAp-d.mjs} +2 -2
- package/dist/{impl-DJ5kJ80R.mjs.map → impl-DnPaAp-d.mjs.map} +1 -1
- package/dist/{impl-CcVNbgw3.mjs → impl-DvLO4Qn3.mjs} +2 -2
- package/dist/{impl-CcVNbgw3.mjs.map → impl-DvLO4Qn3.mjs.map} +1 -1
- package/dist/{impl-B7PA6_OB.mjs → impl-Dw-MR5nR.mjs} +2 -2
- package/dist/{impl-B7PA6_OB.mjs.map → impl-Dw-MR5nR.mjs.map} +1 -1
- package/dist/{impl-DQftQKzh.mjs → impl-DwBrrrR3.mjs} +2 -2
- package/dist/{impl-DQftQKzh.mjs.map → impl-DwBrrrR3.mjs.map} +1 -1
- package/dist/{impl-B_5zE1r4.mjs → impl-DwGZvFYI.mjs} +2 -2
- package/dist/{impl-B_5zE1r4.mjs.map → impl-DwGZvFYI.mjs.map} +1 -1
- package/dist/{impl-tQda5dQ2.mjs → impl-F0lRLx7N.mjs} +2 -2
- package/dist/{impl-tQda5dQ2.mjs.map → impl-F0lRLx7N.mjs.map} +1 -1
- package/dist/impl-HsRwcfRu.mjs.map +1 -1
- package/dist/{impl-Do_3rQWz.mjs → impl-L-TZRGF5.mjs} +2 -2
- package/dist/{impl-Do_3rQWz.mjs.map → impl-L-TZRGF5.mjs.map} +1 -1
- package/dist/{impl-DRmy2-be.mjs → impl-Q8a16IkZ.mjs} +2 -2
- package/dist/{impl-DRmy2-be.mjs.map → impl-Q8a16IkZ.mjs.map} +1 -1
- package/dist/{impl-CIEPBjFF.mjs → impl-S3znb469.mjs} +2 -2
- package/dist/{impl-CIEPBjFF.mjs.map → impl-S3znb469.mjs.map} +1 -1
- package/dist/{impl-CPW2Q51W2.mjs → impl-UlLFb3UK2.mjs} +2 -2
- package/dist/{impl-CPW2Q51W2.mjs.map → impl-UlLFb3UK2.mjs.map} +1 -1
- package/dist/impl-WJBuS_0m.mjs.map +1 -1
- package/dist/{impl-CXOLmyC1.mjs → impl-wymd_Y3k.mjs} +2 -2
- package/dist/{impl-CXOLmyC1.mjs.map → impl-wymd_Y3k.mjs.map} +1 -1
- package/dist/{impl-5s_Ya3XD.mjs → impl-zH16n-0l.mjs} +2 -2
- package/dist/{impl-5s_Ya3XD.mjs.map → impl-zH16n-0l.mjs.map} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{markRequestDataSiloIdsCompleted-ZZvKQhtT.mjs → markRequestDataSiloIdsCompleted-CJdC2ta9.mjs} +2 -2
- package/dist/{markRequestDataSiloIdsCompleted-ZZvKQhtT.mjs.map → markRequestDataSiloIdsCompleted-CJdC2ta9.mjs.map} +1 -1
- package/dist/{markSilentPrivacyRequests-DZ13Jy20.mjs → markSilentPrivacyRequests-CIjtVoXr.mjs} +2 -2
- package/dist/{markSilentPrivacyRequests-DZ13Jy20.mjs.map → markSilentPrivacyRequests-CIjtVoXr.mjs.map} +1 -1
- package/dist/{notifyPrivacyRequestsAdditionalTime-BspmtrPe.mjs → notifyPrivacyRequestsAdditionalTime-DsjlAlh8.mjs} +2 -2
- package/dist/{notifyPrivacyRequestsAdditionalTime-BspmtrPe.mjs.map → notifyPrivacyRequestsAdditionalTime-DsjlAlh8.mjs.map} +1 -1
- package/dist/{policy-bundle-manifest-BKRoT17e.mjs → policy-bundle-manifest-xaiuhXv5.mjs} +2 -2
- package/dist/{policy-bundle-manifest-BKRoT17e.mjs.map → policy-bundle-manifest-xaiuhXv5.mjs.map} +1 -1
- package/dist/{policy-project-discovery-BXcvhfK7.mjs → policy-project-discovery-Dxikd8NT.mjs} +2 -2
- package/dist/{policy-project-discovery-BXcvhfK7.mjs.map → policy-project-discovery-Dxikd8NT.mjs.map} +1 -1
- package/dist/{policy-scaffold-config-DvyJctQz.mjs → policy-scaffold-config-DRWTaw0k.mjs} +2 -2
- package/dist/{policy-scaffold-config-DvyJctQz.mjs.map → policy-scaffold-config-DRWTaw0k.mjs.map} +1 -1
- package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-CDHCpiXU.mjs → pullChunkedCustomSiloOutstandingIdentifiers-DbNvJJrP.mjs} +2 -2
- package/dist/pullChunkedCustomSiloOutstandingIdentifiers-DbNvJJrP.mjs.map +1 -0
- package/dist/{pullManualEnrichmentIdentifiersToCsv-BSM4bSjf.mjs → pullManualEnrichmentIdentifiersToCsv-3hX7b2sn.mjs} +2 -2
- package/dist/{pullManualEnrichmentIdentifiersToCsv-BSM4bSjf.mjs.map → pullManualEnrichmentIdentifiersToCsv-3hX7b2sn.mjs.map} +1 -1
- package/dist/{pushCronIdentifiersFromCsv-CnMWjt94.mjs → pushCronIdentifiersFromCsv-DSsDe8er.mjs} +2 -2
- package/dist/pushCronIdentifiersFromCsv-DSsDe8er.mjs.map +1 -0
- package/dist/{pushManualEnrichmentIdentifiersFromCsv-iv9Ts42q.mjs → pushManualEnrichmentIdentifiersFromCsv-B4NWrYLP.mjs} +2 -2
- package/dist/pushManualEnrichmentIdentifiersFromCsv-B4NWrYLP.mjs.map +1 -0
- package/dist/{removeUnverifiedRequestIdentifiers-Bo5U01oM.mjs → removeUnverifiedRequestIdentifiers-eub1buew.mjs} +2 -2
- package/dist/{removeUnverifiedRequestIdentifiers-Bo5U01oM.mjs.map → removeUnverifiedRequestIdentifiers-eub1buew.mjs.map} +1 -1
- package/dist/resolveBundleIdByName-D7NUOpLc.mjs.map +1 -1
- package/dist/resolvePolicyBundleVersion-CKbF9vqc.mjs.map +1 -1
- package/dist/{retryRequestDataSilos-BWGlpn1o.mjs → retryRequestDataSilos-Bz2krPpO.mjs} +2 -2
- package/dist/{retryRequestDataSilos-BWGlpn1o.mjs.map → retryRequestDataSilos-Bz2krPpO.mjs.map} +1 -1
- package/dist/{skipPreflightJobs-B0LSm9IU.mjs → skipPreflightJobs-DnMtLNHR.mjs} +2 -2
- package/dist/{skipPreflightJobs-B0LSm9IU.mjs.map → skipPreflightJobs-DnMtLNHR.mjs.map} +1 -1
- package/dist/{skipRequestDataSilos-EEaly2ls.mjs → skipRequestDataSilos-hFvX-tmq.mjs} +2 -2
- package/dist/{skipRequestDataSilos-EEaly2ls.mjs.map → skipRequestDataSilos-hFvX-tmq.mjs.map} +1 -1
- package/dist/{streamPrivacyRequestsToCsv-DUFu0-AB.mjs → streamPrivacyRequestsToCsv-1D5tgLIt.mjs} +2 -2
- package/dist/{streamPrivacyRequestsToCsv-DUFu0-AB.mjs.map → streamPrivacyRequestsToCsv-1D5tgLIt.mjs.map} +1 -1
- package/dist/{updateConsentManagerVersionToLatest-C4D6cqMh.mjs → updateConsentManagerVersionToLatest-DYvkq9Lr.mjs} +2 -2
- package/dist/{updateConsentManagerVersionToLatest-C4D6cqMh.mjs.map → updateConsentManagerVersionToLatest-DYvkq9Lr.mjs.map} +1 -1
- package/dist/{uploadConsents-CMTmdRLm.mjs → uploadConsents-BIt4fC8B.mjs} +2 -2
- package/dist/{uploadConsents-CMTmdRLm.mjs.map → uploadConsents-BIt4fC8B.mjs.map} +1 -1
- package/dist/{uploadPrivacyRequestsFromCsv-BIe_wJ4A.mjs → uploadPrivacyRequestsFromCsv-Df79Xp4b.mjs} +2 -2
- package/dist/{uploadPrivacyRequestsFromCsv-BIe_wJ4A.mjs.map → uploadPrivacyRequestsFromCsv-Df79Xp4b.mjs.map} +1 -1
- package/package.json +4 -4
- package/dist/bulkRestartRequests-C9cHasoq.mjs.map +0 -1
- package/dist/downloadPrivacyRequestFiles-DKRfQoAo.mjs.map +0 -1
- package/dist/pullChunkedCustomSiloOutstandingIdentifiers-CDHCpiXU.mjs.map +0 -1
- package/dist/pushCronIdentifiersFromCsv-CnMWjt94.mjs.map +0 -1
- package/dist/pushManualEnrichmentIdentifiersFromCsv-iv9Ts42q.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impl-
|
|
1
|
+
{"version":3,"file":"impl-L-TZRGF5.mjs","names":[],"sources":["../src/commands/consent/update-consent-manager/impl.ts"],"sourcesContent":["import { ConsentBundleType } from '@transcend-io/privacy-types';\nimport { mapSeries } from '@transcend-io/utils';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { validateTranscendAuth } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { updateConsentManagerVersionToLatest } from '../../../lib/consent-manager/index.js';\n\nexport interface UpdateConsentManagerCommandFlags {\n auth: string;\n bundleTypes: ConsentBundleType[];\n deploy: boolean;\n transcendUrl: string;\n}\n\nexport async function updateConsentManager(\n this: LocalContext,\n {\n auth,\n bundleTypes = [ConsentBundleType.Production, ConsentBundleType.Test],\n deploy,\n transcendUrl,\n }: UpdateConsentManagerCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n // Parse authentication as API key or path to list of API keys\n const apiKeyOrList = await validateTranscendAuth(auth, this);\n\n // Handle single update\n if (typeof apiKeyOrList === 'string') {\n // Update consent manager\n await updateConsentManagerVersionToLatest({\n deploy,\n transcendUrl,\n auth: apiKeyOrList,\n bundleTypes,\n });\n this.logger.info(colors.green('Successfully updated Consent Manager!'));\n } else {\n await mapSeries(apiKeyOrList, async (apiKey) => {\n this.logger.info(\n colors.magenta(`Updating Consent Manager for organization \"${apiKey.organizationName}\"...`),\n );\n\n await updateConsentManagerVersionToLatest({\n deploy,\n transcendUrl,\n auth: apiKey.apiKey,\n bundleTypes,\n });\n\n this.logger.info(\n colors.green(\n `Successfully updated Consent Manager for organization \"${apiKey.organizationName}\"!`,\n ),\n );\n });\n this.logger.info(colors.green('Successfully updated Consent Managers!'));\n }\n}\n"],"mappings":"0TAgBA,eAAsB,EAEpB,CACE,OACA,cAAc,CAAC,EAAkB,WAAY,EAAkB,KAAK,CACpE,SACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAGjC,IAAM,EAAe,MAAM,EAAsB,EAAM,KAAK,CAGxD,OAAO,GAAiB,UAE1B,MAAM,EAAoC,CACxC,SACA,eACA,KAAM,EACN,cACD,CAAC,CACF,KAAK,OAAO,KAAK,EAAO,MAAM,wCAAwC,CAAC,GAEvE,MAAM,EAAU,EAAc,KAAO,IAAW,CAC9C,KAAK,OAAO,KACV,EAAO,QAAQ,8CAA8C,EAAO,iBAAiB,MAAM,CAC5F,CAED,MAAM,EAAoC,CACxC,SACA,eACA,KAAM,EAAO,OACb,cACD,CAAC,CAEF,KAAK,OAAO,KACV,EAAO,MACL,0DAA0D,EAAO,iBAAiB,IACnF,CACF,EACD,CACF,KAAK,OAAO,KAAK,EAAO,MAAM,yCAAyC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./notifyPrivacyRequestsAdditionalTime-
|
|
2
|
-
//# sourceMappingURL=impl-
|
|
1
|
+
import{t as e}from"./notifyPrivacyRequestsAdditionalTime-DsjlAlh8.mjs";import{t}from"./done-input-validation-LiTaCEzF.mjs";async function n({auth:n,transcendUrl:r,createdAtBefore:i,createdAtAfter:a,updatedAtBefore:o,updatedAtAfter:s,actions:c,daysLeft:l,days:u,requestIds:d,emailTemplate:f,concurrency:p}){t(this.process),await e({transcendUrl:r,requestActions:c,auth:n,emailTemplate:f,days:u,daysLeft:l,requestIds:d,concurrency:p,createdAtBefore:i,createdAtAfter:a,updatedAtBefore:o,updatedAtAfter:s})}export{n as notifyAdditionalTime};
|
|
2
|
+
//# sourceMappingURL=impl-Q8a16IkZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impl-
|
|
1
|
+
{"version":3,"file":"impl-Q8a16IkZ.mjs","names":[],"sources":["../src/commands/request/notify-additional-time/impl.ts"],"sourcesContent":["import type { RequestAction } from '@transcend-io/privacy-types';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { notifyPrivacyRequestsAdditionalTime } from '../../../lib/requests/index.js';\n\nexport interface NotifyAdditionalTimeCommandFlags {\n auth: string;\n createdAtBefore: Date;\n createdAtAfter?: Date;\n updatedAtBefore?: Date;\n updatedAtAfter?: Date;\n actions?: RequestAction[];\n daysLeft: number;\n days: number;\n requestIds?: string[];\n emailTemplate: string;\n transcendUrl: string;\n concurrency: number;\n}\n\nexport async function notifyAdditionalTime(\n this: LocalContext,\n {\n auth,\n transcendUrl,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n actions,\n daysLeft,\n days,\n requestIds,\n emailTemplate,\n concurrency,\n }: NotifyAdditionalTimeCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await notifyPrivacyRequestsAdditionalTime({\n transcendUrl,\n requestActions: actions,\n auth,\n emailTemplate,\n days,\n daysLeft,\n requestIds,\n concurrency,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n });\n}\n"],"mappings":"2HAqBA,eAAsB,EAEpB,CACE,OACA,eACA,kBACA,iBACA,kBACA,iBACA,UACA,WACA,OACA,aACA,gBACA,eAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAM,EAAoC,CACxC,eACA,eAAgB,EAChB,OACA,gBACA,OACA,WACA,aACA,cACA,kBACA,iBACA,kBACA,iBACD,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as e}from"./constants-
|
|
1
|
+
import{g as e}from"./constants-CusZYsjT.mjs";import{i as t,n,r,t as i}from"./project-plan-output-BHHlkLxe.mjs";import{c as a,d as o,f as s,l as c,t as l,u}from"./project-discovery-CWRjlFnC.mjs";import{b as d,d as f,r as p,t as m,u as h}from"./policy-project-discovery-Dxikd8NT.mjs";import{a as g,c as _,i as v,l as y,o as b,r as x,s as S,t as C}from"./policy-runtime-6jmkXlBk.mjs";import{t as w}from"./done-input-validation-LiTaCEzF.mjs";import{i as T,n as E,r as D,t as O}from"./prompts-BhXfYD6g.mjs";import{t as k}from"./run-captured-process-BjaSDWXG.mjs";import{t as A}from"./project-plan-apply-Bg_1eMX9.mjs";import{a as j,n as ee,o as te,r as ne,t as re}from"./policy-scaffold-config-DRWTaw0k.mjs";import{isAbsolute as M,join as N,posix as P,relative as F,sep as I}from"node:path";import L from"colors";const R={Editor:`editor`,Skill:`skill`,Ci:`ci`};var z=`# Idiomatic Rego and document-tree authoring
|
|
2
2
|
|
|
3
3
|
## Start from the document tree
|
|
4
4
|
|
|
@@ -325,4 +325,4 @@ transcend policy check --noInteractive
|
|
|
325
325
|
products into a single \`.manifest\` unless they share activation and callers.
|
|
326
326
|
`;const W=`transcend-policy-engine`,G=[{path:`SKILL.md`,contents:U},{path:`references/setup-tooling.md`,contents:V},{path:`references/authoring.md`,contents:z},{path:`references/testing-debugging.md`,contents:H},{path:`references/publishing.md`,contents:B}];function K(e){return`${e.hasSkill?`Use the \`${W}\` skill and run`:`Run`} ${e.newCommand} to add a bundle from a template, then adapt the policy document tree and input/output contract to the intended application.`}function q(e,n){return{version:e.version,command:e.command,applied:n.applied,dryRun:n.dryRun,targetDirectory:e.targetDirectory,manifestPath:e.manifestPath,changes:e.changes.map(e=>t(n.cwd,e)),warnings:e.warnings,nextSteps:e.nextSteps,features:[...e.features],aiHandoff:n.aiHandoff,tools:n.tools}}const J={name:W,displayName:`Policy Engine`,owner:`@transcend-io/cli`,files:G};function Y(e,t){let n=new Set(d().map(({path:t})=>N(e.targetDirectory,t))),r=new Set(t.features);return r.has(R.Editor)&&(n.add(N(e.projectRoot,`.vscode`,`settings.json`)),n.add(N(e.projectRoot,`.vscode`,`extensions.json`)),n.add(N(e.projectRoot,`.vscode`,`tasks.json`))),r.has(R.Skill)&&a(e.projectRoot,e.existingSkillDirectories,J).forEach(e=>n.add(e)),r.has(R.Ci)&&e.repositoryRoot&&e.usesGithub&&n.add(N(e.repositoryRoot,j)),[...n].sort((e,t)=>e.localeCompare(t))}function X(e,t){let n=F(e,t);if(n===`..`||n.startsWith(`..${I}`)||M(n))throw Error(`Refusing to modify path outside project root: ${t}`)}function ie(e){let t=new Set([`${h}/input.json`]);return e.forEach(({path:e})=>{t.add(e);let n=P.dirname(e);for(;n!==`.`;)t.add(n),n=P.dirname(n)}),t}function Z(e,t,n){let r=s({snapshot:u(t.snapshots,n.path),after:n.contents,description:n.description,...n.createOnly===void 0?{}:{createOnly:n.createOnly}});r?e.changes.push(r):e.unchanged.push(n.path)}function ae(e,t,n,r,a,o){Z(e,t,{path:n,contents:r.contents,description:a}),e.warnings.push(...r.warnings.map(e=>`${e} (${i(o,n)})`))}function oe(e,t){let{state:n}=e,r=d(),a=`transcend policy new`,s={version:3,command:`init`,rootDirectory:n.projectRoot,targetDirectory:n.targetDirectory,manifestPath:n.targetDirectory,changes:[],unchanged:[],warnings:[],nextSteps:[a],features:[...t.features]},l=Y(n,t);if(X(n.projectRoot,n.targetDirectory),l.forEach(e=>X(n.projectRoot,e)),n.relativeFilePaths.length===0)s.directoryPreconditions=[{path:n.targetDirectory,relativePaths:[...n.relativePaths]}],r.forEach(t=>{let r=N(n.targetDirectory,t.path);if(o(e.snapshots,r).kind!==`absent`)throw Error(`Expected an empty policy target, but found an entry at: ${r}`);Z(s,e,{path:r,contents:t.contents,description:t.description,createOnly:!0})});else{let t=!0;r.forEach(r=>{let a=N(n.targetDirectory,r.path),c=o(e.snapshots,a);if(c.kind===`file`&&c.contents===r.contents){s.unchanged.push(a);return}t=!1,c.kind!==`absent`&&(s.unchanged.push(a),s.warnings.push(`Existing policy scaffold path was left unchanged: ${i(n.invocationDirectory,a)}`))});let c=ie(r),l=n.relativeFilePaths.some(e=>!c.has(e));(!t||l)&&s.warnings.push(`Existing policy target contains custom or partial content, so no workspace files were added or overwritten. Review ${i(n.invocationDirectory,n.targetDirectory)} manually, then run \`${a}\`.`)}let u=new Set(t.features),f=n.projectRoot;if(u.has(R.Editor)){let t=N(f,`.vscode`,`settings.json`),r=N(f,`.vscode`,`extensions.json`),a=N(f,`.vscode`,`tasks.json`);[{path:t,description:`Merge strict target-scoped OPA and Rego editor settings`,merge:(e,t,n)=>ee(e,t,n)},{path:r,description:`Recommend the OPA extension and discourage its syntax-only conflict`,merge:e=>re(e)},{path:a,description:`Create the VS Code task configuration`,merge:(e,t,n)=>ne(e,t,n)}].forEach(({path:t,description:r,merge:a})=>{let c=o(e.snapshots,t);if(c.kind!==`absent`&&c.kind!==`file`){s.unchanged.push(t),s.warnings.push(`Existing VS Code artifact is not a regular file and was left unchanged: ${i(n.invocationDirectory,t)}`);return}ae(s,e,t,a(c.kind===`file`?c.contents:null,f,n.targetDirectory),r,n.invocationDirectory)})}if(u.has(R.Skill)){let t=c({rootDirectory:f,existingDirectories:n.existingSkillDirectories,snapshots:e.snapshots,skill:J,preserveModified:!0});s.changes.push(...t.changes),s.unchanged.push(...t.unchanged),s.warnings.push(...t.warnings.map(e=>t.unchanged.reduce((e,t)=>e.replace(t,i(n.invocationDirectory,t)),e)))}if(u.has(R.Ci))if(!n.repositoryRoot||!n.usesGithub)s.warnings.push(`GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.`);else{let r=N(n.repositoryRoot,j),a=F(n.repositoryRoot,n.targetDirectory).split(I).join(`/`)||`.`,c=te({cliVersion:t.cliVersion,workspaceDirectory:a,bundleDirectories:[]}),l=o(e.snapshots,r);l.kind===`absent`?Z(s,e,{path:r,contents:c,description:`Add credential-free Policy Engine validation`,createOnly:!0}):l.kind===`file`&&l.contents===c?s.unchanged.push(r):(s.unchanged.push(r),s.warnings.push(`Existing GitHub Actions workflow was left unchanged: ${i(n.invocationDirectory,r)}. Adapt it manually to validate each policy bundle.`))}return s.changes.forEach(({path:e})=>X(n.projectRoot,e)),s}const se={[R.Editor]:`VS Code settings and lint task`,[R.Skill]:`Policy Engine Agent Skill`,[R.Ci]:`Validation-only GitHub Actions`},ce=Object.values(R);function Q(e,t){let n=[t.stdout.trim(),t.stderr.trim()].filter(Boolean).join(`
|
|
327
327
|
`),r=e===`OPA`?x:g;return`${e===`OPA`?`OPA 1.x`:`Regal ${C} or newer`} is required, but \`${e.toLowerCase()} version\` exited with code ${t.code}${n?`: ${n}`:`.`} Install or upgrade it using the official instructions: ${r}`}async function le(e,t,n){let r={opa:null,regal:null},i=[],a=await n(`opa`,[`version`],{cwd:t},e);if(a.error?.code===`ENOENT`)i.push(v);else{let e=`${a.stdout}\n${a.stderr}`,t=_(e);a.code===0?t?i.push(t):r.opa=S(e).version:i.push(t??Q(`OPA`,a))}let o=await n(`regal`,[`version`],{cwd:t},e);if(o.error?.code===`ENOENT`)i.push(b);else{let e=`${o.stdout}\n${o.stderr}`,t=y(e,C,`the generated OPA ${f} capabilities configuration`);o.code===0?t?i.push(t):r.regal=S(e).version:i.push(t??Q(`Regal`,o))}return{tools:r,warnings:i}}async function $(t,a=m,o=k){w(this.process);try{let s=await le(this,this.process.cwd(),o),c=p(this,a),u=new E(this),d=D(t,this.process.stdin.isTTY,this.process.stderr.isTTY),f=await T(u,{features:ce,labels:se,enabled:{[R.Editor]:t.editor,[R.Skill]:t.skill,[R.Ci]:t.ci},interactive:d}),m=Y(c,{features:f}),h=oe({state:c,snapshots:l(this,c.projectRoot,m)},{features:f,cliVersion:e});h.warnings.push(...s.warnings),t.json||this.logger.info(r(h,{cwd:this.process.cwd(),title:`Policy initialization plan`,details:[{label:`Target`,path:h.targetDirectory}]}));let g=h.changes.length===0||t.dryRun;if(h.changes.length>0&&!t.dryRun)if(t.yes)g=!0;else if(d)g=await u.confirm(`Apply this complete plan?`,!0);else throw Error(`The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.`);g&&!t.dryRun&&h.changes.length>0&&await A(this,h);let _=g&&!t.dryRun&&h.changes.length>0,v=g&&!t.dryRun,y=K({projectPath:n(i(this.process.cwd(),c.targetDirectory)),hasSkill:v&&f.includes(R.Skill),newCommand:h.nextSteps[0]}),b=q(h,{applied:_,dryRun:t.dryRun,cwd:this.process.cwd(),aiHandoff:y,tools:s.tools});if(t.json){this.process.stdout.write(`${JSON.stringify(b)}\n`);return}if(t.dryRun){this.logger.info(L.yellow(`Dry run complete. No changes were written.`));return}if(!g){this.logger.info(L.yellow(`No changes applied.`));return}if(h.changes.length===0){let e=h.warnings.length===s.warnings.length?`Policy project is already initialized.`:`Existing policy project was left unchanged.`;this.logger.info(L.green(e))}else this.logger.info(L.green(`Policy project initialized.`));h.nextSteps.length>0&&(this.logger.info(`\n${L.bold(`Next steps`)}`),h.nextSteps.forEach(e=>this.logger.info(e))),this.logger.info(`\n${L.bold(`AI handoff — paste into your coding agent`)}`),this.logger.info(y)}catch(e){if(e instanceof O)return this.process.exit(130);throw e}}export{$ as init};
|
|
328
|
-
//# sourceMappingURL=impl-
|
|
328
|
+
//# sourceMappingURL=impl-S3znb469.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impl-CIEPBjFF.mjs","names":["POLICY_SKILL_MD","POLICY_SETUP_TOOLING_REFERENCE_MD","POLICY_AUTHORING_REFERENCE_MD","POLICY_TESTING_DEBUGGING_REFERENCE_MD","POLICY_PUBLISHING_REFERENCE_MD","CLI_VERSION"],"sources":["../src/lib/policy/policy-scaffold-model.ts","../../../skills/transcend-policy-engine/references/authoring.md","../../../skills/transcend-policy-engine/references/publishing.md","../../../skills/transcend-policy-engine/references/setup-tooling.md","../../../skills/transcend-policy-engine/references/testing-debugging.md","../../../skills/transcend-policy-engine/SKILL.md","../src/lib/policy/policy-skill.ts","../src/lib/policy/policy-scaffold-output.ts","../src/lib/policy/policy-scaffold-planning.ts","../src/commands/policy/init/impl.ts"],"sourcesContent":["import type { ExistingProjectSkillDirectory } from '../scaffolding/agent-skill.js';\nimport type { ProjectPlan } from '../scaffolding/project-plan.js';\n\n/** Version of the stable policy initialization JSON result. */\nexport const POLICY_INIT_RESULT_VERSION = 3 as const;\n\n/** Optional repository integrations for policy authoring. */\nexport const PolicySetupFeature = {\n /** Repository-level editor configuration. */\n Editor: 'editor',\n /** Managed policy authoring skill. */\n Skill: 'skill',\n /** Credential-free continuous integration. */\n Ci: 'ci',\n} as const;\n\n/** Optional repository integration for policy authoring. */\nexport type PolicySetupFeature = (typeof PolicySetupFeature)[keyof typeof PolicySetupFeature];\n\n/** Repository and target state collected before policy planning. */\nexport interface PolicyProjectState {\n /** Directory from which the CLI was invoked. */\n invocationDirectory: string;\n /** Absolute user-selected policy directory. */\n targetDirectory: string;\n /** Repository or invocation root that owns setup artifacts. */\n projectRoot: string;\n /** Nearest repository root, when present. */\n repositoryRoot?: string;\n /** Existing project-level skill directories. */\n existingSkillDirectories: ExistingProjectSkillDirectory[];\n /** Whether the repository appears to use GitHub. */\n usesGithub: boolean;\n /** Case-preserving relative paths below the policy directory. */\n relativePaths: string[];\n /** Relative file and link paths below the policy directory. */\n relativeFilePaths: string[];\n}\n\n/** A complete, validated policy initialization plan. */\nexport interface PolicyInitProjectPlan extends ProjectPlan {\n /** JSON contract version. */\n version: typeof POLICY_INIT_RESULT_VERSION;\n /** Command that produced the plan. */\n command: 'init';\n /** Absolute policy project directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Files inspected and deliberately left unchanged. */\n unchanged: string[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Raw commands shown after a successful apply. */\n nextSteps: string[];\n /** Exact generated example that remains safe to replace. */\n disposableExamplePath?: string;\n /** Selected repository integrations. */\n features: PolicySetupFeature[];\n}\n",null,null,null,null,null,"import POLICY_AUTHORING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/authoring.md';\nimport POLICY_PUBLISHING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/publishing.md';\nimport POLICY_SETUP_TOOLING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/setup-tooling.md';\nimport POLICY_TESTING_DEBUGGING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/testing-debugging.md';\nimport POLICY_SKILL_MD from '../../../../../skills/transcend-policy-engine/SKILL.md';\nimport type { AgentSkillFile } from '../scaffolding/agent-skill.js';\n\n/** Namespaced directory and frontmatter name for the installed Agent Skill. */\nexport const POLICY_SKILL_NAME = 'transcend-policy-engine';\n\nexport {\n POLICY_AUTHORING_REFERENCE_MD,\n POLICY_PUBLISHING_REFERENCE_MD,\n POLICY_SETUP_TOOLING_REFERENCE_MD,\n POLICY_SKILL_MD,\n POLICY_TESTING_DEBUGGING_REFERENCE_MD,\n};\n\n/** Complete portable Policy Engine Agent Skill file set. */\nexport const POLICY_SKILL_FILES: readonly AgentSkillFile[] = [\n { path: 'SKILL.md', contents: POLICY_SKILL_MD },\n { path: 'references/setup-tooling.md', contents: POLICY_SETUP_TOOLING_REFERENCE_MD },\n { path: 'references/authoring.md', contents: POLICY_AUTHORING_REFERENCE_MD },\n { path: 'references/testing-debugging.md', contents: POLICY_TESTING_DEBUGGING_REFERENCE_MD },\n { path: 'references/publishing.md', contents: POLICY_PUBLISHING_REFERENCE_MD },\n];\n","import {\n toPublicPlannedChange,\n type PublicPlannedChange,\n} from '../scaffolding/project-plan-output.js';\nimport type { PolicyInitProjectPlan, PolicySetupFeature } from './policy-scaffold-model.js';\nimport { POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Detected local policy tool versions. */\nexport interface PolicyInitToolVersions {\n /** OPA version, or null when missing or incompatible. */\n opa: string | null;\n /** Regal version, or null when missing or incompatible. */\n regal: string | null;\n}\n\n/** Stable machine-readable policy initialization result. */\nexport interface PolicyInitPlanResult {\n /** JSON contract version. */\n version: number;\n /** Command that produced the result. */\n command: 'init';\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Absolute policy target directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Planned mutations without file contents. */\n changes: PublicPlannedChange[];\n /** Non-fatal preservation and runtime warnings. */\n warnings: string[];\n /** Suggested raw one-line follow-up commands. */\n nextSteps: string[];\n /** Explicitly selected repository integrations. */\n features: PolicySetupFeature[];\n /** Compact prompt for continuing with a coding agent. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n}\n\n/**\n * Build the compact policy implementation and CI handoff.\n *\n * @param options - Portable project path and next step\n * @returns Raw one-line prompt\n */\nexport function buildPolicyInitAiHandoff(options: {\n /** Display path to the policy project. */\n projectPath: string;\n /** Whether the policy authoring skill was installed. */\n hasSkill: boolean;\n /** Copyable new-bundle command. */\n newCommand: string;\n}): string {\n const instruction = options.hasSkill ? `Use the \\`${POLICY_SKILL_NAME}\\` skill and run` : 'Run';\n return (\n `${instruction} ${options.newCommand} to add a bundle from a template, ` +\n `then adapt the policy document tree and input/output contract to the intended application.`\n );\n}\n\n/**\n * Build the stable machine-readable initialization result.\n *\n * @param plan - Policy project plan\n * @param options - Apply and runtime state\n * @returns Public JSON result\n */\nexport function buildPolicyInitPlanResult(\n plan: PolicyInitProjectPlan,\n options: {\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Working directory for portable paths. */\n cwd: string;\n /** Compact coding-agent prompt. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n },\n): PolicyInitPlanResult {\n return {\n version: plan.version,\n command: plan.command,\n applied: options.applied,\n dryRun: options.dryRun,\n targetDirectory: plan.targetDirectory,\n manifestPath: plan.manifestPath,\n changes: plan.changes.map((change) => toPublicPlannedChange(options.cwd, change)),\n warnings: plan.warnings,\n nextSteps: plan.nextSteps,\n features: [...plan.features],\n aiHandoff: options.aiHandoff,\n tools: options.tools,\n };\n}\n","import { isAbsolute, join, posix, relative, sep } from 'node:path';\n\nimport {\n getManagedAgentSkillCandidatePaths,\n planManagedAgentSkill,\n type ManagedAgentSkillDefinition,\n} from '../scaffolding/agent-skill.js';\nimport { displayProjectPath } from '../scaffolding/project-plan-output.js';\nimport {\n getPlanningPathSnapshot,\n getPlanningFileSnapshot,\n planFileChange,\n type PlanningPathSnapshot,\n} from '../scaffolding/project-plan.js';\nimport {\n generatePolicyGithubActionsWorkflow,\n POLICY_CI_WORKFLOW_PATH,\n} from './policy-scaffold-artifacts.js';\nimport {\n mergePolicyEditorExtensions,\n mergePolicyEditorSettings,\n mergePolicyEditorTasks,\n type PolicyEditorMergeResult,\n} from './policy-scaffold-config.js';\nimport {\n POLICY_INIT_RESULT_VERSION,\n PolicySetupFeature,\n type PolicyInitProjectPlan,\n type PolicyProjectState,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from './policy-scaffold-model.js';\nimport {\n generatePolicyWorkspaceFiles,\n POLICY_STARTER_BUNDLE_DIRECTORY,\n type PolicyStarterFile,\n} from './policy-scaffold-templates.js';\nimport { POLICY_SKILL_FILES, POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Managed Policy Engine Agent Skill definition. */\nconst POLICY_MANAGED_SKILL: ManagedAgentSkillDefinition = {\n name: POLICY_SKILL_NAME,\n displayName: 'Policy Engine',\n owner: '@transcend-io/cli',\n files: POLICY_SKILL_FILES,\n};\n\n/** In-memory input consumed by the pure policy initializer. */\nexport interface PolicyInitPlanningInput {\n /** Project discovery state. */\n state: PolicyProjectState;\n /** Potential mutation paths keyed by absolute path. */\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>;\n}\n\n/** Optional repository setup selected for policy initialization. */\nexport interface PolicyInitPlanOptions {\n /** Selected setup features. */\n features: readonly PolicySetupFeatureType[];\n /** Exact released Transcend CLI version for generated CI. */\n cliVersion: string;\n}\n\n/**\n * Enumerate all core starter paths that could be created.\n *\n * @param state - Policy project state\n * @param options - Selected repository setup\n * @returns Absolute candidate paths\n */\nexport function getPolicyInitPlanningCandidatePaths(\n state: PolicyProjectState,\n options: Pick<PolicyInitPlanOptions, 'features'>,\n): string[] {\n const paths = new Set(\n generatePolicyWorkspaceFiles().map(({ path }) => join(state.targetDirectory, path)),\n );\n const selected = new Set(options.features);\n if (selected.has(PolicySetupFeature.Editor)) {\n paths.add(join(state.projectRoot, '.vscode', 'settings.json'));\n paths.add(join(state.projectRoot, '.vscode', 'extensions.json'));\n paths.add(join(state.projectRoot, '.vscode', 'tasks.json'));\n }\n if (selected.has(PolicySetupFeature.Skill)) {\n getManagedAgentSkillCandidatePaths(\n state.projectRoot,\n state.existingSkillDirectories,\n POLICY_MANAGED_SKILL,\n ).forEach((path) => paths.add(path));\n }\n if (selected.has(PolicySetupFeature.Ci) && state.repositoryRoot && state.usesGithub) {\n paths.add(join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH));\n }\n return [...paths].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * Ensure a destination stays below an approved project root.\n *\n * @param root - Approved root\n * @param path - Candidate path\n */\nfunction assertContained(root: string, path: string): void {\n const child = relative(root, path);\n if (child === '..' || child.startsWith(`..${sep}`) || isAbsolute(child)) {\n throw new Error(`Refusing to modify path outside project root: ${path}`);\n }\n}\n\n/**\n * Enumerate generated file and directory paths allowed in an exact starter.\n *\n * @param files - Starter files\n * @returns POSIX relative paths\n */\nfunction starterRelativePaths(files: readonly PolicyStarterFile[]): Set<string> {\n const paths = new Set<string>([`${POLICY_STARTER_BUNDLE_DIRECTORY}/input.json`]);\n files.forEach(({ path }) => {\n paths.add(path);\n let parent = posix.dirname(path);\n while (parent !== '.') {\n paths.add(parent);\n parent = posix.dirname(parent);\n }\n });\n return paths;\n}\n\n/**\n * Add or classify one regular-file mutation.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param options - Desired file\n */\nfunction addFileChange(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n options: {\n /** Absolute destination path. */\n path: string;\n /** Complete desired contents. */\n contents: string;\n /** Human-readable plan description. */\n description: string;\n /** Refuse existing contents. */\n createOnly?: boolean;\n },\n): void {\n const change = planFileChange({\n snapshot: getPlanningFileSnapshot(input.snapshots, options.path),\n after: options.contents,\n description: options.description,\n ...(options.createOnly === undefined ? {} : { createOnly: options.createOnly }),\n });\n if (change) {\n plan.changes.push(change);\n } else {\n plan.unchanged.push(options.path);\n }\n}\n\n/**\n * Add one safe editor merge and its preservation warnings.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param path - Absolute editor artifact path\n * @param result - Pure JSONC merge result\n * @param description - Human-readable plan description\n * @param cwd - Invocation directory for portable warning paths\n */\nfunction addEditorMerge(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n path: string,\n result: PolicyEditorMergeResult,\n description: string,\n cwd: string,\n): void {\n addFileChange(plan, input, {\n path,\n contents: result.contents,\n description,\n });\n plan.warnings.push(\n ...result.warnings.map((warning) => `${warning} (${displayProjectPath(cwd, path)})`),\n );\n}\n\n/**\n * Build a safe policy project plan without reading the filesystem.\n *\n * Empty targets receive the complete starter. Existing targets are classified\n * only; no domain file is added, merged, or overwritten.\n *\n * @param input - Collected project state and path snapshots\n * @param options - Selected setup and pinned CLI version\n * @returns Validated policy initialization plan\n */\nexport function buildPolicyInitPlan(\n input: PolicyInitPlanningInput,\n options: PolicyInitPlanOptions,\n): PolicyInitProjectPlan {\n const { state } = input;\n const files = generatePolicyWorkspaceFiles();\n const newCommand = 'transcend policy new';\n const plan: PolicyInitProjectPlan = {\n version: POLICY_INIT_RESULT_VERSION,\n command: 'init',\n rootDirectory: state.projectRoot,\n targetDirectory: state.targetDirectory,\n // Init creates a workspace only; bundles (and their .manifest) come from `policy new`.\n manifestPath: state.targetDirectory,\n changes: [],\n unchanged: [],\n warnings: [],\n nextSteps: [newCommand],\n features: [...options.features],\n };\n\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, options);\n assertContained(state.projectRoot, state.targetDirectory);\n candidatePaths.forEach((path) => assertContained(state.projectRoot, path));\n\n if (state.relativeFilePaths.length === 0) {\n plan.directoryPreconditions = [\n {\n path: state.targetDirectory,\n relativePaths: [...state.relativePaths],\n },\n ];\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent') {\n throw new Error(`Expected an empty policy target, but found an entry at: ${path}`);\n }\n addFileChange(plan, input, {\n path,\n contents: file.contents,\n description: file.description,\n createOnly: true,\n });\n });\n } else {\n let allWorkspaceFilesMatch = true;\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind === 'file' && snapshot.contents === file.contents) {\n plan.unchanged.push(path);\n return;\n }\n allWorkspaceFilesMatch = false;\n if (snapshot.kind !== 'absent') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing policy scaffold path was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n }\n });\n\n const allowedPaths = starterRelativePaths(files);\n const hasCustomPaths = state.relativeFilePaths.some((path) => !allowedPaths.has(path));\n if (!allWorkspaceFilesMatch || hasCustomPaths) {\n plan.warnings.push(\n `Existing policy target contains custom or partial content, so no workspace files were added or overwritten. ` +\n `Review ${displayProjectPath(\n state.invocationDirectory,\n state.targetDirectory,\n )} manually, then run \\`${newCommand}\\`.`,\n );\n }\n }\n\n const selected = new Set(options.features);\n const root = state.projectRoot;\n if (selected.has(PolicySetupFeature.Editor)) {\n const settingsPath = join(root, '.vscode', 'settings.json');\n const extensionsPath = join(root, '.vscode', 'extensions.json');\n const tasksPath = join(root, '.vscode', 'tasks.json');\n\n type EditorMergeFn = (\n contents: string | null,\n repositoryRoot: string,\n targetDirectory: string,\n ) => PolicyEditorMergeResult;\n const editorArtifacts: {\n /** Absolute path. */\n path: string;\n /** Plan description. */\n description: string;\n /** Merge function. */\n merge: EditorMergeFn;\n }[] = [\n {\n path: settingsPath,\n description: 'Merge strict target-scoped OPA and Rego editor settings',\n merge: (contents, repositoryRoot, targetDirectory) =>\n mergePolicyEditorSettings(contents, repositoryRoot, targetDirectory),\n },\n {\n path: extensionsPath,\n description: 'Recommend the OPA extension and discourage its syntax-only conflict',\n merge: (contents) => mergePolicyEditorExtensions(contents),\n },\n {\n path: tasksPath,\n description: 'Create the VS Code task configuration',\n merge: (contents, repositoryRoot, targetDirectory) =>\n mergePolicyEditorTasks(contents, repositoryRoot, targetDirectory),\n },\n ];\n editorArtifacts.forEach(({ path, description, merge }) => {\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent' && snapshot.kind !== 'file') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing VS Code artifact is not a regular file and was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n return;\n }\n addEditorMerge(\n plan,\n input,\n path,\n merge(snapshot.kind === 'file' ? snapshot.contents : null, root, state.targetDirectory),\n description,\n state.invocationDirectory,\n );\n });\n }\n\n if (selected.has(PolicySetupFeature.Skill)) {\n const skillPlan = planManagedAgentSkill({\n rootDirectory: root,\n existingDirectories: state.existingSkillDirectories,\n snapshots: input.snapshots,\n skill: POLICY_MANAGED_SKILL,\n preserveModified: true,\n });\n plan.changes.push(...skillPlan.changes);\n plan.unchanged.push(...skillPlan.unchanged);\n plan.warnings.push(\n ...skillPlan.warnings.map((warning) => {\n return skillPlan.unchanged.reduce(\n (rendered, path) =>\n rendered.replace(path, displayProjectPath(state.invocationDirectory, path)),\n warning,\n );\n }),\n );\n }\n\n if (selected.has(PolicySetupFeature.Ci)) {\n if (!state.repositoryRoot || !state.usesGithub) {\n plan.warnings.push(\n 'GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.',\n );\n } else {\n const workflowPath = join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH);\n const workspaceDirectory =\n relative(state.repositoryRoot, state.targetDirectory).split(sep).join('/') || '.';\n const workflowContents = generatePolicyGithubActionsWorkflow({\n cliVersion: options.cliVersion,\n workspaceDirectory,\n bundleDirectories: [],\n });\n const workflowSnapshot = getPlanningPathSnapshot(input.snapshots, workflowPath);\n if (workflowSnapshot.kind === 'absent') {\n addFileChange(plan, input, {\n path: workflowPath,\n contents: workflowContents,\n description: 'Add credential-free Policy Engine validation',\n createOnly: true,\n });\n } else if (\n workflowSnapshot.kind === 'file' &&\n workflowSnapshot.contents === workflowContents\n ) {\n plan.unchanged.push(workflowPath);\n } else {\n plan.unchanged.push(workflowPath);\n plan.warnings.push(\n `Existing GitHub Actions workflow was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n workflowPath,\n )}. Adapt it manually to validate each policy bundle.`,\n );\n }\n }\n }\n\n plan.changes.forEach(({ path }) => assertContained(state.projectRoot, path));\n return plan;\n}\n","import colors from 'colors';\n\nimport { version as CLI_VERSION } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n runCapturedProcess,\n type CapturedProcessResult,\n type CapturedProcessRunner,\n} from '../../../lib/cli/run-captured-process.js';\nimport {\n DEFAULT_POLICY_PROJECT_DIRECTORY,\n discoverPolicyProject,\n} from '../../../lib/policy/policy-project-discovery.js';\nimport {\n OPA_INSTALL_URL,\n OPA_MISSING_MESSAGE,\n parsePolicyToolVersion,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n REGAL_INSTALL_URL,\n REGAL_MISSING_MESSAGE,\n unsupportedOpaVersionMessage,\n unsupportedRegalVersionMessage,\n} from '../../../lib/policy/policy-runtime.js';\nimport {\n PolicySetupFeature,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from '../../../lib/policy/policy-scaffold-model.js';\nimport {\n buildPolicyInitAiHandoff,\n buildPolicyInitPlanResult,\n type PolicyInitToolVersions,\n} from '../../../lib/policy/policy-scaffold-output.js';\nimport {\n buildPolicyInitPlan,\n getPolicyInitPlanningCandidatePaths,\n} from '../../../lib/policy/policy-scaffold-planning.js';\nimport { POLICY_STARTER_OPA_VERSION } from '../../../lib/policy/policy-scaffold-templates.js';\nimport { collectPlanningSnapshots } from '../../../lib/scaffolding/project-discovery.js';\nimport { applyProjectPlan } from '../../../lib/scaffolding/project-plan-apply.js';\nimport {\n displayProjectPath,\n quoteShellArgument,\n renderProjectPlan,\n} from '../../../lib/scaffolding/project-plan-output.js';\nimport {\n isInteractivePromptInvocation,\n PromptCancelledError,\n resolveSetupFeatures,\n ScaffoldPrompts,\n} from '../../../lib/scaffolding/prompts.js';\n\n/** Flags for `transcend policy init`. */\nexport interface PolicyInitFlags {\n /** Install repository-level VS Code setup. */\n editor?: boolean;\n /** Install the Policy Engine Agent Skill. */\n skill?: boolean;\n /** Install validation-only GitHub Actions CI. */\n ci?: boolean;\n /** Disable prompts. */\n noInteractive: boolean;\n /** Render but do not apply the plan. */\n dryRun: boolean;\n /** Approve the final displayed plan. */\n yes: boolean;\n /** Emit one stable JSON result on stdout. */\n json: boolean;\n}\n\n/** User-facing optional setup labels. */\nconst SETUP_LABELS: Readonly<Record<PolicySetupFeatureType, string>> = {\n [PolicySetupFeature.Editor]: 'VS Code settings and lint task',\n [PolicySetupFeature.Skill]: 'Policy Engine Agent Skill',\n [PolicySetupFeature.Ci]: 'Validation-only GitHub Actions',\n};\n\n/** All optional setup features in stable prompt order. */\nconst ALL_SETUP_FEATURES = Object.values(PolicySetupFeature);\n\n/** Runtime compatibility detected before policy planning. */\ninterface PolicyRuntimeProbe {\n /** Compatible tool versions. */\n tools: PolicyInitToolVersions;\n /** Missing or incompatible runtime guidance. */\n warnings: string[];\n}\n\n/**\n * Explain a failed version subprocess with official installation guidance.\n *\n * @param tool - Policy tool name\n * @param result - Failed captured process\n * @returns Actionable warning\n */\nfunction failedVersionProbeMessage(tool: 'OPA' | 'Regal', result: CapturedProcessResult): string {\n const detail = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join('\\n');\n const url = tool === 'OPA' ? OPA_INSTALL_URL : REGAL_INSTALL_URL;\n const requirement =\n tool === 'OPA' ? 'OPA 1.x' : `Regal ${MINIMUM_POLICY_STARTER_REGAL_VERSION} or newer`;\n return (\n `${requirement} is required, but \\`${tool.toLowerCase()} version\\` exited with code ` +\n `${result.code}${detail ? `: ${detail}` : '.'} ` +\n `Install or upgrade it using the official instructions: ${url}`\n );\n}\n\n/**\n * Probe both local policy runtimes without installing or modifying them.\n *\n * @param context - CLI context\n * @param cwd - Invocation working directory\n * @param runner - Captured subprocess runner\n * @returns Compatible versions and exact runtime guidance\n */\nasync function probePolicyRuntimes(\n context: LocalContext,\n cwd: string,\n runner: CapturedProcessRunner,\n): Promise<PolicyRuntimeProbe> {\n const tools: PolicyInitToolVersions = { opa: null, regal: null };\n const warnings: string[] = [];\n\n const opaResult = await runner('opa', ['version'], { cwd }, context);\n if (opaResult.error?.code === 'ENOENT') {\n warnings.push(OPA_MISSING_MESSAGE);\n } else {\n const output = `${opaResult.stdout}\\n${opaResult.stderr}`;\n const unsupported = unsupportedOpaVersionMessage(output);\n if (opaResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('OPA', opaResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.opa = parsePolicyToolVersion(output)!.version;\n }\n }\n\n const regalResult = await runner('regal', ['version'], { cwd }, context);\n if (regalResult.error?.code === 'ENOENT') {\n warnings.push(REGAL_MISSING_MESSAGE);\n } else {\n const output = `${regalResult.stdout}\\n${regalResult.stderr}`;\n const unsupported = unsupportedRegalVersionMessage(\n output,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n `the generated OPA ${POLICY_STARTER_OPA_VERSION} capabilities configuration`,\n );\n if (regalResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('Regal', regalResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.regal = parsePolicyToolVersion(output)!.version;\n }\n }\n\n return { tools, warnings };\n}\n\n/**\n * Initialize a credential-free local Policy Engine project.\n *\n * @param this - CLI context\n * @param flags - Scaffold and interaction flags\n * @param directory - Target policy directory\n * @param runner - Captured policy tool runner\n */\nexport async function init(\n this: LocalContext,\n flags: PolicyInitFlags,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n runner: CapturedProcessRunner = runCapturedProcess,\n): Promise<void> {\n doneInputValidation(this.process);\n try {\n const runtime = await probePolicyRuntimes(this, this.process.cwd(), runner);\n const state = discoverPolicyProject(this, directory);\n const prompts = new ScaffoldPrompts(this);\n const interactive = isInteractivePromptInvocation(\n flags,\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n const features = await resolveSetupFeatures(prompts, {\n features: ALL_SETUP_FEATURES,\n labels: SETUP_LABELS,\n enabled: {\n [PolicySetupFeature.Editor]: flags.editor,\n [PolicySetupFeature.Skill]: flags.skill,\n [PolicySetupFeature.Ci]: flags.ci,\n },\n interactive,\n });\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, { features });\n const snapshots = collectPlanningSnapshots(this, state.projectRoot, candidatePaths);\n\n const plan = buildPolicyInitPlan(\n { state, snapshots },\n {\n features,\n cliVersion: CLI_VERSION,\n },\n );\n plan.warnings.push(...runtime.warnings);\n\n if (!flags.json) {\n this.logger.info(\n renderProjectPlan(plan, {\n cwd: this.process.cwd(),\n title: 'Policy initialization plan',\n details: [{ label: 'Target', path: plan.targetDirectory }],\n }),\n );\n }\n\n let approved = plan.changes.length === 0 || flags.dryRun;\n if (plan.changes.length > 0 && !flags.dryRun) {\n if (flags.yes) {\n approved = true;\n } else if (interactive) {\n approved = await prompts.confirm('Apply this complete plan?', true);\n } else {\n throw new Error(\n 'The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.',\n );\n }\n }\n\n if (approved && !flags.dryRun && plan.changes.length > 0) {\n await applyProjectPlan(this, plan);\n }\n const applied = approved && !flags.dryRun && plan.changes.length > 0;\n const setupAvailable = approved && !flags.dryRun;\n const aiHandoff = buildPolicyInitAiHandoff({\n projectPath: quoteShellArgument(\n displayProjectPath(this.process.cwd(), state.targetDirectory),\n ),\n hasSkill: setupAvailable && features.includes(PolicySetupFeature.Skill),\n newCommand: plan.nextSteps[0]!,\n });\n const result = buildPolicyInitPlanResult(plan, {\n applied,\n dryRun: flags.dryRun,\n cwd: this.process.cwd(),\n aiHandoff,\n tools: runtime.tools,\n });\n if (flags.json) {\n this.process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n if (flags.dryRun) {\n this.logger.info(colors.yellow('Dry run complete. No changes were written.'));\n return;\n }\n if (!approved) {\n this.logger.info(colors.yellow('No changes applied.'));\n return;\n }\n if (plan.changes.length === 0) {\n const message =\n plan.warnings.length === runtime.warnings.length\n ? 'Policy project is already initialized.'\n : 'Existing policy project was left unchanged.';\n this.logger.info(colors.green(message));\n } else {\n this.logger.info(colors.green('Policy project initialized.'));\n }\n if (plan.nextSteps.length > 0) {\n this.logger.info(`\\n${colors.bold('Next steps')}`);\n plan.nextSteps.forEach((step) => this.logger.info(step));\n }\n this.logger.info(`\\n${colors.bold('AI handoff — paste into your coding agent')}`);\n this.logger.info(aiHandoff);\n } catch (error) {\n if (error instanceof PromptCancelledError) {\n return this.process.exit(130);\n }\n throw error;\n }\n}\n"],"mappings":"uyBAOA,MAAa,EAAqB,CAEhC,OAAQ,SAER,MAAO,QAEP,GAAI,KACL,OCdD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ICAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ICAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ICAA,ilHCAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECQA,MAAa,EAAoB,0BAWpB,EAAgD,CAC3D,CAAE,KAAM,WAAY,SAAUA,EAAiB,CAC/C,CAAE,KAAM,8BAA+B,SAAUC,EAAmC,CACpF,CAAE,KAAM,0BAA2B,SAAUC,EAA+B,CAC5E,CAAE,KAAM,kCAAmC,SAAUC,EAAuC,CAC5F,CAAE,KAAM,2BAA4B,SAAUC,EAAgC,CAC/E,CCwBD,SAAgB,EAAyB,EAO9B,CAET,MACE,GAFkB,EAAQ,SAAW,aAAa,EAAkB,kBAAoB,MAEzE,GAAG,EAAQ,WAAW,8HAYzC,SAAgB,EACd,EACA,EAYsB,CACtB,MAAO,CACL,QAAS,EAAK,QACd,QAAS,EAAK,QACd,QAAS,EAAQ,QACjB,OAAQ,EAAQ,OAChB,gBAAiB,EAAK,gBACtB,aAAc,EAAK,aACnB,QAAS,EAAK,QAAQ,IAAK,GAAW,EAAsB,EAAQ,IAAK,EAAO,CAAC,CACjF,SAAU,EAAK,SACf,UAAW,EAAK,UAChB,SAAU,CAAC,GAAG,EAAK,SAAS,CAC5B,UAAW,EAAQ,UACnB,MAAO,EAAQ,MAChB,CC5DH,MAAM,EAAoD,CACxD,KAAM,EACN,YAAa,gBACb,MAAO,oBACP,MAAO,EACR,CAyBD,SAAgB,EACd,EACA,EACU,CACV,IAAM,EAAQ,IAAI,IAChB,GAA8B,CAAC,KAAK,CAAE,UAAW,EAAK,EAAM,gBAAiB,EAAK,CAAC,CACpF,CACK,EAAW,IAAI,IAAI,EAAQ,SAAS,CAgB1C,OAfI,EAAS,IAAI,EAAmB,OAAO,GACzC,EAAM,IAAI,EAAK,EAAM,YAAa,UAAW,gBAAgB,CAAC,CAC9D,EAAM,IAAI,EAAK,EAAM,YAAa,UAAW,kBAAkB,CAAC,CAChE,EAAM,IAAI,EAAK,EAAM,YAAa,UAAW,aAAa,CAAC,EAEzD,EAAS,IAAI,EAAmB,MAAM,EACxC,EACE,EAAM,YACN,EAAM,yBACN,EACD,CAAC,QAAS,GAAS,EAAM,IAAI,EAAK,CAAC,CAElC,EAAS,IAAI,EAAmB,GAAG,EAAI,EAAM,gBAAkB,EAAM,YACvE,EAAM,IAAI,EAAK,EAAM,eAAgB,EAAwB,CAAC,CAEzD,CAAC,GAAG,EAAM,CAAC,MAAM,EAAM,IAAU,EAAK,cAAc,EAAM,CAAC,CASpE,SAAS,EAAgB,EAAc,EAAoB,CACzD,IAAM,EAAQ,EAAS,EAAM,EAAK,CAClC,GAAI,IAAU,MAAQ,EAAM,WAAW,KAAK,IAAM,EAAI,EAAW,EAAM,CACrE,MAAU,MAAM,iDAAiD,IAAO,CAU5E,SAAS,GAAqB,EAAkD,CAC9E,IAAM,EAAQ,IAAI,IAAY,CAAC,GAAG,EAAgC,aAAa,CAAC,CAShF,OARA,EAAM,SAAS,CAAE,UAAW,CAC1B,EAAM,IAAI,EAAK,CACf,IAAI,EAAS,EAAM,QAAQ,EAAK,CAChC,KAAO,IAAW,KAChB,EAAM,IAAI,EAAO,CACjB,EAAS,EAAM,QAAQ,EAAO,EAEhC,CACK,EAUT,SAAS,EACP,EACA,EACA,EAUM,CACN,IAAM,EAAS,EAAe,CAC5B,SAAU,EAAwB,EAAM,UAAW,EAAQ,KAAK,CAChE,MAAO,EAAQ,SACf,YAAa,EAAQ,YACrB,GAAI,EAAQ,aAAe,IAAA,GAAY,EAAE,CAAG,CAAE,WAAY,EAAQ,WAAY,CAC/E,CAAC,CACE,EACF,EAAK,QAAQ,KAAK,EAAO,CAEzB,EAAK,UAAU,KAAK,EAAQ,KAAK,CAcrC,SAAS,GACP,EACA,EACA,EACA,EACA,EACA,EACM,CACN,EAAc,EAAM,EAAO,CACzB,OACA,SAAU,EAAO,SACjB,cACD,CAAC,CACF,EAAK,SAAS,KACZ,GAAG,EAAO,SAAS,IAAK,GAAY,GAAG,EAAQ,IAAI,EAAmB,EAAK,EAAK,CAAC,GAAG,CACrF,CAaH,SAAgB,GACd,EACA,EACuB,CACvB,GAAM,CAAE,SAAU,EACZ,EAAQ,GAA8B,CACtC,EAAa,uBACb,EAA8B,CAClC,QAAA,EACA,QAAS,OACT,cAAe,EAAM,YACrB,gBAAiB,EAAM,gBAEvB,aAAc,EAAM,gBACpB,QAAS,EAAE,CACX,UAAW,EAAE,CACb,SAAU,EAAE,CACZ,UAAW,CAAC,EAAW,CACvB,SAAU,CAAC,GAAG,EAAQ,SAAS,CAChC,CAEK,EAAiB,EAAoC,EAAO,EAAQ,CAI1E,GAHA,EAAgB,EAAM,YAAa,EAAM,gBAAgB,CACzD,EAAe,QAAS,GAAS,EAAgB,EAAM,YAAa,EAAK,CAAC,CAEtE,EAAM,kBAAkB,SAAW,EACrC,EAAK,uBAAyB,CAC5B,CACE,KAAM,EAAM,gBACZ,cAAe,CAAC,GAAG,EAAM,cAAc,CACxC,CACF,CACD,EAAM,QAAS,GAAS,CACtB,IAAM,EAAO,EAAK,EAAM,gBAAiB,EAAK,KAAK,CAEnD,GADiB,EAAwB,EAAM,UAAW,EAC9C,CAAC,OAAS,SACpB,MAAU,MAAM,2DAA2D,IAAO,CAEpF,EAAc,EAAM,EAAO,CACzB,OACA,SAAU,EAAK,SACf,YAAa,EAAK,YAClB,WAAY,GACb,CAAC,EACF,KACG,CACL,IAAI,EAAyB,GAC7B,EAAM,QAAS,GAAS,CACtB,IAAM,EAAO,EAAK,EAAM,gBAAiB,EAAK,KAAK,CAC7C,EAAW,EAAwB,EAAM,UAAW,EAAK,CAC/D,GAAI,EAAS,OAAS,QAAU,EAAS,WAAa,EAAK,SAAU,CACnE,EAAK,UAAU,KAAK,EAAK,CACzB,OAEF,EAAyB,GACrB,EAAS,OAAS,WACpB,EAAK,UAAU,KAAK,EAAK,CACzB,EAAK,SAAS,KACZ,qDAAqD,EACnD,EAAM,oBACN,EACD,GACF,GAEH,CAEF,IAAM,EAAe,GAAqB,EAAM,CAC1C,EAAiB,EAAM,kBAAkB,KAAM,GAAS,CAAC,EAAa,IAAI,EAAK,CAAC,EAClF,CAAC,GAA0B,IAC7B,EAAK,SAAS,KACZ,sHACY,EACR,EAAM,oBACN,EAAM,gBACP,CAAC,wBAAwB,EAAW,KACxC,CAIL,IAAM,EAAW,IAAI,IAAI,EAAQ,SAAS,CACpC,EAAO,EAAM,YACnB,GAAI,EAAS,IAAI,EAAmB,OAAO,CAAE,CAC3C,IAAM,EAAe,EAAK,EAAM,UAAW,gBAAgB,CACrD,EAAiB,EAAK,EAAM,UAAW,kBAAkB,CACzD,EAAY,EAAK,EAAM,UAAW,aAAa,CAiCrD,CAlBE,CACE,KAAM,EACN,YAAa,0DACb,OAAQ,EAAU,EAAgB,IAChC,GAA0B,EAAU,EAAgB,EAAgB,CACvE,CACD,CACE,KAAM,EACN,YAAa,sEACb,MAAQ,GAAa,GAA4B,EAAS,CAC3D,CACD,CACE,KAAM,EACN,YAAa,wCACb,OAAQ,EAAU,EAAgB,IAChC,GAAuB,EAAU,EAAgB,EAAgB,CACpE,CAEY,CAAC,SAAS,CAAE,OAAM,cAAa,WAAY,CACxD,IAAM,EAAW,EAAwB,EAAM,UAAW,EAAK,CAC/D,GAAI,EAAS,OAAS,UAAY,EAAS,OAAS,OAAQ,CAC1D,EAAK,UAAU,KAAK,EAAK,CACzB,EAAK,SAAS,KACZ,2EAA2E,EACzE,EAAM,oBACN,EACD,GACF,CACD,OAEF,GACE,EACA,EACA,EACA,EAAM,EAAS,OAAS,OAAS,EAAS,SAAW,KAAM,EAAM,EAAM,gBAAgB,CACvF,EACA,EAAM,oBACP,EACD,CAGJ,GAAI,EAAS,IAAI,EAAmB,MAAM,CAAE,CAC1C,IAAM,EAAY,EAAsB,CACtC,cAAe,EACf,oBAAqB,EAAM,yBAC3B,UAAW,EAAM,UACjB,MAAO,EACP,iBAAkB,GACnB,CAAC,CACF,EAAK,QAAQ,KAAK,GAAG,EAAU,QAAQ,CACvC,EAAK,UAAU,KAAK,GAAG,EAAU,UAAU,CAC3C,EAAK,SAAS,KACZ,GAAG,EAAU,SAAS,IAAK,GAClB,EAAU,UAAU,QACxB,EAAU,IACT,EAAS,QAAQ,EAAM,EAAmB,EAAM,oBAAqB,EAAK,CAAC,CAC7E,EACD,CACD,CACH,CAGH,GAAI,EAAS,IAAI,EAAmB,GAAG,CACrC,GAAI,CAAC,EAAM,gBAAkB,CAAC,EAAM,WAClC,EAAK,SAAS,KACZ,iGACD,KACI,CACL,IAAM,EAAe,EAAK,EAAM,eAAgB,EAAwB,CAClE,EACJ,EAAS,EAAM,eAAgB,EAAM,gBAAgB,CAAC,MAAM,EAAI,CAAC,KAAK,IAAI,EAAI,IAC1E,EAAmB,GAAoC,CAC3D,WAAY,EAAQ,WACpB,qBACA,kBAAmB,EAAE,CACtB,CAAC,CACI,EAAmB,EAAwB,EAAM,UAAW,EAAa,CAC3E,EAAiB,OAAS,SAC5B,EAAc,EAAM,EAAO,CACzB,KAAM,EACN,SAAU,EACV,YAAa,+CACb,WAAY,GACb,CAAC,CAEF,EAAiB,OAAS,QAC1B,EAAiB,WAAa,EAE9B,EAAK,UAAU,KAAK,EAAa,EAEjC,EAAK,UAAU,KAAK,EAAa,CACjC,EAAK,SAAS,KACZ,wDAAwD,EACtD,EAAM,oBACN,EACD,CAAC,qDACH,EAMP,OADA,EAAK,QAAQ,SAAS,CAAE,UAAW,EAAgB,EAAM,YAAa,EAAK,CAAC,CACrE,ECzUT,MAAM,GAAiE,EACpE,EAAmB,QAAS,kCAC5B,EAAmB,OAAQ,6BAC3B,EAAmB,IAAK,iCAC1B,CAGK,GAAqB,OAAO,OAAO,EAAmB,CAiB5D,SAAS,EAA0B,EAAuB,EAAuC,CAC/F,IAAM,EAAS,CAAC,EAAO,OAAO,MAAM,CAAE,EAAO,OAAO,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK;EAAK,CAChF,EAAM,IAAS,MAAQ,EAAkB,EAG/C,MACE,GAFA,IAAS,MAAQ,UAAY,SAAS,EAAqC,WAE5D,sBAAsB,EAAK,aAAa,CAAC,8BACrD,EAAO,OAAO,EAAS,KAAK,IAAW,IAAI,0DACY,IAY9D,eAAe,GACb,EACA,EACA,EAC6B,CAC7B,IAAM,EAAgC,CAAE,IAAK,KAAM,MAAO,KAAM,CAC1D,EAAqB,EAAE,CAEvB,EAAY,MAAM,EAAO,MAAO,CAAC,UAAU,CAAE,CAAE,MAAK,CAAE,EAAQ,CACpE,GAAI,EAAU,OAAO,OAAS,SAC5B,EAAS,KAAK,EAAoB,KAC7B,CACL,IAAM,EAAS,GAAG,EAAU,OAAO,IAAI,EAAU,SAC3C,EAAc,EAA6B,EAAO,CACpD,EAAU,OAAS,EAEZ,EACT,EAAS,KAAK,EAAY,CAE1B,EAAM,IAAM,EAAuB,EAAO,CAAE,QAJ5C,EAAS,KAAK,GAAe,EAA0B,MAAO,EAAU,CAAC,CAQ7E,IAAM,EAAc,MAAM,EAAO,QAAS,CAAC,UAAU,CAAE,CAAE,MAAK,CAAE,EAAQ,CACxE,GAAI,EAAY,OAAO,OAAS,SAC9B,EAAS,KAAK,EAAsB,KAC/B,CACL,IAAM,EAAS,GAAG,EAAY,OAAO,IAAI,EAAY,SAC/C,EAAc,EAClB,EACA,EACA,qBAAqB,EAA2B,6BACjD,CACG,EAAY,OAAS,EAEd,EACT,EAAS,KAAK,EAAY,CAE1B,EAAM,MAAQ,EAAuB,EAAO,CAAE,QAJ9C,EAAS,KAAK,GAAe,EAA0B,QAAS,EAAY,CAAC,CAQjF,MAAO,CAAE,QAAO,WAAU,CAW5B,eAAsB,EAEpB,EACA,EAAoB,EACpB,EAAgC,EACjB,CACf,EAAoB,KAAK,QAAQ,CACjC,GAAI,CACF,IAAM,EAAU,MAAM,GAAoB,KAAM,KAAK,QAAQ,KAAK,CAAE,EAAO,CACrE,EAAQ,EAAsB,KAAM,EAAU,CAC9C,EAAU,IAAI,EAAgB,KAAK,CACnC,EAAc,EAClB,EACA,KAAK,QAAQ,MAAM,MACnB,KAAK,QAAQ,OAAO,MACrB,CACK,EAAW,MAAM,EAAqB,EAAS,CACnD,SAAU,GACV,OAAQ,GACR,QAAS,EACN,EAAmB,QAAS,EAAM,QAClC,EAAmB,OAAQ,EAAM,OACjC,EAAmB,IAAK,EAAM,GAChC,CACD,cACD,CAAC,CACI,EAAiB,EAAoC,EAAO,CAAE,WAAU,CAAC,CAGzE,EAAO,GACX,CAAE,QAAO,UAHO,EAAyB,KAAM,EAAM,YAAa,EAGhD,CAAE,CACpB,CACE,WACA,WAAYC,EACb,CACF,CACD,EAAK,SAAS,KAAK,GAAG,EAAQ,SAAS,CAElC,EAAM,MACT,KAAK,OAAO,KACV,EAAkB,EAAM,CACtB,IAAK,KAAK,QAAQ,KAAK,CACvB,MAAO,6BACP,QAAS,CAAC,CAAE,MAAO,SAAU,KAAM,EAAK,gBAAiB,CAAC,CAC3D,CAAC,CACH,CAGH,IAAI,EAAW,EAAK,QAAQ,SAAW,GAAK,EAAM,OAClD,GAAI,EAAK,QAAQ,OAAS,GAAK,CAAC,EAAM,OACpC,GAAI,EAAM,IACR,EAAW,WACF,EACT,EAAW,MAAM,EAAQ,QAAQ,4BAA6B,GAAK,MAEnE,MAAU,MACR,qGACD,CAID,GAAY,CAAC,EAAM,QAAU,EAAK,QAAQ,OAAS,GACrD,MAAM,EAAiB,KAAM,EAAK,CAEpC,IAAM,EAAU,GAAY,CAAC,EAAM,QAAU,EAAK,QAAQ,OAAS,EAC7D,EAAiB,GAAY,CAAC,EAAM,OACpC,EAAY,EAAyB,CACzC,YAAa,EACX,EAAmB,KAAK,QAAQ,KAAK,CAAE,EAAM,gBAAgB,CAC9D,CACD,SAAU,GAAkB,EAAS,SAAS,EAAmB,MAAM,CACvE,WAAY,EAAK,UAAU,GAC5B,CAAC,CACI,EAAS,EAA0B,EAAM,CAC7C,UACA,OAAQ,EAAM,OACd,IAAK,KAAK,QAAQ,KAAK,CACvB,YACA,MAAO,EAAQ,MAChB,CAAC,CACF,GAAI,EAAM,KAAM,CACd,KAAK,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,EAAO,CAAC,IAAI,CACxD,OAEF,GAAI,EAAM,OAAQ,CAChB,KAAK,OAAO,KAAK,EAAO,OAAO,6CAA6C,CAAC,CAC7E,OAEF,GAAI,CAAC,EAAU,CACb,KAAK,OAAO,KAAK,EAAO,OAAO,sBAAsB,CAAC,CACtD,OAEF,GAAI,EAAK,QAAQ,SAAW,EAAG,CAC7B,IAAM,EACJ,EAAK,SAAS,SAAW,EAAQ,SAAS,OACtC,yCACA,8CACN,KAAK,OAAO,KAAK,EAAO,MAAM,EAAQ,CAAC,MAEvC,KAAK,OAAO,KAAK,EAAO,MAAM,8BAA8B,CAAC,CAE3D,EAAK,UAAU,OAAS,IAC1B,KAAK,OAAO,KAAK,KAAK,EAAO,KAAK,aAAa,GAAG,CAClD,EAAK,UAAU,QAAS,GAAS,KAAK,OAAO,KAAK,EAAK,CAAC,EAE1D,KAAK,OAAO,KAAK,KAAK,EAAO,KAAK,4CAA4C,GAAG,CACjF,KAAK,OAAO,KAAK,EAAU,OACpB,EAAO,CACd,GAAI,aAAiB,EACnB,OAAO,KAAK,QAAQ,KAAK,IAAI,CAE/B,MAAM"}
|
|
1
|
+
{"version":3,"file":"impl-S3znb469.mjs","names":["POLICY_SKILL_MD","POLICY_SETUP_TOOLING_REFERENCE_MD","POLICY_AUTHORING_REFERENCE_MD","POLICY_TESTING_DEBUGGING_REFERENCE_MD","POLICY_PUBLISHING_REFERENCE_MD","CLI_VERSION"],"sources":["../src/lib/policy/policy-scaffold-model.ts","../../../skills/transcend-policy-engine/references/authoring.md","../../../skills/transcend-policy-engine/references/publishing.md","../../../skills/transcend-policy-engine/references/setup-tooling.md","../../../skills/transcend-policy-engine/references/testing-debugging.md","../../../skills/transcend-policy-engine/SKILL.md","../src/lib/policy/policy-skill.ts","../src/lib/policy/policy-scaffold-output.ts","../src/lib/policy/policy-scaffold-planning.ts","../src/commands/policy/init/impl.ts"],"sourcesContent":["import type { ExistingProjectSkillDirectory } from '../scaffolding/agent-skill.js';\nimport type { ProjectPlan } from '../scaffolding/project-plan.js';\n\n/** Version of the stable policy initialization JSON result. */\nexport const POLICY_INIT_RESULT_VERSION = 3 as const;\n\n/** Optional repository integrations for policy authoring. */\nexport const PolicySetupFeature = {\n /** Repository-level editor configuration. */\n Editor: 'editor',\n /** Managed policy authoring skill. */\n Skill: 'skill',\n /** Credential-free continuous integration. */\n Ci: 'ci',\n} as const;\n\n/** Optional repository integration for policy authoring. */\nexport type PolicySetupFeature = (typeof PolicySetupFeature)[keyof typeof PolicySetupFeature];\n\n/** Repository and target state collected before policy planning. */\nexport interface PolicyProjectState {\n /** Directory from which the CLI was invoked. */\n invocationDirectory: string;\n /** Absolute user-selected policy directory. */\n targetDirectory: string;\n /** Repository or invocation root that owns setup artifacts. */\n projectRoot: string;\n /** Nearest repository root, when present. */\n repositoryRoot?: string;\n /** Existing project-level skill directories. */\n existingSkillDirectories: ExistingProjectSkillDirectory[];\n /** Whether the repository appears to use GitHub. */\n usesGithub: boolean;\n /** Case-preserving relative paths below the policy directory. */\n relativePaths: string[];\n /** Relative file and link paths below the policy directory. */\n relativeFilePaths: string[];\n}\n\n/** A complete, validated policy initialization plan. */\nexport interface PolicyInitProjectPlan extends ProjectPlan {\n /** JSON contract version. */\n version: typeof POLICY_INIT_RESULT_VERSION;\n /** Command that produced the plan. */\n command: 'init';\n /** Absolute policy project directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Files inspected and deliberately left unchanged. */\n unchanged: string[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Raw commands shown after a successful apply. */\n nextSteps: string[];\n /** Exact generated example that remains safe to replace. */\n disposableExamplePath?: string;\n /** Selected repository integrations. */\n features: PolicySetupFeature[];\n}\n",null,null,null,null,null,"import POLICY_AUTHORING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/authoring.md';\nimport POLICY_PUBLISHING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/publishing.md';\nimport POLICY_SETUP_TOOLING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/setup-tooling.md';\nimport POLICY_TESTING_DEBUGGING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/testing-debugging.md';\nimport POLICY_SKILL_MD from '../../../../../skills/transcend-policy-engine/SKILL.md';\nimport type { AgentSkillFile } from '../scaffolding/agent-skill.js';\n\n/** Namespaced directory and frontmatter name for the installed Agent Skill. */\nexport const POLICY_SKILL_NAME = 'transcend-policy-engine';\n\nexport {\n POLICY_AUTHORING_REFERENCE_MD,\n POLICY_PUBLISHING_REFERENCE_MD,\n POLICY_SETUP_TOOLING_REFERENCE_MD,\n POLICY_SKILL_MD,\n POLICY_TESTING_DEBUGGING_REFERENCE_MD,\n};\n\n/** Complete portable Policy Engine Agent Skill file set. */\nexport const POLICY_SKILL_FILES: readonly AgentSkillFile[] = [\n { path: 'SKILL.md', contents: POLICY_SKILL_MD },\n { path: 'references/setup-tooling.md', contents: POLICY_SETUP_TOOLING_REFERENCE_MD },\n { path: 'references/authoring.md', contents: POLICY_AUTHORING_REFERENCE_MD },\n { path: 'references/testing-debugging.md', contents: POLICY_TESTING_DEBUGGING_REFERENCE_MD },\n { path: 'references/publishing.md', contents: POLICY_PUBLISHING_REFERENCE_MD },\n];\n","import {\n toPublicPlannedChange,\n type PublicPlannedChange,\n} from '../scaffolding/project-plan-output.js';\nimport type { PolicyInitProjectPlan, PolicySetupFeature } from './policy-scaffold-model.js';\nimport { POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Detected local policy tool versions. */\nexport interface PolicyInitToolVersions {\n /** OPA version, or null when missing or incompatible. */\n opa: string | null;\n /** Regal version, or null when missing or incompatible. */\n regal: string | null;\n}\n\n/** Stable machine-readable policy initialization result. */\nexport interface PolicyInitPlanResult {\n /** JSON contract version. */\n version: number;\n /** Command that produced the result. */\n command: 'init';\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Absolute policy target directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Planned mutations without file contents. */\n changes: PublicPlannedChange[];\n /** Non-fatal preservation and runtime warnings. */\n warnings: string[];\n /** Suggested raw one-line follow-up commands. */\n nextSteps: string[];\n /** Explicitly selected repository integrations. */\n features: PolicySetupFeature[];\n /** Compact prompt for continuing with a coding agent. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n}\n\n/**\n * Build the compact policy implementation and CI handoff.\n *\n * @param options - Portable project path and next step\n * @returns Raw one-line prompt\n */\nexport function buildPolicyInitAiHandoff(options: {\n /** Display path to the policy project. */\n projectPath: string;\n /** Whether the policy authoring skill was installed. */\n hasSkill: boolean;\n /** Copyable new-bundle command. */\n newCommand: string;\n}): string {\n const instruction = options.hasSkill ? `Use the \\`${POLICY_SKILL_NAME}\\` skill and run` : 'Run';\n return (\n `${instruction} ${options.newCommand} to add a bundle from a template, ` +\n `then adapt the policy document tree and input/output contract to the intended application.`\n );\n}\n\n/**\n * Build the stable machine-readable initialization result.\n *\n * @param plan - Policy project plan\n * @param options - Apply and runtime state\n * @returns Public JSON result\n */\nexport function buildPolicyInitPlanResult(\n plan: PolicyInitProjectPlan,\n options: {\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Working directory for portable paths. */\n cwd: string;\n /** Compact coding-agent prompt. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n },\n): PolicyInitPlanResult {\n return {\n version: plan.version,\n command: plan.command,\n applied: options.applied,\n dryRun: options.dryRun,\n targetDirectory: plan.targetDirectory,\n manifestPath: plan.manifestPath,\n changes: plan.changes.map((change) => toPublicPlannedChange(options.cwd, change)),\n warnings: plan.warnings,\n nextSteps: plan.nextSteps,\n features: [...plan.features],\n aiHandoff: options.aiHandoff,\n tools: options.tools,\n };\n}\n","import { isAbsolute, join, posix, relative, sep } from 'node:path';\n\nimport {\n getManagedAgentSkillCandidatePaths,\n planManagedAgentSkill,\n type ManagedAgentSkillDefinition,\n} from '../scaffolding/agent-skill.js';\nimport { displayProjectPath } from '../scaffolding/project-plan-output.js';\nimport {\n getPlanningPathSnapshot,\n getPlanningFileSnapshot,\n planFileChange,\n type PlanningPathSnapshot,\n} from '../scaffolding/project-plan.js';\nimport {\n generatePolicyGithubActionsWorkflow,\n POLICY_CI_WORKFLOW_PATH,\n} from './policy-scaffold-artifacts.js';\nimport {\n mergePolicyEditorExtensions,\n mergePolicyEditorSettings,\n mergePolicyEditorTasks,\n type PolicyEditorMergeResult,\n} from './policy-scaffold-config.js';\nimport {\n POLICY_INIT_RESULT_VERSION,\n PolicySetupFeature,\n type PolicyInitProjectPlan,\n type PolicyProjectState,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from './policy-scaffold-model.js';\nimport {\n generatePolicyWorkspaceFiles,\n POLICY_STARTER_BUNDLE_DIRECTORY,\n type PolicyStarterFile,\n} from './policy-scaffold-templates.js';\nimport { POLICY_SKILL_FILES, POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Managed Policy Engine Agent Skill definition. */\nconst POLICY_MANAGED_SKILL: ManagedAgentSkillDefinition = {\n name: POLICY_SKILL_NAME,\n displayName: 'Policy Engine',\n owner: '@transcend-io/cli',\n files: POLICY_SKILL_FILES,\n};\n\n/** In-memory input consumed by the pure policy initializer. */\nexport interface PolicyInitPlanningInput {\n /** Project discovery state. */\n state: PolicyProjectState;\n /** Potential mutation paths keyed by absolute path. */\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>;\n}\n\n/** Optional repository setup selected for policy initialization. */\nexport interface PolicyInitPlanOptions {\n /** Selected setup features. */\n features: readonly PolicySetupFeatureType[];\n /** Exact released Transcend CLI version for generated CI. */\n cliVersion: string;\n}\n\n/**\n * Enumerate all core starter paths that could be created.\n *\n * @param state - Policy project state\n * @param options - Selected repository setup\n * @returns Absolute candidate paths\n */\nexport function getPolicyInitPlanningCandidatePaths(\n state: PolicyProjectState,\n options: Pick<PolicyInitPlanOptions, 'features'>,\n): string[] {\n const paths = new Set(\n generatePolicyWorkspaceFiles().map(({ path }) => join(state.targetDirectory, path)),\n );\n const selected = new Set(options.features);\n if (selected.has(PolicySetupFeature.Editor)) {\n paths.add(join(state.projectRoot, '.vscode', 'settings.json'));\n paths.add(join(state.projectRoot, '.vscode', 'extensions.json'));\n paths.add(join(state.projectRoot, '.vscode', 'tasks.json'));\n }\n if (selected.has(PolicySetupFeature.Skill)) {\n getManagedAgentSkillCandidatePaths(\n state.projectRoot,\n state.existingSkillDirectories,\n POLICY_MANAGED_SKILL,\n ).forEach((path) => paths.add(path));\n }\n if (selected.has(PolicySetupFeature.Ci) && state.repositoryRoot && state.usesGithub) {\n paths.add(join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH));\n }\n return [...paths].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * Ensure a destination stays below an approved project root.\n *\n * @param root - Approved root\n * @param path - Candidate path\n */\nfunction assertContained(root: string, path: string): void {\n const child = relative(root, path);\n if (child === '..' || child.startsWith(`..${sep}`) || isAbsolute(child)) {\n throw new Error(`Refusing to modify path outside project root: ${path}`);\n }\n}\n\n/**\n * Enumerate generated file and directory paths allowed in an exact starter.\n *\n * @param files - Starter files\n * @returns POSIX relative paths\n */\nfunction starterRelativePaths(files: readonly PolicyStarterFile[]): Set<string> {\n const paths = new Set<string>([`${POLICY_STARTER_BUNDLE_DIRECTORY}/input.json`]);\n files.forEach(({ path }) => {\n paths.add(path);\n let parent = posix.dirname(path);\n while (parent !== '.') {\n paths.add(parent);\n parent = posix.dirname(parent);\n }\n });\n return paths;\n}\n\n/**\n * Add or classify one regular-file mutation.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param options - Desired file\n */\nfunction addFileChange(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n options: {\n /** Absolute destination path. */\n path: string;\n /** Complete desired contents. */\n contents: string;\n /** Human-readable plan description. */\n description: string;\n /** Refuse existing contents. */\n createOnly?: boolean;\n },\n): void {\n const change = planFileChange({\n snapshot: getPlanningFileSnapshot(input.snapshots, options.path),\n after: options.contents,\n description: options.description,\n ...(options.createOnly === undefined ? {} : { createOnly: options.createOnly }),\n });\n if (change) {\n plan.changes.push(change);\n } else {\n plan.unchanged.push(options.path);\n }\n}\n\n/**\n * Add one safe editor merge and its preservation warnings.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param path - Absolute editor artifact path\n * @param result - Pure JSONC merge result\n * @param description - Human-readable plan description\n * @param cwd - Invocation directory for portable warning paths\n */\nfunction addEditorMerge(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n path: string,\n result: PolicyEditorMergeResult,\n description: string,\n cwd: string,\n): void {\n addFileChange(plan, input, {\n path,\n contents: result.contents,\n description,\n });\n plan.warnings.push(\n ...result.warnings.map((warning) => `${warning} (${displayProjectPath(cwd, path)})`),\n );\n}\n\n/**\n * Build a safe policy project plan without reading the filesystem.\n *\n * Empty targets receive the complete starter. Existing targets are classified\n * only; no domain file is added, merged, or overwritten.\n *\n * @param input - Collected project state and path snapshots\n * @param options - Selected setup and pinned CLI version\n * @returns Validated policy initialization plan\n */\nexport function buildPolicyInitPlan(\n input: PolicyInitPlanningInput,\n options: PolicyInitPlanOptions,\n): PolicyInitProjectPlan {\n const { state } = input;\n const files = generatePolicyWorkspaceFiles();\n const newCommand = 'transcend policy new';\n const plan: PolicyInitProjectPlan = {\n version: POLICY_INIT_RESULT_VERSION,\n command: 'init',\n rootDirectory: state.projectRoot,\n targetDirectory: state.targetDirectory,\n // Init creates a workspace only; bundles (and their .manifest) come from `policy new`.\n manifestPath: state.targetDirectory,\n changes: [],\n unchanged: [],\n warnings: [],\n nextSteps: [newCommand],\n features: [...options.features],\n };\n\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, options);\n assertContained(state.projectRoot, state.targetDirectory);\n candidatePaths.forEach((path) => assertContained(state.projectRoot, path));\n\n if (state.relativeFilePaths.length === 0) {\n plan.directoryPreconditions = [\n {\n path: state.targetDirectory,\n relativePaths: [...state.relativePaths],\n },\n ];\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent') {\n throw new Error(`Expected an empty policy target, but found an entry at: ${path}`);\n }\n addFileChange(plan, input, {\n path,\n contents: file.contents,\n description: file.description,\n createOnly: true,\n });\n });\n } else {\n let allWorkspaceFilesMatch = true;\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind === 'file' && snapshot.contents === file.contents) {\n plan.unchanged.push(path);\n return;\n }\n allWorkspaceFilesMatch = false;\n if (snapshot.kind !== 'absent') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing policy scaffold path was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n }\n });\n\n const allowedPaths = starterRelativePaths(files);\n const hasCustomPaths = state.relativeFilePaths.some((path) => !allowedPaths.has(path));\n if (!allWorkspaceFilesMatch || hasCustomPaths) {\n plan.warnings.push(\n `Existing policy target contains custom or partial content, so no workspace files were added or overwritten. ` +\n `Review ${displayProjectPath(\n state.invocationDirectory,\n state.targetDirectory,\n )} manually, then run \\`${newCommand}\\`.`,\n );\n }\n }\n\n const selected = new Set(options.features);\n const root = state.projectRoot;\n if (selected.has(PolicySetupFeature.Editor)) {\n const settingsPath = join(root, '.vscode', 'settings.json');\n const extensionsPath = join(root, '.vscode', 'extensions.json');\n const tasksPath = join(root, '.vscode', 'tasks.json');\n\n type EditorMergeFn = (\n contents: string | null,\n repositoryRoot: string,\n targetDirectory: string,\n ) => PolicyEditorMergeResult;\n const editorArtifacts: {\n /** Absolute path. */\n path: string;\n /** Plan description. */\n description: string;\n /** Merge function. */\n merge: EditorMergeFn;\n }[] = [\n {\n path: settingsPath,\n description: 'Merge strict target-scoped OPA and Rego editor settings',\n merge: (contents, repositoryRoot, targetDirectory) =>\n mergePolicyEditorSettings(contents, repositoryRoot, targetDirectory),\n },\n {\n path: extensionsPath,\n description: 'Recommend the OPA extension and discourage its syntax-only conflict',\n merge: (contents) => mergePolicyEditorExtensions(contents),\n },\n {\n path: tasksPath,\n description: 'Create the VS Code task configuration',\n merge: (contents, repositoryRoot, targetDirectory) =>\n mergePolicyEditorTasks(contents, repositoryRoot, targetDirectory),\n },\n ];\n editorArtifacts.forEach(({ path, description, merge }) => {\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent' && snapshot.kind !== 'file') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing VS Code artifact is not a regular file and was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n return;\n }\n addEditorMerge(\n plan,\n input,\n path,\n merge(snapshot.kind === 'file' ? snapshot.contents : null, root, state.targetDirectory),\n description,\n state.invocationDirectory,\n );\n });\n }\n\n if (selected.has(PolicySetupFeature.Skill)) {\n const skillPlan = planManagedAgentSkill({\n rootDirectory: root,\n existingDirectories: state.existingSkillDirectories,\n snapshots: input.snapshots,\n skill: POLICY_MANAGED_SKILL,\n preserveModified: true,\n });\n plan.changes.push(...skillPlan.changes);\n plan.unchanged.push(...skillPlan.unchanged);\n plan.warnings.push(\n ...skillPlan.warnings.map((warning) => {\n return skillPlan.unchanged.reduce(\n (rendered, path) =>\n rendered.replace(path, displayProjectPath(state.invocationDirectory, path)),\n warning,\n );\n }),\n );\n }\n\n if (selected.has(PolicySetupFeature.Ci)) {\n if (!state.repositoryRoot || !state.usesGithub) {\n plan.warnings.push(\n 'GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.',\n );\n } else {\n const workflowPath = join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH);\n const workspaceDirectory =\n relative(state.repositoryRoot, state.targetDirectory).split(sep).join('/') || '.';\n const workflowContents = generatePolicyGithubActionsWorkflow({\n cliVersion: options.cliVersion,\n workspaceDirectory,\n bundleDirectories: [],\n });\n const workflowSnapshot = getPlanningPathSnapshot(input.snapshots, workflowPath);\n if (workflowSnapshot.kind === 'absent') {\n addFileChange(plan, input, {\n path: workflowPath,\n contents: workflowContents,\n description: 'Add credential-free Policy Engine validation',\n createOnly: true,\n });\n } else if (\n workflowSnapshot.kind === 'file' &&\n workflowSnapshot.contents === workflowContents\n ) {\n plan.unchanged.push(workflowPath);\n } else {\n plan.unchanged.push(workflowPath);\n plan.warnings.push(\n `Existing GitHub Actions workflow was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n workflowPath,\n )}. Adapt it manually to validate each policy bundle.`,\n );\n }\n }\n }\n\n plan.changes.forEach(({ path }) => assertContained(state.projectRoot, path));\n return plan;\n}\n","import colors from 'colors';\n\nimport { version as CLI_VERSION } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n runCapturedProcess,\n type CapturedProcessResult,\n type CapturedProcessRunner,\n} from '../../../lib/cli/run-captured-process.js';\nimport {\n DEFAULT_POLICY_PROJECT_DIRECTORY,\n discoverPolicyProject,\n} from '../../../lib/policy/policy-project-discovery.js';\nimport {\n OPA_INSTALL_URL,\n OPA_MISSING_MESSAGE,\n parsePolicyToolVersion,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n REGAL_INSTALL_URL,\n REGAL_MISSING_MESSAGE,\n unsupportedOpaVersionMessage,\n unsupportedRegalVersionMessage,\n} from '../../../lib/policy/policy-runtime.js';\nimport {\n PolicySetupFeature,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from '../../../lib/policy/policy-scaffold-model.js';\nimport {\n buildPolicyInitAiHandoff,\n buildPolicyInitPlanResult,\n type PolicyInitToolVersions,\n} from '../../../lib/policy/policy-scaffold-output.js';\nimport {\n buildPolicyInitPlan,\n getPolicyInitPlanningCandidatePaths,\n} from '../../../lib/policy/policy-scaffold-planning.js';\nimport { POLICY_STARTER_OPA_VERSION } from '../../../lib/policy/policy-scaffold-templates.js';\nimport { collectPlanningSnapshots } from '../../../lib/scaffolding/project-discovery.js';\nimport { applyProjectPlan } from '../../../lib/scaffolding/project-plan-apply.js';\nimport {\n displayProjectPath,\n quoteShellArgument,\n renderProjectPlan,\n} from '../../../lib/scaffolding/project-plan-output.js';\nimport {\n isInteractivePromptInvocation,\n PromptCancelledError,\n resolveSetupFeatures,\n ScaffoldPrompts,\n} from '../../../lib/scaffolding/prompts.js';\n\n/** Flags for `transcend policy init`. */\nexport interface PolicyInitFlags {\n /** Install repository-level VS Code setup. */\n editor?: boolean;\n /** Install the Policy Engine Agent Skill. */\n skill?: boolean;\n /** Install validation-only GitHub Actions CI. */\n ci?: boolean;\n /** Disable prompts. */\n noInteractive: boolean;\n /** Render but do not apply the plan. */\n dryRun: boolean;\n /** Approve the final displayed plan. */\n yes: boolean;\n /** Emit one stable JSON result on stdout. */\n json: boolean;\n}\n\n/** User-facing optional setup labels. */\nconst SETUP_LABELS: Readonly<Record<PolicySetupFeatureType, string>> = {\n [PolicySetupFeature.Editor]: 'VS Code settings and lint task',\n [PolicySetupFeature.Skill]: 'Policy Engine Agent Skill',\n [PolicySetupFeature.Ci]: 'Validation-only GitHub Actions',\n};\n\n/** All optional setup features in stable prompt order. */\nconst ALL_SETUP_FEATURES = Object.values(PolicySetupFeature);\n\n/** Runtime compatibility detected before policy planning. */\ninterface PolicyRuntimeProbe {\n /** Compatible tool versions. */\n tools: PolicyInitToolVersions;\n /** Missing or incompatible runtime guidance. */\n warnings: string[];\n}\n\n/**\n * Explain a failed version subprocess with official installation guidance.\n *\n * @param tool - Policy tool name\n * @param result - Failed captured process\n * @returns Actionable warning\n */\nfunction failedVersionProbeMessage(tool: 'OPA' | 'Regal', result: CapturedProcessResult): string {\n const detail = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join('\\n');\n const url = tool === 'OPA' ? OPA_INSTALL_URL : REGAL_INSTALL_URL;\n const requirement =\n tool === 'OPA' ? 'OPA 1.x' : `Regal ${MINIMUM_POLICY_STARTER_REGAL_VERSION} or newer`;\n return (\n `${requirement} is required, but \\`${tool.toLowerCase()} version\\` exited with code ` +\n `${result.code}${detail ? `: ${detail}` : '.'} ` +\n `Install or upgrade it using the official instructions: ${url}`\n );\n}\n\n/**\n * Probe both local policy runtimes without installing or modifying them.\n *\n * @param context - CLI context\n * @param cwd - Invocation working directory\n * @param runner - Captured subprocess runner\n * @returns Compatible versions and exact runtime guidance\n */\nasync function probePolicyRuntimes(\n context: LocalContext,\n cwd: string,\n runner: CapturedProcessRunner,\n): Promise<PolicyRuntimeProbe> {\n const tools: PolicyInitToolVersions = { opa: null, regal: null };\n const warnings: string[] = [];\n\n const opaResult = await runner('opa', ['version'], { cwd }, context);\n if (opaResult.error?.code === 'ENOENT') {\n warnings.push(OPA_MISSING_MESSAGE);\n } else {\n const output = `${opaResult.stdout}\\n${opaResult.stderr}`;\n const unsupported = unsupportedOpaVersionMessage(output);\n if (opaResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('OPA', opaResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.opa = parsePolicyToolVersion(output)!.version;\n }\n }\n\n const regalResult = await runner('regal', ['version'], { cwd }, context);\n if (regalResult.error?.code === 'ENOENT') {\n warnings.push(REGAL_MISSING_MESSAGE);\n } else {\n const output = `${regalResult.stdout}\\n${regalResult.stderr}`;\n const unsupported = unsupportedRegalVersionMessage(\n output,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n `the generated OPA ${POLICY_STARTER_OPA_VERSION} capabilities configuration`,\n );\n if (regalResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('Regal', regalResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.regal = parsePolicyToolVersion(output)!.version;\n }\n }\n\n return { tools, warnings };\n}\n\n/**\n * Initialize a credential-free local Policy Engine project.\n *\n * @param this - CLI context\n * @param flags - Scaffold and interaction flags\n * @param directory - Target policy directory\n * @param runner - Captured policy tool runner\n */\nexport async function init(\n this: LocalContext,\n flags: PolicyInitFlags,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n runner: CapturedProcessRunner = runCapturedProcess,\n): Promise<void> {\n doneInputValidation(this.process);\n try {\n const runtime = await probePolicyRuntimes(this, this.process.cwd(), runner);\n const state = discoverPolicyProject(this, directory);\n const prompts = new ScaffoldPrompts(this);\n const interactive = isInteractivePromptInvocation(\n flags,\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n const features = await resolveSetupFeatures(prompts, {\n features: ALL_SETUP_FEATURES,\n labels: SETUP_LABELS,\n enabled: {\n [PolicySetupFeature.Editor]: flags.editor,\n [PolicySetupFeature.Skill]: flags.skill,\n [PolicySetupFeature.Ci]: flags.ci,\n },\n interactive,\n });\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, { features });\n const snapshots = collectPlanningSnapshots(this, state.projectRoot, candidatePaths);\n\n const plan = buildPolicyInitPlan(\n { state, snapshots },\n {\n features,\n cliVersion: CLI_VERSION,\n },\n );\n plan.warnings.push(...runtime.warnings);\n\n if (!flags.json) {\n this.logger.info(\n renderProjectPlan(plan, {\n cwd: this.process.cwd(),\n title: 'Policy initialization plan',\n details: [{ label: 'Target', path: plan.targetDirectory }],\n }),\n );\n }\n\n let approved = plan.changes.length === 0 || flags.dryRun;\n if (plan.changes.length > 0 && !flags.dryRun) {\n if (flags.yes) {\n approved = true;\n } else if (interactive) {\n approved = await prompts.confirm('Apply this complete plan?', true);\n } else {\n throw new Error(\n 'The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.',\n );\n }\n }\n\n if (approved && !flags.dryRun && plan.changes.length > 0) {\n await applyProjectPlan(this, plan);\n }\n const applied = approved && !flags.dryRun && plan.changes.length > 0;\n const setupAvailable = approved && !flags.dryRun;\n const aiHandoff = buildPolicyInitAiHandoff({\n projectPath: quoteShellArgument(\n displayProjectPath(this.process.cwd(), state.targetDirectory),\n ),\n hasSkill: setupAvailable && features.includes(PolicySetupFeature.Skill),\n newCommand: plan.nextSteps[0]!,\n });\n const result = buildPolicyInitPlanResult(plan, {\n applied,\n dryRun: flags.dryRun,\n cwd: this.process.cwd(),\n aiHandoff,\n tools: runtime.tools,\n });\n if (flags.json) {\n this.process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n if (flags.dryRun) {\n this.logger.info(colors.yellow('Dry run complete. No changes were written.'));\n return;\n }\n if (!approved) {\n this.logger.info(colors.yellow('No changes applied.'));\n return;\n }\n if (plan.changes.length === 0) {\n const message =\n plan.warnings.length === runtime.warnings.length\n ? 'Policy project is already initialized.'\n : 'Existing policy project was left unchanged.';\n this.logger.info(colors.green(message));\n } else {\n this.logger.info(colors.green('Policy project initialized.'));\n }\n if (plan.nextSteps.length > 0) {\n this.logger.info(`\\n${colors.bold('Next steps')}`);\n plan.nextSteps.forEach((step) => this.logger.info(step));\n }\n this.logger.info(`\\n${colors.bold('AI handoff — paste into your coding agent')}`);\n this.logger.info(aiHandoff);\n } catch (error) {\n if (error instanceof PromptCancelledError) {\n return this.process.exit(130);\n }\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e,n as t,t as n}from"./policy-project-discovery-
|
|
2
|
-
//# sourceMappingURL=impl-
|
|
1
|
+
import{i as e,n as t,t as n}from"./policy-project-discovery-Dxikd8NT.mjs";import{t as r}from"./done-input-validation-LiTaCEzF.mjs";import{t as i}from"./run-captured-process-BjaSDWXG.mjs";import{n as a,r as o,t as s}from"./runRegalLintStep-DPaMm7Gg.mjs";import c from"node:path";import l from"colors";const u=[`opa-version`,`regal-version`,`format`,`regal-lint`],d={"opa-version":`OPA 1.x`,"regal-version":`Regal`,format:`OPA formatting`,"regal-lint":`Regal lint`};function f(e,t,n){n?e.logger.info(`${l.bold(n)}\n`):e.logger.info(`${l.bold(`Policy lint`)}\n`),t.checks.forEach(({name:n,status:r})=>{let i=r===`passed`?`PASS`:r===`failed`?`FAIL`:`SKIP`,a=r===`passed`?l.green(i):r===`failed`?l.red(i):l.yellow(i),o=n===`opa-version`&&t.tools.opa?` (${t.tools.opa})`:n===`regal-version`&&t.tools.regal?` (${t.tools.regal})`:``;e.logger.info(`${a} ${d[n]}${o}`)}),t.diagnostics.length>0&&e.logger.error(``),t.diagnostics.forEach(t=>{let n=t.path?`${t.path}: `:``;e.logger.error(l.red(`error [${t.code}]: ${n}${t.message}`))}),t.status===`passed`?(e.logger.info(``),e.logger.info(l.green(`Policy lint passed.`))):(e.logger.error(``),e.logger.error(l.red(`Policy lint failed.`)))}async function p({fix:e,noInteractive:t,json:n},r,i){let l=u.map(e=>({name:e,status:`skipped`})),d=[],f={version:1,status:`passed`,directory:r,fix:e,tools:{opa:null,regal:null},checks:l,unformattedFiles:[],fixedFiles:[],diagnostics:d},p=(e,t)=>{l.find(t=>t.name===e).status=t},m=(e,t,n)=>{d.push({code:e,severity:`error`,message:t,...n?{path:n}:{}})};if(!this.fs.existsSync(r)||!this.fs.statSync(r).isDirectory())return p(`opa-version`,`failed`),m(`project.directory`,`Policy directory does not exist or is not a directory: ${r}`,c.relative(this.process.cwd(),r)),f.status=`failed`,f;let h=await o.call(this,r,i);if(f.tools={opa:h.opa,regal:h.regal},p(`opa-version`,h.opaStatus),p(`regal-version`,h.regalStatus),h.diagnostics.forEach(e=>{m(e.code,e.message)}),f.tools.opa){let o=await a.call(this,{resolvedDir:r,fix:e,noInteractive:t,json:n,fixCommandHint:`transcend policy lint --fix`,runner:i});f.unformattedFiles=o.unformattedFiles,f.fixedFiles=o.fixedFiles,p(`format`,o.status),o.diagnostics.forEach(e=>{m(e.code,e.message)})}if(f.tools.regal){let e=await s.call(this,{resolvedDir:r,runner:i});p(`regal-lint`,e.status),e.diagnostics.forEach(e=>{m(e.code,e.message)})}return f.status=l.some(({status:e})=>e===`failed`)?`failed`:`passed`,f}async function m(a,o=n,s=i){r(this.process);let{fix:l=!1,noInteractive:d=!1,json:m=!1}=a,h=e(this.process.cwd(),o);if(!this.fs.existsSync(h)||!this.fs.statSync(h).isDirectory()){let e={version:1,status:`failed`,directory:h,fix:l,tools:{opa:null,regal:null},checks:u.map(e=>({name:e,status:e===`opa-version`?`failed`:`skipped`})),unformattedFiles:[],fixedFiles:[],diagnostics:[{code:`project.directory`,severity:`error`,message:`Policy directory does not exist or is not a directory: ${h}`,path:c.relative(this.process.cwd(),h)}]};m?this.process.stdout.write(`${JSON.stringify(e)}\n`):f(this,e),this.process.exitCode=1;return}let g=t(this,h);if(g.length===0){let e={version:1,status:`failed`,directory:h,fix:l,tools:{opa:null,regal:null},checks:u.map(e=>({name:e,status:e===`opa-version`?`failed`:`skipped`})),unformattedFiles:[],fixedFiles:[],diagnostics:[{code:`project.bundles`,severity:`error`,message:"No publishable policy bundles found. Add one with `transcend policy new`, or pass a directory that contains a `.manifest`.",path:c.relative(this.process.cwd(),h)||`.`}]};m?this.process.stdout.write(`${JSON.stringify(e)}\n`):f(this,e),this.process.exitCode=1;return}let _=[];for(let e of g)_.push(await p.call(this,{fix:l,noInteractive:d,json:m},e,s));let v=_.some(e=>e.status===`failed`);if(m)if(_.length===1)this.process.stdout.write(`${JSON.stringify(_[0])}\n`);else{let e={version:1,status:v?`failed`:`passed`,directory:h,fix:l,results:_};this.process.stdout.write(`${JSON.stringify(e)}\n`)}else _.length===1?f(this,_[0]):_.forEach((e,t)=>{t>0&&this.logger.info(``);let n=c.relative(this.process.cwd(),e.directory)||e.directory;f(this,e,`Policy lint — ${n}`)});v&&(this.process.exitCode=1)}export{m as lint};
|
|
2
|
+
//# sourceMappingURL=impl-UlLFb3UK2.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impl-CPW2Q51W2.mjs","names":[],"sources":["../src/lib/policy/policy-lint-model.ts","../src/commands/policy/lint/impl.ts"],"sourcesContent":["/** Stable policy lint result schema version. */\nexport const POLICY_LINT_RESULT_VERSION = 1;\n\n/** Stable multi-bundle lint result schema version. */\nexport const POLICY_LINT_MULTI_RESULT_VERSION = 1;\n\n/** Status of the lint gate or an individual step. */\nexport type PolicyLintStatus = 'passed' | 'failed' | 'skipped';\n\n/** One named policy lint step. */\nexport interface PolicyLintStep {\n /** Stable step name. */\n name: 'opa-version' | 'regal-version' | 'format' | 'regal-lint';\n /** Step outcome. */\n status: PolicyLintStatus;\n}\n\n/** Stable lint step execution order. */\nexport const POLICY_LINT_STEP_NAMES: PolicyLintStep['name'][] = [\n 'opa-version',\n 'regal-version',\n 'format',\n 'regal-lint',\n];\n\n/** User-facing lint step labels. */\nexport const POLICY_LINT_STEP_LABELS: Readonly<Record<PolicyLintStep['name'], string>> = {\n 'opa-version': 'OPA 1.x',\n 'regal-version': 'Regal',\n format: 'OPA formatting',\n 'regal-lint': 'Regal lint',\n};\n\n/** One machine-readable policy lint diagnostic. */\nexport interface PolicyLintDiagnostic {\n /** Stable diagnostic identifier. */\n code: string;\n /** Diagnostic severity. */\n severity: 'error';\n /** Human-readable detail, including captured tool output when available. */\n message: string;\n /** Optional path relative to the invocation directory. */\n path?: string;\n}\n\n/** Detected local policy tool versions. */\nexport interface PolicyLintTools {\n /** Detected OPA version, or null when missing or unsupported. */\n opa: string | null;\n /** Detected Regal version, or null when missing or unsupported. */\n regal: string | null;\n}\n\n/** Stable result emitted by `transcend policy lint --json` for one bundle. */\nexport interface PolicyLintResult {\n /** Result schema version. */\n version: typeof POLICY_LINT_RESULT_VERSION;\n /** Overall lint outcome. */\n status: Exclude<PolicyLintStatus, 'skipped'>;\n /** Absolute policy bundle directory. */\n directory: string;\n /** Whether formatting repair was explicitly requested. */\n fix: boolean;\n /** Detected supported tool versions. */\n tools: PolicyLintTools;\n /** Lint step outcomes in stable execution order. */\n checks: PolicyLintStep[];\n /** Files found to need OPA formatting, relative to the policy directory. */\n unformattedFiles: string[];\n /** Files repaired with OPA formatting, relative to the policy directory. */\n fixedFiles: string[];\n /** Ordered lint diagnostics. */\n diagnostics: PolicyLintDiagnostic[];\n}\n\n/**\n * Stable result when `transcend policy lint --json` lints multiple bundles.\n *\n * Emitted only when the selected path is a workspace with more than one\n * publishable `*-bundle/` directory.\n */\nexport interface PolicyLintMultiResult {\n /** Result schema version. */\n version: typeof POLICY_LINT_MULTI_RESULT_VERSION;\n /** Overall lint outcome across all bundles. */\n status: Exclude<PolicyLintStatus, 'skipped'>;\n /** Absolute policy workspace directory that was searched. */\n directory: string;\n /** Whether formatting repair was explicitly requested. */\n fix: boolean;\n /** Per-bundle results in discovery order. */\n results: PolicyLintResult[];\n}\n","import path from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n runCapturedProcess,\n type CapturedProcessRunner,\n} from '../../../lib/cli/run-captured-process.js';\nimport {\n type PolicyLintDiagnostic,\n type PolicyLintMultiResult,\n type PolicyLintResult,\n type PolicyLintStep,\n POLICY_LINT_MULTI_RESULT_VERSION,\n POLICY_LINT_RESULT_VERSION,\n POLICY_LINT_STEP_LABELS,\n POLICY_LINT_STEP_NAMES,\n} from '../../../lib/policy/policy-lint-model.js';\nimport {\n DEFAULT_POLICY_PROJECT_DIRECTORY,\n discoverPolicyBundleDirectories,\n resolvePolicyProjectDirectory,\n} from '../../../lib/policy/policy-project-discovery.js';\nimport { probePolicyToolVersions } from '../helpers/probePolicyToolVersions.js';\nimport { runOpaFormatStep } from '../helpers/runOpaFormatStep.js';\nimport { runRegalLintStep } from '../helpers/runRegalLintStep.js';\n\n/** CLI flags for `transcend policy lint`. */\nexport interface LintCommandFlags {\n /** Apply OPA formatting. */\n fix: boolean;\n /** Disable the optional formatting confirmation. */\n noInteractive: boolean;\n /** Emit one stable JSON result on stdout. */\n json: boolean;\n}\n\n/**\n * Render the terminal summary for a policy lint result.\n *\n * @param context - CLI context\n * @param result - Completed lint result\n * @param heading - Optional section heading when linting multiple bundles\n */\nfunction renderResult(context: LocalContext, result: PolicyLintResult, heading?: string): void {\n if (heading) {\n context.logger.info(`${colors.bold(heading)}\\n`);\n } else {\n context.logger.info(`${colors.bold('Policy lint')}\\n`);\n }\n result.checks.forEach(({ name, status }) => {\n const label = status === 'passed' ? 'PASS' : status === 'failed' ? 'FAIL' : 'SKIP';\n const styledLabel =\n status === 'passed'\n ? colors.green(label)\n : status === 'failed'\n ? colors.red(label)\n : colors.yellow(label);\n const version =\n name === 'opa-version' && result.tools.opa\n ? ` (${result.tools.opa})`\n : name === 'regal-version' && result.tools.regal\n ? ` (${result.tools.regal})`\n : '';\n context.logger.info(`${styledLabel} ${POLICY_LINT_STEP_LABELS[name]}${version}`);\n });\n if (result.diagnostics.length > 0) {\n context.logger.error('');\n }\n result.diagnostics.forEach((diagnostic) => {\n const location = diagnostic.path ? `${diagnostic.path}: ` : '';\n context.logger.error(\n colors.red(`error [${diagnostic.code}]: ${location}${diagnostic.message}`),\n );\n });\n if (result.status === 'passed') {\n context.logger.info('');\n context.logger.info(colors.green('Policy lint passed.'));\n } else {\n context.logger.error('');\n context.logger.error(colors.red('Policy lint failed.'));\n }\n}\n\n/**\n * Lint one publishable policy bundle directory (format + Regal).\n *\n * @param this - CLI context\n * @param flags - Command flags\n * @param resolvedDir - Absolute bundle directory\n * @param runner - Captured subprocess runner\n * @returns Completed lint result\n */\nasync function lintBundle(\n this: LocalContext,\n { fix, noInteractive, json }: LintCommandFlags,\n resolvedDir: string,\n runner: CapturedProcessRunner,\n): Promise<PolicyLintResult> {\n const checks: PolicyLintStep[] = POLICY_LINT_STEP_NAMES.map((name) => ({\n name,\n status: 'skipped',\n }));\n const diagnostics: PolicyLintDiagnostic[] = [];\n const result: PolicyLintResult = {\n version: POLICY_LINT_RESULT_VERSION,\n status: 'passed',\n directory: resolvedDir,\n fix,\n tools: { opa: null, regal: null },\n checks,\n unformattedFiles: [],\n fixedFiles: [],\n diagnostics,\n };\n const setStatus = (name: PolicyLintStep['name'], status: PolicyLintStep['status']): void => {\n checks.find((check) => check.name === name)!.status = status;\n };\n const addError = (code: string, message: string, diagnosticPath?: string): void => {\n diagnostics.push({\n code,\n severity: 'error',\n message,\n ...(diagnosticPath ? { path: diagnosticPath } : {}),\n });\n };\n\n if (!this.fs.existsSync(resolvedDir) || !this.fs.statSync(resolvedDir).isDirectory()) {\n setStatus('opa-version', 'failed');\n addError(\n 'project.directory',\n `Policy directory does not exist or is not a directory: ${resolvedDir}`,\n path.relative(this.process.cwd(), resolvedDir),\n );\n result.status = 'failed';\n return result;\n }\n\n const toolVersions = await probePolicyToolVersions.call(this, resolvedDir, runner);\n result.tools = { opa: toolVersions.opa, regal: toolVersions.regal };\n setStatus('opa-version', toolVersions.opaStatus);\n setStatus('regal-version', toolVersions.regalStatus);\n toolVersions.diagnostics.forEach((diagnostic) => {\n addError(diagnostic.code, diagnostic.message);\n });\n\n if (result.tools.opa) {\n const formatStep = await runOpaFormatStep.call(this, {\n resolvedDir,\n fix,\n noInteractive,\n json,\n fixCommandHint: 'transcend policy lint --fix',\n runner,\n });\n result.unformattedFiles = formatStep.unformattedFiles;\n result.fixedFiles = formatStep.fixedFiles;\n setStatus('format', formatStep.status);\n formatStep.diagnostics.forEach((diagnostic) => {\n addError(diagnostic.code, diagnostic.message);\n });\n }\n\n if (result.tools.regal) {\n const regalStep = await runRegalLintStep.call(this, { resolvedDir, runner });\n setStatus('regal-lint', regalStep.status);\n regalStep.diagnostics.forEach((diagnostic) => {\n addError(diagnostic.code, diagnostic.message);\n });\n }\n\n result.status = checks.some(({ status }) => status === 'failed') ? 'failed' : 'passed';\n return result;\n}\n\n/**\n * Lint local policy bundles with OPA formatting and Regal.\n *\n * With no directory (or the default workspace path), discovers every immediate\n * child that contains a `.manifest` and lints each. Pass one bundle path to\n * lint a single publishable unit.\n *\n * @param this - CLI context\n * @param flags - Command flags\n * @param directory - Policy workspace or bundle directory\n * @param runner - Captured subprocess runner\n */\nexport async function lint(\n this: LocalContext,\n flags: LintCommandFlags,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n runner: CapturedProcessRunner = runCapturedProcess,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const { fix = false, noInteractive = false, json = false } = flags;\n const resolvedDir = resolvePolicyProjectDirectory(this.process.cwd(), directory);\n\n if (!this.fs.existsSync(resolvedDir) || !this.fs.statSync(resolvedDir).isDirectory()) {\n const missing: PolicyLintResult = {\n version: POLICY_LINT_RESULT_VERSION,\n status: 'failed',\n directory: resolvedDir,\n fix,\n tools: { opa: null, regal: null },\n checks: POLICY_LINT_STEP_NAMES.map((name) => ({\n name,\n status: name === 'opa-version' ? 'failed' : 'skipped',\n })),\n unformattedFiles: [],\n fixedFiles: [],\n diagnostics: [\n {\n code: 'project.directory',\n severity: 'error',\n message: `Policy directory does not exist or is not a directory: ${resolvedDir}`,\n path: path.relative(this.process.cwd(), resolvedDir),\n },\n ],\n };\n if (json) {\n this.process.stdout.write(`${JSON.stringify(missing)}\\n`);\n } else {\n renderResult(this, missing);\n }\n this.process.exitCode = 1;\n return;\n }\n\n const bundleDirectories = discoverPolicyBundleDirectories(this, resolvedDir);\n if (bundleDirectories.length === 0) {\n const empty: PolicyLintResult = {\n version: POLICY_LINT_RESULT_VERSION,\n status: 'failed',\n directory: resolvedDir,\n fix,\n tools: { opa: null, regal: null },\n checks: POLICY_LINT_STEP_NAMES.map((name) => ({\n name,\n status: name === 'opa-version' ? 'failed' : 'skipped',\n })),\n unformattedFiles: [],\n fixedFiles: [],\n diagnostics: [\n {\n code: 'project.bundles',\n severity: 'error',\n message:\n 'No publishable policy bundles found. Add one with `transcend policy new`, ' +\n 'or pass a directory that contains a `.manifest`.',\n path: path.relative(this.process.cwd(), resolvedDir) || '.',\n },\n ],\n };\n if (json) {\n this.process.stdout.write(`${JSON.stringify(empty)}\\n`);\n } else {\n renderResult(this, empty);\n }\n this.process.exitCode = 1;\n return;\n }\n\n const results: PolicyLintResult[] = [];\n for (const bundleDirectory of bundleDirectories) {\n results.push(\n await lintBundle.call(this, { fix, noInteractive, json }, bundleDirectory, runner),\n );\n }\n\n const failed = results.some((result) => result.status === 'failed');\n if (json) {\n if (results.length === 1) {\n this.process.stdout.write(`${JSON.stringify(results[0])}\\n`);\n } else {\n const multi: PolicyLintMultiResult = {\n version: POLICY_LINT_MULTI_RESULT_VERSION,\n status: failed ? 'failed' : 'passed',\n directory: resolvedDir,\n fix,\n results,\n };\n this.process.stdout.write(`${JSON.stringify(multi)}\\n`);\n }\n } else if (results.length === 1) {\n renderResult(this, results[0]!);\n } else {\n results.forEach((result, index) => {\n if (index > 0) {\n this.logger.info('');\n }\n const relative = path.relative(this.process.cwd(), result.directory) || result.directory;\n renderResult(this, result, `Policy lint — ${relative}`);\n });\n }\n\n if (failed) {\n this.process.exitCode = 1;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"impl-UlLFb3UK2.mjs","names":[],"sources":["../src/lib/policy/policy-lint-model.ts","../src/commands/policy/lint/impl.ts"],"sourcesContent":["/** Stable policy lint result schema version. */\nexport const POLICY_LINT_RESULT_VERSION = 1;\n\n/** Stable multi-bundle lint result schema version. */\nexport const POLICY_LINT_MULTI_RESULT_VERSION = 1;\n\n/** Status of the lint gate or an individual step. */\nexport type PolicyLintStatus = 'passed' | 'failed' | 'skipped';\n\n/** One named policy lint step. */\nexport interface PolicyLintStep {\n /** Stable step name. */\n name: 'opa-version' | 'regal-version' | 'format' | 'regal-lint';\n /** Step outcome. */\n status: PolicyLintStatus;\n}\n\n/** Stable lint step execution order. */\nexport const POLICY_LINT_STEP_NAMES: PolicyLintStep['name'][] = [\n 'opa-version',\n 'regal-version',\n 'format',\n 'regal-lint',\n];\n\n/** User-facing lint step labels. */\nexport const POLICY_LINT_STEP_LABELS: Readonly<Record<PolicyLintStep['name'], string>> = {\n 'opa-version': 'OPA 1.x',\n 'regal-version': 'Regal',\n format: 'OPA formatting',\n 'regal-lint': 'Regal lint',\n};\n\n/** One machine-readable policy lint diagnostic. */\nexport interface PolicyLintDiagnostic {\n /** Stable diagnostic identifier. */\n code: string;\n /** Diagnostic severity. */\n severity: 'error';\n /** Human-readable detail, including captured tool output when available. */\n message: string;\n /** Optional path relative to the invocation directory. */\n path?: string;\n}\n\n/** Detected local policy tool versions. */\nexport interface PolicyLintTools {\n /** Detected OPA version, or null when missing or unsupported. */\n opa: string | null;\n /** Detected Regal version, or null when missing or unsupported. */\n regal: string | null;\n}\n\n/** Stable result emitted by `transcend policy lint --json` for one bundle. */\nexport interface PolicyLintResult {\n /** Result schema version. */\n version: typeof POLICY_LINT_RESULT_VERSION;\n /** Overall lint outcome. */\n status: Exclude<PolicyLintStatus, 'skipped'>;\n /** Absolute policy bundle directory. */\n directory: string;\n /** Whether formatting repair was explicitly requested. */\n fix: boolean;\n /** Detected supported tool versions. */\n tools: PolicyLintTools;\n /** Lint step outcomes in stable execution order. */\n checks: PolicyLintStep[];\n /** Files found to need OPA formatting, relative to the policy directory. */\n unformattedFiles: string[];\n /** Files repaired with OPA formatting, relative to the policy directory. */\n fixedFiles: string[];\n /** Ordered lint diagnostics. */\n diagnostics: PolicyLintDiagnostic[];\n}\n\n/**\n * Stable result when `transcend policy lint --json` lints multiple bundles.\n *\n * Emitted only when the selected path is a workspace with more than one\n * publishable `*-bundle/` directory.\n */\nexport interface PolicyLintMultiResult {\n /** Result schema version. */\n version: typeof POLICY_LINT_MULTI_RESULT_VERSION;\n /** Overall lint outcome across all bundles. */\n status: Exclude<PolicyLintStatus, 'skipped'>;\n /** Absolute policy workspace directory that was searched. */\n directory: string;\n /** Whether formatting repair was explicitly requested. */\n fix: boolean;\n /** Per-bundle results in discovery order. */\n results: PolicyLintResult[];\n}\n","import path from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n runCapturedProcess,\n type CapturedProcessRunner,\n} from '../../../lib/cli/run-captured-process.js';\nimport {\n type PolicyLintDiagnostic,\n type PolicyLintMultiResult,\n type PolicyLintResult,\n type PolicyLintStep,\n POLICY_LINT_MULTI_RESULT_VERSION,\n POLICY_LINT_RESULT_VERSION,\n POLICY_LINT_STEP_LABELS,\n POLICY_LINT_STEP_NAMES,\n} from '../../../lib/policy/policy-lint-model.js';\nimport {\n DEFAULT_POLICY_PROJECT_DIRECTORY,\n discoverPolicyBundleDirectories,\n resolvePolicyProjectDirectory,\n} from '../../../lib/policy/policy-project-discovery.js';\nimport { probePolicyToolVersions } from '../helpers/probePolicyToolVersions.js';\nimport { runOpaFormatStep } from '../helpers/runOpaFormatStep.js';\nimport { runRegalLintStep } from '../helpers/runRegalLintStep.js';\n\n/** CLI flags for `transcend policy lint`. */\nexport interface LintCommandFlags {\n /** Apply OPA formatting. */\n fix: boolean;\n /** Disable the optional formatting confirmation. */\n noInteractive: boolean;\n /** Emit one stable JSON result on stdout. */\n json: boolean;\n}\n\n/**\n * Render the terminal summary for a policy lint result.\n *\n * @param context - CLI context\n * @param result - Completed lint result\n * @param heading - Optional section heading when linting multiple bundles\n */\nfunction renderResult(context: LocalContext, result: PolicyLintResult, heading?: string): void {\n if (heading) {\n context.logger.info(`${colors.bold(heading)}\\n`);\n } else {\n context.logger.info(`${colors.bold('Policy lint')}\\n`);\n }\n result.checks.forEach(({ name, status }) => {\n const label = status === 'passed' ? 'PASS' : status === 'failed' ? 'FAIL' : 'SKIP';\n const styledLabel =\n status === 'passed'\n ? colors.green(label)\n : status === 'failed'\n ? colors.red(label)\n : colors.yellow(label);\n const version =\n name === 'opa-version' && result.tools.opa\n ? ` (${result.tools.opa})`\n : name === 'regal-version' && result.tools.regal\n ? ` (${result.tools.regal})`\n : '';\n context.logger.info(`${styledLabel} ${POLICY_LINT_STEP_LABELS[name]}${version}`);\n });\n if (result.diagnostics.length > 0) {\n context.logger.error('');\n }\n result.diagnostics.forEach((diagnostic) => {\n const location = diagnostic.path ? `${diagnostic.path}: ` : '';\n context.logger.error(\n colors.red(`error [${diagnostic.code}]: ${location}${diagnostic.message}`),\n );\n });\n if (result.status === 'passed') {\n context.logger.info('');\n context.logger.info(colors.green('Policy lint passed.'));\n } else {\n context.logger.error('');\n context.logger.error(colors.red('Policy lint failed.'));\n }\n}\n\n/**\n * Lint one publishable policy bundle directory (format + Regal).\n *\n * @param this - CLI context\n * @param flags - Command flags\n * @param resolvedDir - Absolute bundle directory\n * @param runner - Captured subprocess runner\n * @returns Completed lint result\n */\nasync function lintBundle(\n this: LocalContext,\n { fix, noInteractive, json }: LintCommandFlags,\n resolvedDir: string,\n runner: CapturedProcessRunner,\n): Promise<PolicyLintResult> {\n const checks: PolicyLintStep[] = POLICY_LINT_STEP_NAMES.map((name) => ({\n name,\n status: 'skipped',\n }));\n const diagnostics: PolicyLintDiagnostic[] = [];\n const result: PolicyLintResult = {\n version: POLICY_LINT_RESULT_VERSION,\n status: 'passed',\n directory: resolvedDir,\n fix,\n tools: { opa: null, regal: null },\n checks,\n unformattedFiles: [],\n fixedFiles: [],\n diagnostics,\n };\n const setStatus = (name: PolicyLintStep['name'], status: PolicyLintStep['status']): void => {\n checks.find((check) => check.name === name)!.status = status;\n };\n const addError = (code: string, message: string, diagnosticPath?: string): void => {\n diagnostics.push({\n code,\n severity: 'error',\n message,\n ...(diagnosticPath ? { path: diagnosticPath } : {}),\n });\n };\n\n if (!this.fs.existsSync(resolvedDir) || !this.fs.statSync(resolvedDir).isDirectory()) {\n setStatus('opa-version', 'failed');\n addError(\n 'project.directory',\n `Policy directory does not exist or is not a directory: ${resolvedDir}`,\n path.relative(this.process.cwd(), resolvedDir),\n );\n result.status = 'failed';\n return result;\n }\n\n const toolVersions = await probePolicyToolVersions.call(this, resolvedDir, runner);\n result.tools = { opa: toolVersions.opa, regal: toolVersions.regal };\n setStatus('opa-version', toolVersions.opaStatus);\n setStatus('regal-version', toolVersions.regalStatus);\n toolVersions.diagnostics.forEach((diagnostic) => {\n addError(diagnostic.code, diagnostic.message);\n });\n\n if (result.tools.opa) {\n const formatStep = await runOpaFormatStep.call(this, {\n resolvedDir,\n fix,\n noInteractive,\n json,\n fixCommandHint: 'transcend policy lint --fix',\n runner,\n });\n result.unformattedFiles = formatStep.unformattedFiles;\n result.fixedFiles = formatStep.fixedFiles;\n setStatus('format', formatStep.status);\n formatStep.diagnostics.forEach((diagnostic) => {\n addError(diagnostic.code, diagnostic.message);\n });\n }\n\n if (result.tools.regal) {\n const regalStep = await runRegalLintStep.call(this, { resolvedDir, runner });\n setStatus('regal-lint', regalStep.status);\n regalStep.diagnostics.forEach((diagnostic) => {\n addError(diagnostic.code, diagnostic.message);\n });\n }\n\n result.status = checks.some(({ status }) => status === 'failed') ? 'failed' : 'passed';\n return result;\n}\n\n/**\n * Lint local policy bundles with OPA formatting and Regal.\n *\n * With no directory (or the default workspace path), discovers every immediate\n * child that contains a `.manifest` and lints each. Pass one bundle path to\n * lint a single publishable unit.\n *\n * @param this - CLI context\n * @param flags - Command flags\n * @param directory - Policy workspace or bundle directory\n * @param runner - Captured subprocess runner\n */\nexport async function lint(\n this: LocalContext,\n flags: LintCommandFlags,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n runner: CapturedProcessRunner = runCapturedProcess,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const { fix = false, noInteractive = false, json = false } = flags;\n const resolvedDir = resolvePolicyProjectDirectory(this.process.cwd(), directory);\n\n if (!this.fs.existsSync(resolvedDir) || !this.fs.statSync(resolvedDir).isDirectory()) {\n const missing: PolicyLintResult = {\n version: POLICY_LINT_RESULT_VERSION,\n status: 'failed',\n directory: resolvedDir,\n fix,\n tools: { opa: null, regal: null },\n checks: POLICY_LINT_STEP_NAMES.map((name) => ({\n name,\n status: name === 'opa-version' ? 'failed' : 'skipped',\n })),\n unformattedFiles: [],\n fixedFiles: [],\n diagnostics: [\n {\n code: 'project.directory',\n severity: 'error',\n message: `Policy directory does not exist or is not a directory: ${resolvedDir}`,\n path: path.relative(this.process.cwd(), resolvedDir),\n },\n ],\n };\n if (json) {\n this.process.stdout.write(`${JSON.stringify(missing)}\\n`);\n } else {\n renderResult(this, missing);\n }\n this.process.exitCode = 1;\n return;\n }\n\n const bundleDirectories = discoverPolicyBundleDirectories(this, resolvedDir);\n if (bundleDirectories.length === 0) {\n const empty: PolicyLintResult = {\n version: POLICY_LINT_RESULT_VERSION,\n status: 'failed',\n directory: resolvedDir,\n fix,\n tools: { opa: null, regal: null },\n checks: POLICY_LINT_STEP_NAMES.map((name) => ({\n name,\n status: name === 'opa-version' ? 'failed' : 'skipped',\n })),\n unformattedFiles: [],\n fixedFiles: [],\n diagnostics: [\n {\n code: 'project.bundles',\n severity: 'error',\n message:\n 'No publishable policy bundles found. Add one with `transcend policy new`, ' +\n 'or pass a directory that contains a `.manifest`.',\n path: path.relative(this.process.cwd(), resolvedDir) || '.',\n },\n ],\n };\n if (json) {\n this.process.stdout.write(`${JSON.stringify(empty)}\\n`);\n } else {\n renderResult(this, empty);\n }\n this.process.exitCode = 1;\n return;\n }\n\n const results: PolicyLintResult[] = [];\n for (const bundleDirectory of bundleDirectories) {\n results.push(\n await lintBundle.call(this, { fix, noInteractive, json }, bundleDirectory, runner),\n );\n }\n\n const failed = results.some((result) => result.status === 'failed');\n if (json) {\n if (results.length === 1) {\n this.process.stdout.write(`${JSON.stringify(results[0])}\\n`);\n } else {\n const multi: PolicyLintMultiResult = {\n version: POLICY_LINT_MULTI_RESULT_VERSION,\n status: failed ? 'failed' : 'passed',\n directory: resolvedDir,\n fix,\n results,\n };\n this.process.stdout.write(`${JSON.stringify(multi)}\\n`);\n }\n } else if (results.length === 1) {\n renderResult(this, results[0]!);\n } else {\n results.forEach((result, index) => {\n if (index > 0) {\n this.logger.info('');\n }\n const relative = path.relative(this.process.cwd(), result.directory) || result.directory;\n renderResult(this, result, `Policy lint — ${relative}`);\n });\n }\n\n if (failed) {\n this.process.exitCode = 1;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impl-WJBuS_0m.mjs","names":[],"sources":["../src/lib/preference-management/bulkDeletePreferenceRecords.ts","../src/commands/consent/delete-preference-records/impl.ts"],"sourcesContent":["import {\n DeletePreferenceRecordCliCsvRow,\n DeletePreferenceRecordsResponse,\n withTransientRetry,\n} from '@transcend-io/sdk';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport type { Got } from 'got';\nimport { chunk } from 'lodash-es';\n\nimport type { CliLogger } from '../../context.js';\nimport { logger } from '../../logger.js';\nimport { readCsv } from '../requests/index.js';\n\ninterface FailedResult extends DeletePreferenceRecordCliCsvRow {\n /** Error message describing the failure */\n error: string;\n}\n\ninterface DeletePreferenceRecordsRepositoryOptions {\n /** The partition to delete from */\n partition: string;\n /** Chunk of identifiers to delete */\n identifierChunk: DeletePreferenceRecordCliCsvRow[];\n /** the timestamp for the deletion operation */\n timestamp: Date;\n /** Command logger */\n logger: CliLogger;\n}\n\n/**\n * Options for deleting preference records\n */\ntype DeletePreferenceRecordsOptions = Omit<\n DeletePreferenceRecordsRepositoryOptions,\n 'identifierChunk' | 'logger'\n> & {\n /** The file path to read CSV rows from */\n filePath: string;\n /** Maximum items to include in each deletion chunk */\n maxItemsInChunk: number;\n /** Maximum concurrency for deletion requests */\n maxConcurrency: number;\n};\n\ntype DeletePreferenceRecordRowsOptions = Omit<DeletePreferenceRecordsOptions, 'filePath'> & {\n /** Decoded identifiers to delete */\n anchorIdentifiers: DeletePreferenceRecordCliCsvRow[];\n /** Command logger */\n logger: CliLogger;\n};\n\n/**\n *\n * Delete a chunk of preference records\n *\n * @param sombra - Sombra instance (must include auth headers)\n * @param options - Options for deletion\n * @param options.partition - The partition to delete from\n * @param options.identifierChunk - Chunk of identifiers to delete\n * @param options.timestamp - The timestamp for the deletion operation\n * @returns List of failed deletions\n */\nasync function deletePreferenceRecordsRepository(\n sombra: Got,\n {\n partition,\n identifierChunk: chunk,\n timestamp,\n logger: commandLogger,\n }: DeletePreferenceRecordsRepositoryOptions,\n): Promise<FailedResult[]> {\n try {\n const response = await withTransientRetry(\n 'Delete Preference Records',\n () =>\n sombra\n .post(`v1/preferences/${partition}/delete`, {\n json: {\n records: chunk.map((record) => ({\n anchorIdentifier: record,\n timestamp: timestamp.toISOString(),\n })),\n },\n })\n .json(),\n {\n logger: commandLogger,\n maxAttempts: 3,\n onRetry: (attempt, _err, msg) => {\n commandLogger.warn(\n colors.yellow(`Attempt ${attempt} to delete preference records failed: ${msg}`),\n );\n },\n },\n );\n const { failures } = decodeCodec(DeletePreferenceRecordsResponse, response);\n if (failures.length > 0) {\n return failures.map(({ index, error }) => ({\n ...chunk[index],\n error,\n }));\n }\n return [];\n } catch (err) {\n return chunk.map((record) => ({\n ...record,\n error: (err as Error).message,\n }));\n }\n}\n\n/**\n * Delete consent preferences for the managed consent database (delete endpoint)\n *\n * Uses POST /v1/preferences/{partition}/delete.\n *\n *\n * @param sombra - Sombra instance (must include auth headers)\n * @param options - Query options\n * @returns All nodes (only when onItems is not provided)\n */\nexport async function bulkDeletePreferenceRecords(\n sombra: Got,\n {\n partition,\n filePath,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n }: DeletePreferenceRecordsOptions,\n): Promise<FailedResult[]> {\n const anchorIdentifiers = readCsv(filePath, DeletePreferenceRecordCliCsvRow);\n return bulkDeletePreferenceRecordsFromRows(sombra, {\n anchorIdentifiers,\n partition,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n logger,\n });\n}\n\n/**\n * Delete decoded consent preference identifiers from the managed consent database.\n *\n * @param sombra - Sombra instance with authentication headers.\n * @param options - Decoded rows and deletion options.\n * @returns Failed deletions.\n */\nexport async function bulkDeletePreferenceRecordsFromRows(\n sombra: Got,\n {\n anchorIdentifiers,\n partition,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n logger,\n }: DeletePreferenceRecordRowsOptions,\n): Promise<FailedResult[]> {\n const chunks = chunk(anchorIdentifiers, maxItemsInChunk);\n\n const failedResults = await map(\n chunks,\n async (identifierChunk) => {\n const failedResults = await deletePreferenceRecordsRepository(sombra, {\n partition,\n identifierChunk,\n timestamp,\n logger,\n });\n return failedResults;\n },\n { concurrency: maxConcurrency },\n );\n return failedResults.flat();\n}\n","import path from 'node:path';\n\nimport { createSombraGotInstance, DeletePreferenceRecordCliCsvRow } from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { writeCsv } from '../../../lib/helpers/index.js';\nimport { bulkDeletePreferenceRecordsFromRows } from '../../../lib/preference-management/index.js';\nimport { parseCsv } from '../../../lib/requests/readCsv.js';\n\nexport interface DeletePreferenceRecordsCommandFlags {\n /** Transcend API key for authentication */\n auth: string;\n /** Partition ID to delete preference records from */\n partition: string;\n /** Optional Sombra internal key for self-hosted instances */\n sombraAuth?: string;\n /** Path to the CSV file used to identify preference records to delete */\n file?: string;\n /** Path to the directory of CSV files to load preferences from */\n directory?: string;\n /** Base URL for the Transcend API */\n transcendUrl: string;\n /** The timestamp when the deletion operation is made. Used for logging purposes. */\n timestamp: Date;\n /** Maximum items to include in each deletion chunk */\n maxItemsInChunk: number;\n /** Maximum concurrency for deletion requests */\n maxConcurrency: number;\n /** Directory to write receipts of failed deletions to */\n receiptDirectory: string;\n /** Number of files to process concurrently when deleting preference records from multiple files */\n fileConcurrency: number;\n}\n\nexport async function deletePreferenceRecords(\n this: LocalContext,\n {\n auth,\n partition,\n sombraAuth,\n file = '',\n directory,\n transcendUrl,\n timestamp,\n maxConcurrency,\n maxItemsInChunk,\n receiptDirectory,\n fileConcurrency,\n }: DeletePreferenceRecordsCommandFlags,\n): Promise<void> {\n if (!!directory && !!file) {\n this.logger.error(\n colors.red('Cannot provide both a directory and a file. Please provide only one.'),\n );\n this.process.exit(1);\n }\n\n if (!file && !directory) {\n this.logger.error(\n colors.red(\n 'A file or directory must be provided. Please provide one using --file=./preferences.csv or --directory=./preferences',\n ),\n );\n this.process.exit(1);\n }\n doneInputValidation(this.process);\n\n const files: string[] = [];\n\n if (directory) {\n try {\n const filesInDirectory = this.fs.readdirSync(directory);\n const csvFiles = filesInDirectory.filter((file) => file.endsWith('.csv'));\n\n if (csvFiles.length === 0) {\n this.logger.error(colors.red(`No CSV files found in directory: ${directory}`));\n this.process.exit(1);\n }\n\n // Add full paths for each CSV file\n files.push(...csvFiles.map((file) => path.join(directory, file)));\n } catch (err) {\n this.logger.error(colors.red(`Failed to read directory: ${directory}`));\n this.logger.error(colors.red((err as Error).message));\n this.process.exit(1);\n }\n } else {\n try {\n // Verify file exists and is a CSV\n if (!file.endsWith('.csv')) {\n this.logger.error(colors.red('File must be a CSV file'));\n this.process.exit(1);\n }\n files.push(file);\n } catch (err) {\n this.logger.error(colors.red(`Failed to access file: ${file}`));\n this.logger.error(colors.red((err as Error).message));\n this.process.exit(1);\n }\n }\n\n this.logger.debug(\n colors.green(\n `Processing ${files.length} consent preferences files for partition: ${partition}`,\n ),\n );\n this.logger.debug(`\\nFiles to process: ${files.join(', ')}\\n`);\n\n // Create sombra instance to communicate with\n const sombra = await createSombraGotInstance(transcendUrl, auth, {\n logger: this.logger,\n sombraApiKey: sombraAuth,\n sombraUrl: this.process.env.SOMBRA_URL,\n });\n const globalProgressBar = new cliProgress.SingleBar(\n {\n format: `Deletion Progress |${colors.cyan('[{bar}]')}| Duration: ${colors.red(\n '{duration_formatted}',\n )} | {value}/{total} Files Processed `,\n },\n cliProgress.Presets.shades_classic,\n );\n globalProgressBar.start(files.length, 0);\n\n // Process batch of files with concurrency\n const failedResultsArrays = await map(\n files,\n async (filePath) => {\n const anchorIdentifiers = parseCsv(\n this.fs.readFileSync(filePath, 'utf8'),\n DeletePreferenceRecordCliCsvRow,\n );\n const result = await bulkDeletePreferenceRecordsFromRows(sombra, {\n partition,\n anchorIdentifiers,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n logger: this.logger,\n });\n globalProgressBar.increment();\n return result;\n },\n { concurrency: fileConcurrency },\n );\n globalProgressBar.stop();\n const failedResults = failedResultsArrays.flat();\n\n // Check for failed results and write receipt if any\n let receiptPath = '';\n if (failedResults.length > 0) {\n receiptPath = path.join(receiptDirectory, `deletion-failures-${Date.now()}.csv`);\n writeCsv(receiptPath, failedResults, true);\n }\n\n this.logger.info(colors.green('\\n\\n ================================== \\n\\n'));\n this.logger.info(colors.green('\\n#### Deletion Summary Report #####\\n'));\n this.logger.info(\n colors.green(\n `📁 Total Files Processed: ${files.length} \\n` +\n `❌ Errors: ${failedResults.length} \\n` +\n `📝 Receipt Path: ${receiptPath || 'N/A'}`,\n ),\n );\n this.logger.info(colors.green('\\n\\n==================================\\n\\n'));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"impl-WJBuS_0m.mjs","names":[],"sources":["../src/lib/preference-management/bulkDeletePreferenceRecords.ts","../src/commands/consent/delete-preference-records/impl.ts"],"sourcesContent":["import {\n DeletePreferenceRecordCliCsvRow,\n DeletePreferenceRecordsResponse,\n withTransientRetry,\n} from '@transcend-io/sdk';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport type { Got } from 'got';\nimport { chunk } from 'lodash-es';\n\nimport type { CliLogger } from '../../context.js';\nimport { logger } from '../../logger.js';\nimport { readCsv } from '../requests/index.js';\n\ninterface FailedResult extends DeletePreferenceRecordCliCsvRow {\n /** Error message describing the failure */\n error: string;\n}\n\ninterface DeletePreferenceRecordsRepositoryOptions {\n /** The partition to delete from */\n partition: string;\n /** Chunk of identifiers to delete */\n identifierChunk: DeletePreferenceRecordCliCsvRow[];\n /** the timestamp for the deletion operation */\n timestamp: Date;\n /** Command logger */\n logger: CliLogger;\n}\n\n/**\n * Options for deleting preference records\n */\ntype DeletePreferenceRecordsOptions = Omit<\n DeletePreferenceRecordsRepositoryOptions,\n 'identifierChunk' | 'logger'\n> & {\n /** The file path to read CSV rows from */\n filePath: string;\n /** Maximum items to include in each deletion chunk */\n maxItemsInChunk: number;\n /** Maximum concurrency for deletion requests */\n maxConcurrency: number;\n};\n\ntype DeletePreferenceRecordRowsOptions = Omit<DeletePreferenceRecordsOptions, 'filePath'> & {\n /** Decoded identifiers to delete */\n anchorIdentifiers: DeletePreferenceRecordCliCsvRow[];\n /** Command logger */\n logger: CliLogger;\n};\n\n/**\n *\n * Delete a chunk of preference records\n *\n * @param sombra - Sombra instance (must include auth headers)\n * @param options - Options for deletion\n * @param options.partition - The partition to delete from\n * @param options.identifierChunk - Chunk of identifiers to delete\n * @param options.timestamp - The timestamp for the deletion operation\n * @returns List of failed deletions\n */\nasync function deletePreferenceRecordsRepository(\n sombra: Pick<Got, 'post'>,\n {\n partition,\n identifierChunk: chunk,\n timestamp,\n logger: commandLogger,\n }: DeletePreferenceRecordsRepositoryOptions,\n): Promise<FailedResult[]> {\n try {\n const response = await withTransientRetry(\n 'Delete Preference Records',\n () =>\n sombra\n .post(`v1/preferences/${partition}/delete`, {\n json: {\n records: chunk.map((record) => ({\n anchorIdentifier: record,\n timestamp: timestamp.toISOString(),\n })),\n },\n })\n .json(),\n {\n logger: commandLogger,\n maxAttempts: 3,\n onRetry: (attempt, _err, msg) => {\n commandLogger.warn(\n colors.yellow(`Attempt ${attempt} to delete preference records failed: ${msg}`),\n );\n },\n },\n );\n const { failures } = decodeCodec(DeletePreferenceRecordsResponse, response);\n if (failures.length > 0) {\n return failures.map(({ index, error }) => ({\n ...chunk[index],\n error,\n }));\n }\n return [];\n } catch (err) {\n return chunk.map((record) => ({\n ...record,\n error: (err as Error).message,\n }));\n }\n}\n\n/**\n * Delete consent preferences for the managed consent database (delete endpoint)\n *\n * Uses POST /v1/preferences/{partition}/delete.\n *\n *\n * @param sombra - Sombra instance (must include auth headers)\n * @param options - Query options\n * @returns All nodes (only when onItems is not provided)\n */\nexport async function bulkDeletePreferenceRecords(\n sombra: Pick<Got, 'post'>,\n {\n partition,\n filePath,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n }: DeletePreferenceRecordsOptions,\n): Promise<FailedResult[]> {\n const anchorIdentifiers = readCsv(filePath, DeletePreferenceRecordCliCsvRow);\n return bulkDeletePreferenceRecordsFromRows(sombra, {\n anchorIdentifiers,\n partition,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n logger,\n });\n}\n\n/**\n * Delete decoded consent preference identifiers from the managed consent database.\n *\n * @param sombra - Sombra instance with authentication headers.\n * @param options - Decoded rows and deletion options.\n * @returns Failed deletions.\n */\nexport async function bulkDeletePreferenceRecordsFromRows(\n sombra: Pick<Got, 'post'>,\n {\n anchorIdentifiers,\n partition,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n logger,\n }: DeletePreferenceRecordRowsOptions,\n): Promise<FailedResult[]> {\n const chunks = chunk(anchorIdentifiers, maxItemsInChunk);\n\n const failedResults = await map(\n chunks,\n async (identifierChunk) => {\n const failedResults = await deletePreferenceRecordsRepository(sombra, {\n partition,\n identifierChunk,\n timestamp,\n logger,\n });\n return failedResults;\n },\n { concurrency: maxConcurrency },\n );\n return failedResults.flat();\n}\n","import path from 'node:path';\n\nimport { createSombraGotInstance, DeletePreferenceRecordCliCsvRow } from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { writeCsv } from '../../../lib/helpers/index.js';\nimport { bulkDeletePreferenceRecordsFromRows } from '../../../lib/preference-management/index.js';\nimport { parseCsv } from '../../../lib/requests/readCsv.js';\n\nexport interface DeletePreferenceRecordsCommandFlags {\n /** Transcend API key for authentication */\n auth: string;\n /** Partition ID to delete preference records from */\n partition: string;\n /** Optional Sombra internal key for self-hosted instances */\n sombraAuth?: string;\n /** Path to the CSV file used to identify preference records to delete */\n file?: string;\n /** Path to the directory of CSV files to load preferences from */\n directory?: string;\n /** Base URL for the Transcend API */\n transcendUrl: string;\n /** The timestamp when the deletion operation is made. Used for logging purposes. */\n timestamp: Date;\n /** Maximum items to include in each deletion chunk */\n maxItemsInChunk: number;\n /** Maximum concurrency for deletion requests */\n maxConcurrency: number;\n /** Directory to write receipts of failed deletions to */\n receiptDirectory: string;\n /** Number of files to process concurrently when deleting preference records from multiple files */\n fileConcurrency: number;\n}\n\nexport async function deletePreferenceRecords(\n this: LocalContext,\n {\n auth,\n partition,\n sombraAuth,\n file = '',\n directory,\n transcendUrl,\n timestamp,\n maxConcurrency,\n maxItemsInChunk,\n receiptDirectory,\n fileConcurrency,\n }: DeletePreferenceRecordsCommandFlags,\n): Promise<void> {\n if (!!directory && !!file) {\n this.logger.error(\n colors.red('Cannot provide both a directory and a file. Please provide only one.'),\n );\n this.process.exit(1);\n }\n\n if (!file && !directory) {\n this.logger.error(\n colors.red(\n 'A file or directory must be provided. Please provide one using --file=./preferences.csv or --directory=./preferences',\n ),\n );\n this.process.exit(1);\n }\n doneInputValidation(this.process);\n\n const files: string[] = [];\n\n if (directory) {\n try {\n const filesInDirectory = this.fs.readdirSync(directory);\n const csvFiles = filesInDirectory.filter((file) => file.endsWith('.csv'));\n\n if (csvFiles.length === 0) {\n this.logger.error(colors.red(`No CSV files found in directory: ${directory}`));\n this.process.exit(1);\n }\n\n // Add full paths for each CSV file\n files.push(...csvFiles.map((file) => path.join(directory, file)));\n } catch (err) {\n this.logger.error(colors.red(`Failed to read directory: ${directory}`));\n this.logger.error(colors.red((err as Error).message));\n this.process.exit(1);\n }\n } else {\n try {\n // Verify file exists and is a CSV\n if (!file.endsWith('.csv')) {\n this.logger.error(colors.red('File must be a CSV file'));\n this.process.exit(1);\n }\n files.push(file);\n } catch (err) {\n this.logger.error(colors.red(`Failed to access file: ${file}`));\n this.logger.error(colors.red((err as Error).message));\n this.process.exit(1);\n }\n }\n\n this.logger.debug(\n colors.green(\n `Processing ${files.length} consent preferences files for partition: ${partition}`,\n ),\n );\n this.logger.debug(`\\nFiles to process: ${files.join(', ')}\\n`);\n\n // Create sombra instance to communicate with\n const sombra = await createSombraGotInstance(transcendUrl, auth, {\n logger: this.logger,\n sombraApiKey: sombraAuth,\n sombraUrl: this.process.env.SOMBRA_URL,\n });\n const globalProgressBar = new cliProgress.SingleBar(\n {\n format: `Deletion Progress |${colors.cyan('[{bar}]')}| Duration: ${colors.red(\n '{duration_formatted}',\n )} | {value}/{total} Files Processed `,\n },\n cliProgress.Presets.shades_classic,\n );\n globalProgressBar.start(files.length, 0);\n\n // Process batch of files with concurrency\n const failedResultsArrays = await map(\n files,\n async (filePath) => {\n const anchorIdentifiers = parseCsv(\n this.fs.readFileSync(filePath, 'utf8'),\n DeletePreferenceRecordCliCsvRow,\n );\n const result = await bulkDeletePreferenceRecordsFromRows(sombra, {\n partition,\n anchorIdentifiers,\n timestamp,\n maxItemsInChunk,\n maxConcurrency,\n logger: this.logger,\n });\n globalProgressBar.increment();\n return result;\n },\n { concurrency: fileConcurrency },\n );\n globalProgressBar.stop();\n const failedResults = failedResultsArrays.flat();\n\n // Check for failed results and write receipt if any\n let receiptPath = '';\n if (failedResults.length > 0) {\n receiptPath = path.join(receiptDirectory, `deletion-failures-${Date.now()}.csv`);\n writeCsv(receiptPath, failedResults, true);\n }\n\n this.logger.info(colors.green('\\n\\n ================================== \\n\\n'));\n this.logger.info(colors.green('\\n#### Deletion Summary Report #####\\n'));\n this.logger.info(\n colors.green(\n `📁 Total Files Processed: ${files.length} \\n` +\n `❌ Errors: ${failedResults.length} \\n` +\n `📝 Receipt Path: ${receiptPath || 'N/A'}`,\n ),\n );\n this.logger.info(colors.green('\\n\\n==================================\\n\\n'));\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{g as e}from"./constants-
|
|
2
|
-
//# sourceMappingURL=impl-
|
|
1
|
+
import{g as e}from"./constants-CusZYsjT.mjs";import{r as t,t as n}from"./project-plan-output-BHHlkLxe.mjs";import{d as r,f as i,t as a,u as o}from"./project-discovery-CWRjlFnC.mjs";import{S as s,_ as ee,c,h as te,m as l,p as u,r as d,t as f,v as p,x as ne,y as m}from"./policy-project-discovery-Dxikd8NT.mjs";import{t as h}from"./done-input-validation-LiTaCEzF.mjs";import{n as g,r as _,t as v}from"./prompts-BhXfYD6g.mjs";import{t as y}from"./project-plan-apply-Bg_1eMX9.mjs";import{a as b,i as x,n as S,o as re,r as ie}from"./policy-scaffold-config-DRWTaw0k.mjs";import{join as C,relative as ae,sep as w}from"node:path";import T from"colors";const E=/^[a-z][a-z0-9_]*$/u;function D(e){return e?E.test(e)?e.length>64?`Root name cannot exceed 64 characters.`:!0:`Root name must be lowercase alphanumeric with underscores (e.g. "example", "permissions").`:`Enter a bundle root name.`}async function O(E,O=f){h(this.process);try{let f=d(this,O),h=C(f.targetDirectory,`.regal`,`config.yaml`);if(!this.fs.existsSync(h))throw Error(`No policy workspace found at ${n(f.invocationDirectory,f.targetDirectory)}. Run \`transcend policy init\` first.`);let v=new g(this),k=_(E,this.process.stdin.isTTY,this.process.stderr.isTTY),A=E.template??(k?await v.select(`Template:`,l.map(e=>({name:te[e],value:e})),l[0]):void 0);if(!A||!l.includes(A))throw Error(`Missing policy template. Pass --template=${l.join(` or --template=`)}.`);let j=u[A],M=E.name??(k?await v.text(`Bundle root name:`,j,e=>{let t=D(e);return t===!0?!0:t}):void 0);if(!M)throw Error(`Missing bundle root name. Pass --name in a non-interactive invocation.`);let N=D(M);if(N!==!0)throw Error(N);let P=ee(M),F=E[`bundle-dir`]??(k?await v.text(`Bundle directory name:`,P,e=>{let t=s(e);return t===!0?!0:t}):P),I=s(F);if(I!==!0)throw Error(I);let L=C(f.targetDirectory,F);if(this.fs.existsSync(L))throw Error(`Bundle directory already exists: ${n(f.invocationDirectory,L)}. Choose a different --bundle-dir.`);let R=m(A,M,F),{contents:z,roots:B}=ne(this.fs.readFileSync(h,`utf8`),M),V=B.map(e=>e===M?{root:e,bundleDir:F,template:A}:x(e)),H=[h,...R.map(({path:e})=>C(f.targetDirectory,e))],U=C(f.projectRoot,`.vscode`,`settings.json`),W=C(f.projectRoot,`.vscode`,`tasks.json`),G=this.fs.existsSync(C(f.projectRoot,`.vscode`));G&&H.push(U,W);let K=f.repositoryRoot&&f.usesGithub?C(f.repositoryRoot,b):void 0;K&&this.fs.existsSync(K)&&H.push(K);let q=a(this,f.projectRoot,H.sort((e,t)=>e.localeCompare(t))),J=[],Y=[],X=[],Z=i({snapshot:o(q,h),after:z,description:`Merge ${M} root into Regal config`});if(Z?J.push(Z):X.push(h),R.forEach(e=>{let t=C(f.targetDirectory,e.path);if(r(q,t).kind!==`absent`)throw Error(`Expected an empty path but found an entry at: ${t}`);let n=i({snapshot:o(q,t),after:e.contents,description:e.description});n?J.push(n):X.push(t)}),G){let e=r(q,U);if(e.kind===`file`||e.kind===`absent`){let t=S(e.kind===`file`?e.contents:null,f.projectRoot,f.targetDirectory,V),r=i({snapshot:e.kind===`file`?{path:U,contents:e.contents,mode:e.mode}:{path:U,contents:null},after:t.contents,description:`Merge bundle root into VS Code OPA settings`});r?J.push(r):X.push(U),Y.push(...t.warnings.map(e=>`${e} (${n(f.invocationDirectory,U)})`))}let t=r(q,W);if(t.kind===`file`||t.kind===`absent`){let e=ie(t.kind===`file`?t.contents:null,f.projectRoot,f.targetDirectory,V),r=i({snapshot:t.kind===`file`?{path:W,contents:t.contents,mode:t.mode}:{path:W,contents:null},after:e.contents,description:`Add per-bundle and aggregate lint tasks`});r?J.push(r):X.push(W),Y.push(...e.warnings.map(e=>`${e} (${n(f.invocationDirectory,W)})`))}}if(K&&f.repositoryRoot){let t=r(q,K);if(t.kind===`file`){let r=ae(f.repositoryRoot,f.targetDirectory).split(w).join(`/`)||`.`,a=re({cliVersion:e,workspaceDirectory:r,bundleDirectories:V.map(e=>r===`.`?e.bundleDir:`${r}/${e.bundleDir}`)});if(t.contents.startsWith(`# Generated by transcend policy init`)){let e=i({snapshot:{path:K,contents:t.contents,mode:t.mode},after:a,description:`Update Policy Engine CI matrix for all publish directories`});e?J.push(e):X.push(K)}else Y.push(`Existing GitHub Actions workflow was left unchanged: ${n(f.invocationDirectory,K)}. Adapt it manually to lint each \`*-bundle/\` publish directory.`),X.push(K)}}let oe=p({bundleDirectory:n(f.invocationDirectory,L),root:M,template:A}),Q={rootDirectory:f.projectRoot,targetDirectory:f.targetDirectory,manifestPath:C(L,c),changes:J,unchanged:X,warnings:Y,nextSteps:[oe]};E.json||this.logger.info(t(Q,{cwd:this.process.cwd(),title:`Policy bundle plan`,details:[{label:`Workspace`,path:Q.targetDirectory},{label:`Bundle`,path:L}]}));let $=Q.changes.length===0||E.dryRun;if(Q.changes.length>0&&!E.dryRun)if(E.yes)$=!0;else if(k)$=await v.confirm(`Apply this complete plan?`,!0);else throw Error(`The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.`);$&&!E.dryRun&&Q.changes.length>0&&await y(this,Q);let se=$&&!E.dryRun&&Q.changes.length>0;if(E.json){this.process.stdout.write(`${JSON.stringify({applied:se,dryRun:E.dryRun,template:A,root:M,bundleDirectory:L,targetDirectory:Q.targetDirectory,manifestPath:Q.manifestPath,changes:Q.changes.map(e=>({kind:e.kind,target:n(this.process.cwd(),e.path),description:e.description})),warnings:Q.warnings,nextSteps:Q.nextSteps})}\n`);return}if(E.dryRun){this.logger.info(T.yellow(`Dry run complete. No changes were written.`));return}if(!$){this.logger.info(T.yellow(`No changes applied.`));return}this.logger.info(T.green(`Policy bundle ${M} added.`)),Q.nextSteps.length>0&&(this.logger.info(`\n${T.bold(`Next steps`)}`),Q.nextSteps.forEach(e=>this.logger.info(e)))}catch(e){throw e instanceof v&&this.process.exit(130),e}}export{O as _new};
|
|
2
|
+
//# sourceMappingURL=impl-wymd_Y3k.mjs.map
|