@transcend-io/cli 10.29.3 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +229 -84
- package/dist/app-CR3U95JW.mjs +148 -0
- package/dist/app-CR3U95JW.mjs.map +1 -0
- package/dist/{approvePrivacyRequests-DmQY27tf.mjs → approvePrivacyRequests-BDG82nlp.mjs} +2 -2
- package/dist/{approvePrivacyRequests-DmQY27tf.mjs.map → approvePrivacyRequests-BDG82nlp.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-COM0o0UR.mjs → buildExamples-B6BdW0FD.mjs} +2 -2
- package/dist/{buildExamples-COM0o0UR.mjs.map → buildExamples-B6BdW0FD.mjs.map} +1 -1
- package/dist/{buildXdiSyncEndpoint-5tSouA2b.mjs → buildXdiSyncEndpoint-FExEagKc.mjs} +2 -2
- package/dist/{buildXdiSyncEndpoint-5tSouA2b.mjs.map → buildXdiSyncEndpoint-FExEagKc.mjs.map} +1 -1
- package/dist/{bulkRestartRequests-CZrXs34U.mjs → bulkRestartRequests-OKwKXc52.mjs} +2 -2
- package/dist/{bulkRestartRequests-CZrXs34U.mjs.map → bulkRestartRequests-OKwKXc52.mjs.map} +1 -1
- package/dist/{bulkRetryEnrichers-BOXW2gK0.mjs → bulkRetryEnrichers-Dl-n8AFF.mjs} +2 -2
- package/dist/{bulkRetryEnrichers-BOXW2gK0.mjs.map → bulkRetryEnrichers-Dl-n8AFF.mjs.map} +1 -1
- package/dist/{cancelPrivacyRequests-CA8X4g4A.mjs → cancelPrivacyRequests-BIgX5SDz.mjs} +2 -2
- package/dist/{cancelPrivacyRequests-CA8X4g4A.mjs.map → cancelPrivacyRequests-BIgX5SDz.mjs.map} +1 -1
- package/dist/{codecs-CTxFjCg4.mjs → codecs-CfcaFoZR.mjs} +1 -1
- package/dist/{codecs-CTxFjCg4.mjs.map → codecs-CfcaFoZR.mjs.map} +1 -1
- package/dist/{collectCsvFilesOrExit-B1VOVGWN.mjs → collectCsvFilesOrExit-BindZ0dF.mjs} +1 -1
- package/dist/{collectCsvFilesOrExit-B1VOVGWN.mjs.map → collectCsvFilesOrExit-BindZ0dF.mjs.map} +1 -1
- package/dist/{collectParquetFilesOrExit-DVlv5ctt.mjs → collectParquetFilesOrExit-CbNQ9CJc.mjs} +1 -1
- package/dist/{collectParquetFilesOrExit-DVlv5ctt.mjs.map → collectParquetFilesOrExit-CbNQ9CJc.mjs.map} +1 -1
- package/dist/command-X7lkPELf.mjs +9 -0
- package/dist/command-X7lkPELf.mjs.map +1 -0
- package/dist/command-output-BJcDRXNr.mjs +2 -0
- package/dist/command-output-BJcDRXNr.mjs.map +1 -0
- package/dist/command-output-BRfF3YFv.mjs +2 -0
- package/dist/command-output-BRfF3YFv.mjs.map +1 -0
- package/dist/commands/admin/chunk-csv/worker.mjs +1 -1
- package/dist/commands/admin/parquet-to-csv/worker.mjs +1 -1
- package/dist/{consentManagersToBusinessEntities-CBJ81aGO.mjs → consentManagersToBusinessEntities-DG0_eby5.mjs} +1 -1
- package/dist/{consentManagersToBusinessEntities-CBJ81aGO.mjs.map → consentManagersToBusinessEntities-DG0_eby5.mjs.map} +1 -1
- package/dist/constants-BRsj50Nb.mjs +2 -0
- package/dist/{constants-XH8NIJGC.mjs.map → constants-BRsj50Nb.mjs.map} +1 -1
- package/dist/{constants-DXzsg2CQ.mjs → constants-DC_bBO09.mjs} +3 -3
- package/dist/{constants-DXzsg2CQ.mjs.map → constants-DC_bBO09.mjs.map} +1 -1
- package/dist/{constants-D_HVDaOy.mjs → constants-qvGk0wlN.mjs} +1 -1
- package/dist/{constants-D_HVDaOy.mjs.map → constants-qvGk0wlN.mjs.map} +1 -1
- package/dist/{context-B33NT3ki.mjs → context-D0A0LxsP.mjs} +1 -1
- package/dist/{context-B33NT3ki.mjs.map → context-D0A0LxsP.mjs.map} +1 -1
- package/dist/{createPoolingCommandUi-BtyIMQcK.mjs → createPoolingCommandUi-CyPZ3GqN.mjs} +5 -5
- package/dist/{createPoolingCommandUi-BtyIMQcK.mjs.map → createPoolingCommandUi-CyPZ3GqN.mjs.map} +1 -1
- package/dist/{dataFlowsToDataSilos-BF6fzWcm.mjs → dataFlowsToDataSilos-CRqbNjZ0.mjs} +1 -1
- package/dist/{dataFlowsToDataSilos-BF6fzWcm.mjs.map → dataFlowsToDataSilos-CRqbNjZ0.mjs.map} +1 -1
- package/dist/deno-runtime-CB2HBach.mjs +2 -0
- package/dist/deno-runtime-CB2HBach.mjs.map +1 -0
- package/dist/{done-input-validation-BUz-aVC5.mjs → done-input-validation-LiTaCEzF.mjs} +1 -1
- package/dist/{done-input-validation-BUz-aVC5.mjs.map → done-input-validation-LiTaCEzF.mjs.map} +1 -1
- package/dist/{downloadPrivacyRequestFiles-DbZjPjHw.mjs → downloadPrivacyRequestFiles-EBySRnvd.mjs} +2 -2
- package/dist/{downloadPrivacyRequestFiles-DbZjPjHw.mjs.map → downloadPrivacyRequestFiles-EBySRnvd.mjs.map} +1 -1
- package/dist/{extractClientError-HZ2U7yqV.mjs → extractClientError-DUJxHv07.mjs} +1 -1
- package/dist/{extractClientError-HZ2U7yqV.mjs.map → extractClientError-DUJxHv07.mjs.map} +1 -1
- package/dist/{fetchAllRequests-2TZr-LfT.mjs → fetchAllRequests-BI0tFl_a.mjs} +2 -2
- package/dist/{fetchAllRequests-2TZr-LfT.mjs.map → fetchAllRequests-BI0tFl_a.mjs.map} +1 -1
- package/dist/{formatPolicyBundleVersionSummary-CJmMCLtJ.mjs → formatPolicyBundleVersionSummary-DCHl1Vhy.mjs} +1 -1
- package/dist/{formatPolicyBundleVersionSummary-CJmMCLtJ.mjs.map → formatPolicyBundleVersionSummary-DCHl1Vhy.mjs.map} +1 -1
- package/dist/{fuzzyMatchColumns-CQCzpjWC.mjs → fuzzyMatchColumns-2NmQqCZI.mjs} +2 -2
- package/dist/{fuzzyMatchColumns-CQCzpjWC.mjs.map → fuzzyMatchColumns-2NmQqCZI.mjs.map} +1 -1
- package/dist/{generateCrossAccountApiKeys-C1iD6Las.mjs → generateCrossAccountApiKeys-pWTrIUE6.mjs} +2 -2
- package/dist/{generateCrossAccountApiKeys-C1iD6Las.mjs.map → generateCrossAccountApiKeys-pWTrIUE6.mjs.map} +1 -1
- package/dist/impl-0-_oxvck.mjs +2 -0
- package/dist/impl-0-_oxvck.mjs.map +1 -0
- package/dist/{impl-CNgOWzOX.mjs → impl-1SsreZWo.mjs} +2 -2
- package/dist/{impl-CNgOWzOX.mjs.map → impl-1SsreZWo.mjs.map} +1 -1
- package/dist/{impl-BjoGaK1M.mjs → impl-7rdGuHOC.mjs} +2 -2
- package/dist/{impl-BjoGaK1M.mjs.map → impl-7rdGuHOC.mjs.map} +1 -1
- package/dist/{impl-DRpK-QLC.mjs → impl-ApZGIx6l.mjs} +2 -2
- package/dist/{impl-DRpK-QLC.mjs.map → impl-ApZGIx6l.mjs.map} +1 -1
- package/dist/{impl-DVeGQCrr.mjs → impl-Ay6JeH-7.mjs} +2 -2
- package/dist/{impl-DVeGQCrr.mjs.map → impl-Ay6JeH-7.mjs.map} +1 -1
- package/dist/{impl-BR4ReYFA.mjs → impl-B2ZXtnpX.mjs} +2 -2
- package/dist/{impl-BR4ReYFA.mjs.map → impl-B2ZXtnpX.mjs.map} +1 -1
- package/dist/impl-B440iuvL.mjs +3 -0
- package/dist/impl-B440iuvL.mjs.map +1 -0
- package/dist/{impl-v_P8hszk2.mjs → impl-B7l4bLG5.mjs} +2 -2
- package/dist/impl-B7l4bLG5.mjs.map +1 -0
- package/dist/{impl-BPoEH3Nf2.mjs → impl-B94dMG4x2.mjs} +2 -2
- package/dist/{impl-BPoEH3Nf2.mjs.map → impl-B94dMG4x2.mjs.map} +1 -1
- package/dist/{impl-DXowiNOz.mjs → impl-BH1fCPDh.mjs} +2 -2
- package/dist/{impl-DXowiNOz.mjs.map → impl-BH1fCPDh.mjs.map} +1 -1
- package/dist/{impl-CfvxD3RI.mjs → impl-BLOhoP-b2.mjs} +2 -2
- package/dist/impl-BLOhoP-b2.mjs.map +1 -0
- package/dist/{impl-CMxliF19.mjs → impl-BLQDgwxL.mjs} +2 -2
- package/dist/{impl-CMxliF19.mjs.map → impl-BLQDgwxL.mjs.map} +1 -1
- package/dist/{impl-Dqqb0lVN.mjs → impl-BWPPVXG3.mjs} +3 -3
- package/dist/{impl-Dqqb0lVN.mjs.map → impl-BWPPVXG3.mjs.map} +1 -1
- package/dist/{impl-DceiaFcK.mjs → impl-BdTxFv63.mjs} +2 -2
- package/dist/{impl-DceiaFcK.mjs.map → impl-BdTxFv63.mjs.map} +1 -1
- package/dist/impl-BpVe6fMe.mjs +3 -0
- package/dist/{impl--JGnR3wp.mjs.map → impl-BpVe6fMe.mjs.map} +1 -1
- package/dist/impl-BqTMPbwc2.mjs +2 -0
- package/dist/impl-BqTMPbwc2.mjs.map +1 -0
- package/dist/impl-CAoIp9Nl2.mjs +3 -0
- package/dist/impl-CAoIp9Nl2.mjs.map +1 -0
- package/dist/{impl-99xoQXHW.mjs → impl-CU38kdj8.mjs} +2 -2
- package/dist/{impl-99xoQXHW.mjs.map → impl-CU38kdj8.mjs.map} +1 -1
- package/dist/{impl-DxnrCWeR2.mjs → impl-CWP6AXSb.mjs} +2 -2
- package/dist/impl-CWP6AXSb.mjs.map +1 -0
- package/dist/impl-CY8C-Fvj2.mjs +2 -0
- package/dist/impl-CY8C-Fvj2.mjs.map +1 -0
- package/dist/{impl-CfPDnai_.mjs → impl-C_Ifcb00.mjs} +2 -2
- package/dist/{impl-CfPDnai_.mjs.map → impl-C_Ifcb00.mjs.map} +1 -1
- package/dist/{impl-CPSEzCc9.mjs → impl-Cb42aI60.mjs} +2 -2
- package/dist/{impl-CPSEzCc9.mjs.map → impl-Cb42aI60.mjs.map} +1 -1
- package/dist/impl-Cee7Q1Ne.mjs +2 -0
- package/dist/impl-Cee7Q1Ne.mjs.map +1 -0
- package/dist/impl-CieztjdM.mjs +2 -0
- package/dist/impl-CieztjdM.mjs.map +1 -0
- package/dist/{impl-DqhZR11m.mjs → impl-ClqrQo1M.mjs} +2 -2
- package/dist/{impl-DqhZR11m.mjs.map → impl-ClqrQo1M.mjs.map} +1 -1
- package/dist/impl-CnHfn7rr.mjs +5 -0
- package/dist/{impl-DPtx5iZO.mjs.map → impl-CnHfn7rr.mjs.map} +1 -1
- package/dist/{impl-jJnYd4tJ.mjs → impl-CrdqsTUy.mjs} +2 -2
- package/dist/{impl-jJnYd4tJ.mjs.map → impl-CrdqsTUy.mjs.map} +1 -1
- package/dist/{impl-DzUTmaID2.mjs → impl-CsaT3aM2.mjs} +2 -2
- package/dist/impl-CsaT3aM2.mjs.map +1 -0
- package/dist/{impl-DB8Kt2qF2.mjs → impl-CspH2ZWx.mjs} +2 -2
- package/dist/impl-CspH2ZWx.mjs.map +1 -0
- package/dist/{impl-H9kweQnu2.mjs → impl-CudSYx-g.mjs} +2 -2
- package/dist/impl-CudSYx-g.mjs.map +1 -0
- package/dist/{impl-DUBsZL5O.mjs → impl-Cxprr2hw.mjs} +2 -2
- package/dist/{impl-DUBsZL5O.mjs.map → impl-Cxprr2hw.mjs.map} +1 -1
- package/dist/{impl-C5Mq4wv0.mjs → impl-D-a5xGld.mjs} +2 -2
- package/dist/{impl-C5Mq4wv0.mjs.map → impl-D-a5xGld.mjs.map} +1 -1
- package/dist/{impl-CGioITgZ.mjs → impl-D1UogVAq.mjs} +2 -2
- package/dist/{impl-CGioITgZ.mjs.map → impl-D1UogVAq.mjs.map} +1 -1
- package/dist/{impl-B37wtYBz.mjs → impl-D1f9mJL_.mjs} +2 -2
- package/dist/{impl-B37wtYBz.mjs.map → impl-D1f9mJL_.mjs.map} +1 -1
- package/dist/{impl-Cl9ndadE.mjs → impl-DJcNhpbx.mjs} +2 -2
- package/dist/{impl-Cl9ndadE.mjs.map → impl-DJcNhpbx.mjs.map} +1 -1
- package/dist/impl-DQG1pMzD2.mjs +2 -0
- package/dist/impl-DQG1pMzD2.mjs.map +1 -0
- package/dist/impl-DQcgEx7V2.mjs +298 -0
- package/dist/impl-DQcgEx7V2.mjs.map +1 -0
- package/dist/impl-DRKPx_I9.mjs +2 -0
- package/dist/impl-DRKPx_I9.mjs.map +1 -0
- package/dist/{impl-CXQ3OYR9.mjs → impl-DTadLabu.mjs} +2 -2
- package/dist/{impl-CXQ3OYR9.mjs.map → impl-DTadLabu.mjs.map} +1 -1
- package/dist/{impl-B9lSnjby.mjs → impl-DXbxO2VJ.mjs} +2 -2
- package/dist/{impl-B9lSnjby.mjs.map → impl-DXbxO2VJ.mjs.map} +1 -1
- package/dist/{impl-Cel22rUg2.mjs → impl-DcL-8NEa2.mjs} +2 -2
- package/dist/{impl-Cel22rUg2.mjs.map → impl-DcL-8NEa2.mjs.map} +1 -1
- package/dist/{impl-DKepRc812.mjs → impl-DeCRXfAh2.mjs} +2 -2
- package/dist/{impl-DKepRc812.mjs.map → impl-DeCRXfAh2.mjs.map} +1 -1
- package/dist/impl-DezV3QMo.mjs +3 -0
- package/dist/impl-DezV3QMo.mjs.map +1 -0
- package/dist/{impl-COujMWgp.mjs → impl-Dg7XSQdO2.mjs} +2 -2
- package/dist/impl-Dg7XSQdO2.mjs.map +1 -0
- package/dist/{impl-a_Y8bnSn.mjs → impl-DhXzxQDN2.mjs} +5 -5
- package/dist/impl-DhXzxQDN2.mjs.map +1 -0
- package/dist/impl-DiwxYcux.mjs +2 -0
- package/dist/{impl-BKmibZoG.mjs.map → impl-DiwxYcux.mjs.map} +1 -1
- package/dist/{impl-p_M16BEd.mjs → impl-Do2TNA3-.mjs} +2 -2
- package/dist/{impl-p_M16BEd.mjs.map → impl-Do2TNA3-.mjs.map} +1 -1
- package/dist/{impl-DaH1_ZzK.mjs → impl-DqHEIzpj.mjs} +2 -2
- package/dist/{impl-DaH1_ZzK.mjs.map → impl-DqHEIzpj.mjs.map} +1 -1
- package/dist/{impl-GH9uVaGu.mjs → impl-Dr_l_SLd.mjs} +2 -2
- package/dist/{impl-GH9uVaGu.mjs.map → impl-Dr_l_SLd.mjs.map} +1 -1
- package/dist/{impl-Dt5Iik_-.mjs → impl-Ds-gQfdc.mjs} +2 -2
- package/dist/{impl-Dt5Iik_-.mjs.map → impl-Ds-gQfdc.mjs.map} +1 -1
- package/dist/{impl-CJML1Gwo.mjs → impl-DtnYcktN.mjs} +2 -2
- package/dist/{impl-CJML1Gwo.mjs.map → impl-DtnYcktN.mjs.map} +1 -1
- package/dist/impl-DtpgD_as.mjs +2 -0
- package/dist/{impl-DWD4fAPO.mjs.map → impl-DtpgD_as.mjs.map} +1 -1
- package/dist/{impl-CL0y3SFr.mjs → impl-DxQ9yj3H.mjs} +2 -2
- package/dist/{impl-CL0y3SFr.mjs.map → impl-DxQ9yj3H.mjs.map} +1 -1
- package/dist/impl-FerHBNJx2.mjs +4 -0
- package/dist/{impl-BFn-S-Wy2.mjs.map → impl-FerHBNJx2.mjs.map} +1 -1
- package/dist/{impl-Cs1z9k1h2.mjs → impl-HUfaARep.mjs} +2 -2
- package/dist/impl-HUfaARep.mjs.map +1 -0
- package/dist/impl-btKJ1-VJ.mjs +3 -0
- package/dist/impl-btKJ1-VJ.mjs.map +1 -0
- package/dist/impl-eeS2lVi5.mjs +2 -0
- package/dist/impl-eeS2lVi5.mjs.map +1 -0
- package/dist/impl-iD6Fknfe.mjs +2 -0
- package/dist/impl-iD6Fknfe.mjs.map +1 -0
- package/dist/impl-ijoNwhGI.mjs +2 -0
- package/dist/impl-ijoNwhGI.mjs.map +1 -0
- package/dist/{impl-C83WRl40.mjs → impl-vmLq6HCI.mjs} +2 -2
- package/dist/{impl-C83WRl40.mjs.map → impl-vmLq6HCI.mjs.map} +1 -1
- package/dist/{impl-C8vx7N5j.mjs → impl-wBcVYHlA.mjs} +2 -2
- package/dist/{impl-C8vx7N5j.mjs.map → impl-wBcVYHlA.mjs.map} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/{initializeCliRuntime-6wI_VIHV.mjs → initializeCliRuntime-BaATMO1X.mjs} +1 -1
- package/dist/{initializeCliRuntime-6wI_VIHV.mjs.map → initializeCliRuntime-BaATMO1X.mjs.map} +1 -1
- package/dist/{inquirer-BeaBetMO.mjs → inquirer-BU5IpgA8.mjs} +2 -2
- package/dist/{inquirer-BeaBetMO.mjs.map → inquirer-BU5IpgA8.mjs.map} +1 -1
- package/dist/{jsonc-D9dDWb1J.mjs → jsonc-CdTubr53.mjs} +1 -1
- package/dist/{jsonc-D9dDWb1J.mjs.map → jsonc-CdTubr53.mjs.map} +1 -1
- package/dist/{listFiles-BdFUbX5x.mjs → listFiles-DDGCBdtx.mjs} +1 -1
- package/dist/{listFiles-BdFUbX5x.mjs.map → listFiles-DDGCBdtx.mjs.map} +1 -1
- package/dist/logger-CPu6zbyQ.mjs +2 -0
- package/dist/logger-CPu6zbyQ.mjs.map +1 -0
- package/dist/{mapConsentCsvRowsToInputs-Dqb6WL4r.mjs → mapConsentCsvRowsToInputs-CkLfxaIf.mjs} +1 -1
- package/dist/{mapConsentCsvRowsToInputs-Dqb6WL4r.mjs.map → mapConsentCsvRowsToInputs-CkLfxaIf.mjs.map} +1 -1
- package/dist/{markRequestDataSiloIdsCompleted-B5JCHcqh.mjs → markRequestDataSiloIdsCompleted-BYNMCkhy.mjs} +2 -2
- package/dist/{markRequestDataSiloIdsCompleted-B5JCHcqh.mjs.map → markRequestDataSiloIdsCompleted-BYNMCkhy.mjs.map} +1 -1
- package/dist/{markSilentPrivacyRequests-BAIZ97iB.mjs → markSilentPrivacyRequests-gKYivzH1.mjs} +2 -2
- package/dist/{markSilentPrivacyRequests-BAIZ97iB.mjs.map → markSilentPrivacyRequests-gKYivzH1.mjs.map} +1 -1
- package/dist/{mergeTranscendInputs-DFQcbh8b.mjs → mergeTranscendInputs-D1CvxQu0.mjs} +2 -2
- package/dist/{mergeTranscendInputs-DFQcbh8b.mjs.map → mergeTranscendInputs-D1CvxQu0.mjs.map} +1 -1
- package/dist/missing-manifest-D8y1VL4p.mjs +2 -0
- package/dist/missing-manifest-D8y1VL4p.mjs.map +1 -0
- package/dist/{module-graph-Cb0g74Ft.mjs → module-graph-CAT8_JCG.mjs} +1 -1
- package/dist/{module-graph-Cb0g74Ft.mjs.map → module-graph-CAT8_JCG.mjs.map} +1 -1
- package/dist/{notifyPrivacyRequestsAdditionalTime-C2lUoWKP.mjs → notifyPrivacyRequestsAdditionalTime-DbERhQ1Q.mjs} +2 -2
- package/dist/{notifyPrivacyRequestsAdditionalTime-C2lUoWKP.mjs.map → notifyPrivacyRequestsAdditionalTime-DbERhQ1Q.mjs.map} +1 -1
- package/dist/{parquetToCsvOneFile-ChmPC6dL.mjs → parquetToCsvOneFile-DtbCFm08.mjs} +3 -3
- package/dist/{parquetToCsvOneFile-ChmPC6dL.mjs.map → parquetToCsvOneFile-DtbCFm08.mjs.map} +1 -1
- package/dist/{parseAttributesFromString-CO16oAlx.mjs → parseAttributesFromString-C5hJMRvt.mjs} +2 -2
- package/dist/{parseAttributesFromString-CO16oAlx.mjs.map → parseAttributesFromString-C5hJMRvt.mjs.map} +1 -1
- package/dist/{parseVariablesFromString-BOSfQ4QF.mjs → parseVariablesFromString-6TYW65LF.mjs} +1 -1
- package/dist/{parseVariablesFromString-BOSfQ4QF.mjs.map → parseVariablesFromString-6TYW65LF.mjs.map} +1 -1
- package/dist/paths-J5KScOaQ.mjs +2 -0
- package/dist/paths-J5KScOaQ.mjs.map +1 -0
- package/dist/policy-bundle-manifest-BZnBMZQq.mjs +7 -0
- package/dist/policy-bundle-manifest-BZnBMZQq.mjs.map +1 -0
- package/dist/policy-project-discovery-C29UxWwt.mjs +427 -0
- package/dist/policy-project-discovery-C29UxWwt.mjs.map +1 -0
- package/dist/{policy-runtime-BMKa-Upy.mjs → policy-runtime-6jmkXlBk.mjs} +2 -2
- package/dist/{policy-runtime-BMKa-Upy.mjs.map → policy-runtime-6jmkXlBk.mjs.map} +1 -1
- package/dist/policy-scaffold-config-BUKAyPad.mjs +76 -0
- package/dist/policy-scaffold-config-BUKAyPad.mjs.map +1 -0
- package/dist/{policyEngineCliError-DY8V-qkK.mjs → policyEngineCliError-CZrOHhLv.mjs} +1 -1
- package/dist/{policyEngineCliError-DY8V-qkK.mjs.map → policyEngineCliError-CZrOHhLv.mjs.map} +1 -1
- package/dist/{printResult-CHe3nRN4.mjs → printResult-C2K9ODeE.mjs} +3 -3
- package/dist/printResult-C2K9ODeE.mjs.map +1 -0
- package/dist/project-discovery-BkHpTXDx.mjs +2 -0
- package/dist/project-discovery-BkHpTXDx.mjs.map +1 -0
- package/dist/project-discovery-CWRjlFnC.mjs +2 -0
- package/dist/project-discovery-CWRjlFnC.mjs.map +1 -0
- package/dist/project-plan-apply-Bg_1eMX9.mjs +3 -0
- package/dist/{project-plan-apply-Dvndx455.mjs.map → project-plan-apply-Bg_1eMX9.mjs.map} +1 -1
- package/dist/project-plan-output-BHHlkLxe.mjs +4 -0
- package/dist/project-plan-output-BHHlkLxe.mjs.map +1 -0
- package/dist/prompts-BhXfYD6g.mjs +2 -0
- package/dist/prompts-BhXfYD6g.mjs.map +1 -0
- package/dist/{pullAllDatapoints-uk5ggk6O.mjs → pullAllDatapoints-Bm-Orhse.mjs} +2 -2
- package/dist/{pullAllDatapoints-uk5ggk6O.mjs.map → pullAllDatapoints-Bm-Orhse.mjs.map} +1 -1
- package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-BmhJiquf.mjs → pullChunkedCustomSiloOutstandingIdentifiers-DTGQOw--.mjs} +2 -2
- package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-BmhJiquf.mjs.map → pullChunkedCustomSiloOutstandingIdentifiers-DTGQOw--.mjs.map} +1 -1
- package/dist/{pullConsentManagerMetrics-Dv5n1ZGp.mjs → pullConsentManagerMetrics-DKCkfbCB.mjs} +2 -2
- package/dist/{pullConsentManagerMetrics-Dv5n1ZGp.mjs.map → pullConsentManagerMetrics-DKCkfbCB.mjs.map} +1 -1
- package/dist/{pullManualEnrichmentIdentifiersToCsv-BbQc9MDM.mjs → pullManualEnrichmentIdentifiersToCsv-DMC5CQtE.mjs} +2 -2
- package/dist/{pullManualEnrichmentIdentifiersToCsv-BbQc9MDM.mjs.map → pullManualEnrichmentIdentifiersToCsv-DMC5CQtE.mjs.map} +1 -1
- package/dist/{pullTranscendConfiguration-B63M3ild.mjs → pullTranscendConfiguration-CDUDqxpm.mjs} +2 -2
- package/dist/{pullTranscendConfiguration-B63M3ild.mjs.map → pullTranscendConfiguration-CDUDqxpm.mjs.map} +1 -1
- package/dist/{pullUnstructuredSubDataPointRecommendations-YTBzfkRZ.mjs → pullUnstructuredSubDataPointRecommendations-Ci4AOxyH.mjs} +2 -2
- package/dist/{pullUnstructuredSubDataPointRecommendations-YTBzfkRZ.mjs.map → pullUnstructuredSubDataPointRecommendations-Ci4AOxyH.mjs.map} +1 -1
- package/dist/{pushCronIdentifiersFromCsv-Cfo2GibV.mjs → pushCronIdentifiersFromCsv-DhS2z8IG.mjs} +2 -2
- package/dist/{pushCronIdentifiersFromCsv-Cfo2GibV.mjs.map → pushCronIdentifiersFromCsv-DhS2z8IG.mjs.map} +1 -1
- package/dist/{pushManualEnrichmentIdentifiersFromCsv-DokcIxh1.mjs → pushManualEnrichmentIdentifiersFromCsv-BTJGOmdU.mjs} +2 -2
- package/dist/{pushManualEnrichmentIdentifiersFromCsv-DokcIxh1.mjs.map → pushManualEnrichmentIdentifiersFromCsv-BTJGOmdU.mjs.map} +1 -1
- package/dist/{readCsv-DLg8pwjd.mjs → readCsv-DNcJ_UfU.mjs} +1 -1
- package/dist/{readCsv-DLg8pwjd.mjs.map → readCsv-DNcJ_UfU.mjs.map} +1 -1
- package/dist/{readTranscendYaml-BNn6-Ofi.mjs → readTranscendYaml-BfqQbPiT.mjs} +3 -3
- package/dist/{readTranscendYaml-BNn6-Ofi.mjs.map → readTranscendYaml-BfqQbPiT.mjs.map} +1 -1
- package/dist/{removeUnverifiedRequestIdentifiers-p4gFagI0.mjs → removeUnverifiedRequestIdentifiers-BkAcUZZN.mjs} +2 -2
- package/dist/{removeUnverifiedRequestIdentifiers-p4gFagI0.mjs.map → removeUnverifiedRequestIdentifiers-BkAcUZZN.mjs.map} +1 -1
- package/dist/{renderTable-D68QasPc.mjs → renderTable-CZP2roD1.mjs} +1 -1
- package/dist/{renderTable-D68QasPc.mjs.map → renderTable-CZP2roD1.mjs.map} +1 -1
- package/dist/{request-BiPv6jmP.mjs → request-BpKyN9Xm.mjs} +1 -1
- package/dist/{request-BiPv6jmP.mjs.map → request-BpKyN9Xm.mjs.map} +1 -1
- package/dist/{resolveBundleIdByName-qXZBrUz_.mjs → resolveBundleIdByName-Dm_o5_bg.mjs} +2 -2
- package/dist/{resolveBundleIdByName-qXZBrUz_.mjs.map → resolveBundleIdByName-Dm_o5_bg.mjs.map} +1 -1
- package/dist/{resolvePolicyBundleVersion-BG7XqBBP.mjs → resolvePolicyBundleVersion-DRUwe7fA.mjs} +2 -2
- package/dist/{resolvePolicyBundleVersion-BG7XqBBP.mjs.map → resolvePolicyBundleVersion-DRUwe7fA.mjs.map} +1 -1
- package/dist/{retryRequestDataSilos-C6mvi-ET.mjs → retryRequestDataSilos-BoPmcB8-.mjs} +2 -2
- package/dist/{retryRequestDataSilos-C6mvi-ET.mjs.map → retryRequestDataSilos-BoPmcB8-.mjs.map} +1 -1
- package/dist/{run-captured-process-BXwWXuTh.mjs → run-captured-process-BjaSDWXG.mjs} +1 -1
- package/dist/{run-captured-process-BXwWXuTh.mjs.map → run-captured-process-BjaSDWXG.mjs.map} +1 -1
- package/dist/{runOpa-CswzJxIs.mjs → runOpa-ojIqU1tO.mjs} +2 -2
- package/dist/{runOpa-CswzJxIs.mjs.map → runOpa-ojIqU1tO.mjs.map} +1 -1
- package/dist/{scaffold-model-BAbYTR0q.mjs → scaffold-model-CUZER0BC.mjs} +1 -1
- package/dist/scaffold-model-CUZER0BC.mjs.map +1 -0
- package/dist/{scaffold-planning-CNv83t_v.mjs → scaffold-planning-CaetLfv8.mjs} +9 -9
- package/dist/{scaffold-planning-CNv83t_v.mjs.map → scaffold-planning-CaetLfv8.mjs.map} +1 -1
- package/dist/{scaffold-templates-DzDGTZie.mjs → scaffold-templates-CUL82Zf8.mjs} +1 -1
- package/dist/{scaffold-templates-DzDGTZie.mjs.map → scaffold-templates-CUL82Zf8.mjs.map} +1 -1
- package/dist/{skipPreflightJobs-CgUcTgzf.mjs → skipPreflightJobs-DkBdYw-r.mjs} +2 -2
- package/dist/{skipPreflightJobs-CgUcTgzf.mjs.map → skipPreflightJobs-DkBdYw-r.mjs.map} +1 -1
- package/dist/{skipRequestDataSilos-Be-6OhWe.mjs → skipRequestDataSilos-BRFiokix.mjs} +2 -2
- package/dist/{skipRequestDataSilos-Be-6OhWe.mjs.map → skipRequestDataSilos-BRFiokix.mjs.map} +1 -1
- package/dist/{streamPrivacyRequestsToCsv-BaeFrrGF.mjs → streamPrivacyRequestsToCsv-Bt-H5J-y.mjs} +2 -2
- package/dist/{streamPrivacyRequestsToCsv-BaeFrrGF.mjs.map → streamPrivacyRequestsToCsv-Bt-H5J-y.mjs.map} +1 -1
- package/dist/{syncCodePackages-BHE2Tn1Q.mjs → syncCodePackages-CPkEukDm.mjs} +2 -2
- package/dist/{syncCodePackages-BHE2Tn1Q.mjs.map → syncCodePackages-CPkEukDm.mjs.map} +1 -1
- package/dist/{updateConsentManagerVersionToLatest-3mQX2U8F.mjs → updateConsentManagerVersionToLatest-DWblAwus.mjs} +2 -2
- package/dist/{updateConsentManagerVersionToLatest-3mQX2U8F.mjs.map → updateConsentManagerVersionToLatest-DWblAwus.mjs.map} +1 -1
- package/dist/{uploadConsents-Dnbtx9P5.mjs → uploadConsents-D7Vg8ZRW.mjs} +2 -2
- package/dist/{uploadConsents-Dnbtx9P5.mjs.map → uploadConsents-D7Vg8ZRW.mjs.map} +1 -1
- package/dist/{uploadPrivacyRequestsFromCsv-BIW2JPjA.mjs → uploadPrivacyRequestsFromCsv-B_hQwIn6.mjs} +2 -2
- package/dist/{uploadPrivacyRequestsFromCsv-BIW2JPjA.mjs.map → uploadPrivacyRequestsFromCsv-B_hQwIn6.mjs.map} +1 -1
- package/dist/validateTranscendAuth-D-dDINof.mjs +2 -0
- package/dist/{validateTranscendAuth-D6Wr1cxY.mjs.map → validateTranscendAuth-D-dDINof.mjs.map} +1 -1
- package/dist/{writeCsv-D-2siSwE.mjs → writeCsv-CNZrq3zU.mjs} +1 -1
- package/dist/{writeCsv-D-2siSwE.mjs.map → writeCsv-CNZrq3zU.mjs.map} +1 -1
- package/package.json +6 -5
- package/dist/app-D-IPyX64.mjs +0 -148
- package/dist/app-D-IPyX64.mjs.map +0 -1
- package/dist/command-Ddx7b9ik.mjs +0 -9
- package/dist/command-Ddx7b9ik.mjs.map +0 -1
- package/dist/constants-XH8NIJGC.mjs +0 -2
- package/dist/deno-runtime-DV52X8-P.mjs +0 -2
- package/dist/deno-runtime-DV52X8-P.mjs.map +0 -1
- package/dist/impl--JGnR3wp.mjs +0 -3
- package/dist/impl-7UqkSO3x2.mjs +0 -2
- package/dist/impl-7UqkSO3x2.mjs.map +0 -1
- package/dist/impl-B4BgGuF_.mjs +0 -3
- package/dist/impl-B4BgGuF_.mjs.map +0 -1
- package/dist/impl-BFn-S-Wy2.mjs +0 -4
- package/dist/impl-BKmibZoG.mjs +0 -2
- package/dist/impl-C6HtWd1t.mjs +0 -2
- package/dist/impl-C6HtWd1t.mjs.map +0 -1
- package/dist/impl-CO4ZqlLV.mjs +0 -3
- package/dist/impl-CO4ZqlLV.mjs.map +0 -1
- package/dist/impl-COujMWgp.mjs.map +0 -1
- package/dist/impl-CUOVJsRg.mjs +0 -3
- package/dist/impl-CUOVJsRg.mjs.map +0 -1
- package/dist/impl-CUiYbk6G.mjs +0 -3
- package/dist/impl-CUiYbk6G.mjs.map +0 -1
- package/dist/impl-CbAvM_1J.mjs +0 -2
- package/dist/impl-CbAvM_1J.mjs.map +0 -1
- package/dist/impl-CfvxD3RI.mjs.map +0 -1
- package/dist/impl-Cli2XRp02.mjs +0 -2
- package/dist/impl-Cli2XRp02.mjs.map +0 -1
- package/dist/impl-Cs1z9k1h2.mjs.map +0 -1
- package/dist/impl-DB8Kt2qF2.mjs.map +0 -1
- package/dist/impl-DHQh34Eh2.mjs +0 -303
- package/dist/impl-DHQh34Eh2.mjs.map +0 -1
- package/dist/impl-DN6CgOI6.mjs +0 -2
- package/dist/impl-DN6CgOI6.mjs.map +0 -1
- package/dist/impl-DPtx5iZO.mjs +0 -5
- package/dist/impl-DWD4fAPO.mjs +0 -2
- package/dist/impl-DXRDWiB1.mjs +0 -2
- package/dist/impl-DXRDWiB1.mjs.map +0 -1
- package/dist/impl-DdIa0zla.mjs +0 -2
- package/dist/impl-DdIa0zla.mjs.map +0 -1
- package/dist/impl-DryC3OJu.mjs +0 -2
- package/dist/impl-DryC3OJu.mjs.map +0 -1
- package/dist/impl-DxnrCWeR2.mjs.map +0 -1
- package/dist/impl-DzUTmaID2.mjs.map +0 -1
- package/dist/impl-H9kweQnu2.mjs.map +0 -1
- package/dist/impl-Z8oWVENM.mjs +0 -2
- package/dist/impl-Z8oWVENM.mjs.map +0 -1
- package/dist/impl-a_Y8bnSn.mjs.map +0 -1
- package/dist/impl-v_P8hszk2.mjs.map +0 -1
- package/dist/logger-zplFSeXU.mjs +0 -2
- package/dist/logger-zplFSeXU.mjs.map +0 -1
- package/dist/manifest-BNIpO_zW.mjs +0 -2
- package/dist/manifest-BNIpO_zW.mjs.map +0 -1
- package/dist/missing-manifest-DgcukXfg.mjs +0 -2
- package/dist/missing-manifest-DgcukXfg.mjs.map +0 -1
- package/dist/path-safety-D5Qwl40b.mjs +0 -2
- package/dist/path-safety-D5Qwl40b.mjs.map +0 -1
- package/dist/policy-bundle-manifest-D6dkbjNi.mjs +0 -7
- package/dist/policy-bundle-manifest-D6dkbjNi.mjs.map +0 -1
- package/dist/printResult-CHe3nRN4.mjs.map +0 -1
- package/dist/project-plan-apply-Dvndx455.mjs +0 -3
- package/dist/prompts-ClBXdELk.mjs +0 -4
- package/dist/prompts-ClBXdELk.mjs.map +0 -1
- package/dist/scaffold-model-BAbYTR0q.mjs.map +0 -1
- package/dist/validateTranscendAuth-D6Wr1cxY.mjs +0 -2
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-DryC3OJu.mjs","names":[],"sources":["../src/commands/policy/eval/impl.ts"],"sourcesContent":["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 { assertOpaInstalled, runOpa } from '../helpers/index.js';\n\n/** CLI flags for `transcend policy eval`. */\nexport interface EvalCommandFlags {\n /** OPA package/query to evaluate (e.g. `data.transcend.decision`) */\n pkg: string;\n /** Path to a JSON envelope input file */\n input: string;\n /** Optional local policy bundle directory */\n bundle?: string;\n}\n\n/**\n * Evaluate one envelope against a local policy bundle via `opa eval`.\n *\n * @param this - CLI context\n * @param flags - Command flags\n */\nexport async function _eval(\n this: LocalContext,\n { pkg, input, bundle }: EvalCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n assertOpaInstalled();\n\n const inputPath = path.resolve(input);\n if (!this.fs.existsSync(inputPath)) {\n throw new Error(`Input file not found: ${inputPath}`);\n }\n\n const args = ['eval', '--format', 'pretty', '--input', inputPath];\n if (bundle) {\n args.push('-b', path.resolve(bundle));\n }\n args.push(pkg);\n\n this.logger.info(colors.green(`Evaluating ${pkg} with input ${inputPath}...`));\n\n const exitCode = await runOpa(args);\n if (exitCode !== 0) {\n this.process.exit(exitCode);\n }\n}\n"],"mappings":"yJAwBA,eAAsB,EAEpB,CAAE,MAAK,QAAO,UACC,CACf,EAAoB,KAAK,QAAQ,CAEjC,GAAoB,CAEpB,IAAM,EAAY,EAAK,QAAQ,EAAM,CACrC,GAAI,CAAC,KAAK,GAAG,WAAW,EAAU,CAChC,MAAU,MAAM,yBAAyB,IAAY,CAGvD,IAAM,EAAO,CAAC,OAAQ,WAAY,SAAU,UAAW,EAAU,CAC7D,GACF,EAAK,KAAK,KAAM,EAAK,QAAQ,EAAO,CAAC,CAEvC,EAAK,KAAK,EAAI,CAEd,KAAK,OAAO,KAAK,EAAO,MAAM,cAAc,EAAI,cAAc,EAAU,KAAK,CAAC,CAE9E,IAAM,EAAW,MAAM,EAAO,EAAK,CAC/B,IAAa,GACf,KAAK,QAAQ,KAAK,EAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-DxnrCWeR2.mjs","names":[],"sources":["../src/commands/request/cron/pull-profiles/impl.ts"],"sourcesContent":["import type { RequestAction } from '@transcend-io/privacy-types';\nimport { buildTranscendGraphQLClient, fetchRequestFilesForRequest } from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport { uniq, chunk } from 'lodash-es';\n\nimport type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport {\n pullChunkedCustomSiloOutstandingIdentifiers,\n type CsvFormattedIdentifier,\n} from '../../../../lib/cron/index.js';\nimport { parseFilePath, writeLargeCsv } from '../../../../lib/helpers/index.js';\n\nexport interface PullProfilesCommandFlags {\n file: string;\n fileTarget: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n cronDataSiloId: string;\n targetDataSiloId: string;\n actions: RequestAction[];\n skipRequestCount: boolean;\n pageLimit: number;\n chunkSize: number;\n}\n\nexport async function pullProfiles(\n this: LocalContext,\n {\n file,\n fileTarget,\n transcendUrl,\n auth,\n sombraAuth,\n cronDataSiloId,\n targetDataSiloId,\n actions,\n skipRequestCount,\n pageLimit,\n chunkSize,\n }: PullProfilesCommandFlags,\n): Promise<void> {\n if (skipRequestCount) {\n this.logger.info(\n colors.yellow('Skipping request count as requested. This may help speed up the call.'),\n );\n }\n\n if (Number.isNaN(chunkSize) || chunkSize <= 0 || chunkSize % pageLimit !== 0) {\n this.logger.error(\n colors.red(\n `Invalid chunk size: \"${chunkSize}\". Must be a positive integer that is a multiple of ${pageLimit}.`,\n ),\n );\n this.process.exit(1);\n }\n\n doneInputValidation(this.process);\n\n // Create GraphQL client to connect to Transcend backend\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n const { baseName, extension } = parseFilePath(file);\n const { baseName: baseNameTarget, extension: extensionTarget } = parseFilePath(fileTarget);\n\n let allIdentifiersCount = 0;\n let allTargetIdentifiersCount = 0;\n let fileCount = 0;\n // Create onSave callback to handle chunked processing\n const onSave = async (chunkToSave: CsvFormattedIdentifier[]): Promise<void> => {\n // Add to all identifiers\n allIdentifiersCount += chunkToSave.length;\n\n // Get unique request IDs from this chunk\n const requestIds = chunkToSave.map((d) => d.requestId as string);\n const uniqueRequestIds = uniq(requestIds);\n\n // Pull down target identifiers for this chunk\n const chunkedRequestIds = chunk(uniqueRequestIds, pageLimit);\n const results = await map(\n chunkedRequestIds,\n async (requestIds) => {\n this.logger.info(\n colors.magenta(`Fetching target identifiers for ${requestIds.length} requests`),\n );\n const results = await fetchRequestFilesForRequest(client, {\n logger: this.logger,\n pageSize: pageLimit * 2,\n filterBy: {\n requestIds,\n dataSiloIds: [targetDataSiloId],\n },\n });\n return results.map(({ fileName, remoteId }) => {\n if (!remoteId) {\n throw new Error(`Failed to find remoteId for ${fileName}`);\n }\n return {\n RecordId: remoteId,\n Object: fileName.replace('.json', '').split('/').pop()?.replace(' Information', ''),\n Comment: 'Customer data deletion request submitted via transcend.io',\n };\n });\n },\n // We are grabbing all the request files for the 'pageLimit' # of requests at a time\n {\n concurrency: 1,\n },\n );\n\n allTargetIdentifiersCount += results.flat().length;\n\n // Write the identifiers and target identifiers to CSV\n const headers = uniq(chunkToSave.map((d) => Object.keys(d)).flat());\n const numberedFileName = `${baseName}-${fileCount}${extension}`;\n const numberedFileNameTarget = `${baseNameTarget}-${fileCount}${extensionTarget}`;\n await writeLargeCsv(numberedFileName, chunkToSave, headers);\n this.logger.info(\n colors.green(`Successfully wrote ${chunkToSave.length} identifiers to file \"${file}\"`),\n );\n\n const targetIdentifiers = results.flat();\n const headers2 = uniq(targetIdentifiers.map((d) => Object.keys(d)).flat());\n await writeLargeCsv(numberedFileNameTarget, targetIdentifiers, headers2);\n this.logger.info(\n colors.green(\n `Successfully wrote ${targetIdentifiers.length} identifiers to file \"${fileTarget}\"`,\n ),\n );\n\n this.logger.info(\n colors.blue(\n `Processed chunk of ${chunk.length} identifiers, found ${targetIdentifiers.length} target identifiers`,\n ),\n );\n fileCount += 1;\n };\n\n // Pull down outstanding identifiers using the new chunked function\n await pullChunkedCustomSiloOutstandingIdentifiers({\n dataSiloId: cronDataSiloId,\n auth,\n sombraAuth,\n actions,\n apiPageSize: pageLimit,\n savePageSize: chunkSize,\n onSave,\n transcendUrl,\n skipRequestCount,\n });\n\n this.logger.info(\n colors.green(`Successfully wrote ${allIdentifiersCount} identifiers to file \"${file}\"`),\n );\n this.logger.info(\n colors.green(\n `Successfully wrote ${allTargetIdentifiersCount} identifiers to file \"${fileTarget}\"`,\n ),\n );\n}\n"],"mappings":"wYA4BA,eAAsB,EAEpB,CACE,OACA,aACA,eACA,OACA,aACA,iBACA,mBACA,UACA,mBACA,YACA,aAEa,CACX,GACF,KAAK,OAAO,KACV,EAAO,OAAO,wEAAwE,CACvF,EAGC,OAAO,MAAM,EAAU,EAAI,GAAa,GAAK,EAAY,IAAc,KACzE,KAAK,OAAO,MACV,EAAO,IACL,wBAAwB,EAAU,sDAAsD,EAAU,GACnG,CACF,CACD,KAAK,QAAQ,KAAK,EAAE,EAGtB,EAAoB,KAAK,QAAQ,CAGjC,IAAM,EAAS,EAA4B,EAAc,EAAK,CACxD,CAAE,WAAU,aAAc,EAAc,EAAK,CAC7C,CAAE,SAAU,EAAgB,UAAW,GAAoB,EAAc,EAAW,CAEtF,EAAsB,EACtB,EAA4B,EAC5B,EAAY,EAwEhB,MAAM,EAA4C,CAChD,WAAY,EACZ,OACA,aACA,UACA,YAAa,EACb,aAAc,EACd,YA7EoB,IAAyD,CAE7E,GAAuB,EAAY,OAQnC,IAAM,EAAU,MAAM,EADI,EAHD,EADN,EAAY,IAAK,GAAM,EAAE,UACJ,CAGQ,CAAE,EAE/B,CACjB,KAAO,KACL,KAAK,OAAO,KACV,EAAO,QAAQ,mCAAmC,EAAW,OAAO,WAAW,CAChF,EASM,MARe,EAA4B,EAAQ,CACxD,OAAQ,KAAK,OACb,SAAU,EAAY,EACtB,SAAU,CACR,aACA,YAAa,CAAC,EAAiB,CAChC,CACF,CAAC,EACa,KAAK,CAAE,WAAU,cAAe,CAC7C,GAAI,CAAC,EACH,MAAU,MAAM,+BAA+B,IAAW,CAE5D,MAAO,CACL,SAAU,EACV,OAAQ,EAAS,QAAQ,QAAS,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,eAAgB,GAAG,CACnF,QAAS,4DACV,EACD,EAGJ,CACE,YAAa,EACd,CACF,CAED,GAA6B,EAAQ,MAAM,CAAC,OAG5C,IAAM,EAAU,EAAK,EAAY,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAC7D,EAAmB,GAAG,EAAS,GAAG,IAAY,IAC9C,EAAyB,GAAG,EAAe,GAAG,IAAY,IAChE,MAAM,EAAc,EAAkB,EAAa,EAAQ,CAC3D,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAY,OAAO,wBAAwB,EAAK,GAAG,CACvF,CAED,IAAM,EAAoB,EAAQ,MAAM,CAExC,MAAM,EAAc,EAAwB,EAD3B,EAAK,EAAkB,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CACF,CAAC,CACxE,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAAkB,OAAO,wBAAwB,EAAW,GACnF,CACF,CAED,KAAK,OAAO,KACV,EAAO,KACL,sBAAsB,EAAM,OAAO,sBAAsB,EAAkB,OAAO,qBACnF,CACF,CACD,GAAa,GAYb,eACA,mBACD,CAAC,CAEF,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAoB,wBAAwB,EAAK,GAAG,CACxF,CACD,KAAK,OAAO,KACV,EAAO,MACL,sBAAsB,EAA0B,wBAAwB,EAAW,GACpF,CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-DzUTmaID2.mjs","names":[],"sources":["../src/commands/inventory/pull-unstructured-discovery-files/impl.ts"],"sourcesContent":["import type { UnstructuredSubDataPointRecommendationStatus } from '@transcend-io/privacy-types';\nimport { buildTranscendGraphQLClient } from '@transcend-io/sdk';\nimport colors from 'colors';\nimport { uniq } from 'lodash-es';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { pullUnstructuredSubDataPointRecommendations } from '../../../lib/data-inventory/index.js';\nimport { writeLargeCsv } from '../../../lib/helpers/index.js';\n\nexport interface PullUnstructuredDiscoveryFilesCommandFlags {\n auth: string;\n file: string;\n transcendUrl: string;\n dataSiloIds?: string[];\n subCategories?: string[];\n status?: UnstructuredSubDataPointRecommendationStatus[];\n includeEncryptedSnippets: boolean;\n}\n\nexport async function pullUnstructuredDiscoveryFiles(\n this: LocalContext,\n {\n auth,\n file,\n transcendUrl,\n dataSiloIds,\n subCategories,\n status,\n includeEncryptedSnippets,\n }: PullUnstructuredDiscoveryFilesCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n try {\n // Create a GraphQL client\n const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n const entries = await pullUnstructuredSubDataPointRecommendations(client, {\n dataSiloIds,\n subCategories, // TODO: https://transcend.height.app/T-40482 - do by name not ID\n status,\n includeEncryptedSnippets,\n });\n\n this.logger.info(colors.magenta(`Writing unstructured discovery files to file \"${file}\"...`));\n let headers: string[] = [];\n const inputs = entries.map((entry) => {\n const result = {\n 'Entry ID': entry.id,\n 'Data Silo ID': entry.dataSiloId,\n 'Object Path ID': entry.scannedObjectPathId,\n 'Object ID': entry.scannedObjectId,\n ...(includeEncryptedSnippets\n ? { Entry: entry.name, 'Context Snippet': entry.contextSnippet }\n : {}),\n 'Data Category': `${entry.dataSubCategory.category}:${entry.dataSubCategory.name}`,\n 'Classification Status': entry.status,\n 'Confidence Score': entry.confidence,\n 'Classification Method': entry.classificationMethod,\n 'Classifier Version': entry.classifierVersion,\n };\n headers = uniq([...headers, ...Object.keys(result)]);\n return result;\n });\n await writeLargeCsv(file, inputs, headers);\n } catch (err) {\n this.logger.error(\n colors.red(`An error occurred syncing the unstructured discovery files: ${err.message}`),\n );\n this.process.exit(1);\n }\n\n // Indicate success\n this.logger.info(\n colors.green(`Successfully synced unstructured discovery files to disk at ${file}!`),\n );\n}\n"],"mappings":"2SAoBA,eAAsB,EAEpB,CACE,OACA,OACA,eACA,cACA,gBACA,SACA,4BAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,GAAI,CAIF,IAAM,EAAU,MAAM,EAFP,EAA4B,EAAc,EAEe,CAAE,CACxE,cACA,gBACA,SACA,2BACD,CAAC,CAEF,KAAK,OAAO,KAAK,EAAO,QAAQ,iDAAiD,EAAK,MAAM,CAAC,CAC7F,IAAI,EAAoB,EAAE,CAmB1B,MAAM,EAAc,EAlBL,EAAQ,IAAK,GAAU,CACpC,IAAM,EAAS,CACb,WAAY,EAAM,GAClB,eAAgB,EAAM,WACtB,iBAAkB,EAAM,oBACxB,YAAa,EAAM,gBACnB,GAAI,EACA,CAAE,MAAO,EAAM,KAAM,kBAAmB,EAAM,eAAgB,CAC9D,EAAE,CACN,gBAAiB,GAAG,EAAM,gBAAgB,SAAS,GAAG,EAAM,gBAAgB,OAC5E,wBAAyB,EAAM,OAC/B,mBAAoB,EAAM,WAC1B,wBAAyB,EAAM,qBAC/B,qBAAsB,EAAM,kBAC7B,CAED,MADA,GAAU,EAAK,CAAC,GAAG,EAAS,GAAG,OAAO,KAAK,EAAO,CAAC,CAAC,CAC7C,GAEuB,CAAE,EAAQ,OACnC,EAAK,CACZ,KAAK,OAAO,MACV,EAAO,IAAI,+DAA+D,EAAI,UAAU,CACzF,CACD,KAAK,QAAQ,KAAK,EAAE,CAItB,KAAK,OAAO,KACV,EAAO,MAAM,+DAA+D,EAAK,GAAG,CACrF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-H9kweQnu2.mjs","names":[],"sources":["../src/commands/request/approve/impl.ts"],"sourcesContent":["import { RequestAction, RequestOrigin } from '@transcend-io/privacy-types';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { approvePrivacyRequests } from '../../../lib/requests/index.js';\n\nexport interface ApproveCommandFlags {\n auth: string;\n actions: RequestAction[];\n origins?: RequestOrigin[];\n silentModeBefore?: Date;\n createdAtBefore?: Date;\n createdAtAfter?: Date;\n updatedAtBefore?: Date;\n updatedAtAfter?: Date;\n transcendUrl: string;\n concurrency: number;\n}\n\nexport async function approve(\n this: LocalContext,\n {\n auth,\n actions,\n origins,\n silentModeBefore,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n transcendUrl,\n concurrency,\n }: ApproveCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await approvePrivacyRequests({\n transcendUrl,\n requestActions: actions,\n auth,\n requestOrigins: origins,\n concurrency,\n silentModeBefore,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n });\n}\n"],"mappings":"8GAmBA,eAAsB,EAEpB,CACE,OACA,UACA,UACA,mBACA,kBACA,iBACA,kBACA,iBACA,eACA,eAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAM,EAAuB,CAC3B,eACA,eAAgB,EAChB,OACA,eAAgB,EAChB,cACA,mBACA,kBACA,iBACA,kBACA,iBACD,CAAC"}
|
package/dist/impl-Z8oWVENM.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{i as e,n as t,o as n,r,t as i}from"./scaffold-templates-DzDGTZie.mjs";import{t as a}from"./done-input-validation-BUz-aVC5.mjs";import{h as o,n as s,p as c,r as l,t as u}from"./prompts-ClBXdELk.mjs";import{t as d}from"./missing-manifest-DgcukXfg.mjs";import{a as f,i as p,o as m}from"./deno-runtime-DV52X8-P.mjs";import{t as h}from"./project-plan-apply-Dvndx455.mjs";import{a as g,l as _,o as v,r as y,s as b,t as x,u as S}from"./scaffold-planning-CNv83t_v.mjs";import{CustomFunctionType as C}from"@transcend-io/privacy-types";import{join as w}from"node:path";import T from"colors";function E(e,t,n){return!e.json&&!e.noInteractive&&!!(t&&n)}async function D(n){let i=await n.select(`Custom Function type:`,[{name:r[C.General],value:C.General},{name:r[C.Dsr],value:C.Dsr}],C.General),a=e[i];if(a.length<2){let[e]=a;if(e===void 0)throw Error(`No Custom Function templates are defined for type ${i}.`);return e}return n.select(`Template:`,a.map(e=>({name:t[e],value:e})),a[0])}async function O(e,t){a(this.process);try{let r=f(this,{...t?{directory:t}:{},...e.manifest?{manifest:e.manifest}:{}});if(!this.fs.existsSync(r.manifestPath)){let e=this.process.cwd();throw Error(d({cwd:e,manifestPath:r.manifestPath,discoveredManifestPaths:p(this,e),command:`new`}))}let a=new s(this),u=E(e,this.process.stdin.isTTY,this.process.stderr.isTTY),C=e.name??(u?await a.text(`Custom Function display name:`,void 0,e=>{try{return n(e),!0}catch(e){return e instanceof Error?e.message:String(e)}}):void 0);if(!C)throw Error(`Missing Custom Function name. Pass --name in a non-interactive invocation.`);let O=e.template??(u?await D(a):void 0);if(!O||!i.includes(O))throw Error(`Missing Custom Function template. Pass --template=general, --template=dsr-datapoint, --template=dsr-enricher, or --template=dsr-both.`);let k=v(C,O),A=x({state:r,snapshots:l(this,r.manifestDirectory,y(r,k))},{generated:k});this.fs.existsSync(r.denoConfigPath)||A.warnings.push(`No Deno configuration was found. Run transcend custom-functions init ${m(r.targetDirectory,r.manifestPath,this.process.cwd())} --deno --noInteractive.`),e.json||this.logger.info(o(A,{cwd:this.process.cwd(),title:`Custom Function plan`,details:[{label:`Target`,path:A.targetDirectory},{label:`Manifest`,path:A.manifestPath}]}));let j=A.changes.length===0||e.dryRun;if(A.changes.length>0&&!e.dryRun)if(e.yes)j=!0;else if(u)j=await a.confirm(`Apply this complete plan?`,!0);else throw Error(`The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.`);j&&!e.dryRun&&A.changes.length>0&&await h(this,A);let M=j&&!e.dryRun&&A.changes.length>0,N=r.existingSkillDirectories.some(({path:e})=>this.fs.existsSync(w(r.projectRoot,e,S,`SKILL.md`))),P=_({displayName:k.displayName,sourcePath:c(this.process.cwd(),w(r.manifestDirectory,k.sourceFile.path)),targetDirectory:c(this.process.cwd(),r.targetDirectory),manifestPath:c(this.process.cwd(),r.manifestPath),hasSkill:N,variableNames:g(k.manifestEntry)}),F=b(A,{applied:M,dryRun:e.dryRun,cwd:this.process.cwd(),aiHandoff:P});if(e.json){this.process.stdout.write(`${JSON.stringify(F)}\n`);return}if(e.dryRun){this.logger.info(T.yellow(`Dry run complete. No changes were written.`));return}if(!j){this.logger.info(T.yellow(`No changes applied.`));return}this.logger.info(T.green(`Custom Function added.`)),A.nextSteps.length>0&&(this.logger.info(`\n${T.bold(`Next steps`)}`),A.nextSteps.forEach(e=>this.logger.info(e))),this.logger.info(`\n${T.bold(`AI handoff — paste into your coding agent`)}`),this.logger.info(P)}catch(e){throw e instanceof u&&this.process.exit(130),e}}export{O as _new,O as newCustomFunction};
|
|
2
|
-
//# sourceMappingURL=impl-Z8oWVENM.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-Z8oWVENM.mjs","names":[],"sources":["../src/commands/custom-functions/new/impl.ts"],"sourcesContent":["import { join } from 'node:path';\n\nimport { CustomFunctionType } from '@transcend-io/privacy-types';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildNewFunctionAiHandoff } from '../../../lib/custom-functions/ai-handoff.js';\nimport { CUSTOM_FUNCTION_SKILL_NAME } from '../../../lib/custom-functions/custom-function-skill.js';\nimport { formatMissingManifestMessage } from '../../../lib/custom-functions/missing-manifest.js';\nimport { buildCustomFunctionProjectArguments } from '../../../lib/custom-functions/paths.js';\nimport {\n discoverCustomFunctionManifests,\n discoverCustomFunctionProject,\n} from '../../../lib/custom-functions/project-discovery.js';\nimport { buildPlanResult } from '../../../lib/custom-functions/scaffold-output.js';\nimport {\n buildAddFunctionPlan,\n getAddFunctionPlanningCandidatePaths,\n parameterNamesInManifestValue,\n prepareGeneratedCustomFunction,\n} from '../../../lib/custom-functions/scaffold-planning.js';\nimport {\n CUSTOM_FUNCTION_TEMPLATE_NAMES,\n CUSTOM_FUNCTION_TEMPLATE_PROMPT_LABELS,\n CUSTOM_FUNCTION_TYPE_PROMPT_LABELS,\n TEMPLATES_FOR_CUSTOM_FUNCTION_TYPE,\n type CustomFunctionTemplateName,\n validateCustomFunctionDisplayName,\n} from '../../../lib/custom-functions/scaffold-templates.js';\nimport { collectPlanningSnapshots } from '../../../lib/scaffolding/project-discovery.js';\nimport { applyProjectPlan } from '../../../lib/scaffolding/project-plan-apply.js';\nimport {\n displayProjectPath,\n renderProjectPlan,\n} from '../../../lib/scaffolding/project-plan-output.js';\nimport { PromptCancelledError, ScaffoldPrompts } from '../../../lib/scaffolding/prompts.js';\n\n/** Flags for `custom-functions new`. */\nexport interface CustomFunctionNewFlags {\n /** Explicit existing manifest path. */\n manifest?: string;\n /** Custom Function display name. */\n name?: string;\n /** Starter handler shape. */\n template?: CustomFunctionTemplateName;\n /** Disable prompts. */\n noInteractive: boolean;\n /** Render but do not apply. */\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/**\n * Whether this invocation can ask questions.\n *\n * @param context - CLI context\n * @param flags - Interaction flags\n * @returns Whether prompts are enabled\n */\nfunction isInteractiveInvocation(\n flags: Pick<CustomFunctionNewFlags, 'json' | 'noInteractive'>,\n stdinIsTTY: boolean | undefined,\n stderrIsTTY: boolean | undefined,\n): boolean {\n return !flags.json && !flags.noInteractive && Boolean(stdinIsTTY && stderrIsTTY);\n}\n\n/**\n * Ask for the product-level function type, then its available starter template.\n *\n * General currently has one template, so selecting it completes the choice immediately.\n *\n * @param prompts - Context-bound prompt adapter\n * @returns Selected starter template\n */\nexport async function selectInteractiveTemplate(\n prompts: Pick<ScaffoldPrompts, 'select'>,\n): Promise<CustomFunctionTemplateName> {\n const functionType = await prompts.select<CustomFunctionType>(\n 'Custom Function type:',\n [\n {\n name: CUSTOM_FUNCTION_TYPE_PROMPT_LABELS[CustomFunctionType.General],\n value: CustomFunctionType.General,\n },\n {\n name: CUSTOM_FUNCTION_TYPE_PROMPT_LABELS[CustomFunctionType.Dsr],\n value: CustomFunctionType.Dsr,\n },\n ],\n CustomFunctionType.General,\n );\n const templates = TEMPLATES_FOR_CUSTOM_FUNCTION_TYPE[functionType];\n if (templates.length < 2) {\n const [onlyTemplate] = templates;\n if (onlyTemplate === undefined) {\n throw new Error(`No Custom Function templates are defined for type ${functionType}.`);\n }\n return onlyTemplate;\n }\n return prompts.select<CustomFunctionTemplateName>(\n 'Template:',\n templates.map((value) => ({\n name: CUSTOM_FUNCTION_TEMPLATE_PROMPT_LABELS[value],\n value,\n })),\n templates[0],\n );\n}\n\n/**\n * Scaffold one deterministic local Custom Function.\n *\n * @param this - CLI context\n * @param flags - Template and interaction flags\n * @param directory - Optional target directory\n */\nexport async function _new(\n this: LocalContext,\n flags: CustomFunctionNewFlags,\n directory?: string,\n): Promise<void> {\n doneInputValidation(this.process);\n try {\n const state = discoverCustomFunctionProject(this, {\n ...(directory ? { directory } : {}),\n ...(flags.manifest ? { manifest: flags.manifest } : {}),\n });\n if (!this.fs.existsSync(state.manifestPath)) {\n const cwd = this.process.cwd();\n throw new Error(\n formatMissingManifestMessage({\n cwd,\n manifestPath: state.manifestPath,\n discoveredManifestPaths: discoverCustomFunctionManifests(this, cwd),\n command: 'new',\n }),\n );\n }\n const prompts = new ScaffoldPrompts(this);\n const interactive = isInteractiveInvocation(\n flags,\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n const name =\n flags.name ??\n (interactive\n ? await prompts.text('Custom Function display name:', undefined, (value) => {\n try {\n validateCustomFunctionDisplayName(value);\n return true;\n } catch (error) {\n return error instanceof Error ? error.message : String(error);\n }\n })\n : undefined);\n if (!name) {\n throw new Error('Missing Custom Function name. Pass --name in a non-interactive invocation.');\n }\n const template =\n flags.template ?? (interactive ? await selectInteractiveTemplate(prompts) : undefined);\n if (!template || !CUSTOM_FUNCTION_TEMPLATE_NAMES.includes(template)) {\n throw new Error(\n 'Missing Custom Function template. Pass --template=general, --template=dsr-datapoint, --template=dsr-enricher, or --template=dsr-both.',\n );\n }\n const generated = prepareGeneratedCustomFunction(name, template);\n const snapshots = collectPlanningSnapshots(\n this,\n state.manifestDirectory,\n getAddFunctionPlanningCandidatePaths(state, generated),\n );\n const plan = buildAddFunctionPlan(\n {\n state,\n snapshots,\n },\n { generated },\n );\n if (!this.fs.existsSync(state.denoConfigPath)) {\n plan.warnings.push(\n `No Deno configuration was found. Run ` +\n `transcend custom-functions init ${buildCustomFunctionProjectArguments(\n state.targetDirectory,\n state.manifestPath,\n this.process.cwd(),\n )} --deno --noInteractive.`,\n );\n }\n if (!flags.json) {\n this.logger.info(\n renderProjectPlan(plan, {\n cwd: this.process.cwd(),\n title: 'Custom Function plan',\n details: [\n { label: 'Target', path: plan.targetDirectory },\n { label: 'Manifest', path: plan.manifestPath },\n ],\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 hasSkill = state.existingSkillDirectories.some(({ path }) =>\n this.fs.existsSync(join(state.projectRoot, path, CUSTOM_FUNCTION_SKILL_NAME, 'SKILL.md')),\n );\n const aiHandoff = buildNewFunctionAiHandoff({\n displayName: generated.displayName,\n sourcePath: displayProjectPath(\n this.process.cwd(),\n join(state.manifestDirectory, generated.sourceFile.path),\n ),\n targetDirectory: displayProjectPath(this.process.cwd(), state.targetDirectory),\n manifestPath: displayProjectPath(this.process.cwd(), state.manifestPath),\n hasSkill,\n variableNames: parameterNamesInManifestValue(generated.manifestEntry),\n });\n const result = buildPlanResult(plan, {\n applied,\n dryRun: flags.dryRun,\n cwd: this.process.cwd(),\n aiHandoff,\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 this.logger.info(colors.green('Custom Function added.'));\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 this.process.exit(130);\n }\n throw error;\n }\n}\n\nexport { _new as newCustomFunction };\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-a_Y8bnSn.mjs","names":[],"sources":["../src/lib/custom-functions/local-simulator.ts","../src/commands/custom-functions/run/impl.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { stripVTControlCharacters } from 'node:util';\n\nimport {\n DSR_DATAPOINT_CUSTOM_FUNCTION_PAYLOAD_SCHEMA,\n DSR_REQUEST_ENRICHER_CUSTOM_FUNCTION_PAYLOAD_SCHEMA,\n GENERAL_CUSTOM_FUNCTION_PAYLOAD_SCHEMA,\n} from '@transcend-io/custom-function-types';\nimport { CustomFunctionPayloadType, CustomFunctionType } from '@transcend-io/privacy-types';\nimport Ajv from 'ajv';\n\nimport { validateCustomFunctionExecutionContext } from './execution-context.js';\nimport type { CustomFunctionManifestConfig } from './manifest.js';\n\n/** Value injected when production-only identifiers are absent from a fixture. */\nexport const LOCAL_SIMULATOR_IDENTIFIER = 'example-identifier';\n\n/** Synthetic data silo used by local DSR simulations. */\nexport const LOCAL_SIMULATOR_DATA_SILO_ID = '00000000-0000-4000-8000-000000000000';\n\n/** Default local execution timeout. */\nexport const LOCAL_SIMULATOR_TIMEOUT_MS = 30_000;\n\n/** Maximum stdout and stderr retained from one local invocation. */\nexport const LOCAL_SIMULATOR_MAX_OUTPUT_BYTES = 1024 * 1024;\n\n/** Isolated dependency cache readable by simulated functions. */\nexport const LOCAL_SIMULATOR_DENO_DIR = join(tmpdir(), 'transcend-custom-functions-deno');\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\nconst payloadValidators = {\n general: ajv.compile(GENERAL_CUSTOM_FUNCTION_PAYLOAD_SCHEMA),\n datapoint: ajv.compile(DSR_DATAPOINT_CUSTOM_FUNCTION_PAYLOAD_SCHEMA),\n enricher: ajv.compile(DSR_REQUEST_ENRICHER_CUSTOM_FUNCTION_PAYLOAD_SCHEMA),\n};\n\n/** Complete local Deno process invocation. */\nexport interface LocalSimulatorInvocation {\n /** Deno CLI arguments. */\n args: string[];\n /** JSON sent privately over stdin. */\n input: string;\n /** Minimal environment exposed to the process. */\n env: NodeJS.ProcessEnv;\n /** Maximum execution time. */\n timeoutMs: number;\n}\n\n/**\n * Runtime wrapper modeled after Sombra's Deno executor.\n *\n * The local SDK intentionally simulates customer-ingress calls rather than\n * sending authenticated requests. Native fetch remains governed by Deno's\n * allow-net permissions.\n */\nconst LOCAL_SIMULATOR_SOURCE = `\nconst input = JSON.parse(await new Response(Deno.stdin.readable).text());\nfor (const [name, value] of Object.entries(input.functionArgs.environment)) {\n Deno.env.set(name, value);\n}\n\nclass KV {\n constructor() {\n this.store = {};\n }\n\n get(key) {\n return Promise.resolve(key in this.store ? this.store[key] : null);\n }\n\n async set(key, value) {\n if (typeof value !== 'string') throw new Error('Value must be of type string');\n if (value.length > 2048) throw new Error('Cannot store value greater than 2048 bytes');\n if (key.length > 128) throw new Error('Key length cannot be greater than 128 bytes');\n if (!(key in this.store) && Object.keys(this.store).length >= 128) {\n throw new Error('Maximum number of keys allowed is 128');\n }\n this.store[key] = value;\n }\n\n keys() {\n return Promise.resolve(Object.keys(this.store));\n }\n\n has(key) {\n return Promise.resolve(key in this.store);\n }\n\n async del(key) {\n if (!(key in this.store)) return false;\n delete this.store[key];\n return true;\n }\n}\n\nclass SDK {\n constructor(nonce) {\n this.transcendNonce = nonce;\n this.customerIngressBaseUrl = 'local://customer-ingress';\n }\n\n nonce() {\n return this.transcendNonce;\n }\n\n setCustomerIngressUrl(newUrl) {\n this.customerIngressBaseUrl = newUrl;\n }\n\n async ping() {\n await this.fetch('/test', { method: 'GET' });\n }\n\n fetch(path, options = {}) {\n const method = options.method ?? 'GET';\n console.warn(\n \\`[simulator] sdk.fetch \\${method} \\${path} -> HTTP 200 (request not sent)\\`,\n );\n return Promise.resolve(new Response(null, { status: 200, statusText: 'OK' }));\n }\n}\n\ntry {\n const custom = await import(\n \\`data:application/typescript;base64,\\${input.base64Function}\\`\n );\n if (!(input.functionToRun in custom)) {\n throw new Error(\n \\`Custom Function does not export \"\\${input.functionToRun}\" for this payload\\`,\n );\n }\n await custom[input.functionToRun]({\n ...input.functionArgs,\n sdk: new SDK(input.functionArgs.nonce),\n kv: new KV(),\n });\n Deno.exit(0);\n} catch (error) {\n console.error(error);\n Deno.exit(1);\n}\n`;\n\n/**\n * Add values that Sombra normally injects into test payloads.\n *\n * @param config - Selected manifest function\n * @param payload - Parsed test fixture\n * @param payloadType - Optional DSR export selector\n * @returns Prepared local handler payload\n */\nexport function prepareLocalSimulatorPayload(\n config: Pick<CustomFunctionManifestConfig, 'dataSiloId' | 'name' | 'type'>,\n payload: object,\n payloadType?: CustomFunctionPayloadType,\n): object {\n const record = payload as {\n /** Runtime core identifier. */\n coreIdentifier?: { value: string };\n /** DSR metadata. */\n extras?: Record<string, unknown>;\n };\n const extras = record.extras ?? {};\n const profile = extras['profile'] as { identifier?: unknown } | undefined;\n const type = config.type ?? CustomFunctionType.General;\n const isDataPoint =\n type === CustomFunctionType.Dsr && payloadType !== CustomFunctionPayloadType.RequestEnricher;\n const preparedProfile =\n isDataPoint && profile?.identifier === '{{identifier}}'\n ? { ...profile, identifier: LOCAL_SIMULATOR_IDENTIFIER }\n : profile;\n const dataSilo = extras['dataSilo'] as Record<string, unknown> | undefined;\n const preparedExtras =\n type === CustomFunctionType.Dsr\n ? {\n ...extras,\n ...(preparedProfile ? { profile: preparedProfile } : {}),\n dataSilo: {\n title: config.name,\n description: '',\n link: '',\n ...dataSilo,\n id: config.dataSiloId ?? dataSilo?.['id'] ?? LOCAL_SIMULATOR_DATA_SILO_ID,\n },\n }\n : preparedProfile\n ? { ...extras, profile: preparedProfile }\n : extras;\n return {\n ...record,\n ...(Object.keys(preparedExtras).length > 0 ? { extras: preparedExtras } : {}),\n coreIdentifier: record.coreIdentifier ?? { value: LOCAL_SIMULATOR_IDENTIFIER },\n };\n}\n\n/**\n * Validate a fixture with the same published schemas used by `check`.\n *\n * @param config - Selected manifest function\n * @param testPayload - Fixture and optional DSR export selector\n */\nfunction validateLocalSimulatorPayload(\n config: CustomFunctionManifestConfig,\n testPayload: NonNullable<CustomFunctionManifestConfig['testPayloads']>[number],\n): void {\n const type = config.type ?? CustomFunctionType.General;\n const validate =\n type !== CustomFunctionType.Dsr\n ? payloadValidators.general\n : testPayload.payloadType === CustomFunctionPayloadType.RequestEnricher\n ? payloadValidators.enricher\n : payloadValidators.datapoint;\n if (!validate(testPayload.payload)) {\n const details = (validate.errors ?? [])\n .map((error) => `${error.instancePath || '/'} ${error.message ?? 'is invalid'}`)\n .join('; ');\n throw new Error(`Invalid test payload for \"${config.name}\": ${details}`);\n }\n}\n\n/**\n * Build one constrained Deno invocation for a test fixture.\n *\n * @param config - Selected manifest function\n * @param testPayload - Fixture and optional DSR export selector\n * @param options - Discovered Deno configuration\n * @returns Process arguments, input, environment, and timeout\n */\nexport function buildLocalSimulatorInvocation(\n config: CustomFunctionManifestConfig,\n testPayload: NonNullable<CustomFunctionManifestConfig['testPayloads']>[number],\n options: {\n /** Existing deno.json or deno.jsonc path. */\n denoConfigPath?: string;\n /** Permit real native fetch calls to manifest allowed hosts. */\n allowNetwork?: boolean;\n } = {},\n): LocalSimulatorInvocation {\n validateLocalSimulatorPayload(config, testPayload);\n const environment = config.env ?? {};\n const envNames = Object.keys(environment);\n const allowedHosts = config.allowedHosts ?? [];\n validateCustomFunctionExecutionContext(config);\n const allowNetArgs = options.allowNetwork\n ? allowedHosts.length === 0\n ? ['--allow-net=localhost']\n : allowedHosts[0] === '*'\n ? ['--allow-net']\n : [`--allow-net=${allowedHosts.join(',')}`]\n : [];\n const type = config.type ?? CustomFunctionType.General;\n const functionToRun =\n type === CustomFunctionType.Dsr &&\n testPayload.payloadType === CustomFunctionPayloadType.RequestEnricher\n ? 'enricher'\n : 'default';\n const runnerUrl = `data:application/javascript;base64,${Buffer.from(\n LOCAL_SIMULATOR_SOURCE,\n ).toString('base64')}`;\n const args = [\n 'run',\n '--no-check',\n '--no-prompt',\n '--no-lock',\n '--node-modules-dir=none',\n '--vendor=false',\n `--allow-read=${LOCAL_SIMULATOR_DENO_DIR}`,\n ...(envNames.length > 0 ? [`--allow-env=${envNames.join(',')}`] : []),\n ...(options.denoConfigPath ? [`--config=${options.denoConfigPath}`] : ['--no-config']),\n ...allowNetArgs,\n ...(config.allowThirdPartyImports ? [] : ['--no-remote', '--no-npm']),\n runnerUrl,\n ];\n return {\n args,\n input: JSON.stringify({\n base64Function: Buffer.from(config.code).toString('base64'),\n functionToRun,\n functionArgs: {\n environment,\n payload: prepareLocalSimulatorPayload(config, testPayload.payload, testPayload.payloadType),\n nonce: 'local-simulator',\n },\n }),\n env: {\n ...environment,\n DENO_DIR: LOCAL_SIMULATOR_DENO_DIR,\n DENO_TLS_CA_STORE: 'system',\n NO_COLOR: '1',\n },\n timeoutMs:\n config.timeoutMs && config.timeoutMs > 0\n ? Math.min(config.timeoutMs, LOCAL_SIMULATOR_TIMEOUT_MS)\n : LOCAL_SIMULATOR_TIMEOUT_MS,\n };\n}\n\n/**\n * Remove terminal controls and opaque data URLs from local output.\n *\n * @param value - Untrusted terminal text\n * @returns Plain printable text\n */\nfunction sanitizeLocalSimulatorText(value: string): string {\n return Array.from(\n stripVTControlCharacters(\n value.replace(\n /data:application\\/(?:javascript|typescript);base64,[A-Za-z\\d+/=]+/gu,\n '<local-module>',\n ),\n ).replace(/\\r(?!\\n)/gu, '\\n'),\n )\n .filter((character) => {\n const code = character.codePointAt(0)!;\n return (\n code === 9 || code === 10 || (code >= 32 && code !== 127 && !(code >= 128 && code <= 159))\n );\n })\n .join('');\n}\n\n/**\n * Redact configured environment values from captured local output.\n *\n * @param output - Captured stdout or stderr\n * @param environment - User-defined environment\n * @param sourceTruncated - Whether capture stopped before the stream ended\n * @returns Redacted output\n */\nexport function redactLocalSimulatorOutput(\n output: string,\n environment: Record<string, string> = {},\n sourceTruncated = false,\n): string {\n const values = Object.values(environment)\n .filter((value) => value.length > 0)\n .map(sanitizeLocalSimulatorText)\n .sort((left, right) => right.length - left.length);\n let sanitized = sanitizeLocalSimulatorText(output);\n if (sourceTruncated) {\n const trailingFragmentLength = Math.max(\n 0,\n ...values.map((value) => {\n const maximum = Math.min(value.length - 1, sanitized.length);\n for (let length = maximum; length > 0; length -= 1) {\n if (sanitized.endsWith(value.slice(0, length))) {\n return length;\n }\n }\n return 0;\n }),\n );\n if (trailingFragmentLength > 0) {\n sanitized = sanitized.slice(0, -trailingFragmentLength);\n }\n }\n return values.reduce((redacted, value) => redacted.split(value).join('[REDACTED]'), sanitized);\n}\n\n/**\n * Truncate sanitized output without splitting a UTF-8 code point.\n *\n * @param output - Sanitized and redacted output\n * @param maxBytes - Maximum output size\n * @returns Bounded output and whether truncation occurred\n */\nexport function truncateLocalSimulatorOutput(\n output: string,\n maxBytes = LOCAL_SIMULATOR_MAX_OUTPUT_BYTES,\n): { output: string; truncated: boolean } {\n const bytes = Buffer.from(output);\n if (bytes.length <= maxBytes) {\n return { output, truncated: false };\n }\n let end = maxBytes;\n while (end > 0 && (bytes[end]! & 0b1100_0000) === 0b1000_0000) {\n end -= 1;\n }\n return {\n output: bytes.subarray(0, end).toString('utf8'),\n truncated: true,\n };\n}\n","import { Buffer } from 'node:buffer';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { runCapturedProcess } from '../../../lib/cli/run-captured-process.js';\nimport {\n DENO_INSTALL_URL,\n getDenoRuntimeCompatibility,\n SUPPORTED_DENO_MAJOR_VERSION,\n} from '../../../lib/custom-functions/deno-runtime.js';\nimport {\n buildLocalSimulatorInvocation,\n LOCAL_SIMULATOR_MAX_OUTPUT_BYTES,\n redactLocalSimulatorOutput,\n truncateLocalSimulatorOutput,\n} from '../../../lib/custom-functions/local-simulator.js';\nimport {\n parseCustomFunctionsManifest,\n readCustomFunctionManifestEntry,\n type CustomFunctionManifestEntry,\n} from '../../../lib/custom-functions/manifest.js';\nimport { formatMissingManifestMessage } from '../../../lib/custom-functions/missing-manifest.js';\nimport { findNonSelfContainedRuntimeImports } from '../../../lib/custom-functions/module-graph.js';\nimport {\n discoverCustomFunctionManifests,\n discoverCustomFunctionProject,\n} from '../../../lib/custom-functions/project-discovery.js';\nimport { parseVariablesFromString } from '../../../lib/helpers/parseVariablesFromString.js';\nimport { assertPathPhysicallyContained } from '../../../lib/scaffolding/path-safety.js';\nimport { PromptCancelledError, ScaffoldPrompts } from '../../../lib/scaffolding/prompts.js';\n\n/** Flags accepted by `transcend custom-functions run`. */\nexport interface CustomFunctionRunFlags {\n /** Explicit manifest path. */\n manifest?: string;\n /** Exact function name. */\n function?: string;\n /** Manifest variable substitutions. */\n variables: string;\n /** Disable prompts. */\n noInteractive: boolean;\n /** Permit native network calls to allowed hosts. */\n allowNetwork: boolean;\n}\n\n/**\n * Select one function by exact name or ID.\n *\n * @param configs - Hydrated manifest functions\n * @param selector - Optional exact name or ID\n * @returns Selected function, or undefined when interactive selection is needed\n */\nfunction selectNamedFunction<Config extends Pick<CustomFunctionManifestEntry, 'id' | 'name'>>(\n configs: readonly Config[],\n selector: string | undefined,\n): Config | undefined {\n if (!selector) {\n return configs.length === 1 ? configs[0] : undefined;\n }\n const matches = configs.filter((config) => config.name === selector || config.id === selector);\n if (matches.length === 0) {\n throw new Error(`Custom Function \"${selector}\" was not found in the manifest.`);\n }\n if (matches.length > 1) {\n throw new Error(\n `Custom Function selector \"${selector}\" is ambiguous. Pass its manifest ID instead.`,\n );\n }\n return matches[0];\n}\n\n/**\n * Run one manifest function in the credential-free local Deno simulator.\n *\n * @param this - CLI context\n * @param flags - Selection and manifest flags\n * @param directory - Optional project directory\n */\nexport async function run(\n this: LocalContext,\n flags: CustomFunctionRunFlags,\n directory?: string,\n): Promise<void> {\n doneInputValidation(this.process);\n try {\n const state = discoverCustomFunctionProject(this, {\n ...(directory ? { directory } : {}),\n ...(flags.manifest ? { manifest: flags.manifest } : {}),\n });\n if (!this.fs.existsSync(state.manifestPath)) {\n const cwd = this.process.cwd();\n throw new Error(\n formatMissingManifestMessage({\n cwd,\n manifestPath: state.manifestPath,\n discoveredManifestPaths: discoverCustomFunctionManifests(this, cwd),\n command: 'run',\n }),\n );\n }\n\n const parsedManifest = parseCustomFunctionsManifest(\n this.fs.readFileSync(state.manifestPath, 'utf8'),\n );\n if (parsedManifest.functions.length === 0) {\n throw new Error('The Custom Function manifest does not define any functions.');\n }\n const interactive =\n !flags.noInteractive && Boolean(this.process.stdin.isTTY && this.process.stderr.isTTY);\n let selectedEntry = selectNamedFunction(parsedManifest.functions, flags.function);\n if (!selectedEntry && interactive) {\n const prompts = new ScaffoldPrompts(this);\n const selectedIndex = await prompts.select(\n 'Custom Function to run:',\n parsedManifest.functions.map((entry, index) => ({\n name: entry.id ? `${entry.name} (${entry.id})` : entry.name,\n value: String(index),\n })),\n '0',\n );\n selectedEntry = parsedManifest.functions[Number(selectedIndex)];\n }\n if (!selectedEntry) {\n throw new Error('Select a Custom Function with --function in a non-interactive invocation.');\n }\n const { config: selected, sourcePath } = readCustomFunctionManifestEntry(\n state.manifestPath,\n selectedEntry,\n parseVariablesFromString(flags.variables),\n (path) => assertPathPhysicallyContained(this, state.manifestDirectory, path),\n );\n if (!selected.testPayloads || selected.testPayloads.length === 0) {\n throw new Error(\n `Custom Function \"${selected.name}\" has no test payloads. Add test-payload or test-payloads to its manifest entry.`,\n );\n }\n const denoConfig = this.fs.existsSync(state.denoConfigPath)\n ? { denoConfigPath: state.denoConfigPath }\n : {};\n const simulations = selected.testPayloads.map((testPayload) => ({\n testPayload,\n invocation: buildLocalSimulatorInvocation(selected, testPayload, {\n ...denoConfig,\n allowNetwork: flags.allowNetwork,\n }),\n }));\n\n const denoVersion = await runCapturedProcess(\n 'deno',\n ['--version'],\n { cwd: state.manifestDirectory },\n this,\n );\n if (denoVersion.error?.code === 'ENOENT') {\n throw new Error(\n `Deno ${SUPPORTED_DENO_MAJOR_VERSION}.x is required. Install it from ${DENO_INSTALL_URL}`,\n );\n }\n if (denoVersion.code !== 0) {\n throw new Error('Deno was found, but its version could not be determined.');\n }\n const compatibility = getDenoRuntimeCompatibility(denoVersion.stdout);\n if (compatibility.level === 'error') {\n throw new Error(compatibility.message);\n }\n if (compatibility.level === 'warning') {\n this.logger.warn(compatibility.message);\n }\n const moduleGraph = await runCapturedProcess(\n 'deno',\n [\n 'info',\n '--json',\n ...(denoConfig.denoConfigPath\n ? [`--config=${denoConfig.denoConfigPath}`]\n : ['--no-config']),\n sourcePath,\n ],\n { cwd: state.manifestDirectory },\n this,\n );\n if (moduleGraph.code !== 0) {\n throw new Error(\n `Could not inspect Custom Function runtime imports: ${\n moduleGraph.stderr.trim() || `Deno exited with code ${moduleGraph.code}`\n }`,\n );\n }\n const unsupportedImports = findNonSelfContainedRuntimeImports(moduleGraph.stdout);\n if (unsupportedImports.length > 0) {\n throw new Error(\n `Custom Functions must be self-contained. Local or import-map runtime dependencies are not deployed: ${unsupportedImports.join(\n ', ',\n )}`,\n );\n }\n\n this.logger.warn(\n colors.yellow(\n 'Local simulator: sdk.fetch calls are logged and return HTTP 200 without sending a request; KV state starts empty for each payload.',\n ),\n );\n if (flags.allowNetwork) {\n this.logger.warn(\n colors.yellow(\n `Network enabled: native fetch can make real requests to ${\n selected.allowedHosts?.length ? selected.allowedHosts.join(', ') : 'localhost'\n }.`,\n ),\n );\n } else if (selected.allowedHosts?.length) {\n this.logger.warn(\n colors.yellow(\n 'Native network access is disabled. Pass --allowNetwork to permit calls to allowed-hosts.',\n ),\n );\n }\n let failed = false;\n for (const [index, { invocation, testPayload }] of simulations.entries()) {\n const label = testPayload.payloadType ?? `payload ${index + 1}`;\n this.logger.info(`\\n${colors.bold(`Running \"${selected.name}\" (${label})`)}`);\n const result = await runCapturedProcess(\n 'deno',\n invocation.args,\n {\n cwd: state.manifestDirectory,\n input: invocation.input,\n env: invocation.env,\n timeoutMs: invocation.timeoutMs,\n maxOutputBytes:\n LOCAL_SIMULATOR_MAX_OUTPUT_BYTES +\n Math.max(\n 0,\n ...Object.values(selected.env ?? {}).map((value) => Buffer.byteLength(value)),\n ),\n },\n this,\n );\n const environment = selected.env ?? {};\n const stdout = truncateLocalSimulatorOutput(\n redactLocalSimulatorOutput(result.stdout, environment, result.stdoutTruncated),\n );\n const stderr = truncateLocalSimulatorOutput(\n redactLocalSimulatorOutput(result.stderr, environment, result.stderrTruncated),\n );\n if (stdout.output) {\n this.process.stdout.write(\n stdout.output.endsWith('\\n') ? stdout.output : `${stdout.output}\\n`,\n );\n }\n if (stderr.output) {\n this.process.stderr.write(\n stderr.output.endsWith('\\n') ? stderr.output : `${stderr.output}\\n`,\n );\n }\n if (result.outputTruncated || stdout.truncated || stderr.truncated) {\n this.logger.warn(\n colors.yellow(\n `Simulator output was truncated after ${LOCAL_SIMULATOR_MAX_OUTPUT_BYTES} bytes per stream.`,\n ),\n );\n }\n if (result.code === 0) {\n this.logger.info(colors.green(`Passed \"${selected.name}\" (${label})`));\n } else {\n failed = true;\n const detail = result.timedOut\n ? `timed out after ${invocation.timeoutMs}ms`\n : result.inputError\n ? `could not send the fixture to Deno: ${result.inputError.message}`\n : result.error\n ? `could not start Deno: ${result.error.message}`\n : result.signal\n ? `was terminated with ${result.signal}`\n : `exited with code ${result.code}`;\n this.logger.error(colors.red(`Failed \"${selected.name}\" (${label}): ${detail}`));\n }\n }\n if (failed) {\n this.process.exitCode = 1;\n }\n } catch (error) {\n if (error instanceof PromptCancelledError) {\n this.process.exit(130);\n }\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impl-v_P8hszk2.mjs","names":[],"sources":["../src/commands/request/cancel/impl.ts"],"sourcesContent":["import { RequestAction, RequestStatus } from '@transcend-io/privacy-types';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { cancelPrivacyRequests } from '../../../lib/requests/index.js';\n\nexport interface CancelCommandFlags {\n auth: string;\n actions: RequestAction[];\n statuses?: RequestStatus[];\n requestIds?: string[];\n silentModeBefore?: Date;\n createdAtBefore?: Date;\n createdAtAfter?: Date;\n updatedAtBefore?: Date;\n updatedAtAfter?: Date;\n cancellationTitle: string;\n transcendUrl: string;\n concurrency: number;\n}\n\nexport async function cancel(\n this: LocalContext,\n {\n auth,\n actions,\n statuses = [],\n requestIds,\n silentModeBefore,\n createdAtBefore,\n createdAtAfter,\n updatedAtBefore,\n updatedAtAfter,\n cancellationTitle,\n transcendUrl,\n concurrency,\n }: CancelCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await cancelPrivacyRequests({\n transcendUrl,\n requestActions: actions,\n auth,\n cancellationTitle,\n requestIds,\n statuses,\n concurrency,\n silentModeBefore: silentModeBefore ? new Date(silentModeBefore) : undefined,\n createdAtBefore: createdAtBefore ? new Date(createdAtBefore) : undefined,\n createdAtAfter: createdAtAfter ? new Date(createdAtAfter) : undefined,\n updatedAtBefore: updatedAtBefore ? new Date(updatedAtBefore) : undefined,\n updatedAtAfter: updatedAtAfter ? new Date(updatedAtAfter) : undefined,\n });\n}\n"],"mappings":"6GAqBA,eAAsB,EAEpB,CACE,OACA,UACA,WAAW,EAAE,CACb,aACA,mBACA,kBACA,iBACA,kBACA,iBACA,oBACA,eACA,eAEa,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAM,EAAsB,CAC1B,eACA,eAAgB,EAChB,OACA,oBACA,aACA,WACA,cACA,iBAAkB,EAAmB,IAAI,KAAK,EAAiB,CAAG,IAAA,GAClE,gBAAiB,EAAkB,IAAI,KAAK,EAAgB,CAAG,IAAA,GAC/D,eAAgB,EAAiB,IAAI,KAAK,EAAe,CAAG,IAAA,GAC5D,gBAAiB,EAAkB,IAAI,KAAK,EAAgB,CAAG,IAAA,GAC/D,eAAgB,EAAiB,IAAI,KAAK,EAAe,CAAG,IAAA,GAC7D,CAAC"}
|
package/dist/logger-zplFSeXU.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger-zplFSeXU.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["export const logger = console;\n"],"mappings":"AAAA,MAAa,EAAS"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./readTranscendYaml-BNn6-Ofi.mjs";import{CustomFunctionPayloadType as t,CustomFunctionType as n}from"@transcend-io/privacy-types";import{existsSync as r,readFileSync as i,writeFileSync as a}from"node:fs";import{dirname as o,isAbsolute as s,relative as c,resolve as l,sep as u}from"node:path";import{decodeCodec as d}from"@transcend-io/type-utils";import*as f from"io-ts";import p from"js-yaml";import{isMap as m,isScalar as h,isSeq as g,parseDocument as _}from"yaml";import{Buffer as v}from"node:buffer";import{isIP as y}from"node:net";const b=64*1024,x=new Set([`DENO_CERT`,`DENO_DIR`,`DENO_TLS_CA_STORE`,`HTTP_PROXY`,`HTTPS_PROXY`,`NODE_EXTRA_CA_CERTS`,`NO_COLOR`,`NO_PROXY`,`NPM_CONFIG_REGISTRY`]);function S(e){let t=/^\[([^\]]+)\](?::(\d+))?$/u.exec(e);if(t){let e=t[2];return y(t[1])===6&&(!e||Number(e)>0&&Number(e)<=65535)}if(y(e)>0)return!0;let n=/^([^:]+):(\d+)$/u.exec(e),r=n?.[1]??e,i=n?.[2];return(!i||Number(i)>0&&Number(i)<=65535)&&r.length<=253&&r.split(`.`).every(e=>e.length>0&&e.length<=63&&/^[A-Za-z\d](?:[A-Za-z\d-]*[A-Za-z\d])?$/u.test(e))}function C(e){let t=e.env??{},n=Object.keys(t),r=n.filter(e=>!/^[A-Za-z][A-Za-z\d_]*$/u.test(e)),i=n.filter(e=>x.has(e)||e.startsWith(`DENO_`));if(r.length>0||i.length>0)throw Error([r.length>0?`Invalid environment variable names: ${r.join(`, `)}`:void 0,i.length>0?`Reserved environment variable names: ${i.join(`, `)}`:void 0].filter(Boolean).join(`. `));let a=n.filter(e=>v.byteLength(t[e])>b);if(a.length>0)throw Error(`Environment values exceed ${b} bytes: ${a.join(`, `)}`);let o=e.allowedHosts??[];if(o.length>1&&o.includes(`*`))throw Error(`allowed-hosts cannot combine "*" with specific hosts.`);let s=o.filter(e=>e!==`*`&&!S(e));if(s.length>0)throw Error(`Invalid allowed-hosts: ${s.join(`, `)}`)}const w=f.intersection([f.type({name:f.string,code:f.string}),f.partial({id:f.string,description:f.string,type:f.union([f.literal(n.Dsr),f.literal(n.General)]),"data-silo-id":f.string,"sombra-id":f.string,"sombra-auth-env":f.string,"allowed-hosts":f.array(f.string),"timeout-ms":f.number,"allow-third-party-imports":f.boolean,env:f.record(f.string,f.string),"test-payload":f.string,"test-payload-type":f.union([f.literal(t.DataPoint),f.literal(t.RequestEnricher)]),"test-payloads":f.array(f.intersection([f.type({payload:f.string}),f.partial({"payload-type":f.union([f.literal(t.DataPoint),f.literal(t.RequestEnricher)])})]))})]),T=f.type({functions:f.array(w)});function E(e){let t=l(`/`,`__custom-function-manifest__`),n=c(t,l(t,e));return n!==`..`&&!n.startsWith(`..${u}`)&&!s(n)}function D(e,t={}){let r=e.functions.map(({id:e})=>e).filter((e,t,n)=>e!==void 0&&n.indexOf(e)!==t);if(r.length>0)throw Error(`Duplicate custom function ids in manifest: ${[...new Set(r)].join(`, `)}`);let i=e.functions.map(({name:e})=>e),a=e.functions.filter(({id:e,name:t})=>e===void 0&&i.filter(e=>e===t).length>1).map(({name:e})=>e);if(a.length>0)throw Error(`Duplicate custom function names in manifest without ids: ${[...new Set(a)].join(`, `)}. Add an \`id\` field to each duplicated entry to disambiguate.`);e.functions.forEach(e=>{if(e[`test-payload`]!==void 0&&e[`test-payloads`]!==void 0)throw Error(`Custom function "${e.name}" sets both test-payload and test-payloads — use test-payloads alone to define multiple payloads.`);if(e[`test-payload-type`]!==void 0&&e[`test-payload`]===void 0)throw Error(`Custom function "${e.name}" sets test-payload-type without test-payload — set payload-type per item in test-payloads instead.`);if(e.type!==n.Dsr&&(e[`test-payload-type`]!==void 0||e[`test-payloads`]?.some(({"payload-type":e})=>e!==void 0)))throw Error(`Custom function "${e.name}" sets a DSR payload type but is not type DSR.`);[{field:`code`,path:e.code},...e[`test-payload`]===void 0?[]:[{field:`test-payload`,path:e[`test-payload`]}],...(e[`test-payloads`]??[]).map(({payload:e},t)=>({field:`test-payloads[${t}].payload`,path:e}))].forEach(({field:n,path:r})=>{if(!t.skipPathValidation&&!E(r))throw Error(`Custom function "${e.name}" has a ${n} path outside the manifest directory: ${r}`)})})}function O(e,t={}){let n=d(T,p.load(e));return D(n,t),n}function k(e,t,n){let a=o(l(e)),s=(e,t)=>{let o=l(a,t);if(n?.(o),!r(o))throw Error(`Test payload file for custom function "${e}" does not exist: ${o}`);let s=i(o,`utf-8`);try{return JSON.parse(s)}catch(t){throw Error(`Test payload file for custom function "${e}" is not valid JSON (${o}): ${t.message}`)}};return t.functions.map(e=>{C({...e.env?{env:e.env}:{},...e[`allowed-hosts`]?{allowedHosts:e[`allowed-hosts`]}:{}});let t=l(a,e.code);if(n?.(t),!r(t))throw Error(`Code file for custom function "${e.name}" does not exist: ${t}`);let o;return e[`test-payload`]===void 0?e[`test-payloads`]!==void 0&&e[`test-payloads`].length>0&&(o=e[`test-payloads`].map(t=>({payload:s(e.name,t.payload),...t[`payload-type`]===void 0?{}:{payloadType:t[`payload-type`]}}))):o=[{payload:s(e.name,e[`test-payload`]),...e[`test-payload-type`]===void 0?{}:{payloadType:e[`test-payload-type`]}}],{name:e.name,code:i(t,`utf-8`),...e.id===void 0?{}:{id:e.id},...e.description===void 0?{}:{description:e.description},...e.type===void 0?{}:{type:e.type},...e[`data-silo-id`]===void 0?{}:{dataSiloId:e[`data-silo-id`]},...e[`sombra-id`]===void 0?{}:{sombraId:e[`sombra-id`]},...e[`sombra-auth-env`]===void 0?{}:{sombraAuthEnv:e[`sombra-auth-env`]},...e[`allowed-hosts`]===void 0?{}:{allowedHosts:e[`allowed-hosts`]},...e[`timeout-ms`]===void 0?{}:{timeoutMs:e[`timeout-ms`]},...e[`allow-third-party-imports`]===void 0?{}:{allowThirdPartyImports:e[`allow-third-party-imports`]},...e.env===void 0?{}:{env:e.env},...o===void 0?{}:{testPayloads:o}}})}function A(t,n={},r){return k(t,O(e(i(t,`utf-8`),n,`Also check that there are no extra variables defined in your manifest: ${t}`)),r)}function j(t,n,r={},i){let a=O(e(p.dump({functions:[n]}),r,`Also check that there are no extra variables defined for "${n.name}" in: ${t}`)),s=a.functions[0],c=l(o(l(t)),s.code);return{config:k(t,a,i)[0],sourcePath:c}}function M(e,t){let n=_(e);if(n.errors.length>0)throw n.errors[0];let r=n.get(`functions`);if(!g(r))throw Error("Expected a `functions` list in custom function manifest");r.items.length===0&&(r.flow=!1),r.add(n.createNode(t));let i=n.toString();return O(i),i}function N(e,t){let n=_(i(e,`utf-8`)),r=n.get(`functions`);if(!g(r))throw Error(`Expected a \`functions\` list in manifest: ${e}`);let o=0;return r.items.forEach((e,r)=>{let i=t[r];if(!i||!m(e))return;let a=!1;if(i.id&&!e.has(`id`)&&(e.items.unshift(n.createPair(`id`,i.id)),a=!0),i.dataSiloId&&!e.has(`data-silo-id`)){let t=e.items.findIndex(e=>h(e.key)&&e.key.value===`id`);e.items.splice(t+1,0,n.createPair(`data-silo-id`,i.dataSiloId)),a=!0}a&&(o+=1)}),o>0&&a(e,n.toString()),o}export{A as a,j as i,E as n,N as o,O as r,C as s,M as t};
|
|
2
|
-
//# sourceMappingURL=manifest-BNIpO_zW.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-BNIpO_zW.mjs","names":[],"sources":["../src/lib/custom-functions/execution-context.ts","../src/lib/custom-functions/manifest.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { isIP } from 'node:net';\n\n/** Maximum environment value size supported by the local process. */\nexport const CUSTOM_FUNCTION_MAX_ENV_VALUE_BYTES = 64 * 1024;\n\nconst RESERVED_ENV_NAMES = new Set([\n 'DENO_CERT',\n 'DENO_DIR',\n 'DENO_TLS_CA_STORE',\n 'HTTP_PROXY',\n 'HTTPS_PROXY',\n 'NODE_EXTRA_CA_CERTS',\n 'NO_COLOR',\n 'NO_PROXY',\n 'NPM_CONFIG_REGISTRY',\n]);\n\n/**\n * Check whether a value matches Sombra's hostname/IP contract.\n *\n * @param host - Manifest allowed-host value\n * @returns Whether the host is valid\n */\nfunction isValidAllowedHost(host: string): boolean {\n const bracketedIp = /^\\[([^\\]]+)\\](?::(\\d+))?$/u.exec(host);\n if (bracketedIp) {\n const port = bracketedIp[2];\n return isIP(bracketedIp[1]!) === 6 && (!port || (Number(port) > 0 && Number(port) <= 65_535));\n }\n if (isIP(host) > 0) {\n return true;\n }\n const hostWithPort = /^([^:]+):(\\d+)$/u.exec(host);\n const hostname = hostWithPort?.[1] ?? host;\n const port = hostWithPort?.[2];\n return (\n (!port || (Number(port) > 0 && Number(port) <= 65_535)) &&\n hostname.length <= 253 &&\n hostname\n .split('.')\n .every(\n (label) =>\n label.length > 0 &&\n label.length <= 63 &&\n /^[A-Za-z\\d](?:[A-Za-z\\d-]*[A-Za-z\\d])?$/u.test(label),\n )\n );\n}\n\n/**\n * Validate execution settings shared by check, push, and local simulation.\n *\n * @param config - Environment and network settings\n */\nexport function validateCustomFunctionExecutionContext(config: {\n /** User-defined environment variables. */\n env?: Record<string, string>;\n /** Native network destinations. */\n allowedHosts?: string[];\n}): void {\n const environment = config.env ?? {};\n const envNames = Object.keys(environment);\n const malformedEnvNames = envNames.filter((name) => !/^[A-Za-z][A-Za-z\\d_]*$/u.test(name));\n const reservedEnvNames = envNames.filter(\n (name) => RESERVED_ENV_NAMES.has(name) || name.startsWith('DENO_'),\n );\n if (malformedEnvNames.length > 0 || reservedEnvNames.length > 0) {\n throw new Error(\n [\n malformedEnvNames.length > 0\n ? `Invalid environment variable names: ${malformedEnvNames.join(', ')}`\n : undefined,\n reservedEnvNames.length > 0\n ? `Reserved environment variable names: ${reservedEnvNames.join(', ')}`\n : undefined,\n ]\n .filter(Boolean)\n .join('. '),\n );\n }\n const oversizedEnvNames = envNames.filter(\n (name) => Buffer.byteLength(environment[name]!) > CUSTOM_FUNCTION_MAX_ENV_VALUE_BYTES,\n );\n if (oversizedEnvNames.length > 0) {\n throw new Error(\n `Environment values exceed ${CUSTOM_FUNCTION_MAX_ENV_VALUE_BYTES} bytes: ${oversizedEnvNames.join(', ')}`,\n );\n }\n const allowedHosts = config.allowedHosts ?? [];\n if (allowedHosts.length > 1 && allowedHosts.includes('*')) {\n throw new Error('allowed-hosts cannot combine \"*\" with specific hosts.');\n }\n const invalidHosts = allowedHosts.filter((host) => host !== '*' && !isValidAllowedHost(host));\n if (invalidHosts.length > 0) {\n throw new Error(`Invalid allowed-hosts: ${invalidHosts.join(', ')}`);\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, isAbsolute, relative, resolve, sep } from 'node:path';\n\nimport { CustomFunctionPayloadType, CustomFunctionType } from '@transcend-io/privacy-types';\nimport type { CustomFunctionConfigInput } from '@transcend-io/sdk';\nimport { decodeCodec, type ObjByString } from '@transcend-io/type-utils';\nimport * as t from 'io-ts';\nimport yaml from 'js-yaml';\nimport { isMap, isScalar, isSeq, parseDocument } from 'yaml';\n\nimport { replaceVariablesInYaml } from '../readTranscendYaml.js';\nimport { validateCustomFunctionExecutionContext } from './execution-context.js';\n\nexport const CustomFunctionManifestEntry = t.intersection([\n t.type({\n /** Display name of the custom function — used as the sync key when no `id` is set */\n name: t.string,\n /** Path to the TypeScript source file, relative to the manifest */\n code: t.string,\n }),\n t.partial({\n /**\n * Custom function ID. Optional, but required to disambiguate when multiple\n * custom functions share a name. Written back by `push --updateManifest`.\n */\n id: t.string,\n /** Description shown in the Transcend dashboard */\n description: t.string,\n /** Custom function type. Defaults to GENERAL */\n type: t.union([t.literal(CustomFunctionType.Dsr), t.literal(CustomFunctionType.General)]),\n /** Data silo ID to attach to (required for DSR functions) */\n 'data-silo-id': t.string,\n /** The Sombra gateway the function belongs to */\n 'sombra-id': t.string,\n /**\n * Name of the environment variable holding the internal key of the\n * function's Sombra gateway. The key itself never lives in the manifest —\n * it is read from the CLI's process environment at push time. Overrides\n * `--sombraAuth` for this entry.\n */\n 'sombra-auth-env': t.string,\n /** Hosts the function may make network requests to */\n 'allowed-hosts': t.array(t.string),\n /** Execution timeout in milliseconds */\n 'timeout-ms': t.number,\n /** Whether the function may import third party modules */\n 'allow-third-party-imports': t.boolean,\n /** Environment variables to expose to the function */\n env: t.record(t.string, t.string),\n /**\n * Path to a JSON file (relative to the manifest) holding the test payload\n * to run the function with before pushing. When set, the function is\n * test-run after signing and only pushed/promoted when the test passes.\n * Shorthand for a single-item `test-payloads` list.\n */\n 'test-payload': t.string,\n /**\n * Which export to invoke when test-running a DSR function:\n * `DATA_POINT` invokes the default export, `REQUEST_ENRICHER` invokes the\n * `enricher` export. Defaults to DATA_POINT. Ignored for GENERAL functions.\n * Only valid alongside `test-payload`.\n */\n 'test-payload-type': t.union([\n t.literal(CustomFunctionPayloadType.DataPoint),\n t.literal(CustomFunctionPayloadType.RequestEnricher),\n ]),\n /**\n * Test payloads to run the function with before pushing. Every payload\n * runs and all must pass for the function to be pushed/promoted. DSR\n * functions should list one payload per export they implement\n * (`DATA_POINT` for the default export, `REQUEST_ENRICHER` for the\n * `enricher` export). Mutually exclusive with `test-payload`.\n */\n 'test-payloads': t.array(\n t.intersection([\n t.type({\n /** Path to the JSON payload file, relative to the manifest */\n payload: t.string,\n }),\n t.partial({\n /** Which export the payload invokes (DSR only). Defaults to DATA_POINT */\n 'payload-type': t.union([\n t.literal(CustomFunctionPayloadType.DataPoint),\n t.literal(CustomFunctionPayloadType.RequestEnricher),\n ]),\n }),\n ]),\n ),\n }),\n]);\n\n/** Override type */\nexport type CustomFunctionManifestEntry = t.TypeOf<typeof CustomFunctionManifestEntry>;\n\nexport const CustomFunctionsManifest = t.type({\n /** The custom functions to sync */\n functions: t.array(CustomFunctionManifestEntry),\n});\n\n/** Override type */\nexport type CustomFunctionsManifest = t.TypeOf<typeof CustomFunctionsManifest>;\n\n/**\n * Determine whether a relative manifest path stays inside the manifest's\n * directory after normalization.\n *\n * @param filePath - Path from a custom function manifest entry\n * @returns Whether the normalized path is contained by the manifest directory\n */\nexport function isCustomFunctionManifestPathContained(filePath: string): boolean {\n const manifestDirectory = resolve('/', '__custom-function-manifest__');\n const relativePath = relative(manifestDirectory, resolve(manifestDirectory, filePath));\n return relativePath !== '..' && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath);\n}\n\n/**\n * Validate semantic constraints shared by manifest readers and editors.\n *\n * @param manifest - Shape-validated custom function manifest\n * @param options - Validation behavior\n */\nexport function validateCustomFunctionsManifest(\n manifest: CustomFunctionsManifest,\n options: {\n /** Skip path validation while identifying candidate manifest files. */\n skipPathValidation?: boolean;\n } = {},\n): void {\n // IDs must be unique — two entries cannot target the same function\n const duplicateIds = manifest.functions\n .map(({ id }) => id)\n .filter((id, index, ids) => id !== undefined && ids.indexOf(id) !== index);\n if (duplicateIds.length > 0) {\n throw new Error(\n `Duplicate custom function ids in manifest: ${[...new Set(duplicateIds)].join(', ')}`,\n );\n }\n\n // Names may repeat only when every entry sharing the name carries an `id`\n // to disambiguate; an id-less entry syncs by name and would be ambiguous.\n const allNames = manifest.functions.map(({ name }) => name);\n const ambiguousNames = manifest.functions\n .filter(({ id, name }) => id === undefined && allNames.filter((n) => n === name).length > 1)\n .map(({ name }) => name);\n if (ambiguousNames.length > 0) {\n throw new Error(\n `Duplicate custom function names in manifest without ids: ${[...new Set(ambiguousNames)].join(', ')}. ` +\n 'Add an `id` field to each duplicated entry to disambiguate.',\n );\n }\n\n manifest.functions.forEach((entry) => {\n if (entry['test-payload'] !== undefined && entry['test-payloads'] !== undefined) {\n throw new Error(\n `Custom function \"${entry.name}\" sets both test-payload and test-payloads — ` +\n 'use test-payloads alone to define multiple payloads.',\n );\n }\n if (entry['test-payload-type'] !== undefined && entry['test-payload'] === undefined) {\n throw new Error(\n `Custom function \"${entry.name}\" sets test-payload-type without test-payload — ` +\n 'set payload-type per item in test-payloads instead.',\n );\n }\n if (\n entry.type !== CustomFunctionType.Dsr &&\n (entry['test-payload-type'] !== undefined ||\n entry['test-payloads']?.some(\n ({ ['payload-type']: payloadType }) => payloadType !== undefined,\n ))\n ) {\n throw new Error(\n `Custom function \"${entry.name}\" sets a DSR payload type but is not type DSR.`,\n );\n }\n\n const referencedPaths = [\n { field: 'code', path: entry.code },\n ...(entry['test-payload'] === undefined\n ? []\n : [{ field: 'test-payload', path: entry['test-payload'] }]),\n ...(entry['test-payloads'] ?? []).map(({ payload }, index) => ({\n field: `test-payloads[${index}].payload`,\n path: payload,\n })),\n ];\n referencedPaths.forEach(({ field, path }) => {\n if (!options.skipPathValidation && !isCustomFunctionManifestPathContained(path)) {\n throw new Error(\n `Custom function \"${entry.name}\" has a ${field} path outside the manifest directory: ${path}`,\n );\n }\n });\n });\n}\n\n/**\n * Parse and validate a custom functions manifest without resolving variables\n * or reading any referenced files.\n *\n * Unresolved `<<parameters.*>>` values remain plain strings in the returned\n * manifest.\n *\n * @param contents - Custom function manifest YAML\n * @param options - Validation behavior\n * @returns The parsed, shape-validated, and semantically valid manifest\n */\nexport function parseCustomFunctionsManifest(\n contents: string,\n options: {\n /** Skip path validation while identifying candidate manifest files. */\n skipPathValidation?: boolean;\n } = {},\n): CustomFunctionsManifest {\n const manifest = decodeCodec(CustomFunctionsManifest, yaml.load(contents));\n validateCustomFunctionsManifest(manifest, options);\n return manifest;\n}\n\n/**\n * A custom function config from the manifest, plus CLI-level settings that\n * are not part of the SDK sync input.\n */\nexport type CustomFunctionManifestConfig = CustomFunctionConfigInput & {\n /** Env variable name holding the internal key of the function's Sombra gateway */\n sombraAuthEnv?: string;\n /** Parsed JSON test payloads to run the function with before pushing */\n testPayloads?: {\n /** The parsed JSON payload */\n payload: object;\n /** Which export the payload invokes when test-running a DSR function */\n payloadType?: Exclude<CustomFunctionPayloadType, typeof CustomFunctionPayloadType.Maestro>;\n }[];\n};\n\n/**\n * Hydrate parsed manifest entries from their referenced files.\n *\n * @param filePath - Path to the manifest YAML file\n * @param manifest - Parsed manifest\n * @param assertPath - Optional safety check applied before referenced files are read\n * @returns Custom Function configs with code and payloads loaded\n */\nfunction hydrateCustomFunctionsManifest(\n filePath: string,\n manifest: CustomFunctionsManifest,\n assertPath?: (path: string) => void,\n): CustomFunctionManifestConfig[] {\n const manifestDir = dirname(resolve(filePath));\n\n /**\n * Load and parse a JSON test payload file.\n *\n * @param entryName - The manifest entry name, for error messages\n * @param payloadFile - The payload file path, relative to the manifest\n * @returns The parsed payload object\n */\n const loadTestPayload = (entryName: string, payloadFile: string): object => {\n const testPayloadPath = resolve(manifestDir, payloadFile);\n assertPath?.(testPayloadPath);\n if (!existsSync(testPayloadPath)) {\n throw new Error(\n `Test payload file for custom function \"${entryName}\" does not exist: ${testPayloadPath}`,\n );\n }\n const rawPayload = readFileSync(testPayloadPath, 'utf-8');\n try {\n return JSON.parse(rawPayload);\n } catch (err) {\n throw new Error(\n `Test payload file for custom function \"${entryName}\" is not valid JSON ` +\n `(${testPayloadPath}): ${(err as Error).message}`,\n );\n }\n };\n\n return manifest.functions.map((entry) => {\n validateCustomFunctionExecutionContext({\n ...(entry.env ? { env: entry.env } : {}),\n ...(entry['allowed-hosts'] ? { allowedHosts: entry['allowed-hosts'] } : {}),\n });\n const codePath = resolve(manifestDir, entry.code);\n assertPath?.(codePath);\n if (!existsSync(codePath)) {\n throw new Error(`Code file for custom function \"${entry.name}\" does not exist: ${codePath}`);\n }\n\n // `test-payload` is shorthand for a single-item `test-payloads` list\n let testPayloads: CustomFunctionManifestConfig['testPayloads'];\n if (entry['test-payload'] !== undefined) {\n testPayloads = [\n {\n payload: loadTestPayload(entry.name, entry['test-payload']),\n ...(entry['test-payload-type'] !== undefined\n ? { payloadType: entry['test-payload-type'] }\n : {}),\n },\n ];\n } else if (entry['test-payloads'] !== undefined && entry['test-payloads'].length > 0) {\n testPayloads = entry['test-payloads'].map((item) => ({\n payload: loadTestPayload(entry.name, item.payload),\n ...(item['payload-type'] !== undefined ? { payloadType: item['payload-type'] } : {}),\n }));\n }\n\n return {\n name: entry.name,\n code: readFileSync(codePath, 'utf-8'),\n ...(entry.id !== undefined ? { id: entry.id } : {}),\n ...(entry.description !== undefined ? { description: entry.description } : {}),\n ...(entry.type !== undefined ? { type: entry.type } : {}),\n ...(entry['data-silo-id'] !== undefined ? { dataSiloId: entry['data-silo-id'] } : {}),\n ...(entry['sombra-id'] !== undefined ? { sombraId: entry['sombra-id'] } : {}),\n ...(entry['sombra-auth-env'] !== undefined\n ? { sombraAuthEnv: entry['sombra-auth-env'] }\n : {}),\n ...(entry['allowed-hosts'] !== undefined ? { allowedHosts: entry['allowed-hosts'] } : {}),\n ...(entry['timeout-ms'] !== undefined ? { timeoutMs: entry['timeout-ms'] } : {}),\n ...(entry['allow-third-party-imports'] !== undefined\n ? { allowThirdPartyImports: entry['allow-third-party-imports'] }\n : {}),\n ...(entry.env !== undefined ? { env: entry.env } : {}),\n ...(testPayloads !== undefined ? { testPayloads } : {}),\n };\n });\n}\n\n/**\n * Read a custom functions manifest from disk, apply variable substitution,\n * validate it, and hydrate its referenced code and payload files.\n *\n * Variable substitution deliberately happens before parsing and hydration to\n * preserve push behavior.\n *\n * @param filePath - Path to the manifest YAML file\n * @param variables - Variables to fill into `<<parameters.x>>` placeholders\n * @param assertPath - Optional safety check applied before referenced files are read\n * @returns The custom function configs, with code loaded from disk\n */\nexport function readCustomFunctionsManifest(\n filePath: string,\n variables: ObjByString = {},\n assertPath?: (path: string) => void,\n): CustomFunctionManifestConfig[] {\n const fileContents = readFileSync(filePath, 'utf-8');\n const replacedVariables = replaceVariablesInYaml(\n fileContents,\n variables,\n `Also check that there are no extra variables defined in your manifest: ${filePath}`,\n );\n const manifest = parseCustomFunctionsManifest(replacedVariables);\n return hydrateCustomFunctionsManifest(filePath, manifest, assertPath);\n}\n\n/**\n * Resolve and hydrate one selected manifest entry.\n *\n * This lets local execution ignore unrelated entries whose files or\n * variables are currently incomplete.\n *\n * @param filePath - Path to the containing manifest\n * @param entry - Selected raw manifest entry\n * @param variables - Variables to fill into `<<parameters.x>>` placeholders\n * @param assertPath - Optional safety check applied before referenced files are read\n * @returns Hydrated selected configuration and its source path\n */\nexport function readCustomFunctionManifestEntry(\n filePath: string,\n entry: CustomFunctionManifestEntry,\n variables: ObjByString = {},\n assertPath?: (path: string) => void,\n): { config: CustomFunctionManifestConfig; sourcePath: string } {\n const entryContents = yaml.dump({ functions: [entry] });\n const replacedVariables = replaceVariablesInYaml(\n entryContents,\n variables,\n `Also check that there are no extra variables defined for \"${entry.name}\" in: ${filePath}`,\n );\n const manifest = parseCustomFunctionsManifest(replacedVariables);\n const resolvedEntry = manifest.functions[0]!;\n const manifestDirectory = dirname(resolve(filePath));\n const sourcePath = resolve(manifestDirectory, resolvedEntry.code);\n return {\n config: hydrateCustomFunctionsManifest(filePath, manifest, assertPath)[0]!,\n sourcePath,\n };\n}\n\n/**\n * Append an entry to a manifest YAML document while preserving the existing\n * document's comments, ordering, scalar styles, and unresolved placeholders.\n *\n * The complete result is parsed and validated with the same codec and\n * semantic rules used by {@link readCustomFunctionsManifest}.\n *\n * @param contents - Existing custom function manifest YAML\n * @param entry - Manifest entry to append\n * @returns Updated manifest YAML\n */\nexport function insertCustomFunctionManifestEntry(\n contents: string,\n entry: CustomFunctionManifestEntry,\n): string {\n const document = parseDocument(contents);\n if (document.errors.length > 0) {\n throw document.errors[0];\n }\n\n const functions = document.get('functions');\n if (!isSeq(functions)) {\n throw new Error('Expected a `functions` list in custom function manifest');\n }\n\n if (functions.items.length === 0) {\n functions.flow = false;\n }\n functions.add(document.createNode(entry));\n const updatedContents = document.toString();\n parseCustomFunctionsManifest(updatedContents);\n return updatedContents;\n}\n\n/**\n * The IDs assigned to a manifest entry during a push, to write back into the\n * manifest file.\n */\nexport interface CustomFunctionManifestIds {\n /** Custom function ID */\n id?: string;\n /** Data silo (DSR integration) ID, for DSR functions */\n dataSiloId?: string;\n}\n\n/**\n * Write custom function and data silo IDs back into a manifest file, so\n * future pushes match by ID instead of by (potentially non-unique) name and\n * DSR entries keep pointing at their integration.\n *\n * The raw file text is edited via a comment- and formatting-preserving YAML\n * document, so comments and un-substituted `<<parameters.x>>` placeholders\n * survive untouched. Only entries that are missing the respective key are\n * modified.\n *\n * @param filePath - Path to the manifest YAML file\n * @param idsByIndex - IDs for each manifest entry, by array index (undefined\n * entries are left unchanged)\n * @returns The number of entries that were updated\n */\nexport function writeCustomFunctionIdsToManifest(\n filePath: string,\n idsByIndex: (CustomFunctionManifestIds | undefined)[],\n): number {\n const document = parseDocument(readFileSync(filePath, 'utf-8'));\n const functions = document.get('functions');\n if (!isSeq(functions)) {\n throw new Error(`Expected a \\`functions\\` list in manifest: ${filePath}`);\n }\n\n let updated = 0;\n functions.items.forEach((item, index) => {\n const ids = idsByIndex[index];\n if (!ids || !isMap(item)) {\n return;\n }\n let changed = false;\n if (ids.id && !item.has('id')) {\n // Place `id` first so it reads as the entry's key\n item.items.unshift(document.createPair('id', ids.id));\n changed = true;\n }\n if (ids.dataSiloId && !item.has('data-silo-id')) {\n // Place `data-silo-id` right after `id` (or first when there is no id)\n const idIndex = item.items.findIndex((pair) => isScalar(pair.key) && pair.key.value === 'id');\n item.items.splice(idIndex + 1, 0, document.createPair('data-silo-id', ids.dataSiloId));\n changed = true;\n }\n if (changed) {\n updated += 1;\n }\n });\n\n if (updated > 0) {\n writeFileSync(filePath, document.toString());\n }\n return updated;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{m as e}from"./prompts-ClBXdELk.mjs";import{dirname as t,relative as n}from"node:path";function r(r){let{command:i,cwd:a,manifestPath:o}=r,s=n(a,o)||`transcend-functions.yml`,c=r.discoveredManifestPaths.filter(e=>e!==o);return c.length===1?`Custom Function manifest does not exist at ${s}. Did you mean \`transcend custom-functions ${i} ${e(n(a,t(c[0]))||`.`)}\`?`:c.length>1?`Custom Function manifest does not exist at ${s}. Found manifests at: ${c.map(e=>n(a,e)).join(`, `)}. Pass a directory or --manifest explicitly.`:`Custom Function manifest does not exist at ${s}. Run \`transcend custom-functions init\` to create the default project.`}export{r as t};
|
|
2
|
-
//# sourceMappingURL=missing-manifest-DgcukXfg.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"missing-manifest-DgcukXfg.mjs","names":[],"sources":["../src/lib/custom-functions/missing-manifest.ts"],"sourcesContent":["import { dirname, relative } from 'node:path';\n\nimport { quoteShellArgument } from '../scaffolding/project-plan-output.js';\n\n/** Command that can be redirected to a discovered Custom Function project. */\nexport type ManifestConsumerCommand = 'check' | 'new' | 'run';\n\n/**\n * Format actionable guidance when a requested Custom Function manifest is absent.\n *\n * @param options - Requested and discovered manifest paths\n * @returns Missing-manifest explanation\n */\nexport function formatMissingManifestMessage(options: {\n /** Command working directory. */\n cwd: string;\n /** Requested absolute manifest path. */\n manifestPath: string;\n /** Other absolute manifests discovered in the surrounding project. */\n discoveredManifestPaths: readonly string[];\n /** Command the user originally invoked. */\n command: ManifestConsumerCommand;\n}): string {\n const { command, cwd, manifestPath } = options;\n const requested = relative(cwd, manifestPath) || 'transcend-functions.yml';\n const discovered = options.discoveredManifestPaths.filter(\n (candidate) => candidate !== manifestPath,\n );\n if (discovered.length === 1) {\n const directory = relative(cwd, dirname(discovered[0]!)) || '.';\n return (\n `Custom Function manifest does not exist at ${requested}. ` +\n `Did you mean \\`transcend custom-functions ${command} ${quoteShellArgument(directory)}\\`?`\n );\n }\n if (discovered.length > 1) {\n const paths = discovered.map((path) => relative(cwd, path)).join(', ');\n return (\n `Custom Function manifest does not exist at ${requested}. ` +\n `Found manifests at: ${paths}. Pass a directory or --manifest explicitly.`\n );\n }\n return (\n `Custom Function manifest does not exist at ${requested}. ` +\n 'Run `transcend custom-functions init` to create the default project.'\n );\n}\n"],"mappings":"6FAaA,SAAgB,EAA6B,EASlC,CACT,GAAM,CAAE,UAAS,MAAK,gBAAiB,EACjC,EAAY,EAAS,EAAK,EAAa,EAAI,0BAC3C,EAAa,EAAQ,wBAAwB,OAChD,GAAc,IAAc,EAC9B,CAeD,OAdI,EAAW,SAAW,EAGtB,8CAA8C,EAAU,8CACX,EAAQ,GAAG,EAHxC,EAAS,EAAK,EAAQ,EAAW,GAAI,CAAC,EAAI,IAG2B,CAAC,KAGtF,EAAW,OAAS,EAGpB,8CAA8C,EAAU,wBAF5C,EAAW,IAAK,GAAS,EAAS,EAAK,EAAK,CAAC,CAAC,KAAK,KAGnC,CAAC,8CAI/B,8CAA8C,EAAU"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{basename as e,dirname as t,isAbsolute as n,relative as r,resolve as i,sep as a}from"node:path";function o(n,r){let a=i(r),o=[];for(;;)try{return n.fs.lstatSync(a),i(n.fs.realpathSync(a),...o)}catch(n){let r=n.code;if(r!==`ENOENT`&&r!==`ENOTDIR`)throw n;let i=t(a);if(i===a)throw n;o.unshift(e(a)),a=i}}function s(e,t,i){let s=r(o(e,t),o(e,i));return s!==`..`&&!s.startsWith(`..${a}`)&&!n(s)}function c(e,t,n){if(!s(e,t,n))throw Error(`Refusing to access path outside project root through a symlink: ${n}`)}export{s as n,c as t};
|
|
2
|
-
//# sourceMappingURL=path-safety-D5Qwl40b.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"path-safety-D5Qwl40b.mjs","names":[],"sources":["../src/lib/scaffolding/path-safety.ts"],"sourcesContent":["import { basename, dirname, isAbsolute, relative, resolve, sep } from 'node:path';\n\nimport type { LocalContext } from '../../context.js';\n\n/**\n * Resolve a path through its nearest existing ancestor.\n *\n * This retains nonexistent suffixes while resolving every existing symlink in\n * the prefix, which is required before safely creating a new file.\n *\n * @param context - CLI context\n * @param path - Absolute or relative path\n * @returns Physical absolute path\n */\nfunction resolvePhysicalPath(context: LocalContext, path: string): string {\n let current = resolve(path);\n const suffix: string[] = [];\n while (true) {\n try {\n context.fs.lstatSync(current);\n return resolve(context.fs.realpathSync(current), ...suffix);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n throw error;\n }\n const parent = dirname(current);\n if (parent === current) {\n throw error;\n }\n suffix.unshift(basename(current));\n current = parent;\n }\n }\n}\n\n/**\n * Determine whether a path physically remains under an approved root.\n *\n * @param context - CLI context\n * @param root - Approved directory\n * @param path - Candidate destination or referenced file\n * @returns Whether existing symlinks keep the path under the root\n */\nexport function isPathPhysicallyContained(\n context: LocalContext,\n root: string,\n path: string,\n): boolean {\n const physicalRoot = resolvePhysicalPath(context, root);\n const physicalPath = resolvePhysicalPath(context, path);\n const child = relative(physicalRoot, physicalPath);\n return child !== '..' && !child.startsWith(`..${sep}`) && !isAbsolute(child);\n}\n\n/**\n * Reject a path whose existing symlink ancestors escape an approved root.\n *\n * @param context - CLI context\n * @param root - Approved directory\n * @param path - Candidate path\n */\nexport function assertPathPhysicallyContained(\n context: LocalContext,\n root: string,\n path: string,\n): void {\n if (!isPathPhysicallyContained(context, root, path)) {\n throw new Error(`Refusing to access path outside project root through a symlink: ${path}`);\n }\n}\n"],"mappings":"sGAcA,SAAS,EAAoB,EAAuB,EAAsB,CACxE,IAAI,EAAU,EAAQ,EAAK,CACrB,EAAmB,EAAE,CAC3B,OACE,GAAI,CAEF,OADA,EAAQ,GAAG,UAAU,EAAQ,CACtB,EAAQ,EAAQ,GAAG,aAAa,EAAQ,CAAE,GAAG,EAAO,OACpD,EAAO,CACd,IAAM,EAAQ,EAAgC,KAC9C,GAAI,IAAS,UAAY,IAAS,UAChC,MAAM,EAER,IAAM,EAAS,EAAQ,EAAQ,CAC/B,GAAI,IAAW,EACb,MAAM,EAER,EAAO,QAAQ,EAAS,EAAQ,CAAC,CACjC,EAAU,GAahB,SAAgB,EACd,EACA,EACA,EACS,CAGT,IAAM,EAAQ,EAFO,EAAoB,EAAS,EAEf,CADd,EAAoB,EAAS,EACD,CAAC,CAClD,OAAO,IAAU,MAAQ,CAAC,EAAM,WAAW,KAAK,IAAM,EAAI,CAAC,EAAW,EAAM,CAU9E,SAAgB,EACd,EACA,EACA,EACM,CACN,GAAI,CAAC,EAA0B,EAAS,EAAM,EAAK,CACjD,MAAU,MAAM,mEAAmE,IAAO"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
const e=/^\s*package\s+/mu;function t(e,t){let n=/^[A-Za-z_][A-Za-z0-9_]*/u.exec(e.slice(t));return n?{identifier:n[0],end:t+n[0].length}:void 0}function n(e,t){let n=t;for(;n<e.length&&/\s/u.test(e[n]);)n+=1;return n}function r(e,t){if(e[t]==="`"){let n=e.indexOf("`",t+1);return n===-1?void 0:{value:e.slice(t+1,n),end:n+1}}if(e[t]!==`"`)return;let n=t+1;for(;n<e.length;){if(e[n]===`\\`){n+=2;continue}if(e[n]===`"`){let r=e.slice(t,n+1);try{return{value:JSON.parse(r),end:n+1}}catch{return}}n+=1}}function i(e,i){let a=t(e,i);if(!a)return;let o=[a.identifier],s=a.end;for(;s<e.length;){let i=n(e,s);if(e[i]===`.`){let r=t(e,n(e,i+1));if(!r)break;o.push(r.identifier),s=r.end;continue}if(e[i]===`[`){let t=r(e,n(e,i+1));if(!t)break;let a=n(e,t.end);if(e[a]!==`]`)break;o.push(t.value),s=a+1;continue}break}return{source:e.slice(i,s),segments:o,end:s}}function a(t){let n=e.exec(t);if(!n)return;let r=i(t,n.index+n[0].length);return r?{source:r.source,segments:r.segments}:void 0}function o(e,t){let n=e[t],r=t+1;for(;r<e.length;){if(n===`"`&&e[r]===`\\`){r+=2;continue}if(e[r]===n)return r+1;r+=1}return r}function s(e){let n=[],r=0;for(;r<e.length;){if(e[r]===`#`){let t=e.indexOf(`
|
|
2
|
-
`,r);r=t===-1?e.length:t+1;continue}if(e[r]===`"`||e[r]==="`"){r=o(e,r);continue}let a=t(e,r);if(!a){r+=1;continue}if(a.identifier!==`data`){r=a.end;continue}let s=i(e,r);if(!s||s.segments.length===1){r=a.end;continue}let c=e.lastIndexOf(`
|
|
3
|
-
`,r-1)+1;/^\s*import\s+$/u.test(e.slice(c,r))||n.push({reference:s,line:e.slice(0,r).split(`
|
|
4
|
-
`).length}),r=s.end}return n}function c(e){return e.endsWith(`.rego`)&&!e.endsWith(`_test.rego`)}function l(e){if(e===void 0)throw Error(`Policy bundle directory must contain a manifest.json file.`);let t;try{t=JSON.parse(e)}catch(e){throw Error(`manifest.json is not valid JSON: ${e instanceof Error?e.message:String(e)}`,{cause:e})}if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`manifest.json must contain a JSON object.`);let n=t.roots;if(!Array.isArray(n)||n.length===0)throw Error(`manifest.json must declare "roots" as a non-empty array of strings (e.g. {"roots":["policy_engine"]}).`);if(!n.every(e=>typeof e==`string`&&e.length>0))throw Error(`manifest.json "roots" must be an array of non-empty strings.`);if(!n.every(e=>e.split(`/`).every(e=>/^[A-Za-z_][A-Za-z0-9_]*$/u.test(e))))throw Error(`manifest.json "roots" must contain slash-separated Rego identifiers so Policy Engine can re-namespace them safely.`);return{roots:n}}function u(e,t){return e.length>=t.length&&t.every((t,n)=>t===e[n])}function d(e,t){let n=t.join(`.`),r=e.source.slice(n.length);return e.source.startsWith(n)&&(r===``||r.startsWith(`.`)||/^\s*\[/u.test(r))}function f(e,t){return u(e.slice(1),t)}function p(e,t){let n=l(e),r=n.roots.join(`, `),i=t.filter(({path:e})=>c(e)).slice().sort((e,t)=>e.path.localeCompare(t.path));if(i.length===0)throw Error(`Policy bundle directory must contain at least one .rego policy file.`);let o=n.roots.map(e=>e.split(`/`)),u=i.flatMap(({path:e,contents:t})=>{let n=a(t);return!n||o.some(e=>d(n,e))?[]:[` - ${e} (package ${n.source}) is not covered by roots [${r}]`]});if(u.length>0)throw Error([`manifest.json "roots" do not cover all Rego packages in the bundle; uncovered packages will fail-closed at decide time. Either broaden "roots" or move the policy under a covered package:`,...u].join(`
|
|
5
|
-
`));let p=i.flatMap(({path:e,contents:t})=>s(t).filter(({reference:e})=>o.some(t=>f(e.segments,t))).map(({reference:t,line:n})=>` - ${e}:${n} references ${t.source}; import that package and use its local name`));if(p.length>0)throw Error([`Publishable Rego must not reference its declared bundle roots directly because Policy Engine re-namespaces package imports during activation:`,...p].join(`
|
|
6
|
-
`));return{manifest:n,publishableRegoPaths:i.map(({path:e})=>e)}}export{p as t};
|
|
7
|
-
//# sourceMappingURL=policy-bundle-manifest-D6dkbjNi.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"policy-bundle-manifest-D6dkbjNi.mjs","names":[],"sources":["../src/lib/policy/rego-reference.ts","../src/lib/policy/policy-bundle-manifest.ts"],"sourcesContent":["/** Parsed static Rego reference. */\ninterface StaticRegoReference {\n /** Source representation of the reference. */\n source: string;\n /** Logical document path segments. */\n segments: string[];\n /** Offset immediately after the reference. */\n end: number;\n}\n\n/** Matches the beginning of a Rego package declaration. */\nconst PACKAGE_DECLARATION_PATTERN = /^\\s*package\\s+/mu;\n\n/**\n * Read an identifier at a source offset.\n *\n * @param source - Rego source\n * @param start - Candidate identifier offset\n * @returns Identifier and following offset\n */\nfunction readIdentifier(\n source: string,\n start: number,\n): { identifier: string; end: number } | undefined {\n const match = /^[A-Za-z_][A-Za-z0-9_]*/u.exec(source.slice(start));\n return match ? { identifier: match[0], end: start + match[0].length } : undefined;\n}\n\n/**\n * Advance past Rego whitespace.\n *\n * @param source - Rego source\n * @param start - Initial source offset\n * @returns First non-whitespace offset\n */\nfunction skipWhitespace(source: string, start: number): number {\n let current = start;\n while (current < source.length && /\\s/u.test(source[current]!)) {\n current += 1;\n }\n return current;\n}\n\n/**\n * Read a quoted or raw Rego string.\n *\n * @param source - Rego source\n * @param start - Opening quote offset\n * @returns Decoded string and following offset\n */\nfunction readQuotedString(\n source: string,\n start: number,\n): { value: string; end: number } | undefined {\n if (source[start] === '`') {\n const closingQuote = source.indexOf('`', start + 1);\n return closingQuote === -1\n ? undefined\n : { value: source.slice(start + 1, closingQuote), end: closingQuote + 1 };\n }\n if (source[start] !== '\"') {\n return undefined;\n }\n let current = start + 1;\n while (current < source.length) {\n if (source[current] === '\\\\') {\n current += 2;\n continue;\n }\n if (source[current] === '\"') {\n const raw = source.slice(start, current + 1);\n try {\n return { value: JSON.parse(raw) as string, end: current + 1 };\n } catch {\n return undefined;\n }\n }\n current += 1;\n }\n return undefined;\n}\n\n/**\n * Parse a static Rego reference with dotted or quoted bracket segments.\n *\n * @param source - Rego source\n * @param start - First identifier offset\n * @returns Parsed reference\n */\nfunction parseStaticRegoReference(source: string, start: number): StaticRegoReference | undefined {\n const first = readIdentifier(source, start);\n if (!first) {\n return undefined;\n }\n const segments = [first.identifier];\n let current = first.end;\n while (current < source.length) {\n const separator = skipWhitespace(source, current);\n if (source[separator] === '.') {\n const identifierStart = skipWhitespace(source, separator + 1);\n const identifier = readIdentifier(source, identifierStart);\n if (!identifier) {\n break;\n }\n segments.push(identifier.identifier);\n current = identifier.end;\n continue;\n }\n if (source[separator] === '[') {\n const stringStart = skipWhitespace(source, separator + 1);\n const value = readQuotedString(source, stringStart);\n if (!value) {\n break;\n }\n const closingBracket = skipWhitespace(source, value.end);\n if (source[closingBracket] !== ']') {\n break;\n }\n segments.push(value.value);\n current = closingBracket + 1;\n continue;\n }\n break;\n }\n return {\n source: source.slice(start, current),\n segments,\n end: current,\n };\n}\n\n/**\n * Read the package reference declared by Rego source.\n *\n * @param contents - Rego source\n * @returns Package reference, or undefined when no declaration is present\n */\nexport function parseRegoPackageReference(\n contents: string,\n): Omit<StaticRegoReference, 'end'> | undefined {\n const declaration = PACKAGE_DECLARATION_PATTERN.exec(contents);\n if (!declaration) {\n return undefined;\n }\n const reference = parseStaticRegoReference(contents, declaration.index + declaration[0].length);\n return reference ? { source: reference.source, segments: reference.segments } : undefined;\n}\n\n/**\n * Skip a string literal while scanning executable Rego source.\n *\n * @param source - Rego source\n * @param start - Opening delimiter offset\n * @returns Offset immediately after the string\n */\nfunction skipStringLiteral(source: string, start: number): number {\n const delimiter = source[start]!;\n let current = start + 1;\n while (current < source.length) {\n if (delimiter === '\"' && source[current] === '\\\\') {\n current += 2;\n continue;\n }\n if (source[current] === delimiter) {\n return current + 1;\n }\n current += 1;\n }\n return current;\n}\n\n/**\n * Find executable static `data` references outside imports.\n *\n * @param contents - Rego source\n * @returns References with one-based source lines\n */\nexport function findDirectDataReferences(\n contents: string,\n): { reference: StaticRegoReference; line: number }[] {\n const references: { reference: StaticRegoReference; line: number }[] = [];\n let current = 0;\n while (current < contents.length) {\n if (contents[current] === '#') {\n const newline = contents.indexOf('\\n', current);\n current = newline === -1 ? contents.length : newline + 1;\n continue;\n }\n if (contents[current] === '\"' || contents[current] === '`') {\n current = skipStringLiteral(contents, current);\n continue;\n }\n const identifier = readIdentifier(contents, current);\n if (!identifier) {\n current += 1;\n continue;\n }\n if (identifier.identifier !== 'data') {\n current = identifier.end;\n continue;\n }\n const reference = parseStaticRegoReference(contents, current);\n if (!reference || reference.segments.length === 1) {\n current = identifier.end;\n continue;\n }\n const lineStart = contents.lastIndexOf('\\n', current - 1) + 1;\n if (!/^\\s*import\\s+$/u.test(contents.slice(lineStart, current))) {\n references.push({\n reference,\n line: contents.slice(0, current).split('\\n').length,\n });\n }\n current = reference.end;\n }\n return references;\n}\n","import { findDirectDataReferences, parseRegoPackageReference } from './rego-reference.js';\n\n/** Shape of the policy bundle `manifest.json` accepted by Policy Engine. */\nexport interface PolicyBundleManifest {\n /** Roots of the bundle, such as `policy_engine/transcend`. */\n roots: string[];\n}\n\n/** In-memory Rego file used to validate a policy bundle. */\nexport interface PolicyBundleRegoFile {\n /** POSIX-style path relative to the policy bundle directory. */\n path: string;\n /** Rego source contents. */\n contents: string;\n}\n\n/** Validated publishable policy bundle contents. */\nexport interface ValidatedPolicyBundleContents {\n /** Parsed and validated bundle manifest. */\n manifest: PolicyBundleManifest;\n /** Publishable Rego paths, excluding local test modules. */\n publishableRegoPaths: string[];\n}\n\n/**\n * Returns whether a relative path is a publishable Rego policy file.\n *\n * OPA test files (`*_test.rego`) are local-only and excluded from uploads.\n *\n * @param relativePath - Path relative to the bundle directory\n * @returns Whether the file belongs in the uploaded archive\n */\nexport function isPublishableRegoFile(relativePath: string): boolean {\n return relativePath.endsWith('.rego') && !relativePath.endsWith('_test.rego');\n}\n\n/**\n * Parse and validate the Policy Engine bundle manifest.\n *\n * @param contents - Raw manifest contents, or undefined when absent\n * @returns Parsed manifest\n */\nexport function parsePolicyBundleManifest(contents: string | undefined): PolicyBundleManifest {\n if (contents === undefined) {\n throw new Error('Policy bundle directory must contain a manifest.json file.');\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(contents);\n } catch (error) {\n throw new Error(\n `manifest.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('manifest.json must contain a JSON object.');\n }\n\n const roots = (parsed as { roots?: unknown }).roots;\n if (!Array.isArray(roots) || roots.length === 0) {\n throw new Error(\n 'manifest.json must declare \"roots\" as a non-empty array of strings (e.g. {\"roots\":[\"policy_engine\"]}).',\n );\n }\n if (!roots.every((root) => typeof root === 'string' && root.length > 0)) {\n throw new Error('manifest.json \"roots\" must be an array of non-empty strings.');\n }\n if (\n !roots.every((root) =>\n root.split('/').every((segment: string) => /^[A-Za-z_][A-Za-z0-9_]*$/u.test(segment)),\n )\n ) {\n throw new Error(\n 'manifest.json \"roots\" must contain slash-separated Rego identifiers so Policy Engine can re-namespace them safely.',\n );\n }\n\n return { roots };\n}\n\n/**\n * Determine whether one document path starts with another.\n *\n * @param segments - Complete document path\n * @param prefix - Candidate root\n * @returns Whether the root covers the document path\n */\nfunction hasSegmentPrefix(segments: readonly string[], prefix: readonly string[]): boolean {\n return (\n segments.length >= prefix.length &&\n prefix.every((segment, index) => segment === segments[index])\n );\n}\n\n/**\n * Match the package syntax supported by Policy Engine activation.\n *\n * Bracketed segments remain supported below a declared dotted root.\n *\n * @param reference - Parsed package reference\n * @param root - Declared manifest root\n * @returns Whether activation can re-namespace the package\n */\nfunction rootCoversPackage(reference: { source: string }, root: readonly string[]): boolean {\n const dottedRoot = root.join('.');\n const suffix = reference.source.slice(dottedRoot.length);\n return (\n reference.source.startsWith(dottedRoot) &&\n (suffix === '' || suffix.startsWith('.') || /^\\s*\\[/u.test(suffix))\n );\n}\n\n/**\n * Determine whether `data.<root>` is referenced directly.\n *\n * @param segments - Parsed `data` reference segments\n * @param root - Declared manifest root\n * @returns Whether the reference targets the declared root\n */\nfunction referencesDeclaredRoot(segments: readonly string[], root: readonly string[]): boolean {\n return hasSegmentPrefix(segments.slice(1), root);\n}\n\n/**\n * Validate the manifest, publishable file requirement, and root coverage.\n *\n * This is the shared pure upload contract used by both `policy lint` and\n * `policy publish`.\n *\n * @param manifestContents - Raw manifest contents, or undefined when absent\n * @param regoFiles - All Rego files in the policy directory\n * @returns Validated manifest and publishable paths\n */\nexport function validatePolicyBundleContents(\n manifestContents: string | undefined,\n regoFiles: readonly PolicyBundleRegoFile[],\n): ValidatedPolicyBundleContents {\n const manifest = parsePolicyBundleManifest(manifestContents);\n const renderedRoots = manifest.roots.join(', ');\n const publishableFiles = regoFiles\n .filter(({ path }) => isPublishableRegoFile(path))\n .slice()\n .sort((left, right) => left.path.localeCompare(right.path));\n if (publishableFiles.length === 0) {\n throw new Error('Policy bundle directory must contain at least one .rego policy file.');\n }\n\n const rootPrefixes = manifest.roots.map((root) => root.split('/'));\n const uncovered = publishableFiles.flatMap(({ path, contents }) => {\n const packageReference = parseRegoPackageReference(contents);\n if (\n !packageReference ||\n rootPrefixes.some((prefix) => rootCoversPackage(packageReference, prefix))\n ) {\n return [];\n }\n return [\n ` - ${path} (package ${packageReference.source}) is not covered by roots [${renderedRoots}]`,\n ];\n });\n if (uncovered.length > 0) {\n throw new Error(\n [\n 'manifest.json \"roots\" do not cover all Rego packages in the bundle; ' +\n 'uncovered packages will fail-closed at decide time. Either broaden \"roots\" or move the policy under a covered package:',\n ...uncovered,\n ].join('\\n'),\n );\n }\n\n const unsupportedReferences = publishableFiles.flatMap(({ path, contents }) =>\n findDirectDataReferences(contents)\n .filter(({ reference }) =>\n rootPrefixes.some((prefix) => referencesDeclaredRoot(reference.segments, prefix)),\n )\n .map(\n ({ reference, line }) =>\n ` - ${path}:${line} references ${reference.source}; import that package and use its local name`,\n ),\n );\n if (unsupportedReferences.length > 0) {\n throw new Error(\n [\n 'Publishable Rego must not reference its declared bundle roots directly because Policy Engine re-namespaces package imports during activation:',\n ...unsupportedReferences,\n ].join('\\n'),\n );\n }\n\n return {\n manifest,\n publishableRegoPaths: publishableFiles.map(({ path }) => path),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"printResult-CHe3nRN4.mjs","names":[],"sources":["../src/commands/policy/constants.ts","../src/commands/policy/helpers/buildPolicyEngineClient.ts","../src/commands/policy/helpers/formatPolicyEngineRequestError.ts","../src/commands/policy/helpers/printResult.ts"],"sourcesContent":["/** Maximum compressed policy bundle upload size in bytes (5 KiB). */\nexport const MAX_BUNDLE_COMPRESSED_BYTES = 5120;\n\n/** Maximum decompressed policy bundle size enforced by the server (50 KiB). */\nexport const MAX_BUNDLE_DECOMPRESSED_BYTES = 51200;\n\n/** Placeholder for nullable API fields in table output. */\nexport const EMPTY_CELL = '-';\n","import got, { type Got } from 'got';\n\n/**\n * Creates a got client for Policy Engine REST endpoints on the monolith.\n *\n * The CLI appends `v1/...` paths to this base URL, so callers must NOT include\n * a trailing `/v1` (that would produce `/v1/v1/...` and an opaque `400`). We\n * detect and reject that mistake with a clear hint.\n *\n * @param transcendUrl - Transcend API base URL (without `/v1`)\n * @param auth - Transcend API key\n * @returns Configured got instance\n */\nexport function buildPolicyEngineClient(transcendUrl: string, auth: string): Got {\n const normalized = transcendUrl.replace(/\\/$/, '');\n if (/(^|\\/)v1$/i.test(normalized)) {\n throw new Error(\n `--transcend-url must not include a trailing \"/v1\" (the CLI appends it automatically). ` +\n `Got \"${transcendUrl}\"; use \"${normalized.replace(/\\/v1$/i, '')}\" instead.`,\n );\n }\n return got.extend({\n prefixUrl: normalized,\n headers: {\n Authorization: `Bearer ${auth}`,\n accept: 'application/json',\n },\n });\n}\n","import { PolicyEngineCliError } from './policyEngineCliError.js';\n\n/** Parsed JSON error body from a Policy Engine API response. */\ninterface PolicyEngineErrorBody {\n /** Human-readable error message */\n message?: string;\n}\n\n/** HTTP response metadata on a got HTTPError. */\ninterface PolicyEngineHttpResponse {\n /** HTTP status code */\n statusCode?: number;\n /** Response body (JSON or raw text) */\n body?: unknown;\n /** Response headers */\n headers?: Record<string, string | string[] | undefined>;\n}\n\n/** Shape of a got HTTPError with response metadata. */\ninterface PolicyEngineHttpError {\n /** HTTP response metadata */\n response?: PolicyEngineHttpResponse;\n}\n\nconst AUTH_ERROR_MESSAGE = `Authentication failed (401 Unauthorized).\n\nYour Transcend API key is missing, invalid, or does not have permission for this command.\n\nFix:\n- Set a valid API key: export TRANSCEND_API_KEY=<your-key>\n or pass --auth=<your-key>\n- Ensure the key has the required Policy Engine scopes (e.g. View/Manage/Activate Policy)\n- Confirm you are pointing at the correct environment (--transcend-url)`;\n\nconst NOT_FOUND_MESSAGE = `Resource not found (404 Not Found).\n\nThe requested policy bundle or version does not exist.\n\nFix:\n- Check the --bundle-name value\n- Run \\`transcend policy bundles\\` to see available bundles\n- Run \\`transcend policy versions --bundle-name=<name>\\` to see available versions`;\n\nconst PAYLOAD_TOO_LARGE_MESSAGE = `Policy bundle upload is too large (413 Payload Too Large).\n\nUploaded bundles must be at most 5 KiB compressed and 50 KiB decompressed gzip tarballs containing only manifest.json and .rego files.\n\nFix:\n- Remove unnecessary files from the bundle directory before publishing\n- Ensure the compiled .tar.gz stays within the upload limits`;\n\nconst NETWORK_ERROR_MESSAGE = `Connection to Transcend failed.\n\nThe Policy Engine API could not be reached.\n\nFix:\n- Check your network connection\n- Confirm --transcend-url points at the correct environment\n- Retry the command in a few moments`;\n\n/**\n * Extracts a human-readable message from a Policy Engine API error body.\n *\n * @param body - Raw or parsed response body\n * @returns API message when present\n */\nfunction extractApiMessage(body: unknown): string | undefined {\n if (typeof body === 'string') {\n try {\n const parsed = JSON.parse(body) as PolicyEngineErrorBody;\n return parsed.message;\n } catch {\n return body.length > 0 ? body : undefined;\n }\n }\n\n if (body && typeof body === 'object' && 'message' in body) {\n const message = (body as PolicyEngineErrorBody).message;\n if (typeof message === 'string' && message.length > 0) {\n return message;\n }\n }\n\n return undefined;\n}\n\n/**\n * Reads a single response header value.\n *\n * @param headers - Response headers\n * @param name - Header name\n * @returns Header value when present\n */\nfunction readResponseHeader(\n headers: Record<string, string | string[] | undefined> | undefined,\n name: string,\n): string | undefined {\n if (!headers) {\n return undefined;\n }\n\n const value = headers[name] ?? headers[name.toLowerCase()];\n if (Array.isArray(value)) {\n return value[0];\n }\n\n return value;\n}\n\n/**\n * Builds a rate-limit error message using response headers when available.\n *\n * @param apiMessage - Message from the response body, when present\n * @param headers - Response headers\n * @returns User-readable rate-limit text\n */\nfunction formatRateLimitMessage(\n apiMessage: string | undefined,\n headers: Record<string, string | string[] | undefined> | undefined,\n): string {\n if (apiMessage) {\n return apiMessage;\n }\n\n const retryAfter = readResponseHeader(headers, 'retry-after');\n const resetAt = readResponseHeader(headers, 'x-ratelimit-reset');\n\n let message = `Rate limit exceeded (429 Too Many Requests).\n\nFix:\n- Wait and retry the command`;\n\n if (retryAfter) {\n message += `\\n- Retry after ${retryAfter} second(s)`;\n } else if (resetAt) {\n message += `\\n- Retry after ${resetAt}`;\n }\n\n return message;\n}\n\n/**\n * Maps common HTTP status codes to actionable CLI messages.\n *\n * @param statusCode - HTTP status code\n * @param apiMessage - Message from the API response body, when present\n * @param headers - Response headers\n * @returns User-readable error text\n */\nfunction formatHttpStatusError(\n statusCode: number,\n apiMessage?: string,\n headers?: Record<string, string | string[] | undefined>,\n): string {\n switch (statusCode) {\n case 401:\n return AUTH_ERROR_MESSAGE;\n case 403:\n return (\n apiMessage ??\n 'Access was denied (403 Forbidden). If this persists, contact your Transcend admin.'\n );\n case 404:\n return NOT_FOUND_MESSAGE;\n case 400:\n return apiMessage ?? 'The request was invalid. Check your command flags and try again.';\n case 409:\n return apiMessage ?? 'The request conflicted with the current policy bundle state.';\n case 413:\n return apiMessage ?? PAYLOAD_TOO_LARGE_MESSAGE;\n case 429:\n return formatRateLimitMessage(apiMessage, headers);\n default:\n if (statusCode >= 500) {\n return `Transcend server error (${statusCode}). Try again in a few moments. If the problem persists, contact Transcend support.`;\n }\n return apiMessage ?? `Request failed with status code ${statusCode}.`;\n }\n}\n\n/**\n * Returns true when the error looks like a network or timeout failure.\n *\n * @param error - Thrown error\n * @returns Whether the error is likely a connectivity issue\n */\nfunction isNetworkError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const code = (error as NodeJS.ErrnoException).code;\n if (\n code === 'ECONNREFUSED' ||\n code === 'ENOTFOUND' ||\n code === 'ETIMEDOUT' ||\n code === 'ECONNRESET'\n ) {\n return true;\n }\n\n const message = error.message.toLowerCase();\n return (\n message.includes('network') ||\n message.includes('timeout') ||\n message.includes('econnrefused') ||\n message.includes('enotfound') ||\n message.includes('etimedout')\n );\n}\n\n/**\n * Extracts a useful error message from a failed Policy Engine HTTP request.\n *\n * @param error - The thrown error, typically a got `HTTPError`\n * @returns A message suitable for CLI output\n */\nexport function formatPolicyEngineRequestError(error: unknown): string {\n if (isNetworkError(error)) {\n return NETWORK_ERROR_MESSAGE;\n }\n\n if (error && typeof error === 'object' && 'response' in error) {\n const response = (error as PolicyEngineHttpError).response;\n const statusCode = response?.statusCode;\n const apiMessage = extractApiMessage(response?.body);\n\n if (statusCode) {\n return formatHttpStatusError(statusCode, apiMessage, response?.headers);\n }\n\n if (apiMessage) {\n return apiMessage;\n }\n }\n\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Rethrows a Policy Engine request failure with a user-readable message.\n *\n * @param error - The thrown error, typically a got `HTTPError`\n */\nexport function throwPolicyEngineRequestError(error: unknown): never {\n throw new PolicyEngineCliError(formatPolicyEngineRequestError(error), { cause: error });\n}\n\n/**\n * Awaits a Policy Engine HTTP request and maps failures to user-readable errors.\n *\n * @param request - Promise returned by a got client call (e.g. `.json()`)\n * @returns Parsed response body\n */\nexport async function policyEngineRequest<T>(request: Promise<T>): Promise<T> {\n try {\n return await request;\n } catch (error) {\n throwPolicyEngineRequestError(error);\n }\n}\n","/** Options for printing CLI command output. */\nexport interface PrintResultOptions {\n /** When true, print raw JSON */\n json: boolean;\n /** JSON-serializable payload */\n data: unknown;\n /** Table renderer used when json is false */\n renderTable?: () => string;\n}\n\n/**\n * Prints JSON or a human-readable table to stdout.\n *\n * @param stdout - Process stdout stream\n * @param options - Output options\n */\nexport function printResult(stdout: NodeJS.WriteStream, options: PrintResultOptions): void {\n if (options.json) {\n stdout.write(`${JSON.stringify(options.data, null, 2)}\\n`);\n return;\n }\n\n if (options.renderTable) {\n stdout.write(`${options.renderTable()}\\n`);\n }\n}\n"],"mappings":"2EACA,MAAa,EAA8B,KAG9B,EAAgC,MCS7C,SAAgB,EAAwB,EAAsB,EAAmB,CAC/E,IAAM,EAAa,EAAa,QAAQ,MAAO,GAAG,CAClD,GAAI,aAAa,KAAK,EAAW,CAC/B,MAAU,MACR,8FACU,EAAa,UAAU,EAAW,QAAQ,SAAU,GAAG,CAAC,YACnE,CAEH,OAAO,EAAI,OAAO,CAChB,UAAW,EACX,QAAS,CACP,cAAe,UAAU,IACzB,OAAQ,mBACT,CACF,CAAC,CCuCJ,SAAS,EAAkB,EAAmC,CAC5D,GAAI,OAAO,GAAS,SAClB,GAAI,CAEF,OADe,KAAK,MAAM,EACb,CAAC,aACR,CACN,OAAO,EAAK,OAAS,EAAI,EAAO,IAAA,GAIpC,GAAI,GAAQ,OAAO,GAAS,UAAY,YAAa,EAAM,CACzD,IAAM,EAAW,EAA+B,QAChD,GAAI,OAAO,GAAY,UAAY,EAAQ,OAAS,EAClD,OAAO,GAcb,SAAS,EACP,EACA,EACoB,CACpB,GAAI,CAAC,EACH,OAGF,IAAM,EAAQ,EAAQ,IAAS,EAAQ,EAAK,aAAa,EAKzD,OAJI,MAAM,QAAQ,EAAM,CACf,EAAM,GAGR,EAUT,SAAS,EACP,EACA,EACQ,CACR,GAAI,EACF,OAAO,EAGT,IAAM,EAAa,EAAmB,EAAS,cAAc,CACvD,EAAU,EAAmB,EAAS,oBAAoB,CAE5D,EAAU;;;8BAWd,OANI,EACF,GAAW,mBAAmB,EAAW,YAChC,IACT,GAAW,mBAAmB,KAGzB,EAWT,SAAS,EACP,EACA,EACA,EACQ,CACR,OAAQ,EAAR,CACE,IAAK,KACH,MAAO;;;;;;;;yEACT,IAAK,KACH,OACE,GACA,qFAEJ,IAAK,KACH,MAAO;;;;;;;oFACT,IAAK,KACH,OAAO,GAAc,mEACvB,IAAK,KACH,OAAO,GAAc,+DACvB,IAAK,KACH,OAAO,GAAc;;;;;;8DACvB,IAAK,KACH,OAAO,EAAuB,EAAY,EAAQ,CACpD,QAIE,OAHI,GAAc,IACT,2BAA2B,EAAW,oFAExC,GAAc,mCAAmC,EAAW,IAUzE,SAAS,EAAe,EAAyB,CAC/C,GAAI,EAAE,aAAiB,OACrB,MAAO,GAGT,IAAM,EAAQ,EAAgC,KAC9C,GACE,IAAS,gBACT,IAAS,aACT,IAAS,aACT,IAAS,aAET,MAAO,GAGT,IAAM,EAAU,EAAM,QAAQ,aAAa,CAC3C,OACE,EAAQ,SAAS,UAAU,EAC3B,EAAQ,SAAS,UAAU,EAC3B,EAAQ,SAAS,eAAe,EAChC,EAAQ,SAAS,YAAY,EAC7B,EAAQ,SAAS,YAAY,CAUjC,SAAgB,EAA+B,EAAwB,CACrE,GAAI,EAAe,EAAM,CACvB,MAAO;;;;;;;sCAGT,GAAI,GAAS,OAAO,GAAU,UAAY,aAAc,EAAO,CAC7D,IAAM,EAAY,EAAgC,SAC5C,EAAa,GAAU,WACvB,EAAa,EAAkB,GAAU,KAAK,CAEpD,GAAI,EACF,OAAO,EAAsB,EAAY,EAAY,GAAU,QAAQ,CAGzE,GAAI,EACF,OAAO,EAIX,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAQ/D,SAAgB,EAA8B,EAAuB,CACnE,MAAM,IAAI,EAAqB,EAA+B,EAAM,CAAE,CAAE,MAAO,EAAO,CAAC,CASzF,eAAsB,EAAuB,EAAiC,CAC5E,GAAI,CACF,OAAO,MAAM,QACN,EAAO,CACd,EAA8B,EAAM,EClPxC,SAAgB,EAAY,EAA4B,EAAmC,CACzF,GAAI,EAAQ,KAAM,CAChB,EAAO,MAAM,GAAG,KAAK,UAAU,EAAQ,KAAM,KAAM,EAAE,CAAC,IAAI,CAC1D,OAGE,EAAQ,aACV,EAAO,MAAM,GAAG,EAAQ,aAAa,CAAC,IAAI"}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./prompts-ClBXdELk.mjs";import{t}from"./path-safety-D5Qwl40b.mjs";import{basename as n,dirname as r,join as i,relative as a,resolve as o,sep as s}from"node:path";function c(e,t){try{return e.fs.lstatSync(t),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}function l(e,t){if(!c(e,t))return{kind:`absent`,path:t};let n=e.fs.lstatSync(t);if(n.isSymbolicLink())return{kind:`link`,path:t,target:e.fs.readlinkSync(t)};if(!n.isFile())throw Error(`Cannot transactionally replace non-file path: ${t}`);return{kind:`file`,path:t,contents:e.fs.readFileSync(t,`utf8`),mode:n.mode}}function u(e,t,a,o){e.fs.mkdirSync(r(t),{recursive:!0});let s=i(r(t),`.${n(t)}.${e.process.pid}.${Date.now()}.tmp`);try{e.fs.writeFileSync(s,a,o===void 0?void 0:{mode:o&511}),e.fs.renameSync(s,t)}finally{c(e,s)&&e.fs.rmSync(s,{force:!0})}}function d(e,t,a,o){e.fs.mkdirSync(r(t),{recursive:!0});let s=i(r(t),`.${n(t)}.${e.process.pid}.${Date.now()}.tmp`);try{e.fs.writeFileSync(s,a,o===void 0?void 0:{mode:o&511}),e.fs.linkSync(s,t)}finally{c(e,s)&&e.fs.rmSync(s,{force:!0})}}function f(e,t){if(t.kind===`absent`){c(e,t.path)&&e.fs.rmSync(t.path,{recursive:!0,force:!0});return}if(e.fs.mkdirSync(r(t.path),{recursive:!0}),t.kind===`link`){c(e,t.path)&&e.fs.rmSync(t.path,{recursive:!0,force:!0}),e.fs.symlinkSync(t.target,t.path,`dir`);return}c(e,t.path)&&!e.fs.lstatSync(t.path).isFile()&&e.fs.rmSync(t.path,{recursive:!0,force:!0}),u(e,t.path,t.contents,t.mode)}function p(e,t){let n=c(e,t.path);if(t.before===null){if(n)throw Error(`File appeared after preview: ${t.path}`);return}if(!n)throw Error(`File changed after preview: ${t.path}`);let r=e.fs.lstatSync(t.path);if(!r.isFile()||t.mode!==void 0&&r.mode!==t.mode||e.fs.readFileSync(t.path,`utf8`)!==t.before)throw Error(`File changed after preview: ${t.path}`);if(t.createOnly)throw Error(`Refusing to overwrite existing file: ${t.path}`)}function m(e,t){if(t.kind===`file`){p(e,t);return}if(c(e,t.path))throw Error(`Skill target appeared after preview: ${t.path}`)}function h(t,n){let r=e(t,n.path);if(r.length!==n.relativePaths.length||r.some((e,t)=>e!==n.relativePaths[t]))throw Error(`Directory changed after preview: ${n.path}`)}function g(e,t){let n=o(t.rootDirectory),i=new Set;for(let l of t.changes){let t=r(o(l.path));for(;;){let o=a(n,t);if(o===`..`||o.startsWith(`..${s}`)||(c(e,t)||i.add(t),t===n))break;t=r(t)}}return[...i].sort((e,t)=>t.split(s).length-e.split(s).length)}function _(e,t){let n=[];for(let r of t)if(c(e,r))try{e.fs.rmdirSync(r)}catch(e){e.code!==`ENOENT`&&n.push(`${r}: ${e.message}`)}return n}function v(e,n,a){try{e.fs.symlinkSync(n.target,n.path,`dir`)}catch(o){let s=o.code;if(![`EPERM`,`EACCES`,`ENOTSUP`,`UNKNOWN`].includes(s??``))throw o;n.fallbackFiles.forEach(o=>{let s=i(n.path,o.path);t(e,a,s),e.fs.mkdirSync(r(s),{recursive:!0}),e.fs.writeFileSync(s,o.contents)})}}async function y(e,n){for(let r of n.changes)t(e,n.rootDirectory,r.path),m(e,r);for(let r of n.directoryPreconditions??[])t(e,n.rootDirectory,r.path),h(e,r);let r=g(e,n),i=[];try{for(let r of n.changes)if(t(e,n.rootDirectory,r.path),m(e,r),r.kind===`file`){let t=l(e,r.path);r.before===null?d(e,r.path,r.after,r.mode):u(e,r.path,r.after,r.mode),i.push(t)}else i.push({kind:`absent`,path:r.path}),v(e,r,n.rootDirectory)}catch(t){let n=[];for(let t of i.reverse())try{f(e,t)}catch(e){n.push(`${t.path}: ${e.message}`)}throw n.push(..._(e,r)),n.length>0?Error(`${t.message}\nRollback also failed:\n${n.join(`
|
|
2
|
-
`)}`):t}}export{y as t};
|
|
3
|
-
//# sourceMappingURL=project-plan-apply-Dvndx455.mjs.map
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./path-safety-D5Qwl40b.mjs";import{dirname as t,isAbsolute as n,join as r,relative as i,resolve as a,sep as o}from"node:path";import s from"colors";import c from"inquirer";import{createTwoFilesPatch as l}from"diff";import{createHash as u}from"node:crypto";function d(e,t){let r=i(e,t).split(o).join(`/`);return r.length===0?`.`:r===`..`||r.startsWith(`../`)||n(r)?t.split(o).join(`/`):r}function f(e){return`'${e.replace(/'/gu,`'\\''`)}'`}function p(e,t){return t.kind===`link`?{kind:`link`,target:`${d(e,t.path)} -> ${t.target}`,description:t.description}:{kind:t.before===null?`create`:`merge`,target:d(e,t.path),description:t.description}}function m(e,t){let n=Math.max(...t.details.map(({label:e})=>e.length+1),0),r=[s.bold(t.title),...t.details.map(({label:e,path:r})=>{let i=`${e}:`.padEnd(n);return` ${s.dim(i)} ${s.cyan(d(t.cwd,r))}`}),``];return e.changes.length===0?r.push(s.dim(`No changes needed.`)):(r.push(s.bold(`Changes`)),e.changes.forEach(e=>{let n=p(t.cwd,e),i={create:s.green(n.kind.padEnd(7)),merge:s.cyan(n.kind.padEnd(7)),link:s.magenta(n.kind.padEnd(7))}[n.kind];if(r.push(` ${i} ${n.target}`),e.kind===`file`&&e.before!==null){let n=d(t.cwd,e.path),i=l(n,n,e.before,e.after,``,``,{context:3});r.push(...i.trimEnd().split(`
|
|
2
|
-
`).map(e=>` ${e}`))}})),e.unchanged.length>0&&(r.push(``,s.bold(`Left unchanged`)),e.unchanged.forEach(e=>r.push(` ${s.dim(d(t.cwd,e))}`))),e.warnings.length>0&&(r.push(``,s.bold(s.yellow(`Warnings`))),e.warnings.forEach(e=>r.push(` ${s.yellow(e)}`))),`${r.join(`
|
|
3
|
-
`)}\n`}function h(e,t){let n=e[t];if(!n)throw Error(`Missing preflight snapshot for ${t}`);return n}function g(e,t){let n=h(e,t);if(n.kind===`directory`||n.kind===`link`)throw Error(`Expected a regular file or absent path: ${t}`);return n.kind===`file`?{path:t,contents:n.contents,mode:n.mode}:{path:t,contents:null}}function _(e){let{snapshot:t,after:n,description:r,createOnly:i}=e;if(i&&t.contents!==null)throw Error(`Refusing to overwrite existing file: ${t.path}`);if(t.contents!==n)return{kind:`file`,path:t.path,before:t.contents,after:n,description:r,...t.mode===void 0?{}:{mode:t.mode},...i===void 0?{}:{createOnly:i}}}const v=`.agents/skills`,y=[`.aider-desk/skills`,v,`.autohand/skills`,`.augment/skills`,`.bob/skills`,`.claude/skills`,`.codeartsdoer/skills`,`.codebuddy/skills`,`.codemaker/skills`,`.codestudio/skills`,`.commandcode/skills`,`.continue/skills`,`.cortex/skills`,`.crush/skills`,`.devin/skills`,`.factory/skills`,`agent/skills`,`.forge/skills`,`.goose/skills`,`.grok/skills`,`.hermes/skills`,`.inferencesh/skills`,`.jazz/skills`,`.junie/skills`,`.iflow/skills`,`.kilocode/skills`,`.kimchi/skills`,`.kiro/skills`,`.kode/skills`,`.lingma/skills`,`.mcpjam/skills`,`.minimax/skills`,`.vibe/skills`,`.moxby/skills`,`.mux/skills`,`.openhands/skills`,`.ona/skills`,`.pi/skills`,`.posit/assistant/skills`,`.qoder/skills`,`.qwen/skills`,`.reasonix/skills`,`.rovodev/skills`,`.roo/skills`,`.tabnine/agent/skills`,`.terramind/skills`,`.tinycloud/skills`,`.trae/skills`,`.windsurf/skills`,`.zcode/skills`,`.zencoder/skills`,`.neovate/skills`,`.pochi/skills`,`.adal/skills`],b=[v,`.cursor/skills`,`.codex/skills`,`.github/skills`,`.gemini/skills`,`.opencode/skills`,`.cline/skills`,`.warp/skills`,`.zed/skills`,`.replit/skills`];function x(e){return e.length===1?{canonical:e[0].path,aliases:[]}:{canonical:v,aliases:e.length>1?e.filter(({path:e,supportsAgentsSkills:t})=>e!==`.agents/skills`&&!t).map(({path:e})=>e):[]}}function S(e,t){let n=e.trimEnd();return`${n}\n\n<!-- managed-by: ${t}; content-sha256: ${u(`sha256`).update(n).digest(`hex`)} -->\n`}function C(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`),r=e.match(RegExp(`<!-- managed-by: ${n}; content-sha256: ([a-f0-9]{64}) -->\\s*$`,`u`));if(!r||r.index===void 0)return!1;let i=e.slice(0,r.index).trimEnd();return u(`sha256`).update(i).digest(`hex`)===r[1]}function w(e,t,n){let i=x(t),a=new Set,o=r(e,i.canonical,n.name);return n.files.forEach(({path:e})=>a.add(r(o,e))),i.aliases.forEach(t=>{let i=r(e,t,n.name);a.add(i),n.files.forEach(({path:e})=>a.add(r(i,e)))}),t.forEach(({path:t})=>{n.files.forEach(({path:i})=>{a.add(r(e,t,n.name,i))})}),[...a].sort((e,t)=>e.localeCompare(t))}function T(e){let{rootDirectory:n,existingDirectories:a,snapshots:o,skill:s,preserveModified:c=!1}=e,l={changes:[],unchanged:[],warnings:[]},u=x(a),d=r(n,u.canonical,s.name),f=s.files.map(e=>({path:e.path,contents:S(e.contents,s.owner)})),p=(e,t)=>{f.forEach(n=>{let i=r(e,n.path),a=g(o,i);if(a.contents!==null&&a.contents!==n.contents&&!C(a.contents,s.owner)){if(c){l.unchanged.push(i),l.warnings.push(`Customized managed skill file was left unchanged: ${i}. Merge the updated guidance manually.`);return}throw Error(`Refusing to replace user-managed skill: ${i}. Apply the skill update manually.`)}let u=_({snapshot:a,after:n.contents,description:`${t}: ${n.path}`});u?l.changes.push(u):l.unchanged.push(i)})};return p(d,`Install ${s.displayName} skill file`),u.aliases.forEach(e=>{let a=r(n,e,s.name),u=h(o,a),m=i(t(a),d);if(u.kind===`link`&&u.target===m){l.unchanged.push(a);return}if(u.kind===`directory`){p(a,`Update ${s.displayName} skill copy in ${e}`);return}if(u.kind!==`absent`){if(c){l.unchanged.push(a),l.warnings.push(`Customized skill target was left unchanged: ${a}. Expose the canonical skill manually if needed.`);return}throw Error(`Refusing to replace unexpected skill target: ${a}`)}let g={kind:`link`,path:a,target:m,fallbackFiles:f,description:`Expose the canonical skill in ${e}`};l.changes.push(g)}),a.map(({path:e})=>e).filter(e=>e!==u.canonical&&!u.aliases.includes(e)).forEach(e=>{let t=r(n,e,s.name),i=r(t,`SKILL.md`),a=g(o,i);a.contents!==null&&C(a.contents,s.owner)?p(t,`Update existing managed skill in ${e}`):a.contents?.includes(`managed-by: ${s.owner}`)&&(l.unchanged.push(i),l.warnings.push(`Existing customized managed skill was left unchanged: ${t}`))}),l}function E(t,n,r){return Object.fromEntries(r.map(r=>{e(t,n,r);try{let e=t.fs.lstatSync(r);if(e.isSymbolicLink())return[r,{kind:`link`,path:r,target:t.fs.readlinkSync(r)}];if(e.isDirectory())return[r,{kind:`directory`,path:r}];if(!e.isFile())throw Error(`Unsupported filesystem entry: ${r}`);return[r,{kind:`file`,path:r,contents:t.fs.readFileSync(r,`utf8`),mode:e.mode}]}catch(e){if(e.code===`ENOENT`)return[r,{kind:`absent`,path:r}];throw e}}))}function D(e,n){let i=n;for(;;){if(e.fs.existsSync(r(i,`.git`)))return i;let n=t(i);if(n===i)return;i=n}}function O(e,n){let r=n;for(;!e.fs.existsSync(r);){let e=t(r);if(e===r)return r;r=e}return e.fs.statSync(r).isDirectory()?r:t(r)}function k(e,t){let r=i(e,t);return r!==`..`&&!r.startsWith(`..${o}`)&&!n(r)}function A(e,t,n={}){if(!e.fs.existsSync(t))return[];let a=[],s=c=>{e.fs.readdirSync(c,{withFileTypes:!0}).forEach(e=>{if(e.name===`.git`||e.name===`node_modules`)return;let l=r(c,e.name),u=e.isDirectory()&&!e.isSymbolicLink();(n.includeDirectories!==!1||!u)&&a.push(i(t,l).split(o).join(`/`)),u&&s(l)})};return s(t),a.sort((e,t)=>e.localeCompare(t))}function j(e,t,n){return n===0?!1:e.fs.readdirSync(t,{withFileTypes:!0}).some(i=>{if(!i.isDirectory()||i.isSymbolicLink())return!1;let a=r(t,i.name);return e.fs.existsSync(r(a,`SKILL.md`))||j(e,a,n-1)})}function M(e,t){if(!e.fs.existsSync(t)||!e.fs.statSync(t).isDirectory())return[];let n=new Set(b),i=new Set([...y,...b]);return e.fs.readdirSync(t,{withFileTypes:!0}).forEach(n=>{if(!n.isDirectory()||n.isSymbolicLink())return;let a=r(t,n.name,`skills`);e.fs.existsSync(a)&&e.fs.statSync(a).isDirectory()&&j(e,a,3)&&i.add(`${n.name}/skills`)}),[...i].filter(n=>{let i=r(t,n);return e.fs.existsSync(i)&&e.fs.statSync(i).isDirectory()}).sort((e,t)=>e.localeCompare(t)).map(e=>({path:e,supportsAgentsSkills:n.has(e)}))}function N(e,t){if(!t)return!1;if(e.fs.existsSync(r(t,`.github`)))return!0;let n=r(t,`.git`),i=n;if(e.fs.existsSync(n)&&e.fs.statSync(n).isFile()){let r=e.fs.readFileSync(n,`utf8`).match(/^gitdir:\s*(.+)$/mu)?.[1];r&&(i=a(t,r))}let o=r(i,`commondir`);e.fs.existsSync(o)&&e.fs.statSync(o).isFile()&&(i=a(i,e.fs.readFileSync(o,`utf8`).trim()));let s=r(i,`config`);return e.fs.existsSync(s)&&e.fs.readFileSync(s,`utf8`).includes(`github.com`)}function P(t,n){let r=D(t,O(t,n.invocationDirectory)),i=r&&k(r,n.targetDirectory)?r:D(t,O(t,n.targetDirectory)),a=n.standaloneProjectRoot!==n.targetDirectory&&k(n.standaloneProjectRoot,n.targetDirectory),o=i,s=a?r??n.standaloneProjectRoot:o??n.standaloneProjectRoot;return e(t,s,n.targetDirectory),{projectRoot:s,...o?{repositoryRoot:o}:{},existingSkillDirectories:M(t,s),usesGithub:N(t,o)}}var F=class extends Error{constructor(){super(`Prompt cancelled.`),this.name=`PromptCancelledError`}};function I(e){let t=e instanceof Error?e.message:String(e);return e instanceof F||/force closed|prompt.*cancel|user.*close|SIGINT/iu.test(t)?new F:e instanceof Error?e:Error(t)}var L=class{prompt;constructor(e){this.prompt=c.createPromptModule({input:e.process.stdin,output:e.process.stderr})}async text(e,t,n){try{return(await this.prompt([{type:`input`,name:`value`,message:e,...t===void 0?{}:{default:t},validate:e=>{let t=e.trim();return t.length>0?n?.(t)??!0:`Enter a value.`}}])).value.trim()}catch(e){throw I(e)}}async select(e,t,n){try{return(await this.prompt([{type:`list`,name:`value`,message:e,choices:[...t],...n===void 0?{}:{default:n}}])).value}catch(e){throw I(e)}}async checkbox(e,t){try{return(await this.prompt([{type:`checkbox`,name:`value`,message:e,choices:[...t]}])).value}catch(e){throw I(e)}}async confirm(e,t=!0){try{return(await this.prompt([{type:`confirm`,name:`value`,message:e,default:t}])).value}catch(e){throw I(e)}}};export{P as a,w as c,h as d,_ as f,p as g,m as h,A as i,T as l,f as m,L as n,O as o,d as p,E as r,D as s,F as t,g as u};
|
|
4
|
-
//# sourceMappingURL=prompts-ClBXdELk.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prompts-ClBXdELk.mjs","names":[],"sources":["../src/lib/scaffolding/project-plan-output.ts","../src/lib/scaffolding/project-plan.ts","../src/lib/scaffolding/agent-skill.ts","../src/lib/scaffolding/project-discovery.ts","../src/lib/scaffolding/prompts.ts"],"sourcesContent":["import { isAbsolute, relative, sep } from 'node:path';\n\nimport colors from 'colors';\nimport { createTwoFilesPatch } from 'diff';\n\nimport type { PlannedChange, ProjectPlan } from './project-plan.js';\n\n/** Stable public description of one planned mutation. */\nexport interface PublicPlannedChange {\n /** Create, merge, or link. */\n kind: 'create' | 'merge' | 'link';\n /** Display path. */\n target: string;\n /** Human-readable reason. */\n description: string;\n}\n\n/** Project plan fields displayed in a terminal preview. */\nexport interface DisplayableProjectPlan extends ProjectPlan {\n /** Files inspected and deliberately left unchanged. */\n unchanged: readonly string[];\n /** Non-fatal plan warnings. */\n warnings: readonly string[];\n}\n\n/** One project path displayed above a plan. */\nexport interface ProjectPlanDetail {\n /** Human-readable field label without a colon. */\n label: string;\n /** Absolute project path. */\n path: string;\n}\n\n/**\n * Prefer a portable path relative to the invocation directory.\n *\n * @param cwd - Process working directory\n * @param path - Absolute path\n * @returns Relative path when contained by cwd, otherwise the absolute path\n */\nexport function displayProjectPath(cwd: string, path: string): string {\n const value = relative(cwd, path).split(sep).join('/');\n if (value.length === 0) {\n return '.';\n }\n if (value === '..' || value.startsWith('../') || isAbsolute(value)) {\n return path.split(sep).join('/');\n }\n return value;\n}\n\n/**\n * Quote one value for POSIX-compatible command snippets.\n *\n * @param value - Raw command argument\n * @returns Safely single-quoted argument\n */\nexport function quoteShellArgument(value: string): string {\n return `'${value.replace(/'/gu, \"'\\\\''\")}'`;\n}\n\n/**\n * Convert an internal mutation to its stable public shape.\n *\n * @param cwd - Working directory\n * @param change - Internal mutation\n * @returns Public mutation\n */\nexport function toPublicPlannedChange(cwd: string, change: PlannedChange): PublicPlannedChange {\n if (change.kind === 'link') {\n return {\n kind: 'link',\n target: `${displayProjectPath(cwd, change.path)} -> ${change.target}`,\n description: change.description,\n };\n }\n return {\n kind: change.before === null ? 'create' : 'merge',\n target: displayProjectPath(cwd, change.path),\n description: change.description,\n };\n}\n\n/**\n * Render a human-readable complete project plan.\n *\n * @param plan - Project plan\n * @param options - Domain heading and project paths\n * @returns Preview text\n */\nexport function renderProjectPlan(\n plan: DisplayableProjectPlan,\n options: {\n /** Working directory for portable paths. */\n cwd: string;\n /** Domain-specific plan heading. */\n title: string;\n /** Project paths displayed above changes. */\n details: readonly ProjectPlanDetail[];\n },\n): string {\n const widestLabel = Math.max(...options.details.map(({ label }) => label.length + 1), 0);\n const lines = [\n colors.bold(options.title),\n ...options.details.map(({ label, path }) => {\n const paddedLabel = `${label}:`.padEnd(widestLabel);\n return ` ${colors.dim(paddedLabel)} ${colors.cyan(displayProjectPath(options.cwd, path))}`;\n }),\n '',\n ];\n if (plan.changes.length === 0) {\n lines.push(colors.dim('No changes needed.'));\n } else {\n lines.push(colors.bold('Changes'));\n plan.changes.forEach((change) => {\n const item = toPublicPlannedChange(options.cwd, change);\n const kind = {\n create: colors.green(item.kind.padEnd(7)),\n merge: colors.cyan(item.kind.padEnd(7)),\n link: colors.magenta(item.kind.padEnd(7)),\n }[item.kind];\n lines.push(` ${kind} ${item.target}`);\n if (change.kind === 'file' && change.before !== null) {\n const path = displayProjectPath(options.cwd, change.path);\n const patch = createTwoFilesPatch(path, path, change.before, change.after, '', '', {\n context: 3,\n });\n lines.push(\n ...patch\n .trimEnd()\n .split('\\n')\n .map((line) => ` ${line}`),\n );\n }\n });\n }\n if (plan.unchanged.length > 0) {\n lines.push('', colors.bold('Left unchanged'));\n plan.unchanged.forEach((path) =>\n lines.push(` ${colors.dim(displayProjectPath(options.cwd, path))}`),\n );\n }\n if (plan.warnings.length > 0) {\n lines.push('', colors.bold(colors.yellow('Warnings')));\n plan.warnings.forEach((warning) => lines.push(` ${colors.yellow(warning)}`));\n }\n return `${lines.join('\\n')}\\n`;\n}\n","/** A file observed while collecting project state. */\nexport interface ProjectFileSnapshot {\n /** Absolute path. */\n path: string;\n /** Existing UTF-8 contents, or null when absent. */\n contents: string | null;\n /** Existing file mode, when present. */\n mode?: number;\n}\n\n/** State of one potentially mutated path. */\nexport type PlanningPathSnapshot =\n | {\n /** Snapshot kind. */\n kind: 'absent';\n /** Absolute path. */\n path: string;\n }\n | {\n /** Snapshot kind. */\n kind: 'file';\n /** Absolute path. */\n path: string;\n /** UTF-8 contents. */\n contents: string;\n /** File mode. */\n mode: number;\n }\n | {\n /** Snapshot kind. */\n kind: 'link';\n /** Absolute path. */\n path: string;\n /** Link target. */\n target: string;\n }\n | {\n /** Snapshot kind. */\n kind: 'directory';\n /** Absolute path. */\n path: string;\n };\n\n/** A planned regular-file create or update. */\nexport interface PlannedFileChange {\n /** Discriminator. */\n kind: 'file';\n /** Absolute destination path. */\n path: string;\n /** Existing contents expected immediately before apply. */\n before: string | null;\n /** Complete desired contents. */\n after: string;\n /** Human-readable reason. */\n description: string;\n /** Existing file mode to preserve. */\n mode?: number;\n /** Whether an existing destination must always be rejected. */\n createOnly?: boolean;\n}\n\n/** A planned project-local symbolic link with a copy fallback. */\nexport interface PlannedLinkChange {\n /** Discriminator. */\n kind: 'link';\n /** Absolute link path. */\n path: string;\n /** Relative link target. */\n target: string;\n /** Managed files to copy when links are unavailable. */\n fallbackFiles: {\n /** Destination relative to the link path. */\n path: string;\n /** Complete desired contents. */\n contents: string;\n }[];\n /** Human-readable reason. */\n description: string;\n}\n\n/** One staged project mutation. */\nexport type PlannedChange = PlannedFileChange | PlannedLinkChange;\n\n/** Directory contents that must still match their planning snapshot. */\nexport interface PlannedDirectoryPrecondition {\n /** Directory inspected during planning. */\n path: string;\n /** Sorted relative entries expected immediately before apply. */\n relativePaths: string[];\n}\n\n/** Minimal plan consumed by the transactional filesystem applicator. */\nexport interface ProjectPlan {\n /** Approved physical root for every planned mutation. */\n rootDirectory: string;\n /** Directory-wide state that must still match the preview. */\n directoryPreconditions?: PlannedDirectoryPrecondition[];\n /** Ordered staged mutations. */\n changes: PlannedChange[];\n}\n\n/**\n * Read a required candidate snapshot.\n *\n * @param snapshots - Snapshots keyed by absolute path\n * @param path - Absolute path\n * @returns Snapshot\n */\nexport function getPlanningPathSnapshot(\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>,\n path: string,\n): PlanningPathSnapshot {\n const snapshot = snapshots[path];\n if (!snapshot) {\n throw new Error(`Missing preflight snapshot for ${path}`);\n }\n return snapshot;\n}\n\n/**\n * Adapt a planning snapshot to a regular-file plan input.\n *\n * @param snapshots - Snapshots keyed by absolute path\n * @param path - Absolute file path\n * @returns File snapshot\n */\nexport function getPlanningFileSnapshot(\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>,\n path: string,\n): ProjectFileSnapshot {\n const snapshot = getPlanningPathSnapshot(snapshots, path);\n if (snapshot.kind === 'directory' || snapshot.kind === 'link') {\n throw new Error(`Expected a regular file or absent path: ${path}`);\n }\n return snapshot.kind === 'file'\n ? { path, contents: snapshot.contents, mode: snapshot.mode }\n : { path, contents: null };\n}\n\n/**\n * Stage a file only when its desired content differs.\n *\n * @param input - File change input\n * @returns A file change, or undefined for a no-op\n */\nexport function planFileChange(input: {\n /** File snapshot. */\n snapshot: ProjectFileSnapshot;\n /** Desired contents. */\n after: string;\n /** Human-readable reason. */\n description: string;\n /** Refuse every existing file. */\n createOnly?: boolean;\n}): PlannedFileChange | undefined {\n const { snapshot, after, description, createOnly } = input;\n if (createOnly && snapshot.contents !== null) {\n throw new Error(`Refusing to overwrite existing file: ${snapshot.path}`);\n }\n if (snapshot.contents === after) {\n return undefined;\n }\n return {\n kind: 'file',\n path: snapshot.path,\n before: snapshot.contents,\n after,\n description,\n ...(snapshot.mode === undefined ? {} : { mode: snapshot.mode }),\n ...(createOnly === undefined ? {} : { createOnly }),\n };\n}\n","import { createHash } from 'node:crypto';\nimport { dirname, join, relative } from 'node:path';\n\nimport {\n getPlanningFileSnapshot,\n getPlanningPathSnapshot,\n planFileChange,\n type PlannedChange,\n type PlannedLinkChange,\n type PlanningPathSnapshot,\n} from './project-plan.js';\n\n/** Universal project-level Agent Skills directory. */\nexport const UNIVERSAL_AGENT_SKILLS_DIRECTORY = '.agents/skills';\n\n/**\n * Unambiguous agent-owned project directories from vercel-labs/skills at\n * 1682051d48c34f5eb135e6475c1a965dce05e820. Generic skill catalog paths such\n * as `skills` and `data/skills` are excluded because they do not prove that a\n * project has configured an agent.\n */\nexport const PROJECT_SKILL_DIRECTORIES = [\n '.aider-desk/skills',\n UNIVERSAL_AGENT_SKILLS_DIRECTORY,\n '.autohand/skills',\n '.augment/skills',\n '.bob/skills',\n '.claude/skills',\n '.codeartsdoer/skills',\n '.codebuddy/skills',\n '.codemaker/skills',\n '.codestudio/skills',\n '.commandcode/skills',\n '.continue/skills',\n '.cortex/skills',\n '.crush/skills',\n '.devin/skills',\n '.factory/skills',\n 'agent/skills',\n '.forge/skills',\n '.goose/skills',\n '.grok/skills',\n '.hermes/skills',\n '.inferencesh/skills',\n '.jazz/skills',\n '.junie/skills',\n '.iflow/skills',\n '.kilocode/skills',\n '.kimchi/skills',\n '.kiro/skills',\n '.kode/skills',\n '.lingma/skills',\n '.mcpjam/skills',\n '.minimax/skills',\n '.vibe/skills',\n '.moxby/skills',\n '.mux/skills',\n '.openhands/skills',\n '.ona/skills',\n '.pi/skills',\n '.posit/assistant/skills',\n '.qoder/skills',\n '.qwen/skills',\n '.reasonix/skills',\n '.rovodev/skills',\n '.roo/skills',\n '.tabnine/agent/skills',\n '.terramind/skills',\n '.tinycloud/skills',\n '.trae/skills',\n '.windsurf/skills',\n '.zcode/skills',\n '.zencoder/skills',\n '.neovate/skills',\n '.pochi/skills',\n '.adal/skills',\n] as const;\n\n/**\n * Existing legacy/native project directories for agents that the pinned\n * registry installs through `.agents/skills`.\n */\nexport const AGENTS_SKILLS_COMPATIBLE_PROJECT_DIRECTORIES = [\n UNIVERSAL_AGENT_SKILLS_DIRECTORY,\n '.cursor/skills',\n '.codex/skills',\n '.github/skills',\n '.gemini/skills',\n '.opencode/skills',\n '.cline/skills',\n '.warp/skills',\n '.zed/skills',\n '.replit/skills',\n] as const;\n\n/** One existing project-level skill container. */\nexport interface ExistingProjectSkillDirectory {\n /** Repository-relative directory. */\n path: string;\n /** Whether its agent can read the universal Agent Skills directory. */\n supportsAgentsSkills: boolean;\n}\n\n/** One source file in a managed Agent Skill. */\nexport interface AgentSkillFile {\n /** Path relative to the skill directory. */\n path: string;\n /** Complete Markdown contents. */\n contents: string;\n}\n\n/** Portable definition of one CLI-managed Agent Skill. */\nexport interface ManagedAgentSkillDefinition {\n /** Namespaced skill directory name. */\n name: string;\n /** Human-readable domain name used in plan descriptions. */\n displayName: string;\n /** Stable tool identifier written into integrity markers. */\n owner: string;\n /** Complete portable file set. */\n files: readonly AgentSkillFile[];\n}\n\n/** Pure planned mutations for one managed Agent Skill. */\nexport interface ManagedAgentSkillPlan {\n /** Skill file and link changes. */\n changes: PlannedChange[];\n /** Skill paths already in their desired state. */\n unchanged: string[];\n /** Customized paths preserved for manual review. */\n warnings: string[];\n}\n\n/**\n * Choose one canonical skill directory and aliases for incompatible agents.\n *\n * @param existingDirectories - Existing project-level skill containers\n * @returns Canonical and alias directories\n */\nexport function resolveAgentSkillDirectories(\n existingDirectories: readonly ExistingProjectSkillDirectory[],\n): {\n /** Directory that owns the canonical skill. */\n canonical: string;\n /** Existing directories that require links to the canonical skill. */\n aliases: string[];\n} {\n if (existingDirectories.length === 1) {\n return { canonical: existingDirectories[0]!.path, aliases: [] };\n }\n return {\n canonical: UNIVERSAL_AGENT_SKILLS_DIRECTORY,\n aliases:\n existingDirectories.length > 1\n ? existingDirectories\n .filter(({ path, supportsAgentsSkills }) => {\n return path !== UNIVERSAL_AGENT_SKILLS_DIRECTORY && !supportsAgentsSkills;\n })\n .map(({ path }) => path)\n : [],\n };\n}\n\n/**\n * Add a digest marker to CLI-managed skill contents.\n *\n * @param contents - Skill Markdown\n * @param owner - Stable tool identifier\n * @returns Managed skill contents\n */\nexport function buildManagedAgentSkill(contents: string, owner: string): string {\n const body = contents.trimEnd();\n const digest = createHash('sha256').update(body).digest('hex');\n return `${body}\\n\\n<!-- managed-by: ${owner}; content-sha256: ${digest} -->\\n`;\n}\n\n/**\n * Check whether managed skill contents still match their recorded digest.\n *\n * @param contents - Existing skill Markdown\n * @param owner - Stable tool identifier\n * @returns Whether automatic replacement is safe\n */\nexport function isUnmodifiedManagedAgentSkill(contents: string, owner: string): boolean {\n const escapedOwner = owner.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n const marker = contents.match(\n new RegExp(`<!-- managed-by: ${escapedOwner}; content-sha256: ([a-f0-9]{64}) -->\\\\s*$`, 'u'),\n );\n if (!marker || marker.index === undefined) {\n return false;\n }\n const body = contents.slice(0, marker.index).trimEnd();\n return createHash('sha256').update(body).digest('hex') === marker[1];\n}\n\n/**\n * Enumerate paths that may be touched while installing a managed Agent Skill.\n *\n * @param rootDirectory - Root that owns project-level skill directories\n * @param existingDirectories - Existing project-level skill containers\n * @param skill - Managed skill definition\n * @returns Absolute candidate paths\n */\nexport function getManagedAgentSkillCandidatePaths(\n rootDirectory: string,\n existingDirectories: readonly ExistingProjectSkillDirectory[],\n skill: ManagedAgentSkillDefinition,\n): string[] {\n const directories = resolveAgentSkillDirectories(existingDirectories);\n const paths = new Set<string>();\n const canonicalDirectory = join(rootDirectory, directories.canonical, skill.name);\n skill.files.forEach(({ path }) => paths.add(join(canonicalDirectory, path)));\n directories.aliases.forEach((directory) => {\n const aliasDirectory = join(rootDirectory, directory, skill.name);\n paths.add(aliasDirectory);\n skill.files.forEach(({ path }) => paths.add(join(aliasDirectory, path)));\n });\n existingDirectories.forEach(({ path: directory }) => {\n skill.files.forEach(({ path }) => {\n paths.add(join(rootDirectory, directory, skill.name, path));\n });\n });\n return [...paths].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * Plan one direct managed skill installation and links into other existing directories.\n *\n * @param input - Root, discovered directories, snapshots, and skill definition\n * @returns Pure skill plan\n */\nexport function planManagedAgentSkill(input: {\n /** Root that owns project-level skill directories. */\n rootDirectory: string;\n /** Existing project-level skill containers. */\n existingDirectories: readonly ExistingProjectSkillDirectory[];\n /** Potential mutation paths keyed by absolute path. */\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>;\n /** Managed skill definition. */\n skill: ManagedAgentSkillDefinition;\n /** Preserve customized files and unexpected alias targets with warnings. */\n preserveModified?: boolean;\n}): ManagedAgentSkillPlan {\n const { rootDirectory, existingDirectories, snapshots, skill, preserveModified = false } = input;\n const plan: ManagedAgentSkillPlan = { changes: [], unchanged: [], warnings: [] };\n const directories = resolveAgentSkillDirectories(existingDirectories);\n const canonicalDirectory = join(rootDirectory, directories.canonical, skill.name);\n const managedFiles = skill.files.map((file) => ({\n path: file.path,\n contents: buildManagedAgentSkill(file.contents, skill.owner),\n }));\n const planManagedFiles = (directory: string, description: string): void => {\n managedFiles.forEach((file) => {\n const path = join(directory, file.path);\n const snapshot = getPlanningFileSnapshot(snapshots, path);\n if (\n snapshot.contents !== null &&\n snapshot.contents !== file.contents &&\n !isUnmodifiedManagedAgentSkill(snapshot.contents, skill.owner)\n ) {\n if (preserveModified) {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Customized managed skill file was left unchanged: ${path}. Merge the updated guidance manually.`,\n );\n return;\n }\n throw new Error(\n `Refusing to replace user-managed skill: ${path}. Apply the skill update manually.`,\n );\n }\n const change = planFileChange({\n snapshot,\n after: file.contents,\n description: `${description}: ${file.path}`,\n });\n if (change) {\n plan.changes.push(change);\n } else {\n plan.unchanged.push(path);\n }\n });\n };\n planManagedFiles(canonicalDirectory, `Install ${skill.displayName} skill file`);\n\n directories.aliases.forEach((directory) => {\n const targetDirectory = join(rootDirectory, directory, skill.name);\n const snapshot = getPlanningPathSnapshot(snapshots, targetDirectory);\n const relativeTarget = relative(dirname(targetDirectory), canonicalDirectory);\n if (snapshot.kind === 'link' && snapshot.target === relativeTarget) {\n plan.unchanged.push(targetDirectory);\n return;\n }\n if (snapshot.kind === 'directory') {\n planManagedFiles(targetDirectory, `Update ${skill.displayName} skill copy in ${directory}`);\n return;\n }\n if (snapshot.kind !== 'absent') {\n if (preserveModified) {\n plan.unchanged.push(targetDirectory);\n plan.warnings.push(\n `Customized skill target was left unchanged: ${targetDirectory}. Expose the canonical skill manually if needed.`,\n );\n return;\n }\n throw new Error(`Refusing to replace unexpected skill target: ${targetDirectory}`);\n }\n const change: PlannedLinkChange = {\n kind: 'link',\n path: targetDirectory,\n target: relativeTarget,\n fallbackFiles: managedFiles,\n description: `Expose the canonical skill in ${directory}`,\n };\n plan.changes.push(change);\n });\n\n existingDirectories\n .map(({ path }) => path)\n .filter(\n (directory) =>\n directory !== directories.canonical && !directories.aliases.includes(directory),\n )\n .forEach((directory) => {\n const existingDirectory = join(rootDirectory, directory, skill.name);\n const skillPath = join(existingDirectory, 'SKILL.md');\n const snapshot = getPlanningFileSnapshot(snapshots, skillPath);\n if (\n snapshot.contents !== null &&\n isUnmodifiedManagedAgentSkill(snapshot.contents, skill.owner)\n ) {\n planManagedFiles(existingDirectory, `Update existing managed skill in ${directory}`);\n } else if (snapshot.contents?.includes(`managed-by: ${skill.owner}`)) {\n plan.unchanged.push(skillPath);\n plan.warnings.push(\n `Existing customized managed skill was left unchanged: ${existingDirectory}`,\n );\n }\n });\n\n return plan;\n}\n","import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\n\nimport type { LocalContext } from '../../context.js';\nimport {\n AGENTS_SKILLS_COMPATIBLE_PROJECT_DIRECTORIES,\n PROJECT_SKILL_DIRECTORIES,\n type ExistingProjectSkillDirectory,\n} from './agent-skill.js';\nimport { assertPathPhysicallyContained } from './path-safety.js';\nimport type { PlanningPathSnapshot } from './project-plan.js';\n\n/** Repository-level state shared by project scaffolds. */\nexport interface ProjectRepositoryState {\n /** Root that owns repository-level setup. */\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}\n\n/**\n * Collect candidate paths once, before preview.\n *\n * @param context - CLI context\n * @param rootDirectory - Approved planning root\n * @param paths - Absolute paths\n * @returns In-memory path snapshots\n */\nexport function collectPlanningSnapshots(\n context: LocalContext,\n rootDirectory: string,\n paths: readonly string[],\n): Readonly<Record<string, PlanningPathSnapshot>> {\n return Object.fromEntries(\n paths.map((path): [string, PlanningPathSnapshot] => {\n assertPathPhysicallyContained(context, rootDirectory, path);\n try {\n const stat = context.fs.lstatSync(path);\n if (stat.isSymbolicLink()) {\n return [path, { kind: 'link', path, target: context.fs.readlinkSync(path) }];\n }\n if (stat.isDirectory()) {\n return [path, { kind: 'directory', path }];\n }\n if (!stat.isFile()) {\n throw new Error(`Unsupported filesystem entry: ${path}`);\n }\n return [\n path,\n {\n kind: 'file',\n path,\n contents: context.fs.readFileSync(path, 'utf8'),\n mode: stat.mode,\n },\n ];\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [path, { kind: 'absent', path }];\n }\n throw error;\n }\n }),\n );\n}\n\n/**\n * Walk upward for a repository marker.\n *\n * @param context - CLI context\n * @param startDirectory - Starting directory\n * @returns Nearest repository root\n */\nexport function findRepositoryRoot(\n context: LocalContext,\n startDirectory: string,\n): string | undefined {\n let current = startDirectory;\n while (true) {\n if (context.fs.existsSync(join(current, '.git'))) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n return undefined;\n }\n current = parent;\n }\n}\n\n/**\n * Find the nearest existing ancestor of a target that may not exist yet.\n *\n * @param context - CLI context\n * @param target - Absolute target\n * @returns Existing directory\n */\nexport function findExistingAncestor(context: LocalContext, target: string): string {\n let current = target;\n while (!context.fs.existsSync(current)) {\n const parent = dirname(current);\n if (parent === current) {\n return current;\n }\n current = parent;\n }\n const stat = context.fs.statSync(current);\n return stat.isDirectory() ? current : dirname(current);\n}\n\n/**\n * Determine whether a path is lexically at or below a root.\n *\n * @param root - Candidate parent directory\n * @param path - Candidate descendant\n * @returns Whether the path is contained without resolving links\n */\nfunction isPathContained(root: string, path: string): boolean {\n const child = relative(root, path);\n return child !== '..' && !child.startsWith(`..${sep}`) && !isAbsolute(child);\n}\n\n/**\n * Collect relative paths below a project directory for collision checks.\n *\n * @param context - CLI context\n * @param root - Directory to inspect\n * @param options - Directory-entry inclusion\n * @returns Relative file, link, and directory paths\n */\nexport function collectProjectRelativePaths(\n context: LocalContext,\n root: string,\n options: {\n /** Include directory entries in addition to files and links. */\n includeDirectories?: boolean;\n } = {},\n): string[] {\n if (!context.fs.existsSync(root)) {\n return [];\n }\n const paths: string[] = [];\n const visit = (directory: string): void => {\n context.fs.readdirSync(directory, { withFileTypes: true }).forEach((entry) => {\n if (entry.name === '.git' || entry.name === 'node_modules') {\n return;\n }\n const absolute = join(directory, entry.name);\n const isDirectory = entry.isDirectory() && !entry.isSymbolicLink();\n if (options.includeDirectories !== false || !isDirectory) {\n paths.push(relative(root, absolute).split(sep).join('/'));\n }\n if (isDirectory) {\n visit(absolute);\n }\n });\n };\n visit(root);\n return paths.sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * Determine whether a skill container has a SKILL.md within three levels.\n *\n * @param context - CLI context\n * @param directory - Candidate skill container\n * @param depth - Remaining nested directory levels\n * @returns Whether a skill exists below the container\n */\nfunction containsSkill(context: LocalContext, directory: string, depth: number): boolean {\n if (depth === 0) {\n return false;\n }\n return context.fs.readdirSync(directory, { withFileTypes: true }).some((entry) => {\n if (!entry.isDirectory() || entry.isSymbolicLink()) {\n return false;\n }\n const child = join(directory, entry.name);\n return (\n context.fs.existsSync(join(child, 'SKILL.md')) || containsSkill(context, child, depth - 1)\n );\n });\n}\n\n/**\n * Find existing project skill containers without consulting home directories.\n *\n * @param context - CLI context\n * @param projectRoot - Repository root or standalone project root\n * @returns Existing containers and `.agents/skills` compatibility\n */\nexport function detectExistingProjectSkillDirectories(\n context: LocalContext,\n projectRoot: string,\n): ExistingProjectSkillDirectory[] {\n if (!context.fs.existsSync(projectRoot) || !context.fs.statSync(projectRoot).isDirectory()) {\n return [];\n }\n const compatible = new Set<string>(AGENTS_SKILLS_COMPATIBLE_PROJECT_DIRECTORIES);\n const candidates = new Set<string>([\n ...PROJECT_SKILL_DIRECTORIES,\n ...AGENTS_SKILLS_COMPATIBLE_PROJECT_DIRECTORIES,\n ]);\n context.fs.readdirSync(projectRoot, { withFileTypes: true }).forEach((entry) => {\n if (!entry.isDirectory() || entry.isSymbolicLink()) {\n return;\n }\n const skillsDirectory = join(projectRoot, entry.name, 'skills');\n if (\n context.fs.existsSync(skillsDirectory) &&\n context.fs.statSync(skillsDirectory).isDirectory() &&\n containsSkill(context, skillsDirectory, 3)\n ) {\n candidates.add(`${entry.name}/skills`);\n }\n });\n return [...candidates]\n .filter((candidate) => {\n const path = join(projectRoot, candidate);\n return context.fs.existsSync(path) && context.fs.statSync(path).isDirectory();\n })\n .sort((left, right) => left.localeCompare(right))\n .map((path) => ({\n path,\n supportsAgentsSkills: compatible.has(path),\n }));\n}\n\n/**\n * Detect whether a git repository points at GitHub.\n *\n * @param context - CLI context\n * @param repositoryRoot - Repository root\n * @returns Whether GitHub setup is applicable\n */\nexport function repositoryUsesGithub(\n context: LocalContext,\n repositoryRoot: string | undefined,\n): boolean {\n if (!repositoryRoot) {\n return false;\n }\n if (context.fs.existsSync(join(repositoryRoot, '.github'))) {\n return true;\n }\n const gitMarker = join(repositoryRoot, '.git');\n let gitDirectory = gitMarker;\n if (context.fs.existsSync(gitMarker) && context.fs.statSync(gitMarker).isFile()) {\n const marker = context.fs.readFileSync(gitMarker, 'utf8').match(/^gitdir:\\s*(.+)$/mu)?.[1];\n if (marker) {\n gitDirectory = resolve(repositoryRoot, marker);\n }\n }\n const commonDirectoryPath = join(gitDirectory, 'commondir');\n if (\n context.fs.existsSync(commonDirectoryPath) &&\n context.fs.statSync(commonDirectoryPath).isFile()\n ) {\n gitDirectory = resolve(\n gitDirectory,\n context.fs.readFileSync(commonDirectoryPath, 'utf8').trim(),\n );\n }\n const configPath = join(gitDirectory, 'config');\n return (\n context.fs.existsSync(configPath) &&\n context.fs.readFileSync(configPath, 'utf8').includes('github.com')\n );\n}\n\n/**\n * Discover repository-owned state for a project scaffold.\n *\n * @param context - CLI context\n * @param options - Target and standalone root\n * @returns Repository-level project state\n */\nexport function discoverProjectRepository(\n context: LocalContext,\n options: {\n /** Directory from which the CLI was invoked. */\n invocationDirectory: string;\n /** Absolute project target used to locate a surrounding repository. */\n targetDirectory: string;\n /** Root to use when the target is not inside a repository. */\n standaloneProjectRoot: string;\n },\n): ProjectRepositoryState {\n const invocationAncestor = findExistingAncestor(context, options.invocationDirectory);\n const invocationRepositoryRoot = findRepositoryRoot(context, invocationAncestor);\n const targetRepositoryRoot =\n invocationRepositoryRoot && isPathContained(invocationRepositoryRoot, options.targetDirectory)\n ? invocationRepositoryRoot\n : findRepositoryRoot(context, findExistingAncestor(context, options.targetDirectory));\n const shouldAnchorToStandaloneRoot =\n options.standaloneProjectRoot !== options.targetDirectory &&\n isPathContained(options.standaloneProjectRoot, options.targetDirectory);\n const repositoryRoot = targetRepositoryRoot;\n const projectRoot = shouldAnchorToStandaloneRoot\n ? (invocationRepositoryRoot ?? options.standaloneProjectRoot)\n : (repositoryRoot ?? options.standaloneProjectRoot);\n assertPathPhysicallyContained(context, projectRoot, options.targetDirectory);\n return {\n projectRoot,\n ...(repositoryRoot ? { repositoryRoot } : {}),\n existingSkillDirectories: detectExistingProjectSkillDirectories(context, projectRoot),\n usesGithub: repositoryUsesGithub(context, repositoryRoot),\n };\n}\n","import inquirer from 'inquirer';\n\nimport type { LocalContext } from '../../context.js';\n\n/** One select or checkbox option. */\nexport interface PromptChoice<T extends string> {\n /** User-facing label. */\n name: string;\n /** Stable answer value. */\n value: T;\n /** Whether a checkbox starts selected. */\n checked?: boolean;\n}\n\n/** Error used to map prompt cancellation to exit status 130. */\nexport class PromptCancelledError extends Error {\n /** Construct a stable cancellation error. */\n public constructor() {\n super('Prompt cancelled.');\n this.name = 'PromptCancelledError';\n }\n}\n\n/**\n * Normalize Inquirer cancellation across supported versions.\n *\n * @param error - Prompt error\n * @returns Stable cancellation error or original error\n */\nfunction normalizePromptError(error: unknown): Error {\n const message = error instanceof Error ? error.message : String(error);\n if (\n error instanceof PromptCancelledError ||\n /force closed|prompt.*cancel|user.*close|SIGINT/iu.test(message)\n ) {\n return new PromptCancelledError();\n }\n return error instanceof Error ? error : new Error(message);\n}\n\n/** Context-stream-bound scaffold prompt adapters. */\nexport class ScaffoldPrompts {\n /** Inquirer prompt module. */\n private readonly prompt: ReturnType<typeof inquirer.createPromptModule>;\n\n /**\n * Create adapters bound to command-owned streams.\n *\n * @param context - CLI context\n */\n public constructor(context: LocalContext) {\n this.prompt = inquirer.createPromptModule({\n input: context.process.stdin,\n output: context.process.stderr,\n });\n }\n\n /**\n * Prompt for non-empty text.\n *\n * @param message - User-facing question\n * @param defaultValue - Suggested value\n * @param validate - Optional command-specific validation\n * @returns Answer\n */\n public async text(\n message: string,\n defaultValue?: string,\n validate?: (value: string) => true | string,\n ): Promise<string> {\n try {\n const answer = await this.prompt<{ value: string }>([\n {\n type: 'input',\n name: 'value',\n message,\n ...(defaultValue === undefined ? {} : { default: defaultValue }),\n validate: (value: string) => {\n const trimmed = value.trim();\n return trimmed.length > 0 ? (validate?.(trimmed) ?? true) : 'Enter a value.';\n },\n },\n ]);\n return answer.value.trim();\n } catch (error) {\n throw normalizePromptError(error);\n }\n }\n\n /**\n * Prompt for one choice.\n *\n * @param message - User-facing question\n * @param choices - Available choices\n * @param defaultValue - Suggested value\n * @returns Selected value\n */\n public async select<T extends string>(\n message: string,\n choices: readonly PromptChoice<T>[],\n defaultValue?: T,\n ): Promise<T> {\n try {\n const answer = await this.prompt<{ value: T }>([\n {\n type: 'list',\n name: 'value',\n message,\n choices: [...choices],\n ...(defaultValue === undefined ? {} : { default: defaultValue }),\n },\n ]);\n return answer.value;\n } catch (error) {\n throw normalizePromptError(error);\n }\n }\n\n /**\n * Prompt for any number of choices.\n *\n * @param message - User-facing question\n * @param choices - Available choices\n * @returns Selected values\n */\n public async checkbox<T extends string>(\n message: string,\n choices: readonly PromptChoice<T>[],\n ): Promise<T[]> {\n try {\n const answer = await this.prompt<{ value: T[] }>([\n {\n type: 'checkbox',\n name: 'value',\n message,\n choices: [...choices],\n },\n ]);\n return answer.value;\n } catch (error) {\n throw normalizePromptError(error);\n }\n }\n\n /**\n * Prompt for final approval.\n *\n * @param message - User-facing question\n * @param defaultValue - Suggested answer\n * @returns Approval\n */\n public async confirm(message: string, defaultValue = true): Promise<boolean> {\n try {\n const answer = await this.prompt<{ value: boolean }>([\n {\n type: 'confirm',\n name: 'value',\n message,\n default: defaultValue,\n },\n ]);\n return answer.value;\n } catch (error) {\n throw normalizePromptError(error);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold-model-BAbYTR0q.mjs","names":[],"sources":["../src/lib/custom-functions/scaffold-model.ts"],"sourcesContent":["import type { ExistingProjectSkillDirectory } from '../scaffolding/agent-skill.js';\nimport type { ProjectPlan } from '../scaffolding/project-plan.js';\n\n/** Version of the stable scaffold/check JSON result contract. */\nexport const CUSTOM_FUNCTION_RESULT_VERSION = 1 as const;\n\n/** One repository setup capability. */\nexport const CustomFunctionSetupFeature = {\n /** Deno import map and strict compiler configuration. */\n Deno: 'deno',\n /** Target-scoped editor configuration. */\n Editor: 'editor',\n /** Coding-agent authoring skill. */\n Skill: 'skill',\n /** GitHub Actions validation workflow. */\n Ci: 'ci',\n} as const;\n\n/** One repository setup capability. */\nexport type CustomFunctionSetupFeature =\n (typeof CustomFunctionSetupFeature)[keyof typeof CustomFunctionSetupFeature];\n\n/** Repository and target state collected before planning. */\nexport interface CustomFunctionProjectState {\n /** Directory from which the CLI was invoked. */\n invocationDirectory: string;\n /** Absolute user-selected target directory. */\n targetDirectory: string;\n /** Root that owns repository-level editor and agent setup. */\n projectRoot: string;\n /** Directory relative to which manifest file references resolve. */\n manifestDirectory: string;\n /** Absolute manifest path. */\n manifestPath: string;\n /** Nearest repository root, when present. */\n repositoryRoot?: string;\n /** Existing Deno configuration path, or desired deno.json path. */\n denoConfigPath: string;\n /** Existing project-level skill directories; home state is deliberately ignored. */\n existingSkillDirectories: ExistingProjectSkillDirectory[];\n /** Whether the repository appears to use GitHub. */\n usesGithub: boolean;\n /** Case-preserving relative paths below the manifest directory. */\n relativePaths: string[];\n}\n\n/** A complete, validated scaffold plan. */\nexport interface CustomFunctionProjectPlan extends ProjectPlan {\n /** JSON contract version. */\n version: typeof CUSTOM_FUNCTION_RESULT_VERSION;\n /** Command that produced the plan. */\n command: 'init' | 'new';\n /** Absolute project target directory. */\n targetDirectory: string;\n /** Absolute manifest path. */\n manifestPath: string;\n /** Files inspected and deliberately left unchanged. */\n unchanged: string[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Commands shown after a successful apply. */\n nextSteps: string[];\n}\n"],"mappings":"AAOA,MAAa,EAA6B,CAExC,KAAM,OAEN,OAAQ,SAER,MAAO,QAEP,GAAI,KACL"}
|