@transcend-io/cli 10.29.1 → 10.29.3

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.
Files changed (127) hide show
  1. package/dist/{app-B9yoXd7q.mjs → app-D-IPyX64.mjs} +16 -16
  2. package/dist/{app-B9yoXd7q.mjs.map → app-D-IPyX64.mjs.map} +1 -1
  3. package/dist/{approvePrivacyRequests-DDT8Zjhc.mjs → approvePrivacyRequests-DmQY27tf.mjs} +2 -2
  4. package/dist/{approvePrivacyRequests-DDT8Zjhc.mjs.map → approvePrivacyRequests-DmQY27tf.mjs.map} +1 -1
  5. package/dist/bin/bash-complete.mjs +1 -1
  6. package/dist/bin/cli.mjs +1 -1
  7. package/dist/bin/deprecated-command.mjs +1 -1
  8. package/dist/{buildExamples-DLDlrgWE.mjs → buildExamples-COM0o0UR.mjs} +2 -2
  9. package/dist/{buildExamples-DLDlrgWE.mjs.map → buildExamples-COM0o0UR.mjs.map} +1 -1
  10. package/dist/{buildXdiSyncEndpoint-uSDQEXT2.mjs → buildXdiSyncEndpoint-5tSouA2b.mjs} +2 -2
  11. package/dist/{buildXdiSyncEndpoint-uSDQEXT2.mjs.map → buildXdiSyncEndpoint-5tSouA2b.mjs.map} +1 -1
  12. package/dist/{bulkRestartRequests-C4wyNZ65.mjs → bulkRestartRequests-CZrXs34U.mjs} +2 -2
  13. package/dist/{bulkRestartRequests-C4wyNZ65.mjs.map → bulkRestartRequests-CZrXs34U.mjs.map} +1 -1
  14. package/dist/{bulkRetryEnrichers-VbIb-WIs.mjs → bulkRetryEnrichers-BOXW2gK0.mjs} +2 -2
  15. package/dist/{bulkRetryEnrichers-VbIb-WIs.mjs.map → bulkRetryEnrichers-BOXW2gK0.mjs.map} +1 -1
  16. package/dist/{cancelPrivacyRequests-Ds6HKabX.mjs → cancelPrivacyRequests-CA8X4g4A.mjs} +2 -2
  17. package/dist/{cancelPrivacyRequests-Ds6HKabX.mjs.map → cancelPrivacyRequests-CA8X4g4A.mjs.map} +1 -1
  18. package/dist/{command-BVK929yJ.mjs → command-Ddx7b9ik.mjs} +2 -2
  19. package/dist/{command-BVK929yJ.mjs.map → command-Ddx7b9ik.mjs.map} +1 -1
  20. package/dist/{constants-X60pMfSm.mjs → constants-XH8NIJGC.mjs} +2 -2
  21. package/dist/{constants-X60pMfSm.mjs.map → constants-XH8NIJGC.mjs.map} +1 -1
  22. package/dist/{createPoolingCommandUi-Dr6Cmq63.mjs → createPoolingCommandUi-BtyIMQcK.mjs} +2 -2
  23. package/dist/{createPoolingCommandUi-Dr6Cmq63.mjs.map → createPoolingCommandUi-BtyIMQcK.mjs.map} +1 -1
  24. package/dist/{downloadPrivacyRequestFiles-BZjAtiKF.mjs → downloadPrivacyRequestFiles-DbZjPjHw.mjs} +2 -2
  25. package/dist/{downloadPrivacyRequestFiles-BZjAtiKF.mjs.map → downloadPrivacyRequestFiles-DbZjPjHw.mjs.map} +1 -1
  26. package/dist/{generateCrossAccountApiKeys-POFAc7bo.mjs → generateCrossAccountApiKeys-C1iD6Las.mjs} +2 -2
  27. package/dist/{generateCrossAccountApiKeys-POFAc7bo.mjs.map → generateCrossAccountApiKeys-C1iD6Las.mjs.map} +1 -1
  28. package/dist/{impl-CQtMFz1O.mjs → impl-99xoQXHW.mjs} +2 -2
  29. package/dist/{impl-CQtMFz1O.mjs.map → impl-99xoQXHW.mjs.map} +1 -1
  30. package/dist/{impl-DInF5q00.mjs → impl-B37wtYBz.mjs} +2 -2
  31. package/dist/{impl-DInF5q00.mjs.map → impl-B37wtYBz.mjs.map} +1 -1
  32. package/dist/{impl-dXDmiiG6.mjs → impl-B9lSnjby.mjs} +2 -2
  33. package/dist/{impl-dXDmiiG6.mjs.map → impl-B9lSnjby.mjs.map} +1 -1
  34. package/dist/{impl-_erU3Uzt2.mjs → impl-BFn-S-Wy2.mjs} +2 -2
  35. package/dist/{impl-_erU3Uzt2.mjs.map → impl-BFn-S-Wy2.mjs.map} +1 -1
  36. package/dist/{impl-Bguphgoc.mjs → impl-BKmibZoG.mjs} +2 -2
  37. package/dist/{impl-Bguphgoc.mjs.map → impl-BKmibZoG.mjs.map} +1 -1
  38. package/dist/{impl-CfMrFWb_.mjs → impl-BR4ReYFA.mjs} +2 -2
  39. package/dist/{impl-CfMrFWb_.mjs.map → impl-BR4ReYFA.mjs.map} +1 -1
  40. package/dist/{impl-lcLJ4Wp-.mjs → impl-BjoGaK1M.mjs} +2 -2
  41. package/dist/{impl-lcLJ4Wp-.mjs.map → impl-BjoGaK1M.mjs.map} +1 -1
  42. package/dist/{impl-DOuVyX0O.mjs → impl-C5Mq4wv0.mjs} +2 -2
  43. package/dist/{impl-DOuVyX0O.mjs.map → impl-C5Mq4wv0.mjs.map} +1 -1
  44. package/dist/{impl-BTff-yNX.mjs → impl-C83WRl40.mjs} +2 -2
  45. package/dist/{impl-BTff-yNX.mjs.map → impl-C83WRl40.mjs.map} +1 -1
  46. package/dist/{impl-Dv8ecMWN.mjs → impl-C8vx7N5j.mjs} +2 -2
  47. package/dist/{impl-Dv8ecMWN.mjs.map → impl-C8vx7N5j.mjs.map} +1 -1
  48. package/dist/{impl-IFoIxW9s.mjs → impl-CGioITgZ.mjs} +2 -2
  49. package/dist/{impl-IFoIxW9s.mjs.map → impl-CGioITgZ.mjs.map} +1 -1
  50. package/dist/{impl-xKt-NwTT.mjs → impl-CJML1Gwo.mjs} +2 -2
  51. package/dist/{impl-xKt-NwTT.mjs.map → impl-CJML1Gwo.mjs.map} +1 -1
  52. package/dist/{impl-BT0N2HwU.mjs → impl-CL0y3SFr.mjs} +2 -2
  53. package/dist/{impl-BT0N2HwU.mjs.map → impl-CL0y3SFr.mjs.map} +1 -1
  54. package/dist/{impl-ymZeayvp.mjs → impl-CMxliF19.mjs} +2 -2
  55. package/dist/{impl-ymZeayvp.mjs.map → impl-CMxliF19.mjs.map} +1 -1
  56. package/dist/{impl-Z_ZuLfFK.mjs → impl-CNgOWzOX.mjs} +2 -2
  57. package/dist/{impl-Z_ZuLfFK.mjs.map → impl-CNgOWzOX.mjs.map} +1 -1
  58. package/dist/{impl-CE_nprLV.mjs → impl-CXQ3OYR9.mjs} +2 -2
  59. package/dist/{impl-CE_nprLV.mjs.map → impl-CXQ3OYR9.mjs.map} +1 -1
  60. package/dist/{impl-C1xIUoJS.mjs → impl-CbAvM_1J.mjs} +2 -2
  61. package/dist/{impl-C1xIUoJS.mjs.map → impl-CbAvM_1J.mjs.map} +1 -1
  62. package/dist/{impl-CF0ts8Fz2.mjs → impl-Cel22rUg2.mjs} +2 -2
  63. package/dist/{impl-CF0ts8Fz2.mjs.map → impl-Cel22rUg2.mjs.map} +1 -1
  64. package/dist/{impl-nvYE0p_K.mjs → impl-CfPDnai_.mjs} +2 -2
  65. package/dist/{impl-nvYE0p_K.mjs.map → impl-CfPDnai_.mjs.map} +1 -1
  66. package/dist/{impl-DRW2qfyk.mjs → impl-Cl9ndadE.mjs} +2 -2
  67. package/dist/{impl-DRW2qfyk.mjs.map → impl-Cl9ndadE.mjs.map} +1 -1
  68. package/dist/{impl-BDgc5PEC2.mjs → impl-Cs1z9k1h2.mjs} +2 -2
  69. package/dist/{impl-BDgc5PEC2.mjs.map → impl-Cs1z9k1h2.mjs.map} +1 -1
  70. package/dist/{impl-BnvfuqEA2.mjs → impl-DB8Kt2qF2.mjs} +2 -2
  71. package/dist/{impl-BnvfuqEA2.mjs.map → impl-DB8Kt2qF2.mjs.map} +1 -1
  72. package/dist/{impl-CMK8Qm_I2.mjs → impl-DHQh34Eh2.mjs} +2 -2
  73. package/dist/{impl-CMK8Qm_I2.mjs.map → impl-DHQh34Eh2.mjs.map} +1 -1
  74. package/dist/{impl-C8sWVJUG.mjs → impl-DN6CgOI6.mjs} +2 -2
  75. package/dist/{impl-C8sWVJUG.mjs.map → impl-DN6CgOI6.mjs.map} +1 -1
  76. package/dist/{impl-WxoE0bN_.mjs → impl-DUBsZL5O.mjs} +2 -2
  77. package/dist/{impl-WxoE0bN_.mjs.map → impl-DUBsZL5O.mjs.map} +1 -1
  78. package/dist/{impl-BPzANN8n.mjs → impl-DWD4fAPO.mjs} +2 -2
  79. package/dist/{impl-BPzANN8n.mjs.map → impl-DWD4fAPO.mjs.map} +1 -1
  80. package/dist/{impl-BkqQI3vZ.mjs → impl-DceiaFcK.mjs} +2 -2
  81. package/dist/{impl-BkqQI3vZ.mjs.map → impl-DceiaFcK.mjs.map} +1 -1
  82. package/dist/{impl-BeHsB-Zk.mjs → impl-Dt5Iik_-.mjs} +2 -2
  83. package/dist/{impl-BeHsB-Zk.mjs.map → impl-Dt5Iik_-.mjs.map} +1 -1
  84. package/dist/{impl-CSmFd6iO2.mjs → impl-DxnrCWeR2.mjs} +2 -2
  85. package/dist/{impl-CSmFd6iO2.mjs.map → impl-DxnrCWeR2.mjs.map} +1 -1
  86. package/dist/{impl-DkHzw1nR.mjs → impl-GH9uVaGu.mjs} +2 -2
  87. package/dist/{impl-DkHzw1nR.mjs.map → impl-GH9uVaGu.mjs.map} +1 -1
  88. package/dist/{impl-DKNJFnFv2.mjs → impl-H9kweQnu2.mjs} +2 -2
  89. package/dist/{impl-DKNJFnFv2.mjs.map → impl-H9kweQnu2.mjs.map} +1 -1
  90. package/dist/{impl-Bg7zZ_F_.mjs → impl-jJnYd4tJ.mjs} +2 -2
  91. package/dist/{impl-Bg7zZ_F_.mjs.map → impl-jJnYd4tJ.mjs.map} +1 -1
  92. package/dist/{impl-BScGBm2o.mjs → impl-p_M16BEd.mjs} +2 -2
  93. package/dist/{impl-BScGBm2o.mjs.map → impl-p_M16BEd.mjs.map} +1 -1
  94. package/dist/{impl-CSRal4Rj2.mjs → impl-v_P8hszk2.mjs} +2 -2
  95. package/dist/{impl-CSRal4Rj2.mjs.map → impl-v_P8hszk2.mjs.map} +1 -1
  96. package/dist/index.mjs +1 -1
  97. package/dist/{markRequestDataSiloIdsCompleted-2DHClQ32.mjs → markRequestDataSiloIdsCompleted-B5JCHcqh.mjs} +2 -2
  98. package/dist/{markRequestDataSiloIdsCompleted-2DHClQ32.mjs.map → markRequestDataSiloIdsCompleted-B5JCHcqh.mjs.map} +1 -1
  99. package/dist/{markSilentPrivacyRequests-BUYzKbhW.mjs → markSilentPrivacyRequests-BAIZ97iB.mjs} +2 -2
  100. package/dist/{markSilentPrivacyRequests-BUYzKbhW.mjs.map → markSilentPrivacyRequests-BAIZ97iB.mjs.map} +1 -1
  101. package/dist/{notifyPrivacyRequestsAdditionalTime-G8IZ0Ooy.mjs → notifyPrivacyRequestsAdditionalTime-C2lUoWKP.mjs} +2 -2
  102. package/dist/{notifyPrivacyRequestsAdditionalTime-G8IZ0Ooy.mjs.map → notifyPrivacyRequestsAdditionalTime-C2lUoWKP.mjs.map} +1 -1
  103. package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-BxolFAfF.mjs → pullChunkedCustomSiloOutstandingIdentifiers-BmhJiquf.mjs} +2 -2
  104. package/dist/{pullChunkedCustomSiloOutstandingIdentifiers-BxolFAfF.mjs.map → pullChunkedCustomSiloOutstandingIdentifiers-BmhJiquf.mjs.map} +1 -1
  105. package/dist/{pullManualEnrichmentIdentifiersToCsv-DcLZeqF2.mjs → pullManualEnrichmentIdentifiersToCsv-BbQc9MDM.mjs} +2 -2
  106. package/dist/{pullManualEnrichmentIdentifiersToCsv-DcLZeqF2.mjs.map → pullManualEnrichmentIdentifiersToCsv-BbQc9MDM.mjs.map} +1 -1
  107. package/dist/{pushCronIdentifiersFromCsv-CVTCk6s3.mjs → pushCronIdentifiersFromCsv-Cfo2GibV.mjs} +2 -2
  108. package/dist/{pushCronIdentifiersFromCsv-CVTCk6s3.mjs.map → pushCronIdentifiersFromCsv-Cfo2GibV.mjs.map} +1 -1
  109. package/dist/{pushManualEnrichmentIdentifiersFromCsv-BIkBbKfs.mjs → pushManualEnrichmentIdentifiersFromCsv-DokcIxh1.mjs} +2 -2
  110. package/dist/{pushManualEnrichmentIdentifiersFromCsv-BIkBbKfs.mjs.map → pushManualEnrichmentIdentifiersFromCsv-DokcIxh1.mjs.map} +1 -1
  111. package/dist/{removeUnverifiedRequestIdentifiers-CzEvT_WR.mjs → removeUnverifiedRequestIdentifiers-p4gFagI0.mjs} +2 -2
  112. package/dist/{removeUnverifiedRequestIdentifiers-CzEvT_WR.mjs.map → removeUnverifiedRequestIdentifiers-p4gFagI0.mjs.map} +1 -1
  113. package/dist/{retryRequestDataSilos-C2csdZmC.mjs → retryRequestDataSilos-C6mvi-ET.mjs} +2 -2
  114. package/dist/{retryRequestDataSilos-C2csdZmC.mjs.map → retryRequestDataSilos-C6mvi-ET.mjs.map} +1 -1
  115. package/dist/{skipPreflightJobs-CB_lGpri.mjs → skipPreflightJobs-CgUcTgzf.mjs} +2 -2
  116. package/dist/{skipPreflightJobs-CB_lGpri.mjs.map → skipPreflightJobs-CgUcTgzf.mjs.map} +1 -1
  117. package/dist/{skipRequestDataSilos-Bf85wXUC.mjs → skipRequestDataSilos-Be-6OhWe.mjs} +2 -2
  118. package/dist/{skipRequestDataSilos-Bf85wXUC.mjs.map → skipRequestDataSilos-Be-6OhWe.mjs.map} +1 -1
  119. package/dist/{streamPrivacyRequestsToCsv-CPwLKjTm.mjs → streamPrivacyRequestsToCsv-BaeFrrGF.mjs} +2 -2
  120. package/dist/{streamPrivacyRequestsToCsv-CPwLKjTm.mjs.map → streamPrivacyRequestsToCsv-BaeFrrGF.mjs.map} +1 -1
  121. package/dist/{updateConsentManagerVersionToLatest-ikIE5dHp.mjs → updateConsentManagerVersionToLatest-3mQX2U8F.mjs} +2 -2
  122. package/dist/{updateConsentManagerVersionToLatest-ikIE5dHp.mjs.map → updateConsentManagerVersionToLatest-3mQX2U8F.mjs.map} +1 -1
  123. package/dist/{uploadConsents-BrWpoV6_.mjs → uploadConsents-Dnbtx9P5.mjs} +2 -2
  124. package/dist/{uploadConsents-BrWpoV6_.mjs.map → uploadConsents-Dnbtx9P5.mjs.map} +1 -1
  125. package/dist/{uploadPrivacyRequestsFromCsv-BuB0-XpH.mjs → uploadPrivacyRequestsFromCsv-BIW2JPjA.mjs} +2 -2
  126. package/dist/{uploadPrivacyRequestsFromCsv-BuB0-XpH.mjs.map → uploadPrivacyRequestsFromCsv-BIW2JPjA.mjs.map} +1 -1
  127. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"impl-DRW2qfyk.mjs","names":[],"sources":["../src/commands/admin/generate-api-keys/impl.ts"],"sourcesContent":["import { ScopeName } from '@transcend-io/privacy-types';\n\nimport { SCOPES_BY_TITLE } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { generateCrossAccountApiKeys } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\n\n// Command flag interface\nexport interface GenerateApiKeysCommandFlags {\n email: string;\n password: string;\n apiKeyTitle: string;\n file: string;\n scopes: string[];\n deleteExistingApiKey: boolean;\n createNewApiKey: boolean;\n parentOrganizationId?: string;\n transcendUrl: string;\n}\n\n// Command implementation\nexport async function generateApiKeys(\n this: LocalContext,\n {\n email,\n password,\n apiKeyTitle,\n file,\n scopes,\n deleteExistingApiKey,\n createNewApiKey,\n parentOrganizationId,\n transcendUrl,\n }: GenerateApiKeysCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const scopeNames = scopes.map((scopeTitle) => SCOPES_BY_TITLE[scopeTitle].name as ScopeName);\n\n // Upload privacy requests\n const { errors, apiKeys } = await generateCrossAccountApiKeys({\n transcendUrl,\n password,\n email,\n parentOrganizationId,\n deleteExistingApiKey,\n createNewApiKey,\n apiKeyTitle,\n scopes: scopeNames,\n });\n\n // Write to disk\n this.fs.writeFileSync(file, `${JSON.stringify(apiKeys, null, 2)}\\n`);\n if (errors.length > 0) {\n this.process.exit(1);\n }\n}\n"],"mappings":"gKAqBA,eAAsB,EAEpB,CACE,QACA,WACA,cACA,OACA,SACA,uBACA,kBACA,uBACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAKjC,GAAM,CAAE,SAAQ,WAAY,MAAM,EAA4B,CAC5D,eACA,WACA,QACA,uBACA,uBACA,kBACA,cACA,OAXiB,EAAO,IAAK,GAAe,EAAgB,GAAY,KAWtD,CACnB,CAAC,CAGF,KAAK,GAAG,cAAc,EAAM,GAAG,KAAK,UAAU,EAAS,KAAM,EAAE,CAAC,IAAI,CAChE,EAAO,OAAS,GAClB,KAAK,QAAQ,KAAK,EAAE"}
1
+ {"version":3,"file":"impl-Cl9ndadE.mjs","names":[],"sources":["../src/commands/admin/generate-api-keys/impl.ts"],"sourcesContent":["import { ScopeName } from '@transcend-io/privacy-types';\n\nimport { SCOPES_BY_TITLE } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { generateCrossAccountApiKeys } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\n\n// Command flag interface\nexport interface GenerateApiKeysCommandFlags {\n email: string;\n password: string;\n apiKeyTitle: string;\n file: string;\n scopes: string[];\n deleteExistingApiKey: boolean;\n createNewApiKey: boolean;\n parentOrganizationId?: string;\n transcendUrl: string;\n}\n\n// Command implementation\nexport async function generateApiKeys(\n this: LocalContext,\n {\n email,\n password,\n apiKeyTitle,\n file,\n scopes,\n deleteExistingApiKey,\n createNewApiKey,\n parentOrganizationId,\n transcendUrl,\n }: GenerateApiKeysCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n const scopeNames = scopes.map((scopeTitle) => SCOPES_BY_TITLE[scopeTitle].name as ScopeName);\n\n // Upload privacy requests\n const { errors, apiKeys } = await generateCrossAccountApiKeys({\n transcendUrl,\n password,\n email,\n parentOrganizationId,\n deleteExistingApiKey,\n createNewApiKey,\n apiKeyTitle,\n scopes: scopeNames,\n });\n\n // Write to disk\n this.fs.writeFileSync(file, `${JSON.stringify(apiKeys, null, 2)}\\n`);\n if (errors.length > 0) {\n this.process.exit(1);\n }\n}\n"],"mappings":"gKAqBA,eAAsB,EAEpB,CACE,QACA,WACA,cACA,OACA,SACA,uBACA,kBACA,uBACA,gBAEa,CACf,EAAoB,KAAK,QAAQ,CAKjC,GAAM,CAAE,SAAQ,WAAY,MAAM,EAA4B,CAC5D,eACA,WACA,QACA,uBACA,uBACA,kBACA,cACA,OAXiB,EAAO,IAAK,GAAe,EAAgB,GAAY,KAWtD,CACnB,CAAC,CAGF,KAAK,GAAG,cAAc,EAAM,GAAG,KAAK,UAAU,EAAS,KAAM,EAAE,CAAC,IAAI,CAChE,EAAO,OAAS,GAClB,KAAK,QAAQ,KAAK,EAAE"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./pushCronIdentifiersFromCsv-CVTCk6s3.mjs";import{t}from"./done-input-validation-BUz-aVC5.mjs";async function n({file:n,transcendUrl:r,auth:i,sombraAuth:a,dataSiloId:o}){t(this.process),await e({file:n,transcendUrl:r,auth:i,sombraAuth:a,dataSiloId:o})}export{n as markIdentifiersCompleted};
2
- //# sourceMappingURL=impl-BDgc5PEC2.mjs.map
1
+ import{t as e}from"./pushCronIdentifiersFromCsv-Cfo2GibV.mjs";import{t}from"./done-input-validation-BUz-aVC5.mjs";async function n({file:n,transcendUrl:r,auth:i,sombraAuth:a,dataSiloId:o}){t(this.process),await e({file:n,transcendUrl:r,auth:i,sombraAuth:a,dataSiloId:o})}export{n as markIdentifiersCompleted};
2
+ //# sourceMappingURL=impl-Cs1z9k1h2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BDgc5PEC2.mjs","names":[],"sources":["../src/commands/request/cron/mark-identifiers-completed/impl.ts"],"sourcesContent":["import type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport { pushCronIdentifiersFromCsv } from '../../../../lib/cron/index.js';\n\nexport interface MarkIdentifiersCompletedCommandFlags {\n file: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n dataSiloId: string;\n}\n\nexport async function markIdentifiersCompleted(\n this: LocalContext,\n { file, transcendUrl, auth, sombraAuth, dataSiloId }: MarkIdentifiersCompletedCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await pushCronIdentifiersFromCsv({\n file,\n transcendUrl,\n auth,\n sombraAuth,\n dataSiloId,\n });\n}\n"],"mappings":"kHAYA,eAAsB,EAEpB,CAAE,OAAM,eAAc,OAAM,aAAY,cACzB,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAM,EAA2B,CAC/B,OACA,eACA,OACA,aACA,aACD,CAAC"}
1
+ {"version":3,"file":"impl-Cs1z9k1h2.mjs","names":[],"sources":["../src/commands/request/cron/mark-identifiers-completed/impl.ts"],"sourcesContent":["import type { LocalContext } from '../../../../context.js';\nimport { doneInputValidation } from '../../../../lib/cli/done-input-validation.js';\nimport { pushCronIdentifiersFromCsv } from '../../../../lib/cron/index.js';\n\nexport interface MarkIdentifiersCompletedCommandFlags {\n file: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n dataSiloId: string;\n}\n\nexport async function markIdentifiersCompleted(\n this: LocalContext,\n { file, transcendUrl, auth, sombraAuth, dataSiloId }: MarkIdentifiersCompletedCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n\n await pushCronIdentifiersFromCsv({\n file,\n transcendUrl,\n auth,\n sombraAuth,\n dataSiloId,\n });\n}\n"],"mappings":"kHAYA,eAAsB,EAEpB,CAAE,OAAM,eAAc,OAAM,aAAY,cACzB,CACf,EAAoB,KAAK,QAAQ,CAEjC,MAAM,EAA2B,CAC/B,OACA,eACA,OACA,aACA,aACD,CAAC"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./pullChunkedCustomSiloOutstandingIdentifiers-BxolFAfF.mjs";import{i as t,s as n}from"./writeCsv-D-2siSwE.mjs";import{t as r}from"./done-input-validation-BUz-aVC5.mjs";import{uniq as i}from"lodash-es";import a from"colors";async function o({file:o,transcendUrl:s,auth:c,sombraAuth:l,dataSiloId:u,actions:d,pageLimit:f,skipRequestCount:p,chunkSize:m}){p&&this.logger.info(a.yellow(`Skipping request count as requested. This may help speed up the call.`)),(Number.isNaN(m)||m<=0||m%f!==0)&&(this.logger.error(a.red(`Invalid chunk size: "${m}". Must be a positive integer that is a multiple of ${f}.`)),this.process.exit(1)),r(this.process);let{baseName:h,extension:g}=t(o),_=0;await e({transcendUrl:s,apiPageSize:f,savePageSize:m,onSave:async e=>{let t=`${h}-${_}${g}`;return this.logger.info(a.blue(`Saving ${e.length} identifiers to file "${t}"`)),await n(t,e,i(e.map(e=>Object.keys(e)).flat())),this.logger.info(a.green(`Successfully wrote ${e.length} identifiers to file "${t}"`)),_+=1,Promise.resolve()},actions:d,auth:c,sombraAuth:l,dataSiloId:u,skipRequestCount:p})}export{o as pullIdentifiers};
2
- //# sourceMappingURL=impl-BnvfuqEA2.mjs.map
1
+ import{t as e}from"./pullChunkedCustomSiloOutstandingIdentifiers-BmhJiquf.mjs";import{i as t,s as n}from"./writeCsv-D-2siSwE.mjs";import{t as r}from"./done-input-validation-BUz-aVC5.mjs";import{uniq as i}from"lodash-es";import a from"colors";async function o({file:o,transcendUrl:s,auth:c,sombraAuth:l,dataSiloId:u,actions:d,pageLimit:f,skipRequestCount:p,chunkSize:m}){p&&this.logger.info(a.yellow(`Skipping request count as requested. This may help speed up the call.`)),(Number.isNaN(m)||m<=0||m%f!==0)&&(this.logger.error(a.red(`Invalid chunk size: "${m}". Must be a positive integer that is a multiple of ${f}.`)),this.process.exit(1)),r(this.process);let{baseName:h,extension:g}=t(o),_=0;await e({transcendUrl:s,apiPageSize:f,savePageSize:m,onSave:async e=>{let t=`${h}-${_}${g}`;return this.logger.info(a.blue(`Saving ${e.length} identifiers to file "${t}"`)),await n(t,e,i(e.map(e=>Object.keys(e)).flat())),this.logger.info(a.green(`Successfully wrote ${e.length} identifiers to file "${t}"`)),_+=1,Promise.resolve()},actions:d,auth:c,sombraAuth:l,dataSiloId:u,skipRequestCount:p})}export{o as pullIdentifiers};
2
+ //# sourceMappingURL=impl-DB8Kt2qF2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-BnvfuqEA2.mjs","names":[],"sources":["../src/commands/request/cron/pull-identifiers/impl.ts"],"sourcesContent":["import { RequestAction } from '@transcend-io/privacy-types';\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 {\n CsvFormattedIdentifier,\n pullChunkedCustomSiloOutstandingIdentifiers,\n} from '../../../../lib/cron/index.js';\nimport { parseFilePath, writeLargeCsv } from '../../../../lib/helpers/index.js';\n\nexport interface PullIdentifiersCommandFlags {\n file: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n dataSiloId: string;\n actions: RequestAction[];\n pageLimit: number;\n skipRequestCount: boolean;\n chunkSize: number;\n}\n\nexport async function pullIdentifiers(\n this: LocalContext,\n {\n file,\n transcendUrl,\n auth,\n sombraAuth,\n dataSiloId,\n actions,\n pageLimit,\n skipRequestCount,\n chunkSize,\n }: PullIdentifiersCommandFlags,\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 const { baseName, extension } = parseFilePath(file);\n let fileCount = 0;\n\n const onSave = async (chunk: CsvFormattedIdentifier[]): Promise<void> => {\n const numberedFileName = `${baseName}-${fileCount}${extension}`;\n this.logger.info(\n colors.blue(`Saving ${chunk.length} identifiers to file \"${numberedFileName}\"`),\n );\n\n const headers = uniq(chunk.map((d) => Object.keys(d)).flat());\n await writeLargeCsv(numberedFileName, chunk, headers);\n this.logger.info(\n colors.green(`Successfully wrote ${chunk.length} identifiers to file \"${numberedFileName}\"`),\n );\n fileCount += 1;\n return Promise.resolve();\n };\n\n // Pull down outstanding identifiers\n await pullChunkedCustomSiloOutstandingIdentifiers({\n transcendUrl,\n apiPageSize: pageLimit,\n savePageSize: chunkSize,\n onSave,\n actions,\n auth,\n sombraAuth,\n dataSiloId,\n skipRequestCount,\n });\n}\n"],"mappings":"kPAwBA,eAAsB,EAEpB,CACE,OACA,eACA,OACA,aACA,aACA,UACA,YACA,mBACA,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,CAEjC,GAAM,CAAE,WAAU,aAAc,EAAc,EAAK,CAC/C,EAAY,EAkBhB,MAAM,EAA4C,CAChD,eACA,YAAa,EACb,aAAc,EACd,YApBoB,IAAmD,CACvE,IAAM,EAAmB,GAAG,EAAS,GAAG,IAAY,IAWpD,OAVA,KAAK,OAAO,KACV,EAAO,KAAK,UAAU,EAAM,OAAO,wBAAwB,EAAiB,GAAG,CAChF,CAGD,MAAM,EAAc,EAAkB,EADtB,EAAK,EAAM,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CACR,CAAC,CACrD,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAM,OAAO,wBAAwB,EAAiB,GAAG,CAC7F,CACD,GAAa,EACN,QAAQ,SAAS,EASxB,UACA,OACA,aACA,aACA,mBACD,CAAC"}
1
+ {"version":3,"file":"impl-DB8Kt2qF2.mjs","names":[],"sources":["../src/commands/request/cron/pull-identifiers/impl.ts"],"sourcesContent":["import { RequestAction } from '@transcend-io/privacy-types';\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 {\n CsvFormattedIdentifier,\n pullChunkedCustomSiloOutstandingIdentifiers,\n} from '../../../../lib/cron/index.js';\nimport { parseFilePath, writeLargeCsv } from '../../../../lib/helpers/index.js';\n\nexport interface PullIdentifiersCommandFlags {\n file: string;\n transcendUrl: string;\n auth: string;\n sombraAuth?: string;\n dataSiloId: string;\n actions: RequestAction[];\n pageLimit: number;\n skipRequestCount: boolean;\n chunkSize: number;\n}\n\nexport async function pullIdentifiers(\n this: LocalContext,\n {\n file,\n transcendUrl,\n auth,\n sombraAuth,\n dataSiloId,\n actions,\n pageLimit,\n skipRequestCount,\n chunkSize,\n }: PullIdentifiersCommandFlags,\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 const { baseName, extension } = parseFilePath(file);\n let fileCount = 0;\n\n const onSave = async (chunk: CsvFormattedIdentifier[]): Promise<void> => {\n const numberedFileName = `${baseName}-${fileCount}${extension}`;\n this.logger.info(\n colors.blue(`Saving ${chunk.length} identifiers to file \"${numberedFileName}\"`),\n );\n\n const headers = uniq(chunk.map((d) => Object.keys(d)).flat());\n await writeLargeCsv(numberedFileName, chunk, headers);\n this.logger.info(\n colors.green(`Successfully wrote ${chunk.length} identifiers to file \"${numberedFileName}\"`),\n );\n fileCount += 1;\n return Promise.resolve();\n };\n\n // Pull down outstanding identifiers\n await pullChunkedCustomSiloOutstandingIdentifiers({\n transcendUrl,\n apiPageSize: pageLimit,\n savePageSize: chunkSize,\n onSave,\n actions,\n auth,\n sombraAuth,\n dataSiloId,\n skipRequestCount,\n });\n}\n"],"mappings":"kPAwBA,eAAsB,EAEpB,CACE,OACA,eACA,OACA,aACA,aACA,UACA,YACA,mBACA,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,CAEjC,GAAM,CAAE,WAAU,aAAc,EAAc,EAAK,CAC/C,EAAY,EAkBhB,MAAM,EAA4C,CAChD,eACA,YAAa,EACb,aAAc,EACd,YApBoB,IAAmD,CACvE,IAAM,EAAmB,GAAG,EAAS,GAAG,IAAY,IAWpD,OAVA,KAAK,OAAO,KACV,EAAO,KAAK,UAAU,EAAM,OAAO,wBAAwB,EAAiB,GAAG,CAChF,CAGD,MAAM,EAAc,EAAkB,EADtB,EAAK,EAAM,IAAK,GAAM,OAAO,KAAK,EAAE,CAAC,CAAC,MAAM,CACR,CAAC,CACrD,KAAK,OAAO,KACV,EAAO,MAAM,sBAAsB,EAAM,OAAO,wBAAwB,EAAiB,GAAG,CAC7F,CACD,GAAa,EACN,QAAQ,SAAS,EASxB,UACA,OACA,aACA,aACA,mBACD,CAAC"}
@@ -1,4 +1,4 @@
1
- import{g as e}from"./constants-X60pMfSm.mjs";import{a as t,c as n,i as r,l as i,o as a,r as o,s,t as c}from"./policy-runtime-BMKa-Upy.mjs";import{t as l}from"./done-input-validation-BUz-aVC5.mjs";import{a as u,c as d,d as f,f as p,g as m,h,i as g,l as ee,m as _,n as v,p as y,r as te,t as ne,u as re}from"./prompts-ClBXdELk.mjs";import{t as ie}from"./run-captured-process-BXwWXuTh.mjs";import{t as ae}from"./project-plan-apply-Dvndx455.mjs";import{n as b,r as x,t as S}from"./jsonc-D9dDWb1J.mjs";import{isAbsolute as C,join as w,posix as T,relative as E,resolve as oe,sep as D}from"node:path";import O from"colors";const k=`transcend/policy`;function se(e,t=k){let n=e.process.cwd(),r=oe(n,t);if(e.fs.existsSync(r)&&!e.fs.statSync(r).isDirectory())throw Error(`Policy target is not a directory: ${r}`);return{invocationDirectory:n,targetDirectory:r,...u(e,{invocationDirectory:n,targetDirectory:r,standaloneProjectRoot:n}),relativePaths:g(e,r),relativeFilePaths:g(e,r,{includeDirectories:!1})}}function ce(e){return w(e.targetDirectory,`manifest.json`)}const A={Editor:`editor`,Skill:`skill`,Ci:`ci`};var le=`# Idiomatic Rego and document-tree authoring
1
+ import{g as e}from"./constants-XH8NIJGC.mjs";import{a as t,c as n,i as r,l as i,o as a,r as o,s,t as c}from"./policy-runtime-BMKa-Upy.mjs";import{t as l}from"./done-input-validation-BUz-aVC5.mjs";import{a as u,c as d,d as f,f as p,g as m,h,i as g,l as ee,m as _,n as v,p as y,r as te,t as ne,u as re}from"./prompts-ClBXdELk.mjs";import{t as ie}from"./run-captured-process-BXwWXuTh.mjs";import{t as ae}from"./project-plan-apply-Dvndx455.mjs";import{n as b,r as x,t as S}from"./jsonc-D9dDWb1J.mjs";import{isAbsolute as C,join as w,posix as T,relative as E,resolve as oe,sep as D}from"node:path";import O from"colors";const k=`transcend/policy`;function se(e,t=k){let n=e.process.cwd(),r=oe(n,t);if(e.fs.existsSync(r)&&!e.fs.statSync(r).isDirectory())throw Error(`Policy target is not a directory: ${r}`);return{invocationDirectory:n,targetDirectory:r,...u(e,{invocationDirectory:n,targetDirectory:r,standaloneProjectRoot:n}),relativePaths:g(e,r),relativeFilePaths:g(e,r,{includeDirectories:!1})}}function ce(e){return w(e.targetDirectory,`manifest.json`)}const A={Editor:`editor`,Skill:`skill`,Ci:`ci`};var le=`# Idiomatic Rego and document-tree authoring
2
2
 
3
3
  ## Start from the document tree
4
4
 
@@ -300,4 +300,4 @@ jobs:
300
300
  `,warnings:r};try{return{contents:S(e,t,n),warnings:r}}catch(t){return{contents:e??`{}
301
301
  `,warnings:[...r,`${t instanceof Error?t.message:String(t)} Existing content was left unchanged.`]}}}function K(e,t,n,r){t.forEach(({path:t,value:i,label:a})=>{let o=t.reduce((e,t)=>e&&typeof e==`object`&&!Array.isArray(e)?e[t]:void 0,e);o===void 0?n.push({path:t,value:i}):U(o,i)||r.push(`VS Code setting "${a}" has a repository-specific value and was left unchanged.`)})}function me(e,t){let n=E(e,t).split(D).join(`/`)||`.`;return n===`.`?"${workspaceFolder}":`\${workspaceFolder}/${n}`}function he(e,t,n){let r=W(e,`VS Code policy settings`);if(`warning`in r)return{contents:r.contents,warnings:[r.warning]};let{current:i}=r,a=[],o=[],s=i[`opa.roots`],c=me(t,n);if(s===void 0)a.push({path:[`opa.roots`],value:[c]});else if(Array.isArray(s)&&s.every(e=>typeof e==`string`)){let e=b(s,[c]);U(e,s)||a.push({path:[`opa.roots`],value:e})}else o.push(`VS Code setting "opa.roots" is customized and was left unchanged.`);K(i,[{path:[`opa.checkOnSave`],value:!0,label:`opa.checkOnSave`},{path:[`opa.strictMode`],value:!0,label:`opa.strictMode`},{path:[`opa.bundleMode`],value:!0,label:`opa.bundleMode`},{path:[`opa.formatter`],value:`opa-fmt-rego-v1`,label:`opa.formatter`}],a,o);let l=i[`[rego]`];return l===void 0?a.push({path:[`[rego]`],value:{"editor.defaultFormatter":V,"editor.formatOnSave":!0,"editor.insertSpaces":!1,"editor.tabSize":4}}):typeof l==`object`&&l&&!Array.isArray(l)?K(i,[{path:[`[rego]`,`editor.defaultFormatter`],value:V,label:`[rego].editor.defaultFormatter`},{path:[`[rego]`,`editor.formatOnSave`],value:!0,label:`[rego].editor.formatOnSave`},{path:[`[rego]`,`editor.insertSpaces`],value:!1,label:`[rego].editor.insertSpaces`},{path:[`[rego]`,`editor.tabSize`],value:4,label:`[rego].editor.tabSize`}],a,o):o.push(`VS Code language setting "[rego]" is customized and was left unchanged.`),G(e,a,`VS Code policy settings`,o)}function ge(e){let t=W(e,`VS Code policy extension recommendations`);if(`warning`in t)return{contents:t.contents,warnings:[t.warning]};let{current:n}=t,r=[],i=[],a=n.recommendations;if(a===void 0||Array.isArray(a)&&a.every(e=>typeof e==`string`)){let e=a??[],t=b(e,[V]).filter(e=>e!==H);U(e,t)||r.push({path:[`recommendations`],value:t})}else i.push(`VS Code extension recommendations use an unknown shape and were left unchanged.`);let o=n.unwantedRecommendations;if(o===void 0||Array.isArray(o)&&o.every(e=>typeof e==`string`)){let e=o??[],t=b(e,[H]);U(e,t)||r.push({path:[`unwantedRecommendations`],value:t})}else i.push(`VS Code unwanted extension recommendations use an unknown shape and were left unchanged.`);return G(e,r,`VS Code policy extension recommendations`,i)}function _e(e,t){return{label:`policy: lint`,type:`process`,command:`transcend`,args:[`policy`,`lint`,`--dir`,E(e,t).split(D).join(`/`)||`.`,`--noInteractive`],group:{kind:`test`,isDefault:!0},problemMatcher:[]}}function ve(e,t,n){let r=W(e,`VS Code policy tasks`);if(`warning`in r)return{contents:r.contents,warnings:[r.warning]};let{current:i}=r,a=[],o=[],s=i.version;s===void 0?a.push({path:[`version`],value:`2.0.0`}):s!==`2.0.0`&&o.push(`VS Code task schema version is customized and was left unchanged.`);let c=_e(t,n),l=i.tasks;if(l===void 0)a.push({path:[`tasks`],value:[c]});else if(Array.isArray(l)){let e=l.find(e=>typeof e==`object`&&!!e&&!Array.isArray(e)&&e.label===`policy: lint`);e===void 0?a.push({path:[`tasks`],value:[...l,c]}):U(e,c)||o.push(`VS Code task "policy: lint" has repository-specific customization and was left unchanged.`)}else o.push(`VS Code tasks use an unknown shape and were left unchanged.`);return G(e,a,`VS Code policy tasks`,o)}const q={name:j,displayName:`Policy Engine`,owner:`@transcend-io/cli`,files:M};function ye(e){return`transcend policy lint --dir ${_(y(e.invocationDirectory,e.targetDirectory))} --noInteractive`}function J(e,t){let n=new Set(L().map(({path:t})=>w(e.targetDirectory,t))),r=new Set(t.features);return r.has(A.Editor)&&(n.add(w(e.projectRoot,`.vscode`,`settings.json`)),n.add(w(e.projectRoot,`.vscode`,`extensions.json`)),n.add(w(e.projectRoot,`.vscode`,`tasks.json`))),r.has(A.Skill)&&d(e.projectRoot,e.existingSkillDirectories,q).forEach(e=>n.add(e)),r.has(A.Ci)&&e.repositoryRoot&&e.usesGithub&&n.add(w(e.repositoryRoot,R)),[...n].sort((e,t)=>e.localeCompare(t))}function Y(e,t){let n=E(e,t);if(n===`..`||n.startsWith(`..${D}`)||C(n))throw Error(`Refusing to modify path outside project root: ${t}`)}function be(e){let t=new Set([`input.json`]);return e.forEach(({path:e})=>{t.add(e);let n=T.dirname(e);for(;n!==`.`;)t.add(n),n=T.dirname(n)}),t}function X(e,t,n){let r=p({snapshot:re(t.snapshots,n.path),after:n.contents,description:n.description,...n.createOnly===void 0?{}:{createOnly:n.createOnly}});r?e.changes.push(r):e.unchanged.push(n.path)}function xe(e,t,n,r,i,a){X(e,t,{path:n,contents:r.contents,description:i}),e.warnings.push(...r.warnings.map(e=>`${e} (${y(a,n)})`))}function Se(e,t){let{state:n}=e,r=L(),i=ce(n),a=ye(n),o=w(n.targetDirectory,`policy_engine`,`example`,`result.rego`),s={version:1,command:`init`,rootDirectory:n.projectRoot,targetDirectory:n.targetDirectory,manifestPath:i,changes:[],unchanged:[],warnings:[],nextSteps:[a],features:[...t.features]},c=J(n,t);Y(n.projectRoot,n.targetDirectory),c.forEach(e=>Y(n.projectRoot,e));let l=!1;if(n.relativeFilePaths.length===0)l=!0,s.directoryPreconditions=[{path:n.targetDirectory,relativePaths:[...n.relativePaths]}],r.forEach(t=>{let r=w(n.targetDirectory,t.path);if(f(e.snapshots,r).kind!==`absent`)throw Error(`Expected an empty policy target, but found an entry at: ${r}`);X(s,e,{path:r,contents:t.contents,description:t.description,createOnly:!0})});else{let t=!0;r.forEach(r=>{let i=w(n.targetDirectory,r.path),a=f(e.snapshots,i);if(a.kind===`file`&&a.contents===r.contents){s.unchanged.push(i);return}t=!1,a.kind!==`absent`&&(s.unchanged.push(i),s.warnings.push(`Existing policy scaffold path was left unchanged: ${y(n.invocationDirectory,i)}`))}),l=t;let i=be(r),o=n.relativeFilePaths.some(e=>!i.has(e));(!t||o)&&s.warnings.push(`Existing policy target contains custom or partial content, so no starter files were added or overwritten. Review ${y(n.invocationDirectory,n.targetDirectory)} manually, then run \`${a}\`.`)}l&&(s.disposableExamplePath=o,s.nextSteps.push(`Edit ${_(y(n.invocationDirectory,o))}`));let u=new Set(t.features),d=n.projectRoot;if(u.has(A.Editor)){let t=w(d,`.vscode`,`settings.json`),r=w(d,`.vscode`,`extensions.json`),i=w(d,`.vscode`,`tasks.json`);[{path:t,description:`Merge strict target-scoped OPA and Rego editor settings`,merge:he},{path:r,description:`Recommend the OPA extension and discourage its syntax-only conflict`,merge:(e,t,n)=>ge(e)},{path:i,description:`Add the default target-scoped policy lint task`,merge:ve}].forEach(({path:t,description:r,merge:i})=>{let a=f(e.snapshots,t);if(a.kind!==`absent`&&a.kind!==`file`){s.unchanged.push(t),s.warnings.push(`Existing VS Code artifact is not a regular file and was left unchanged: ${y(n.invocationDirectory,t)}`);return}xe(s,e,t,i(a.kind===`file`?a.contents:null,d,n.targetDirectory),r,n.invocationDirectory)})}if(u.has(A.Skill)){let t=ee({rootDirectory:d,existingDirectories:n.existingSkillDirectories,snapshots:e.snapshots,skill:q,preserveModified:!0});s.changes.push(...t.changes),s.unchanged.push(...t.unchanged),s.warnings.push(...t.warnings.map(e=>t.unchanged.reduce((e,t)=>e.replace(t,y(n.invocationDirectory,t)),e)))}if(u.has(A.Ci))if(!n.repositoryRoot||!n.usesGithub)s.warnings.push(`GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.`);else{let r=w(n.repositoryRoot,R),i=E(n.repositoryRoot,n.targetDirectory).split(D).join(`/`)||`.`,o=B({cliVersion:t.cliVersion,targetDirectory:i}),c=f(e.snapshots,r);c.kind===`absent`?X(s,e,{path:r,contents:o,description:`Add credential-free Policy Engine validation`,createOnly:!0}):c.kind===`file`&&c.contents===o?s.unchanged.push(r):(s.unchanged.push(r),s.warnings.push(`Existing GitHub Actions workflow was left unchanged: ${y(n.invocationDirectory,r)}. Adapt it manually to run \`${a}\`.`))}return s.changes.forEach(({path:e})=>Y(n.projectRoot,e)),s}const Z={[A.Editor]:`VS Code settings and lint task`,[A.Skill]:`Policy Engine Agent Skill`,[A.Ci]:`Validation-only GitHub Actions`},Q=Object.values(A);function Ce(e,t,n){return!e.json&&!e.noInteractive&&!!(t&&n)}async function we(e,t,n){let r={[A.Editor]:t.editor,[A.Skill]:t.skill,[A.Ci]:t.ci};if(!n.interactive)return Q.filter(e=>r[e]===!0);let i=Q.map(e=>({name:Z[e],value:e,checked:r[e]!==!1}));return e.checkbox(`Choose repository setup:`,i)}function $(e,n){let r=[n.stdout.trim(),n.stderr.trim()].filter(Boolean).join(`
302
302
  `),i=e===`OPA`?o:t;return`${e===`OPA`?`OPA 1.x`:`Regal ${c} or newer`} is required, but \`${e.toLowerCase()} version\` exited with code ${n.code}${r?`: ${r}`:`.`} Install or upgrade it using the official instructions: ${i}`}async function Te(e,t,o){let l={opa:null,regal:null},u=[],d=await o(`opa`,[`version`],{cwd:t},e);if(d.error?.code===`ENOENT`)u.push(r);else{let e=`${d.stdout}\n${d.stderr}`,t=n(e);d.code===0?t?u.push(t):l.opa=s(e).version:u.push(t??$(`OPA`,d))}let f=await o(`regal`,[`version`],{cwd:t},e);if(f.error?.code===`ENOENT`)u.push(a);else{let e=`${f.stdout}\n${f.stderr}`,t=i(e,c,`the generated OPA 1.13.1 capabilities configuration`);f.code===0?t?u.push(t):l.regal=s(e).version:u.push(t??$(`Regal`,f))}return{tools:l,warnings:u}}async function Ee(t,n=k,r=ie){l(this.process);try{let i=await Te(this,this.process.cwd(),r),a=se(this,n),o=new v(this),s=Ce(t,this.process.stdin.isTTY,this.process.stderr.isTTY),c=await we(o,t,{interactive:s}),l=J(a,{features:c}),u=Se({state:a,snapshots:te(this,a.projectRoot,l)},{features:c,cliVersion:e});u.warnings.push(...i.warnings),t.json||this.logger.info(h(u,{cwd:this.process.cwd(),title:`Policy initialization plan`,details:[{label:`Target`,path:u.targetDirectory},{label:`Manifest`,path:u.manifestPath}]}));let d=u.changes.length===0||t.dryRun;if(u.changes.length>0&&!t.dryRun)if(t.yes)d=!0;else if(s)d=await o.confirm(`Apply this complete plan?`,!0);else throw Error(`The plan requires approval in a non-interactive invocation. Review with --dryRun, then pass --yes.`);d&&!t.dryRun&&u.changes.length>0&&await ae(this,u);let f=d&&!t.dryRun&&u.changes.length>0,p=d&&!t.dryRun,m=N({projectPath:_(y(this.process.cwd(),a.targetDirectory)),...u.disposableExamplePath?{examplePath:_(y(this.process.cwd(),u.disposableExamplePath))}:{},hasSkill:p&&c.includes(A.Skill),lintCommand:u.nextSteps[0]}),g=P(u,{applied:f,dryRun:t.dryRun,cwd:this.process.cwd(),aiHandoff:m,tools:i.tools});if(t.json){this.process.stdout.write(`${JSON.stringify(g)}\n`);return}if(t.dryRun){this.logger.info(O.yellow(`Dry run complete. No changes were written.`));return}if(!d){this.logger.info(O.yellow(`No changes applied.`));return}if(u.changes.length===0){let e=u.warnings.length===i.warnings.length?`Policy project is already initialized.`:`Existing policy project was left unchanged.`;this.logger.info(O.green(e))}else this.logger.info(O.green(`Policy project initialized.`));u.nextSteps.length>0&&(this.logger.info(`\n${O.bold(`Next steps`)}`),u.nextSteps.forEach(e=>this.logger.info(e))),this.logger.info(`\n${O.bold(`AI handoff — paste into your coding agent`)}`),this.logger.info(m)}catch(e){if(e instanceof ne)return this.process.exit(130);throw e}}export{Ee as init};
303
- //# sourceMappingURL=impl-CMK8Qm_I2.mjs.map
303
+ //# sourceMappingURL=impl-DHQh34Eh2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-CMK8Qm_I2.mjs","names":["POLICY_SKILL_MD","POLICY_SETUP_TOOLING_REFERENCE_MD","POLICY_AUTHORING_REFERENCE_MD","POLICY_TESTING_DEBUGGING_REFERENCE_MD","POLICY_PUBLISHING_REFERENCE_MD","CLI_VERSION"],"sources":["../src/lib/policy/policy-project-discovery.ts","../src/lib/policy/policy-scaffold-model.ts","../../../skills/transcend-policy-engine/references/authoring.md","../../../skills/transcend-policy-engine/references/publishing.md","../../../skills/transcend-policy-engine/references/setup-tooling.md","../../../skills/transcend-policy-engine/references/testing-debugging.md","../../../skills/transcend-policy-engine/SKILL.md","../src/lib/policy/policy-skill.ts","../src/lib/policy/policy-scaffold-output.ts","../src/lib/policy/policy-scaffold-templates.ts","../src/lib/policy/policy-scaffold-artifacts.ts","../src/lib/policy/policy-scaffold-config.ts","../src/lib/policy/policy-scaffold-planning.ts","../src/commands/policy/init/impl.ts"],"sourcesContent":["import { join, resolve } from 'node:path';\n\nimport type { LocalContext } from '../../context.js';\nimport {\n collectProjectRelativePaths,\n discoverProjectRepository,\n} from '../scaffolding/project-discovery.js';\nimport type { PolicyProjectState } from './policy-scaffold-model.js';\n\n/** Default local policy project directory. */\nexport const DEFAULT_POLICY_PROJECT_DIRECTORY = 'transcend/policy';\n\n/**\n * Collect repository state required by the pure policy planner.\n *\n * @param context - CLI context\n * @param directory - User-selected target directory\n * @returns Policy project discovery state\n */\nexport function discoverPolicyProject(\n context: LocalContext,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n): PolicyProjectState {\n const invocationDirectory = context.process.cwd();\n const targetDirectory = resolve(invocationDirectory, directory);\n if (\n context.fs.existsSync(targetDirectory) &&\n !context.fs.statSync(targetDirectory).isDirectory()\n ) {\n throw new Error(`Policy target is not a directory: ${targetDirectory}`);\n }\n const repository = discoverProjectRepository(context, {\n invocationDirectory,\n targetDirectory,\n standaloneProjectRoot: invocationDirectory,\n });\n return {\n invocationDirectory,\n targetDirectory,\n ...repository,\n relativePaths: collectProjectRelativePaths(context, targetDirectory),\n relativeFilePaths: collectProjectRelativePaths(context, targetDirectory, {\n includeDirectories: false,\n }),\n };\n}\n\n/**\n * Resolve the bundle manifest path for a discovered project.\n *\n * @param state - Policy project state\n * @returns Absolute manifest path\n */\nexport function getPolicyManifestPath(state: PolicyProjectState): string {\n return join(state.targetDirectory, 'manifest.json');\n}\n","import type { ExistingProjectSkillDirectory } from '../scaffolding/agent-skill.js';\nimport type { ProjectPlan } from '../scaffolding/project-plan.js';\n\n/** Version of the stable policy initialization JSON result. */\nexport const POLICY_INIT_RESULT_VERSION = 1 as const;\n\n/** Optional repository integrations for policy authoring. */\nexport const PolicySetupFeature = {\n /** Repository-level editor configuration. */\n Editor: 'editor',\n /** Managed policy authoring skill. */\n Skill: 'skill',\n /** Credential-free continuous integration. */\n Ci: 'ci',\n} as const;\n\n/** Optional repository integration for policy authoring. */\nexport type PolicySetupFeature = (typeof PolicySetupFeature)[keyof typeof PolicySetupFeature];\n\n/** Repository and target state collected before policy planning. */\nexport interface PolicyProjectState {\n /** Directory from which the CLI was invoked. */\n invocationDirectory: string;\n /** Absolute user-selected policy directory. */\n targetDirectory: string;\n /** Repository or invocation root that owns setup artifacts. */\n projectRoot: string;\n /** Nearest repository root, when present. */\n repositoryRoot?: string;\n /** Existing project-level skill directories. */\n existingSkillDirectories: ExistingProjectSkillDirectory[];\n /** Whether the repository appears to use GitHub. */\n usesGithub: boolean;\n /** Case-preserving relative paths below the policy directory. */\n relativePaths: string[];\n /** Relative file and link paths below the policy directory. */\n relativeFilePaths: string[];\n}\n\n/** A complete, validated policy initialization plan. */\nexport interface PolicyInitProjectPlan extends ProjectPlan {\n /** JSON contract version. */\n version: typeof POLICY_INIT_RESULT_VERSION;\n /** Command that produced the plan. */\n command: 'init';\n /** Absolute policy project directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Files inspected and deliberately left unchanged. */\n unchanged: string[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Raw commands shown after a successful apply. */\n nextSteps: string[];\n /** Exact generated example that remains safe to replace. */\n disposableExamplePath?: string;\n /** Selected repository integrations. */\n features: PolicySetupFeature[];\n}\n",null,null,null,null,null,"import POLICY_AUTHORING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/authoring.md';\nimport POLICY_PUBLISHING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/publishing.md';\nimport POLICY_SETUP_TOOLING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/setup-tooling.md';\nimport POLICY_TESTING_DEBUGGING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/testing-debugging.md';\nimport POLICY_SKILL_MD from '../../../../../skills/transcend-policy-engine/SKILL.md';\nimport type { AgentSkillFile } from '../scaffolding/agent-skill.js';\n\n/** Namespaced directory and frontmatter name for the installed Agent Skill. */\nexport const POLICY_SKILL_NAME = 'transcend-policy-engine';\n\nexport {\n POLICY_AUTHORING_REFERENCE_MD,\n POLICY_PUBLISHING_REFERENCE_MD,\n POLICY_SETUP_TOOLING_REFERENCE_MD,\n POLICY_SKILL_MD,\n POLICY_TESTING_DEBUGGING_REFERENCE_MD,\n};\n\n/** Complete portable Policy Engine Agent Skill file set. */\nexport const POLICY_SKILL_FILES: readonly AgentSkillFile[] = [\n { path: 'SKILL.md', contents: POLICY_SKILL_MD },\n { path: 'references/setup-tooling.md', contents: POLICY_SETUP_TOOLING_REFERENCE_MD },\n { path: 'references/authoring.md', contents: POLICY_AUTHORING_REFERENCE_MD },\n { path: 'references/testing-debugging.md', contents: POLICY_TESTING_DEBUGGING_REFERENCE_MD },\n { path: 'references/publishing.md', contents: POLICY_PUBLISHING_REFERENCE_MD },\n];\n","import {\n toPublicPlannedChange,\n type PublicPlannedChange,\n} from '../scaffolding/project-plan-output.js';\nimport type { PolicyInitProjectPlan, PolicySetupFeature } from './policy-scaffold-model.js';\nimport { POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Detected local policy tool versions. */\nexport interface PolicyInitToolVersions {\n /** OPA version, or null when missing or incompatible. */\n opa: string | null;\n /** Regal version, or null when missing or incompatible. */\n regal: string | null;\n}\n\n/** Stable machine-readable policy initialization result. */\nexport interface PolicyInitPlanResult {\n /** JSON contract version. */\n version: number;\n /** Command that produced the result. */\n command: 'init';\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Absolute policy target directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Planned mutations without file contents. */\n changes: PublicPlannedChange[];\n /** Non-fatal preservation and runtime warnings. */\n warnings: string[];\n /** Suggested raw one-line follow-up commands. */\n nextSteps: string[];\n /** Explicitly selected repository integrations. */\n features: PolicySetupFeature[];\n /** Compact prompt for continuing with a coding agent. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n}\n\n/**\n * Build the compact policy implementation and CI handoff.\n *\n * @param options - Portable example path and lint command\n * @returns Raw one-line prompt\n */\nexport function buildPolicyInitAiHandoff(options: {\n /** Display path to the policy project. */\n projectPath: string;\n /** Display path to an exact disposable example. */\n examplePath?: string;\n /** Whether the policy authoring skill was installed. */\n hasSkill: boolean;\n /** Copyable lint command. */\n lintCommand: string;\n}): string {\n if (!options.examplePath) {\n const instruction = options.hasSkill\n ? `Use the \\`${POLICY_SKILL_NAME}\\` skill to review`\n : 'Review';\n return (\n `${instruction} the existing policy project in ${options.projectPath}, ` +\n `align its document tree and input/output contract with the intended application, adapt ` +\n `repository validation as needed, and rerun ${options.lintCommand}.`\n );\n }\n const instruction = options.hasSkill\n ? `Use the \\`${POLICY_SKILL_NAME}\\` skill to replace`\n : 'Replace';\n return (\n `${instruction} the disposable example in ${options.examplePath} with ` +\n `the intended policy document tree and input/output contract, adapt repository validation ` +\n `to local conventions, and rerun ${options.lintCommand}.`\n );\n}\n\n/**\n * Build the stable machine-readable initialization result.\n *\n * @param plan - Policy project plan\n * @param options - Apply and runtime state\n * @returns Public JSON result\n */\nexport function buildPolicyInitPlanResult(\n plan: PolicyInitProjectPlan,\n options: {\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Working directory for portable paths. */\n cwd: string;\n /** Compact coding-agent prompt. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n },\n): PolicyInitPlanResult {\n return {\n version: plan.version,\n command: plan.command,\n applied: options.applied,\n dryRun: options.dryRun,\n targetDirectory: plan.targetDirectory,\n manifestPath: plan.manifestPath,\n changes: plan.changes.map((change) => toPublicPlannedChange(options.cwd, change)),\n warnings: plan.warnings,\n nextSteps: plan.nextSteps,\n features: [...plan.features],\n aiHandoff: options.aiHandoff,\n tools: options.tools,\n };\n}\n","/** OPA version targeted by generated policy authoring configuration. */\nexport const POLICY_STARTER_OPA_VERSION = '1.13.1';\n\n/** One deterministic file in the safe policy starter. */\nexport interface PolicyStarterFile {\n /** POSIX-style path relative to the policy directory. */\n path: string;\n /** Complete UTF-8 file contents. */\n contents: string;\n /** Human-readable reason shown in the plan. */\n description: string;\n}\n\n/** Publishable Policy Engine bundle manifest. */\nexport const POLICY_MANIFEST_TEMPLATE = `{\n \"roots\": [\"policy_engine\"]\n}\n`;\n\n/** Strict Regal project configuration pinned to the deployed OPA capabilities. */\nexport const POLICY_REGAL_CONFIG_TEMPLATE = `capabilities:\n from:\n engine: opa\n version: v${POLICY_STARTER_OPA_VERSION}\nproject:\n roots:\n - .\n rego-version: 1\n`;\n\n/** Disposable, fail-closed example policy. */\nexport const POLICY_RESULT_REGO_TEMPLATE = `package policy_engine.example\n\nimport rego.v1\n\n# METADATA\n# title: Disposable example result\n# description: |\n# A fail-closed teaching entrypoint. Replace this example with the document\n# tree and result contract required by your application.\n# entrypoint: true\ndefault result := {\n\t\"decision\": \"deny\",\n\t\"reason_code\": \"untrusted_or_invalid_input\",\n}\n\nresult := {\n\t\"decision\": \"allow\",\n\t\"reason_code\": \"trusted_subject\",\n} if {\n\tinput.subject.trusted == true\n}\n`;\n\n/** Executable tests adjacent to the disposable example policy. */\nexport const POLICY_RESULT_TEST_REGO_TEMPLATE = `package policy_engine.example_test\n\nimport data.policy_engine.example\nimport rego.v1\n\ntest_denies_untrusted_subject if {\n\tresult := example.result with input as {\"subject\": {\"trusted\": false}}\n\tresult == {\n\t\t\"decision\": \"deny\",\n\t\t\"reason_code\": \"untrusted_or_invalid_input\",\n\t}\n}\n\ntest_fails_closed_for_missing_subject if {\n\tresult := example.result with input as {}\n\tresult == {\n\t\t\"decision\": \"deny\",\n\t\t\"reason_code\": \"untrusted_or_invalid_input\",\n\t}\n}\n\ntest_allows_trusted_subject if {\n\tresult := example.result with input as {\"subject\": {\"trusted\": true}}\n\tresult == {\n\t\t\"decision\": \"allow\",\n\t\t\"reason_code\": \"trusted_subject\",\n\t}\n}\n`;\n\n/** Sanitized local input example containing no credentials or personal data. */\nexport const POLICY_INPUT_EXAMPLE_TEMPLATE = `{\n \"subject\": {\n \"trusted\": false\n }\n}\n`;\n\n/** Target-local ignore rules for private evaluation input only. */\nexport const POLICY_GITIGNORE_TEMPLATE = `# Local policy evaluation input.\n/input.json\n`;\n\n/** Concise project-local authoring guide. */\nexport const POLICY_README_TEMPLATE = `# Transcend Policy Project\n\nThis directory is an OPA document tree that can be published to Transcend Policy Engine.\n\nThe policy under \\`policy_engine/example\\` is disposable teaching material. Replace it with your intended package tree, input shape, and extensible result documents. Keep decisions fail-closed and cover every non-test package with \\`manifest.json\\`.\n\nValidate formatting, strict Rego v1 compatibility, Regal lint, tests, and the publish contract:\n\n\\`\\`\\`sh\ntranscend policy lint --dir .\n\\`\\`\\`\n`;\n\n/** Complete safe starter in deterministic plan order. */\nconst POLICY_STARTER_FILES: readonly PolicyStarterFile[] = [\n {\n path: 'manifest.json',\n contents: POLICY_MANIFEST_TEMPLATE,\n description: 'Create the publishable Policy Engine manifest',\n },\n {\n path: '.regal/config.yaml',\n contents: POLICY_REGAL_CONFIG_TEMPLATE,\n description: 'Pin strict Rego v1 linting to OPA 1.13.1 capabilities',\n },\n {\n path: 'policy_engine/example/result.rego',\n contents: POLICY_RESULT_REGO_TEMPLATE,\n description: 'Create a documented fail-closed result entrypoint',\n },\n {\n path: 'policy_engine/example/result_test.rego',\n contents: POLICY_RESULT_TEST_REGO_TEMPLATE,\n description: 'Create executable tests for allow and fail-closed decisions',\n },\n {\n path: 'input.example.json',\n contents: POLICY_INPUT_EXAMPLE_TEMPLATE,\n description: 'Create a sanitized local evaluation input',\n },\n {\n path: '.gitignore',\n contents: POLICY_GITIGNORE_TEMPLATE,\n description: 'Ignore only the private local input file',\n },\n {\n path: 'README.md',\n contents: POLICY_README_TEMPLATE,\n description: 'Create the concise policy project guide',\n },\n];\n\n/**\n * Generate an independent copy of the safe policy starter.\n *\n * @returns Deterministic relative files\n */\nexport function generatePolicyStarterFiles(): PolicyStarterFile[] {\n return POLICY_STARTER_FILES.map((file) => ({ ...file }));\n}\n","import { posix } from 'node:path';\n\nimport { POLICY_STARTER_OPA_VERSION } from './policy-scaffold-templates.js';\n\n/** Regal version pinned by generated policy validation. */\nexport const POLICY_STARTER_REGAL_VERSION = '0.42.0';\n\n/** Repository-relative generated workflow path. */\nexport const POLICY_CI_WORKFLOW_PATH = '.github/workflows/transcend-policy.yml';\n\n/** Immutable actions/checkout v6 release commit. */\nexport const ACTIONS_CHECKOUT_SHA = 'd23441a48e516b6c34aea4fa41551a30e30af803';\n\n/** Immutable open-policy-agent/setup-opa v2.4.0 release commit. */\nexport const SETUP_OPA_SHA = 'b2b258e089860efaadaaf71bf6e3aecb4a3eeff1';\n\n/** Immutable open-policy-agent/setup-regal v2.0.0 release commit. */\nexport const SETUP_REGAL_SHA = '761188c3b435761fa254beca508a44875619648f';\n\n/**\n * Prefix a path below the repository-relative policy target.\n *\n * @param targetDirectory - POSIX repository-relative target\n * @param child - POSIX target-relative path or pattern\n * @returns Repository-relative path or pattern\n */\nfunction targetPath(targetDirectory: string, child: string): string {\n return targetDirectory === '.' ? child : posix.join(targetDirectory, child);\n}\n\n/**\n * Generate credential-free, validation-only Policy Engine CI.\n *\n * @param options - Repository paths and exact CLI release\n * @returns Complete GitHub Actions workflow YAML\n */\nexport function generatePolicyGithubActionsWorkflow(options: {\n /** Exact released Transcend CLI version. */\n cliVersion: string;\n /** Policy directory relative to the repository root. */\n targetDirectory: string;\n}): string {\n const watchedPaths = [\n targetPath(options.targetDirectory, '**/*.rego'),\n targetPath(options.targetDirectory, '**/*.json'),\n targetPath(options.targetDirectory, '**/*.yaml'),\n targetPath(options.targetDirectory, '**/*.yml'),\n targetPath(options.targetDirectory, '.regal/config.yaml'),\n targetPath(options.targetDirectory, '.regal.yaml'),\n POLICY_CI_WORKFLOW_PATH,\n ];\n const pathFilters = watchedPaths.map((path) => ` - ${JSON.stringify(path)}`).join('\\n');\n\n return `# Generated by transcend policy init.\nname: Transcend Policy\n\non:\n pull_request:\n paths:\n${pathFilters}\n push:\n paths:\n${pathFilters}\n\npermissions:\n contents: read\n\njobs:\n lint:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@${ACTIONS_CHECKOUT_SHA} # v6\n - name: Set up OPA\n uses: open-policy-agent/setup-opa@${SETUP_OPA_SHA} # v2.4.0\n with:\n version: ${JSON.stringify(POLICY_STARTER_OPA_VERSION)}\n - name: Set up Regal\n uses: open-policy-agent/setup-regal@${SETUP_REGAL_SHA} # v2.0.0\n with:\n version: ${JSON.stringify(POLICY_STARTER_REGAL_VERSION)}\n - name: Install the Transcend CLI\n run: npm install --global @transcend-io/cli@${options.cliVersion}\n - name: Validate Policy Engine project\n env:\n POLICY_DIRECTORY: ${JSON.stringify(options.targetDirectory)}\n run: >-\n transcend policy lint\n --dir \"$POLICY_DIRECTORY\"\n --noInteractive\n --json\n`;\n}\n","import { relative, sep } from 'node:path';\n\nimport {\n mergeJsonc,\n mergeStringArray,\n parseJsoncObject,\n type JsoncUpdate,\n} from '../scaffolding/jsonc.js';\n\n/** Recommended VS Code extension for OPA and Regal authoring. */\nexport const POLICY_VSCODE_EXTENSION = 'tsandall.opa';\n\n/** Conflicting syntax-only VS Code extension. */\nexport const CONFLICTING_POLICY_VSCODE_EXTENSION = 'glebbash.opa-highlight-only';\n\n/** Result of safely merging one repository editor artifact. */\nexport interface PolicyEditorMergeResult {\n /** Complete merged contents, or the unchanged original when unsafe. */\n contents: string;\n /** Actionable preservation warnings. */\n warnings: string[];\n}\n\n/** One desired scalar setting that must not replace a customization. */\ninterface DesiredSetting {\n /** JSONC object path. */\n path: string[];\n /** Desired generated value. */\n value: unknown;\n /** Human-readable setting key. */\n label: string;\n}\n\n/**\n * Compare JSON-compatible configuration values.\n *\n * @param left - Existing value\n * @param right - Desired value\n * @returns Whether the values are structurally equal\n */\nfunction configurationValuesEqual(left: unknown, right: unknown): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\n/**\n * Parse an editor object while preserving malformed existing content.\n *\n * @param contents - Existing JSONC, or null\n * @param label - Configuration label\n * @returns Parsed object or a preservation result\n */\nfunction parseEditorObject(\n contents: string | null,\n label: string,\n):\n | {\n /** Parsed JSONC object. */\n current: Record<string, unknown>;\n }\n | {\n /** Complete unchanged contents. */\n contents: string;\n /** Actionable warning. */\n warning: string;\n } {\n try {\n return { current: parseJsoncObject(contents ?? '{}\\n', label) };\n } catch (error) {\n return {\n contents: contents ?? '{}\\n',\n warning: `${error instanceof Error ? error.message : String(error)} Existing content was left unchanged.`,\n };\n }\n}\n\n/**\n * Apply safe JSONC updates or preserve the existing file when comments prevent it.\n *\n * @param contents - Existing JSONC\n * @param updates - Proven-safe updates\n * @param label - Configuration label\n * @param warnings - Existing merge warnings\n * @returns Complete contents and warnings\n */\nfunction applyEditorUpdates(\n contents: string | null,\n updates: readonly JsoncUpdate[],\n label: string,\n warnings: string[],\n): PolicyEditorMergeResult {\n if (updates.length === 0) {\n return { contents: contents ?? '{}\\n', warnings };\n }\n try {\n return {\n contents: mergeJsonc(contents, updates, label),\n warnings,\n };\n } catch (error) {\n return {\n contents: contents ?? '{}\\n',\n warnings: [\n ...warnings,\n `${error instanceof Error ? error.message : String(error)} Existing content was left unchanged.`,\n ],\n };\n }\n}\n\n/**\n * Add absent scalar settings without replacing repository customizations.\n *\n * @param current - Parsed editor object\n * @param desired - Desired settings\n * @param updates - Safe updates to append to\n * @param warnings - Conflict warnings to append to\n */\nfunction collectSafeScalarUpdates(\n current: Record<string, unknown>,\n desired: readonly DesiredSetting[],\n updates: JsoncUpdate[],\n warnings: string[],\n): void {\n desired.forEach(({ path, value, label }) => {\n const existing = path.reduce<unknown>((parent, key) => {\n return parent && typeof parent === 'object' && !Array.isArray(parent)\n ? (parent as Record<string, unknown>)[key]\n : undefined;\n }, current);\n if (existing === undefined) {\n updates.push({ path, value });\n } else if (!configurationValuesEqual(existing, value)) {\n warnings.push(\n `VS Code setting \"${label}\" has a repository-specific value and was left unchanged.`,\n );\n }\n });\n}\n\n/**\n * Build the workspace-relative OPA bundle root.\n *\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns VS Code workspace path\n */\nfunction buildOpaWorkspaceRoot(repositoryRoot: string, targetDirectory: string): string {\n const target = relative(repositoryRoot, targetDirectory).split(sep).join('/') || '.';\n return target === '.' ? '${workspaceFolder}' : `\\${workspaceFolder}/${target}`;\n}\n\n/**\n * Merge strict target-scoped OPA and Rego editor settings.\n *\n * Setting names match the authoritative `open-policy-agent/vscode-opa`\n * extension metadata. Existing conflicting values are preserved and reported.\n *\n * @param contents - Existing `.vscode/settings.json` JSONC\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns Merged settings and conflict warnings\n */\nexport function mergePolicyEditorSettings(\n contents: string | null,\n repositoryRoot: string,\n targetDirectory: string,\n): PolicyEditorMergeResult {\n const parsed = parseEditorObject(contents, 'VS Code policy settings');\n if ('warning' in parsed) {\n return { contents: parsed.contents, warnings: [parsed.warning] };\n }\n const { current } = parsed;\n const updates: JsoncUpdate[] = [];\n const warnings: string[] = [];\n\n const roots = current['opa.roots'];\n const desiredRoot = buildOpaWorkspaceRoot(repositoryRoot, targetDirectory);\n if (roots === undefined) {\n updates.push({ path: ['opa.roots'], value: [desiredRoot] });\n } else if (Array.isArray(roots) && roots.every((value) => typeof value === 'string')) {\n const merged = mergeStringArray(roots, [desiredRoot]);\n if (!configurationValuesEqual(merged, roots)) {\n updates.push({ path: ['opa.roots'], value: merged });\n }\n } else {\n warnings.push('VS Code setting \"opa.roots\" is customized and was left unchanged.');\n }\n\n collectSafeScalarUpdates(\n current,\n [\n { path: ['opa.checkOnSave'], value: true, label: 'opa.checkOnSave' },\n { path: ['opa.strictMode'], value: true, label: 'opa.strictMode' },\n { path: ['opa.bundleMode'], value: true, label: 'opa.bundleMode' },\n { path: ['opa.formatter'], value: 'opa-fmt-rego-v1', label: 'opa.formatter' },\n ],\n updates,\n warnings,\n );\n\n const regoSettings = current['[rego]'];\n if (regoSettings === undefined) {\n updates.push({\n path: ['[rego]'],\n value: {\n 'editor.defaultFormatter': POLICY_VSCODE_EXTENSION,\n 'editor.formatOnSave': true,\n 'editor.insertSpaces': false,\n 'editor.tabSize': 4,\n },\n });\n } else if (\n regoSettings !== null &&\n typeof regoSettings === 'object' &&\n !Array.isArray(regoSettings)\n ) {\n collectSafeScalarUpdates(\n current,\n [\n {\n path: ['[rego]', 'editor.defaultFormatter'],\n value: POLICY_VSCODE_EXTENSION,\n label: '[rego].editor.defaultFormatter',\n },\n {\n path: ['[rego]', 'editor.formatOnSave'],\n value: true,\n label: '[rego].editor.formatOnSave',\n },\n {\n path: ['[rego]', 'editor.insertSpaces'],\n value: false,\n label: '[rego].editor.insertSpaces',\n },\n {\n path: ['[rego]', 'editor.tabSize'],\n value: 4,\n label: '[rego].editor.tabSize',\n },\n ],\n updates,\n warnings,\n );\n } else {\n warnings.push('VS Code language setting \"[rego]\" is customized and was left unchanged.');\n }\n\n return applyEditorUpdates(contents, updates, 'VS Code policy settings', warnings);\n}\n\n/**\n * Merge OPA extension recommendations without disturbing unknown entries.\n *\n * VS Code's `extensions.json` schema supports `unwantedRecommendations`, so\n * the syntax-only extension can be removed from recommendations and discouraged.\n *\n * @param contents - Existing `.vscode/extensions.json` JSONC\n * @returns Merged extension recommendations and warnings\n */\nexport function mergePolicyEditorExtensions(contents: string | null): PolicyEditorMergeResult {\n const parsed = parseEditorObject(contents, 'VS Code policy extension recommendations');\n if ('warning' in parsed) {\n return { contents: parsed.contents, warnings: [parsed.warning] };\n }\n const { current } = parsed;\n const updates: JsoncUpdate[] = [];\n const warnings: string[] = [];\n\n const recommendations = current.recommendations;\n if (\n recommendations === undefined ||\n (Array.isArray(recommendations) && recommendations.every((value) => typeof value === 'string'))\n ) {\n const existing = recommendations ?? [];\n const desired = mergeStringArray(existing, [POLICY_VSCODE_EXTENSION]).filter(\n (value) => value !== CONFLICTING_POLICY_VSCODE_EXTENSION,\n );\n if (!configurationValuesEqual(existing, desired)) {\n updates.push({ path: ['recommendations'], value: desired });\n }\n } else {\n warnings.push(\n 'VS Code extension recommendations use an unknown shape and were left unchanged.',\n );\n }\n\n const unwanted = current.unwantedRecommendations;\n if (\n unwanted === undefined ||\n (Array.isArray(unwanted) && unwanted.every((value) => typeof value === 'string'))\n ) {\n const existing = unwanted ?? [];\n const desired = mergeStringArray(existing, [CONFLICTING_POLICY_VSCODE_EXTENSION]);\n if (!configurationValuesEqual(existing, desired)) {\n updates.push({ path: ['unwantedRecommendations'], value: desired });\n }\n } else {\n warnings.push(\n 'VS Code unwanted extension recommendations use an unknown shape and were left unchanged.',\n );\n }\n\n return applyEditorUpdates(\n contents,\n updates,\n 'VS Code policy extension recommendations',\n warnings,\n );\n}\n\n/**\n * Build the generated target-scoped VS Code lint task.\n *\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns VS Code task object\n */\nexport function buildPolicyLintTask(\n repositoryRoot: string,\n targetDirectory: string,\n): Record<string, unknown> {\n const target = relative(repositoryRoot, targetDirectory).split(sep).join('/') || '.';\n return {\n label: 'policy: lint',\n type: 'process',\n command: 'transcend',\n args: ['policy', 'lint', '--dir', target, '--noInteractive'],\n group: {\n kind: 'test',\n isDefault: true,\n },\n problemMatcher: [],\n };\n}\n\n/**\n * Merge the default policy lint task while preserving custom tasks.\n *\n * @param contents - Existing `.vscode/tasks.json` JSONC\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns Merged task configuration and warnings\n */\nexport function mergePolicyEditorTasks(\n contents: string | null,\n repositoryRoot: string,\n targetDirectory: string,\n): PolicyEditorMergeResult {\n const parsed = parseEditorObject(contents, 'VS Code policy tasks');\n if ('warning' in parsed) {\n return { contents: parsed.contents, warnings: [parsed.warning] };\n }\n const { current } = parsed;\n const updates: JsoncUpdate[] = [];\n const warnings: string[] = [];\n const version = current.version;\n if (version === undefined) {\n updates.push({ path: ['version'], value: '2.0.0' });\n } else if (version !== '2.0.0') {\n warnings.push('VS Code task schema version is customized and was left unchanged.');\n }\n\n const desiredTask = buildPolicyLintTask(repositoryRoot, targetDirectory);\n const tasks = current.tasks;\n if (tasks === undefined) {\n updates.push({ path: ['tasks'], value: [desiredTask] });\n } else if (Array.isArray(tasks)) {\n const matchingTask = tasks.find(\n (task) =>\n task !== null &&\n typeof task === 'object' &&\n !Array.isArray(task) &&\n (task as Record<string, unknown>).label === 'policy: lint',\n );\n if (matchingTask === undefined) {\n updates.push({ path: ['tasks'], value: [...tasks, desiredTask] });\n } else if (!configurationValuesEqual(matchingTask, desiredTask)) {\n warnings.push(\n 'VS Code task \"policy: lint\" has repository-specific customization and was left unchanged.',\n );\n }\n } else {\n warnings.push('VS Code tasks use an unknown shape and were left unchanged.');\n }\n\n return applyEditorUpdates(contents, updates, 'VS Code policy tasks', warnings);\n}\n","import { isAbsolute, join, posix, relative, sep } from 'node:path';\n\nimport {\n getManagedAgentSkillCandidatePaths,\n planManagedAgentSkill,\n type ManagedAgentSkillDefinition,\n} from '../scaffolding/agent-skill.js';\nimport { displayProjectPath, quoteShellArgument } from '../scaffolding/project-plan-output.js';\nimport {\n getPlanningPathSnapshot,\n getPlanningFileSnapshot,\n planFileChange,\n type PlanningPathSnapshot,\n} from '../scaffolding/project-plan.js';\nimport { getPolicyManifestPath } from './policy-project-discovery.js';\nimport {\n generatePolicyGithubActionsWorkflow,\n POLICY_CI_WORKFLOW_PATH,\n} from './policy-scaffold-artifacts.js';\nimport {\n mergePolicyEditorExtensions,\n mergePolicyEditorSettings,\n mergePolicyEditorTasks,\n type PolicyEditorMergeResult,\n} from './policy-scaffold-config.js';\nimport {\n POLICY_INIT_RESULT_VERSION,\n PolicySetupFeature,\n type PolicyInitProjectPlan,\n type PolicyProjectState,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from './policy-scaffold-model.js';\nimport { generatePolicyStarterFiles, type PolicyStarterFile } from './policy-scaffold-templates.js';\nimport { POLICY_SKILL_FILES, POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Managed Policy Engine Agent Skill definition. */\nconst POLICY_MANAGED_SKILL: ManagedAgentSkillDefinition = {\n name: POLICY_SKILL_NAME,\n displayName: 'Policy Engine',\n owner: '@transcend-io/cli',\n files: POLICY_SKILL_FILES,\n};\n\n/** In-memory input consumed by the pure policy initializer. */\nexport interface PolicyInitPlanningInput {\n /** Project discovery state. */\n state: PolicyProjectState;\n /** Potential mutation paths keyed by absolute path. */\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>;\n}\n\n/** Optional repository setup selected for policy initialization. */\nexport interface PolicyInitPlanOptions {\n /** Selected setup features. */\n features: readonly PolicySetupFeatureType[];\n /** Exact released Transcend CLI version for generated CI. */\n cliVersion: string;\n}\n\n/**\n * Build the copyable policy lint command for one target.\n *\n * @param state - Discovered project state\n * @returns Raw one-line command\n */\nexport function buildPolicyLintCommand(state: PolicyProjectState): string {\n const directory = displayProjectPath(state.invocationDirectory, state.targetDirectory);\n return `transcend policy lint --dir ${quoteShellArgument(directory)} --noInteractive`;\n}\n\n/**\n * Enumerate all core starter paths that could be created.\n *\n * @param state - Policy project state\n * @param options - Selected repository setup\n * @returns Absolute candidate paths\n */\nexport function getPolicyInitPlanningCandidatePaths(\n state: PolicyProjectState,\n options: Pick<PolicyInitPlanOptions, 'features'>,\n): string[] {\n const paths = new Set(\n generatePolicyStarterFiles().map(({ path }) => join(state.targetDirectory, path)),\n );\n const selected = new Set(options.features);\n if (selected.has(PolicySetupFeature.Editor)) {\n paths.add(join(state.projectRoot, '.vscode', 'settings.json'));\n paths.add(join(state.projectRoot, '.vscode', 'extensions.json'));\n paths.add(join(state.projectRoot, '.vscode', 'tasks.json'));\n }\n if (selected.has(PolicySetupFeature.Skill)) {\n getManagedAgentSkillCandidatePaths(\n state.projectRoot,\n state.existingSkillDirectories,\n POLICY_MANAGED_SKILL,\n ).forEach((path) => paths.add(path));\n }\n if (selected.has(PolicySetupFeature.Ci) && state.repositoryRoot && state.usesGithub) {\n paths.add(join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH));\n }\n return [...paths].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * Ensure a destination stays below an approved project root.\n *\n * @param root - Approved root\n * @param path - Candidate path\n */\nfunction assertContained(root: string, path: string): void {\n const child = relative(root, path);\n if (child === '..' || child.startsWith(`..${sep}`) || isAbsolute(child)) {\n throw new Error(`Refusing to modify path outside project root: ${path}`);\n }\n}\n\n/**\n * Enumerate generated file and directory paths allowed in an exact starter.\n *\n * @param files - Starter files\n * @returns POSIX relative paths\n */\nfunction starterRelativePaths(files: readonly PolicyStarterFile[]): Set<string> {\n const paths = new Set<string>(['input.json']);\n files.forEach(({ path }) => {\n paths.add(path);\n let parent = posix.dirname(path);\n while (parent !== '.') {\n paths.add(parent);\n parent = posix.dirname(parent);\n }\n });\n return paths;\n}\n\n/**\n * Add or classify one regular-file mutation.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param options - Desired file\n */\nfunction addFileChange(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n options: {\n /** Absolute destination path. */\n path: string;\n /** Complete desired contents. */\n contents: string;\n /** Human-readable plan description. */\n description: string;\n /** Refuse existing contents. */\n createOnly?: boolean;\n },\n): void {\n const change = planFileChange({\n snapshot: getPlanningFileSnapshot(input.snapshots, options.path),\n after: options.contents,\n description: options.description,\n ...(options.createOnly === undefined ? {} : { createOnly: options.createOnly }),\n });\n if (change) {\n plan.changes.push(change);\n } else {\n plan.unchanged.push(options.path);\n }\n}\n\n/**\n * Add one safe editor merge and its preservation warnings.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param path - Absolute editor artifact path\n * @param result - Pure JSONC merge result\n * @param description - Human-readable plan description\n * @param cwd - Invocation directory for portable warning paths\n */\nfunction addEditorMerge(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n path: string,\n result: PolicyEditorMergeResult,\n description: string,\n cwd: string,\n): void {\n addFileChange(plan, input, {\n path,\n contents: result.contents,\n description,\n });\n plan.warnings.push(\n ...result.warnings.map((warning) => `${warning} (${displayProjectPath(cwd, path)})`),\n );\n}\n\n/**\n * Build a safe policy project plan without reading the filesystem.\n *\n * Empty targets receive the complete starter. Existing targets are classified\n * only; no domain file is added, merged, or overwritten.\n *\n * @param input - Collected project state and path snapshots\n * @param options - Selected setup and pinned CLI version\n * @returns Validated policy initialization plan\n */\nexport function buildPolicyInitPlan(\n input: PolicyInitPlanningInput,\n options: PolicyInitPlanOptions,\n): PolicyInitProjectPlan {\n const { state } = input;\n const files = generatePolicyStarterFiles();\n const manifestPath = getPolicyManifestPath(state);\n const lintCommand = buildPolicyLintCommand(state);\n const resultPath = join(state.targetDirectory, 'policy_engine', 'example', 'result.rego');\n const plan: PolicyInitProjectPlan = {\n version: POLICY_INIT_RESULT_VERSION,\n command: 'init',\n rootDirectory: state.projectRoot,\n targetDirectory: state.targetDirectory,\n manifestPath,\n changes: [],\n unchanged: [],\n warnings: [],\n nextSteps: [lintCommand],\n features: [...options.features],\n };\n\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, options);\n assertContained(state.projectRoot, state.targetDirectory);\n candidatePaths.forEach((path) => assertContained(state.projectRoot, path));\n\n let hasDisposableExample = false;\n if (state.relativeFilePaths.length === 0) {\n hasDisposableExample = true;\n plan.directoryPreconditions = [\n {\n path: state.targetDirectory,\n relativePaths: [...state.relativePaths],\n },\n ];\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent') {\n throw new Error(`Expected an empty policy target, but found an entry at: ${path}`);\n }\n addFileChange(plan, input, {\n path,\n contents: file.contents,\n description: file.description,\n createOnly: true,\n });\n });\n } else {\n let allStarterFilesMatch = true;\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind === 'file' && snapshot.contents === file.contents) {\n plan.unchanged.push(path);\n return;\n }\n allStarterFilesMatch = false;\n if (snapshot.kind !== 'absent') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing policy scaffold path was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n }\n });\n hasDisposableExample = allStarterFilesMatch;\n\n const allowedPaths = starterRelativePaths(files);\n const hasCustomPaths = state.relativeFilePaths.some((path) => !allowedPaths.has(path));\n if (!allStarterFilesMatch || hasCustomPaths) {\n plan.warnings.push(\n `Existing policy target contains custom or partial content, so no starter files were added or overwritten. ` +\n `Review ${displayProjectPath(\n state.invocationDirectory,\n state.targetDirectory,\n )} manually, then run \\`${lintCommand}\\`.`,\n );\n }\n }\n if (hasDisposableExample) {\n plan.disposableExamplePath = resultPath;\n plan.nextSteps.push(\n `Edit ${quoteShellArgument(displayProjectPath(state.invocationDirectory, resultPath))}`,\n );\n }\n\n const selected = new Set(options.features);\n const root = state.projectRoot;\n if (selected.has(PolicySetupFeature.Editor)) {\n const settingsPath = join(root, '.vscode', 'settings.json');\n const extensionsPath = join(root, '.vscode', 'extensions.json');\n const tasksPath = join(root, '.vscode', 'tasks.json');\n const editorArtifacts = [\n {\n path: settingsPath,\n description: 'Merge strict target-scoped OPA and Rego editor settings',\n merge: mergePolicyEditorSettings,\n },\n {\n path: extensionsPath,\n description: 'Recommend the OPA extension and discourage its syntax-only conflict',\n merge: (\n contents: string | null,\n _repositoryRoot: string,\n _targetDirectory: string,\n ): PolicyEditorMergeResult => mergePolicyEditorExtensions(contents),\n },\n {\n path: tasksPath,\n description: 'Add the default target-scoped policy lint task',\n merge: mergePolicyEditorTasks,\n },\n ];\n editorArtifacts.forEach(({ path, description, merge }) => {\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent' && snapshot.kind !== 'file') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing VS Code artifact is not a regular file and was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n return;\n }\n addEditorMerge(\n plan,\n input,\n path,\n merge(snapshot.kind === 'file' ? snapshot.contents : null, root, state.targetDirectory),\n description,\n state.invocationDirectory,\n );\n });\n }\n\n if (selected.has(PolicySetupFeature.Skill)) {\n const skillPlan = planManagedAgentSkill({\n rootDirectory: root,\n existingDirectories: state.existingSkillDirectories,\n snapshots: input.snapshots,\n skill: POLICY_MANAGED_SKILL,\n preserveModified: true,\n });\n plan.changes.push(...skillPlan.changes);\n plan.unchanged.push(...skillPlan.unchanged);\n plan.warnings.push(\n ...skillPlan.warnings.map((warning) => {\n return skillPlan.unchanged.reduce(\n (rendered, path) =>\n rendered.replace(path, displayProjectPath(state.invocationDirectory, path)),\n warning,\n );\n }),\n );\n }\n\n if (selected.has(PolicySetupFeature.Ci)) {\n if (!state.repositoryRoot || !state.usesGithub) {\n plan.warnings.push(\n 'GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.',\n );\n } else {\n const workflowPath = join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH);\n const target =\n relative(state.repositoryRoot, state.targetDirectory).split(sep).join('/') || '.';\n const workflowContents = generatePolicyGithubActionsWorkflow({\n cliVersion: options.cliVersion,\n targetDirectory: target,\n });\n const workflowSnapshot = getPlanningPathSnapshot(input.snapshots, workflowPath);\n if (workflowSnapshot.kind === 'absent') {\n addFileChange(plan, input, {\n path: workflowPath,\n contents: workflowContents,\n description: 'Add credential-free Policy Engine validation',\n createOnly: true,\n });\n } else if (\n workflowSnapshot.kind === 'file' &&\n workflowSnapshot.contents === workflowContents\n ) {\n plan.unchanged.push(workflowPath);\n } else {\n plan.unchanged.push(workflowPath);\n plan.warnings.push(\n `Existing GitHub Actions workflow was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n workflowPath,\n )}. Adapt it manually to run \\`${lintCommand}\\`.`,\n );\n }\n }\n }\n\n plan.changes.forEach(({ path }) => assertContained(state.projectRoot, path));\n return plan;\n}\n","import colors from 'colors';\n\nimport { version as CLI_VERSION } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n runCapturedProcess,\n type CapturedProcessResult,\n type CapturedProcessRunner,\n} from '../../../lib/cli/run-captured-process.js';\nimport {\n DEFAULT_POLICY_PROJECT_DIRECTORY,\n discoverPolicyProject,\n} from '../../../lib/policy/policy-project-discovery.js';\nimport {\n OPA_INSTALL_URL,\n OPA_MISSING_MESSAGE,\n parsePolicyToolVersion,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n REGAL_INSTALL_URL,\n REGAL_MISSING_MESSAGE,\n unsupportedOpaVersionMessage,\n unsupportedRegalVersionMessage,\n} from '../../../lib/policy/policy-runtime.js';\nimport {\n PolicySetupFeature,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from '../../../lib/policy/policy-scaffold-model.js';\nimport {\n buildPolicyInitAiHandoff,\n buildPolicyInitPlanResult,\n type PolicyInitToolVersions,\n} from '../../../lib/policy/policy-scaffold-output.js';\nimport {\n buildPolicyInitPlan,\n getPolicyInitPlanningCandidatePaths,\n} from '../../../lib/policy/policy-scaffold-planning.js';\nimport { collectPlanningSnapshots } from '../../../lib/scaffolding/project-discovery.js';\nimport { applyProjectPlan } from '../../../lib/scaffolding/project-plan-apply.js';\nimport {\n displayProjectPath,\n quoteShellArgument,\n renderProjectPlan,\n} from '../../../lib/scaffolding/project-plan-output.js';\nimport {\n PromptCancelledError,\n type PromptChoice,\n ScaffoldPrompts,\n} from '../../../lib/scaffolding/prompts.js';\n\n/** Flags for `transcend policy init`. */\nexport interface PolicyInitFlags {\n /** Install repository-level VS Code setup. */\n editor?: boolean;\n /** Install the Policy Engine Agent Skill. */\n skill?: boolean;\n /** Install validation-only GitHub Actions CI. */\n ci?: boolean;\n /** Disable prompts. */\n noInteractive: boolean;\n /** Render but do not apply the plan. */\n dryRun: boolean;\n /** Approve the final displayed plan. */\n yes: boolean;\n /** Emit one stable JSON result on stdout. */\n json: boolean;\n}\n\n/** User-facing optional setup labels. */\nconst SETUP_LABELS: Readonly<Record<PolicySetupFeatureType, string>> = {\n [PolicySetupFeature.Editor]: 'VS Code settings and lint task',\n [PolicySetupFeature.Skill]: 'Policy Engine Agent Skill',\n [PolicySetupFeature.Ci]: 'Validation-only GitHub Actions',\n};\n\n/** All optional setup features in stable prompt order. */\nconst ALL_SETUP_FEATURES = Object.values(PolicySetupFeature);\n\n/** Runtime compatibility detected before policy planning. */\ninterface PolicyRuntimeProbe {\n /** Compatible tool versions. */\n tools: PolicyInitToolVersions;\n /** Missing or incompatible runtime guidance. */\n warnings: string[];\n}\n\n/**\n * Whether this invocation can ask questions.\n *\n * @param flags - Interaction flags\n * @param stdinIsTTY - Whether standard input is interactive\n * @param stderrIsTTY - Whether prompt output is interactive\n * @returns Whether prompts are enabled\n */\nfunction isInteractiveInvocation(\n flags: Pick<PolicyInitFlags, '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 * Resolve setup from explicit flags or one default-selected checklist.\n *\n * @param prompts - Prompt adapters\n * @param flags - Setup flags\n * @param options - Interaction state\n * @returns Explicitly selected setup features\n */\nasync function resolveFeatures(\n prompts: ScaffoldPrompts,\n flags: PolicyInitFlags,\n options: {\n /** Whether prompts are available. */\n interactive: boolean;\n },\n): Promise<PolicySetupFeatureType[]> {\n const enabled: Readonly<Record<PolicySetupFeatureType, boolean | undefined>> = {\n [PolicySetupFeature.Editor]: flags.editor,\n [PolicySetupFeature.Skill]: flags.skill,\n [PolicySetupFeature.Ci]: flags.ci,\n };\n if (!options.interactive) {\n return ALL_SETUP_FEATURES.filter((feature) => enabled[feature] === true);\n }\n const choices: PromptChoice<PolicySetupFeatureType>[] = ALL_SETUP_FEATURES.map((feature) => ({\n name: SETUP_LABELS[feature],\n value: feature,\n checked: enabled[feature] !== false,\n }));\n return prompts.checkbox('Choose repository setup:', choices);\n}\n\n/**\n * Explain a failed version subprocess with official installation guidance.\n *\n * @param tool - Policy tool name\n * @param result - Failed captured process\n * @returns Actionable warning\n */\nfunction failedVersionProbeMessage(tool: 'OPA' | 'Regal', result: CapturedProcessResult): string {\n const detail = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join('\\n');\n const url = tool === 'OPA' ? OPA_INSTALL_URL : REGAL_INSTALL_URL;\n const requirement =\n tool === 'OPA' ? 'OPA 1.x' : `Regal ${MINIMUM_POLICY_STARTER_REGAL_VERSION} or newer`;\n return (\n `${requirement} is required, but \\`${tool.toLowerCase()} version\\` exited with code ` +\n `${result.code}${detail ? `: ${detail}` : '.'} ` +\n `Install or upgrade it using the official instructions: ${url}`\n );\n}\n\n/**\n * Probe both local policy runtimes without installing or modifying them.\n *\n * @param context - CLI context\n * @param cwd - Invocation working directory\n * @param runner - Captured subprocess runner\n * @returns Compatible versions and exact runtime guidance\n */\nasync function probePolicyRuntimes(\n context: LocalContext,\n cwd: string,\n runner: CapturedProcessRunner,\n): Promise<PolicyRuntimeProbe> {\n const tools: PolicyInitToolVersions = { opa: null, regal: null };\n const warnings: string[] = [];\n\n const opaResult = await runner('opa', ['version'], { cwd }, context);\n if (opaResult.error?.code === 'ENOENT') {\n warnings.push(OPA_MISSING_MESSAGE);\n } else {\n const output = `${opaResult.stdout}\\n${opaResult.stderr}`;\n const unsupported = unsupportedOpaVersionMessage(output);\n if (opaResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('OPA', opaResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.opa = parsePolicyToolVersion(output)!.version;\n }\n }\n\n const regalResult = await runner('regal', ['version'], { cwd }, context);\n if (regalResult.error?.code === 'ENOENT') {\n warnings.push(REGAL_MISSING_MESSAGE);\n } else {\n const output = `${regalResult.stdout}\\n${regalResult.stderr}`;\n const unsupported = unsupportedRegalVersionMessage(\n output,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n 'the generated OPA 1.13.1 capabilities configuration',\n );\n if (regalResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('Regal', regalResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.regal = parsePolicyToolVersion(output)!.version;\n }\n }\n\n return { tools, warnings };\n}\n\n/**\n * Initialize a credential-free local Policy Engine project.\n *\n * @param this - CLI context\n * @param flags - Scaffold and interaction flags\n * @param directory - Target policy directory\n * @param runner - Captured policy tool runner\n */\nexport async function init(\n this: LocalContext,\n flags: PolicyInitFlags,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n runner: CapturedProcessRunner = runCapturedProcess,\n): Promise<void> {\n doneInputValidation(this.process);\n try {\n const runtime = await probePolicyRuntimes(this, this.process.cwd(), runner);\n const state = discoverPolicyProject(this, directory);\n const prompts = new ScaffoldPrompts(this);\n const interactive = isInteractiveInvocation(\n flags,\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n const features = await resolveFeatures(prompts, flags, { interactive });\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, { features });\n const snapshots = collectPlanningSnapshots(this, state.projectRoot, candidatePaths);\n\n const plan = buildPolicyInitPlan(\n { state, snapshots },\n {\n features,\n cliVersion: CLI_VERSION,\n },\n );\n plan.warnings.push(...runtime.warnings);\n\n if (!flags.json) {\n this.logger.info(\n renderProjectPlan(plan, {\n cwd: this.process.cwd(),\n title: 'Policy initialization plan',\n details: [\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 setupAvailable = approved && !flags.dryRun;\n const aiHandoff = buildPolicyInitAiHandoff({\n projectPath: quoteShellArgument(\n displayProjectPath(this.process.cwd(), state.targetDirectory),\n ),\n ...(plan.disposableExamplePath\n ? {\n examplePath: quoteShellArgument(\n displayProjectPath(this.process.cwd(), plan.disposableExamplePath),\n ),\n }\n : {}),\n hasSkill: setupAvailable && features.includes(PolicySetupFeature.Skill),\n lintCommand: plan.nextSteps[0]!,\n });\n const result = buildPolicyInitPlanResult(plan, {\n applied,\n dryRun: flags.dryRun,\n cwd: this.process.cwd(),\n aiHandoff,\n tools: runtime.tools,\n });\n if (flags.json) {\n this.process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n if (flags.dryRun) {\n this.logger.info(colors.yellow('Dry run complete. No changes were written.'));\n return;\n }\n if (!approved) {\n this.logger.info(colors.yellow('No changes applied.'));\n return;\n }\n if (plan.changes.length === 0) {\n const message =\n plan.warnings.length === runtime.warnings.length\n ? 'Policy project is already initialized.'\n : 'Existing policy project was left unchanged.';\n this.logger.info(colors.green(message));\n } else {\n this.logger.info(colors.green('Policy project initialized.'));\n }\n if (plan.nextSteps.length > 0) {\n this.logger.info(`\\n${colors.bold('Next steps')}`);\n plan.nextSteps.forEach((step) => this.logger.info(step));\n }\n this.logger.info(`\\n${colors.bold('AI handoff — paste into your coding agent')}`);\n this.logger.info(aiHandoff);\n } catch (error) {\n if (error instanceof PromptCancelledError) {\n return this.process.exit(130);\n }\n throw error;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"impl-DHQh34Eh2.mjs","names":["POLICY_SKILL_MD","POLICY_SETUP_TOOLING_REFERENCE_MD","POLICY_AUTHORING_REFERENCE_MD","POLICY_TESTING_DEBUGGING_REFERENCE_MD","POLICY_PUBLISHING_REFERENCE_MD","CLI_VERSION"],"sources":["../src/lib/policy/policy-project-discovery.ts","../src/lib/policy/policy-scaffold-model.ts","../../../skills/transcend-policy-engine/references/authoring.md","../../../skills/transcend-policy-engine/references/publishing.md","../../../skills/transcend-policy-engine/references/setup-tooling.md","../../../skills/transcend-policy-engine/references/testing-debugging.md","../../../skills/transcend-policy-engine/SKILL.md","../src/lib/policy/policy-skill.ts","../src/lib/policy/policy-scaffold-output.ts","../src/lib/policy/policy-scaffold-templates.ts","../src/lib/policy/policy-scaffold-artifacts.ts","../src/lib/policy/policy-scaffold-config.ts","../src/lib/policy/policy-scaffold-planning.ts","../src/commands/policy/init/impl.ts"],"sourcesContent":["import { join, resolve } from 'node:path';\n\nimport type { LocalContext } from '../../context.js';\nimport {\n collectProjectRelativePaths,\n discoverProjectRepository,\n} from '../scaffolding/project-discovery.js';\nimport type { PolicyProjectState } from './policy-scaffold-model.js';\n\n/** Default local policy project directory. */\nexport const DEFAULT_POLICY_PROJECT_DIRECTORY = 'transcend/policy';\n\n/**\n * Collect repository state required by the pure policy planner.\n *\n * @param context - CLI context\n * @param directory - User-selected target directory\n * @returns Policy project discovery state\n */\nexport function discoverPolicyProject(\n context: LocalContext,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n): PolicyProjectState {\n const invocationDirectory = context.process.cwd();\n const targetDirectory = resolve(invocationDirectory, directory);\n if (\n context.fs.existsSync(targetDirectory) &&\n !context.fs.statSync(targetDirectory).isDirectory()\n ) {\n throw new Error(`Policy target is not a directory: ${targetDirectory}`);\n }\n const repository = discoverProjectRepository(context, {\n invocationDirectory,\n targetDirectory,\n standaloneProjectRoot: invocationDirectory,\n });\n return {\n invocationDirectory,\n targetDirectory,\n ...repository,\n relativePaths: collectProjectRelativePaths(context, targetDirectory),\n relativeFilePaths: collectProjectRelativePaths(context, targetDirectory, {\n includeDirectories: false,\n }),\n };\n}\n\n/**\n * Resolve the bundle manifest path for a discovered project.\n *\n * @param state - Policy project state\n * @returns Absolute manifest path\n */\nexport function getPolicyManifestPath(state: PolicyProjectState): string {\n return join(state.targetDirectory, 'manifest.json');\n}\n","import type { ExistingProjectSkillDirectory } from '../scaffolding/agent-skill.js';\nimport type { ProjectPlan } from '../scaffolding/project-plan.js';\n\n/** Version of the stable policy initialization JSON result. */\nexport const POLICY_INIT_RESULT_VERSION = 1 as const;\n\n/** Optional repository integrations for policy authoring. */\nexport const PolicySetupFeature = {\n /** Repository-level editor configuration. */\n Editor: 'editor',\n /** Managed policy authoring skill. */\n Skill: 'skill',\n /** Credential-free continuous integration. */\n Ci: 'ci',\n} as const;\n\n/** Optional repository integration for policy authoring. */\nexport type PolicySetupFeature = (typeof PolicySetupFeature)[keyof typeof PolicySetupFeature];\n\n/** Repository and target state collected before policy planning. */\nexport interface PolicyProjectState {\n /** Directory from which the CLI was invoked. */\n invocationDirectory: string;\n /** Absolute user-selected policy directory. */\n targetDirectory: string;\n /** Repository or invocation root that owns setup artifacts. */\n projectRoot: string;\n /** Nearest repository root, when present. */\n repositoryRoot?: string;\n /** Existing project-level skill directories. */\n existingSkillDirectories: ExistingProjectSkillDirectory[];\n /** Whether the repository appears to use GitHub. */\n usesGithub: boolean;\n /** Case-preserving relative paths below the policy directory. */\n relativePaths: string[];\n /** Relative file and link paths below the policy directory. */\n relativeFilePaths: string[];\n}\n\n/** A complete, validated policy initialization plan. */\nexport interface PolicyInitProjectPlan extends ProjectPlan {\n /** JSON contract version. */\n version: typeof POLICY_INIT_RESULT_VERSION;\n /** Command that produced the plan. */\n command: 'init';\n /** Absolute policy project directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Files inspected and deliberately left unchanged. */\n unchanged: string[];\n /** Non-fatal plan warnings. */\n warnings: string[];\n /** Raw commands shown after a successful apply. */\n nextSteps: string[];\n /** Exact generated example that remains safe to replace. */\n disposableExamplePath?: string;\n /** Selected repository integrations. */\n features: PolicySetupFeature[];\n}\n",null,null,null,null,null,"import POLICY_AUTHORING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/authoring.md';\nimport POLICY_PUBLISHING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/publishing.md';\nimport POLICY_SETUP_TOOLING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/setup-tooling.md';\nimport POLICY_TESTING_DEBUGGING_REFERENCE_MD from '../../../../../skills/transcend-policy-engine/references/testing-debugging.md';\nimport POLICY_SKILL_MD from '../../../../../skills/transcend-policy-engine/SKILL.md';\nimport type { AgentSkillFile } from '../scaffolding/agent-skill.js';\n\n/** Namespaced directory and frontmatter name for the installed Agent Skill. */\nexport const POLICY_SKILL_NAME = 'transcend-policy-engine';\n\nexport {\n POLICY_AUTHORING_REFERENCE_MD,\n POLICY_PUBLISHING_REFERENCE_MD,\n POLICY_SETUP_TOOLING_REFERENCE_MD,\n POLICY_SKILL_MD,\n POLICY_TESTING_DEBUGGING_REFERENCE_MD,\n};\n\n/** Complete portable Policy Engine Agent Skill file set. */\nexport const POLICY_SKILL_FILES: readonly AgentSkillFile[] = [\n { path: 'SKILL.md', contents: POLICY_SKILL_MD },\n { path: 'references/setup-tooling.md', contents: POLICY_SETUP_TOOLING_REFERENCE_MD },\n { path: 'references/authoring.md', contents: POLICY_AUTHORING_REFERENCE_MD },\n { path: 'references/testing-debugging.md', contents: POLICY_TESTING_DEBUGGING_REFERENCE_MD },\n { path: 'references/publishing.md', contents: POLICY_PUBLISHING_REFERENCE_MD },\n];\n","import {\n toPublicPlannedChange,\n type PublicPlannedChange,\n} from '../scaffolding/project-plan-output.js';\nimport type { PolicyInitProjectPlan, PolicySetupFeature } from './policy-scaffold-model.js';\nimport { POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Detected local policy tool versions. */\nexport interface PolicyInitToolVersions {\n /** OPA version, or null when missing or incompatible. */\n opa: string | null;\n /** Regal version, or null when missing or incompatible. */\n regal: string | null;\n}\n\n/** Stable machine-readable policy initialization result. */\nexport interface PolicyInitPlanResult {\n /** JSON contract version. */\n version: number;\n /** Command that produced the result. */\n command: 'init';\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Absolute policy target directory. */\n targetDirectory: string;\n /** Absolute policy manifest path. */\n manifestPath: string;\n /** Planned mutations without file contents. */\n changes: PublicPlannedChange[];\n /** Non-fatal preservation and runtime warnings. */\n warnings: string[];\n /** Suggested raw one-line follow-up commands. */\n nextSteps: string[];\n /** Explicitly selected repository integrations. */\n features: PolicySetupFeature[];\n /** Compact prompt for continuing with a coding agent. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n}\n\n/**\n * Build the compact policy implementation and CI handoff.\n *\n * @param options - Portable example path and lint command\n * @returns Raw one-line prompt\n */\nexport function buildPolicyInitAiHandoff(options: {\n /** Display path to the policy project. */\n projectPath: string;\n /** Display path to an exact disposable example. */\n examplePath?: string;\n /** Whether the policy authoring skill was installed. */\n hasSkill: boolean;\n /** Copyable lint command. */\n lintCommand: string;\n}): string {\n if (!options.examplePath) {\n const instruction = options.hasSkill\n ? `Use the \\`${POLICY_SKILL_NAME}\\` skill to review`\n : 'Review';\n return (\n `${instruction} the existing policy project in ${options.projectPath}, ` +\n `align its document tree and input/output contract with the intended application, adapt ` +\n `repository validation as needed, and rerun ${options.lintCommand}.`\n );\n }\n const instruction = options.hasSkill\n ? `Use the \\`${POLICY_SKILL_NAME}\\` skill to replace`\n : 'Replace';\n return (\n `${instruction} the disposable example in ${options.examplePath} with ` +\n `the intended policy document tree and input/output contract, adapt repository validation ` +\n `to local conventions, and rerun ${options.lintCommand}.`\n );\n}\n\n/**\n * Build the stable machine-readable initialization result.\n *\n * @param plan - Policy project plan\n * @param options - Apply and runtime state\n * @returns Public JSON result\n */\nexport function buildPolicyInitPlanResult(\n plan: PolicyInitProjectPlan,\n options: {\n /** Whether the plan was applied. */\n applied: boolean;\n /** Whether this was a dry run. */\n dryRun: boolean;\n /** Working directory for portable paths. */\n cwd: string;\n /** Compact coding-agent prompt. */\n aiHandoff: string;\n /** Compatible local policy tool versions. */\n tools: PolicyInitToolVersions;\n },\n): PolicyInitPlanResult {\n return {\n version: plan.version,\n command: plan.command,\n applied: options.applied,\n dryRun: options.dryRun,\n targetDirectory: plan.targetDirectory,\n manifestPath: plan.manifestPath,\n changes: plan.changes.map((change) => toPublicPlannedChange(options.cwd, change)),\n warnings: plan.warnings,\n nextSteps: plan.nextSteps,\n features: [...plan.features],\n aiHandoff: options.aiHandoff,\n tools: options.tools,\n };\n}\n","/** OPA version targeted by generated policy authoring configuration. */\nexport const POLICY_STARTER_OPA_VERSION = '1.13.1';\n\n/** One deterministic file in the safe policy starter. */\nexport interface PolicyStarterFile {\n /** POSIX-style path relative to the policy directory. */\n path: string;\n /** Complete UTF-8 file contents. */\n contents: string;\n /** Human-readable reason shown in the plan. */\n description: string;\n}\n\n/** Publishable Policy Engine bundle manifest. */\nexport const POLICY_MANIFEST_TEMPLATE = `{\n \"roots\": [\"policy_engine\"]\n}\n`;\n\n/** Strict Regal project configuration pinned to the deployed OPA capabilities. */\nexport const POLICY_REGAL_CONFIG_TEMPLATE = `capabilities:\n from:\n engine: opa\n version: v${POLICY_STARTER_OPA_VERSION}\nproject:\n roots:\n - .\n rego-version: 1\n`;\n\n/** Disposable, fail-closed example policy. */\nexport const POLICY_RESULT_REGO_TEMPLATE = `package policy_engine.example\n\nimport rego.v1\n\n# METADATA\n# title: Disposable example result\n# description: |\n# A fail-closed teaching entrypoint. Replace this example with the document\n# tree and result contract required by your application.\n# entrypoint: true\ndefault result := {\n\t\"decision\": \"deny\",\n\t\"reason_code\": \"untrusted_or_invalid_input\",\n}\n\nresult := {\n\t\"decision\": \"allow\",\n\t\"reason_code\": \"trusted_subject\",\n} if {\n\tinput.subject.trusted == true\n}\n`;\n\n/** Executable tests adjacent to the disposable example policy. */\nexport const POLICY_RESULT_TEST_REGO_TEMPLATE = `package policy_engine.example_test\n\nimport data.policy_engine.example\nimport rego.v1\n\ntest_denies_untrusted_subject if {\n\tresult := example.result with input as {\"subject\": {\"trusted\": false}}\n\tresult == {\n\t\t\"decision\": \"deny\",\n\t\t\"reason_code\": \"untrusted_or_invalid_input\",\n\t}\n}\n\ntest_fails_closed_for_missing_subject if {\n\tresult := example.result with input as {}\n\tresult == {\n\t\t\"decision\": \"deny\",\n\t\t\"reason_code\": \"untrusted_or_invalid_input\",\n\t}\n}\n\ntest_allows_trusted_subject if {\n\tresult := example.result with input as {\"subject\": {\"trusted\": true}}\n\tresult == {\n\t\t\"decision\": \"allow\",\n\t\t\"reason_code\": \"trusted_subject\",\n\t}\n}\n`;\n\n/** Sanitized local input example containing no credentials or personal data. */\nexport const POLICY_INPUT_EXAMPLE_TEMPLATE = `{\n \"subject\": {\n \"trusted\": false\n }\n}\n`;\n\n/** Target-local ignore rules for private evaluation input only. */\nexport const POLICY_GITIGNORE_TEMPLATE = `# Local policy evaluation input.\n/input.json\n`;\n\n/** Concise project-local authoring guide. */\nexport const POLICY_README_TEMPLATE = `# Transcend Policy Project\n\nThis directory is an OPA document tree that can be published to Transcend Policy Engine.\n\nThe policy under \\`policy_engine/example\\` is disposable teaching material. Replace it with your intended package tree, input shape, and extensible result documents. Keep decisions fail-closed and cover every non-test package with \\`manifest.json\\`.\n\nValidate formatting, strict Rego v1 compatibility, Regal lint, tests, and the publish contract:\n\n\\`\\`\\`sh\ntranscend policy lint --dir .\n\\`\\`\\`\n`;\n\n/** Complete safe starter in deterministic plan order. */\nconst POLICY_STARTER_FILES: readonly PolicyStarterFile[] = [\n {\n path: 'manifest.json',\n contents: POLICY_MANIFEST_TEMPLATE,\n description: 'Create the publishable Policy Engine manifest',\n },\n {\n path: '.regal/config.yaml',\n contents: POLICY_REGAL_CONFIG_TEMPLATE,\n description: 'Pin strict Rego v1 linting to OPA 1.13.1 capabilities',\n },\n {\n path: 'policy_engine/example/result.rego',\n contents: POLICY_RESULT_REGO_TEMPLATE,\n description: 'Create a documented fail-closed result entrypoint',\n },\n {\n path: 'policy_engine/example/result_test.rego',\n contents: POLICY_RESULT_TEST_REGO_TEMPLATE,\n description: 'Create executable tests for allow and fail-closed decisions',\n },\n {\n path: 'input.example.json',\n contents: POLICY_INPUT_EXAMPLE_TEMPLATE,\n description: 'Create a sanitized local evaluation input',\n },\n {\n path: '.gitignore',\n contents: POLICY_GITIGNORE_TEMPLATE,\n description: 'Ignore only the private local input file',\n },\n {\n path: 'README.md',\n contents: POLICY_README_TEMPLATE,\n description: 'Create the concise policy project guide',\n },\n];\n\n/**\n * Generate an independent copy of the safe policy starter.\n *\n * @returns Deterministic relative files\n */\nexport function generatePolicyStarterFiles(): PolicyStarterFile[] {\n return POLICY_STARTER_FILES.map((file) => ({ ...file }));\n}\n","import { posix } from 'node:path';\n\nimport { POLICY_STARTER_OPA_VERSION } from './policy-scaffold-templates.js';\n\n/** Regal version pinned by generated policy validation. */\nexport const POLICY_STARTER_REGAL_VERSION = '0.42.0';\n\n/** Repository-relative generated workflow path. */\nexport const POLICY_CI_WORKFLOW_PATH = '.github/workflows/transcend-policy.yml';\n\n/** Immutable actions/checkout v6 release commit. */\nexport const ACTIONS_CHECKOUT_SHA = 'd23441a48e516b6c34aea4fa41551a30e30af803';\n\n/** Immutable open-policy-agent/setup-opa v2.4.0 release commit. */\nexport const SETUP_OPA_SHA = 'b2b258e089860efaadaaf71bf6e3aecb4a3eeff1';\n\n/** Immutable open-policy-agent/setup-regal v2.0.0 release commit. */\nexport const SETUP_REGAL_SHA = '761188c3b435761fa254beca508a44875619648f';\n\n/**\n * Prefix a path below the repository-relative policy target.\n *\n * @param targetDirectory - POSIX repository-relative target\n * @param child - POSIX target-relative path or pattern\n * @returns Repository-relative path or pattern\n */\nfunction targetPath(targetDirectory: string, child: string): string {\n return targetDirectory === '.' ? child : posix.join(targetDirectory, child);\n}\n\n/**\n * Generate credential-free, validation-only Policy Engine CI.\n *\n * @param options - Repository paths and exact CLI release\n * @returns Complete GitHub Actions workflow YAML\n */\nexport function generatePolicyGithubActionsWorkflow(options: {\n /** Exact released Transcend CLI version. */\n cliVersion: string;\n /** Policy directory relative to the repository root. */\n targetDirectory: string;\n}): string {\n const watchedPaths = [\n targetPath(options.targetDirectory, '**/*.rego'),\n targetPath(options.targetDirectory, '**/*.json'),\n targetPath(options.targetDirectory, '**/*.yaml'),\n targetPath(options.targetDirectory, '**/*.yml'),\n targetPath(options.targetDirectory, '.regal/config.yaml'),\n targetPath(options.targetDirectory, '.regal.yaml'),\n POLICY_CI_WORKFLOW_PATH,\n ];\n const pathFilters = watchedPaths.map((path) => ` - ${JSON.stringify(path)}`).join('\\n');\n\n return `# Generated by transcend policy init.\nname: Transcend Policy\n\non:\n pull_request:\n paths:\n${pathFilters}\n push:\n paths:\n${pathFilters}\n\npermissions:\n contents: read\n\njobs:\n lint:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@${ACTIONS_CHECKOUT_SHA} # v6\n - name: Set up OPA\n uses: open-policy-agent/setup-opa@${SETUP_OPA_SHA} # v2.4.0\n with:\n version: ${JSON.stringify(POLICY_STARTER_OPA_VERSION)}\n - name: Set up Regal\n uses: open-policy-agent/setup-regal@${SETUP_REGAL_SHA} # v2.0.0\n with:\n version: ${JSON.stringify(POLICY_STARTER_REGAL_VERSION)}\n - name: Install the Transcend CLI\n run: npm install --global @transcend-io/cli@${options.cliVersion}\n - name: Validate Policy Engine project\n env:\n POLICY_DIRECTORY: ${JSON.stringify(options.targetDirectory)}\n run: >-\n transcend policy lint\n --dir \"$POLICY_DIRECTORY\"\n --noInteractive\n --json\n`;\n}\n","import { relative, sep } from 'node:path';\n\nimport {\n mergeJsonc,\n mergeStringArray,\n parseJsoncObject,\n type JsoncUpdate,\n} from '../scaffolding/jsonc.js';\n\n/** Recommended VS Code extension for OPA and Regal authoring. */\nexport const POLICY_VSCODE_EXTENSION = 'tsandall.opa';\n\n/** Conflicting syntax-only VS Code extension. */\nexport const CONFLICTING_POLICY_VSCODE_EXTENSION = 'glebbash.opa-highlight-only';\n\n/** Result of safely merging one repository editor artifact. */\nexport interface PolicyEditorMergeResult {\n /** Complete merged contents, or the unchanged original when unsafe. */\n contents: string;\n /** Actionable preservation warnings. */\n warnings: string[];\n}\n\n/** One desired scalar setting that must not replace a customization. */\ninterface DesiredSetting {\n /** JSONC object path. */\n path: string[];\n /** Desired generated value. */\n value: unknown;\n /** Human-readable setting key. */\n label: string;\n}\n\n/**\n * Compare JSON-compatible configuration values.\n *\n * @param left - Existing value\n * @param right - Desired value\n * @returns Whether the values are structurally equal\n */\nfunction configurationValuesEqual(left: unknown, right: unknown): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\n/**\n * Parse an editor object while preserving malformed existing content.\n *\n * @param contents - Existing JSONC, or null\n * @param label - Configuration label\n * @returns Parsed object or a preservation result\n */\nfunction parseEditorObject(\n contents: string | null,\n label: string,\n):\n | {\n /** Parsed JSONC object. */\n current: Record<string, unknown>;\n }\n | {\n /** Complete unchanged contents. */\n contents: string;\n /** Actionable warning. */\n warning: string;\n } {\n try {\n return { current: parseJsoncObject(contents ?? '{}\\n', label) };\n } catch (error) {\n return {\n contents: contents ?? '{}\\n',\n warning: `${error instanceof Error ? error.message : String(error)} Existing content was left unchanged.`,\n };\n }\n}\n\n/**\n * Apply safe JSONC updates or preserve the existing file when comments prevent it.\n *\n * @param contents - Existing JSONC\n * @param updates - Proven-safe updates\n * @param label - Configuration label\n * @param warnings - Existing merge warnings\n * @returns Complete contents and warnings\n */\nfunction applyEditorUpdates(\n contents: string | null,\n updates: readonly JsoncUpdate[],\n label: string,\n warnings: string[],\n): PolicyEditorMergeResult {\n if (updates.length === 0) {\n return { contents: contents ?? '{}\\n', warnings };\n }\n try {\n return {\n contents: mergeJsonc(contents, updates, label),\n warnings,\n };\n } catch (error) {\n return {\n contents: contents ?? '{}\\n',\n warnings: [\n ...warnings,\n `${error instanceof Error ? error.message : String(error)} Existing content was left unchanged.`,\n ],\n };\n }\n}\n\n/**\n * Add absent scalar settings without replacing repository customizations.\n *\n * @param current - Parsed editor object\n * @param desired - Desired settings\n * @param updates - Safe updates to append to\n * @param warnings - Conflict warnings to append to\n */\nfunction collectSafeScalarUpdates(\n current: Record<string, unknown>,\n desired: readonly DesiredSetting[],\n updates: JsoncUpdate[],\n warnings: string[],\n): void {\n desired.forEach(({ path, value, label }) => {\n const existing = path.reduce<unknown>((parent, key) => {\n return parent && typeof parent === 'object' && !Array.isArray(parent)\n ? (parent as Record<string, unknown>)[key]\n : undefined;\n }, current);\n if (existing === undefined) {\n updates.push({ path, value });\n } else if (!configurationValuesEqual(existing, value)) {\n warnings.push(\n `VS Code setting \"${label}\" has a repository-specific value and was left unchanged.`,\n );\n }\n });\n}\n\n/**\n * Build the workspace-relative OPA bundle root.\n *\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns VS Code workspace path\n */\nfunction buildOpaWorkspaceRoot(repositoryRoot: string, targetDirectory: string): string {\n const target = relative(repositoryRoot, targetDirectory).split(sep).join('/') || '.';\n return target === '.' ? '${workspaceFolder}' : `\\${workspaceFolder}/${target}`;\n}\n\n/**\n * Merge strict target-scoped OPA and Rego editor settings.\n *\n * Setting names match the authoritative `open-policy-agent/vscode-opa`\n * extension metadata. Existing conflicting values are preserved and reported.\n *\n * @param contents - Existing `.vscode/settings.json` JSONC\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns Merged settings and conflict warnings\n */\nexport function mergePolicyEditorSettings(\n contents: string | null,\n repositoryRoot: string,\n targetDirectory: string,\n): PolicyEditorMergeResult {\n const parsed = parseEditorObject(contents, 'VS Code policy settings');\n if ('warning' in parsed) {\n return { contents: parsed.contents, warnings: [parsed.warning] };\n }\n const { current } = parsed;\n const updates: JsoncUpdate[] = [];\n const warnings: string[] = [];\n\n const roots = current['opa.roots'];\n const desiredRoot = buildOpaWorkspaceRoot(repositoryRoot, targetDirectory);\n if (roots === undefined) {\n updates.push({ path: ['opa.roots'], value: [desiredRoot] });\n } else if (Array.isArray(roots) && roots.every((value) => typeof value === 'string')) {\n const merged = mergeStringArray(roots, [desiredRoot]);\n if (!configurationValuesEqual(merged, roots)) {\n updates.push({ path: ['opa.roots'], value: merged });\n }\n } else {\n warnings.push('VS Code setting \"opa.roots\" is customized and was left unchanged.');\n }\n\n collectSafeScalarUpdates(\n current,\n [\n { path: ['opa.checkOnSave'], value: true, label: 'opa.checkOnSave' },\n { path: ['opa.strictMode'], value: true, label: 'opa.strictMode' },\n { path: ['opa.bundleMode'], value: true, label: 'opa.bundleMode' },\n { path: ['opa.formatter'], value: 'opa-fmt-rego-v1', label: 'opa.formatter' },\n ],\n updates,\n warnings,\n );\n\n const regoSettings = current['[rego]'];\n if (regoSettings === undefined) {\n updates.push({\n path: ['[rego]'],\n value: {\n 'editor.defaultFormatter': POLICY_VSCODE_EXTENSION,\n 'editor.formatOnSave': true,\n 'editor.insertSpaces': false,\n 'editor.tabSize': 4,\n },\n });\n } else if (\n regoSettings !== null &&\n typeof regoSettings === 'object' &&\n !Array.isArray(regoSettings)\n ) {\n collectSafeScalarUpdates(\n current,\n [\n {\n path: ['[rego]', 'editor.defaultFormatter'],\n value: POLICY_VSCODE_EXTENSION,\n label: '[rego].editor.defaultFormatter',\n },\n {\n path: ['[rego]', 'editor.formatOnSave'],\n value: true,\n label: '[rego].editor.formatOnSave',\n },\n {\n path: ['[rego]', 'editor.insertSpaces'],\n value: false,\n label: '[rego].editor.insertSpaces',\n },\n {\n path: ['[rego]', 'editor.tabSize'],\n value: 4,\n label: '[rego].editor.tabSize',\n },\n ],\n updates,\n warnings,\n );\n } else {\n warnings.push('VS Code language setting \"[rego]\" is customized and was left unchanged.');\n }\n\n return applyEditorUpdates(contents, updates, 'VS Code policy settings', warnings);\n}\n\n/**\n * Merge OPA extension recommendations without disturbing unknown entries.\n *\n * VS Code's `extensions.json` schema supports `unwantedRecommendations`, so\n * the syntax-only extension can be removed from recommendations and discouraged.\n *\n * @param contents - Existing `.vscode/extensions.json` JSONC\n * @returns Merged extension recommendations and warnings\n */\nexport function mergePolicyEditorExtensions(contents: string | null): PolicyEditorMergeResult {\n const parsed = parseEditorObject(contents, 'VS Code policy extension recommendations');\n if ('warning' in parsed) {\n return { contents: parsed.contents, warnings: [parsed.warning] };\n }\n const { current } = parsed;\n const updates: JsoncUpdate[] = [];\n const warnings: string[] = [];\n\n const recommendations = current.recommendations;\n if (\n recommendations === undefined ||\n (Array.isArray(recommendations) && recommendations.every((value) => typeof value === 'string'))\n ) {\n const existing = recommendations ?? [];\n const desired = mergeStringArray(existing, [POLICY_VSCODE_EXTENSION]).filter(\n (value) => value !== CONFLICTING_POLICY_VSCODE_EXTENSION,\n );\n if (!configurationValuesEqual(existing, desired)) {\n updates.push({ path: ['recommendations'], value: desired });\n }\n } else {\n warnings.push(\n 'VS Code extension recommendations use an unknown shape and were left unchanged.',\n );\n }\n\n const unwanted = current.unwantedRecommendations;\n if (\n unwanted === undefined ||\n (Array.isArray(unwanted) && unwanted.every((value) => typeof value === 'string'))\n ) {\n const existing = unwanted ?? [];\n const desired = mergeStringArray(existing, [CONFLICTING_POLICY_VSCODE_EXTENSION]);\n if (!configurationValuesEqual(existing, desired)) {\n updates.push({ path: ['unwantedRecommendations'], value: desired });\n }\n } else {\n warnings.push(\n 'VS Code unwanted extension recommendations use an unknown shape and were left unchanged.',\n );\n }\n\n return applyEditorUpdates(\n contents,\n updates,\n 'VS Code policy extension recommendations',\n warnings,\n );\n}\n\n/**\n * Build the generated target-scoped VS Code lint task.\n *\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns VS Code task object\n */\nexport function buildPolicyLintTask(\n repositoryRoot: string,\n targetDirectory: string,\n): Record<string, unknown> {\n const target = relative(repositoryRoot, targetDirectory).split(sep).join('/') || '.';\n return {\n label: 'policy: lint',\n type: 'process',\n command: 'transcend',\n args: ['policy', 'lint', '--dir', target, '--noInteractive'],\n group: {\n kind: 'test',\n isDefault: true,\n },\n problemMatcher: [],\n };\n}\n\n/**\n * Merge the default policy lint task while preserving custom tasks.\n *\n * @param contents - Existing `.vscode/tasks.json` JSONC\n * @param repositoryRoot - Root that owns `.vscode`\n * @param targetDirectory - Selected policy project directory\n * @returns Merged task configuration and warnings\n */\nexport function mergePolicyEditorTasks(\n contents: string | null,\n repositoryRoot: string,\n targetDirectory: string,\n): PolicyEditorMergeResult {\n const parsed = parseEditorObject(contents, 'VS Code policy tasks');\n if ('warning' in parsed) {\n return { contents: parsed.contents, warnings: [parsed.warning] };\n }\n const { current } = parsed;\n const updates: JsoncUpdate[] = [];\n const warnings: string[] = [];\n const version = current.version;\n if (version === undefined) {\n updates.push({ path: ['version'], value: '2.0.0' });\n } else if (version !== '2.0.0') {\n warnings.push('VS Code task schema version is customized and was left unchanged.');\n }\n\n const desiredTask = buildPolicyLintTask(repositoryRoot, targetDirectory);\n const tasks = current.tasks;\n if (tasks === undefined) {\n updates.push({ path: ['tasks'], value: [desiredTask] });\n } else if (Array.isArray(tasks)) {\n const matchingTask = tasks.find(\n (task) =>\n task !== null &&\n typeof task === 'object' &&\n !Array.isArray(task) &&\n (task as Record<string, unknown>).label === 'policy: lint',\n );\n if (matchingTask === undefined) {\n updates.push({ path: ['tasks'], value: [...tasks, desiredTask] });\n } else if (!configurationValuesEqual(matchingTask, desiredTask)) {\n warnings.push(\n 'VS Code task \"policy: lint\" has repository-specific customization and was left unchanged.',\n );\n }\n } else {\n warnings.push('VS Code tasks use an unknown shape and were left unchanged.');\n }\n\n return applyEditorUpdates(contents, updates, 'VS Code policy tasks', warnings);\n}\n","import { isAbsolute, join, posix, relative, sep } from 'node:path';\n\nimport {\n getManagedAgentSkillCandidatePaths,\n planManagedAgentSkill,\n type ManagedAgentSkillDefinition,\n} from '../scaffolding/agent-skill.js';\nimport { displayProjectPath, quoteShellArgument } from '../scaffolding/project-plan-output.js';\nimport {\n getPlanningPathSnapshot,\n getPlanningFileSnapshot,\n planFileChange,\n type PlanningPathSnapshot,\n} from '../scaffolding/project-plan.js';\nimport { getPolicyManifestPath } from './policy-project-discovery.js';\nimport {\n generatePolicyGithubActionsWorkflow,\n POLICY_CI_WORKFLOW_PATH,\n} from './policy-scaffold-artifacts.js';\nimport {\n mergePolicyEditorExtensions,\n mergePolicyEditorSettings,\n mergePolicyEditorTasks,\n type PolicyEditorMergeResult,\n} from './policy-scaffold-config.js';\nimport {\n POLICY_INIT_RESULT_VERSION,\n PolicySetupFeature,\n type PolicyInitProjectPlan,\n type PolicyProjectState,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from './policy-scaffold-model.js';\nimport { generatePolicyStarterFiles, type PolicyStarterFile } from './policy-scaffold-templates.js';\nimport { POLICY_SKILL_FILES, POLICY_SKILL_NAME } from './policy-skill.js';\n\n/** Managed Policy Engine Agent Skill definition. */\nconst POLICY_MANAGED_SKILL: ManagedAgentSkillDefinition = {\n name: POLICY_SKILL_NAME,\n displayName: 'Policy Engine',\n owner: '@transcend-io/cli',\n files: POLICY_SKILL_FILES,\n};\n\n/** In-memory input consumed by the pure policy initializer. */\nexport interface PolicyInitPlanningInput {\n /** Project discovery state. */\n state: PolicyProjectState;\n /** Potential mutation paths keyed by absolute path. */\n snapshots: Readonly<Record<string, PlanningPathSnapshot>>;\n}\n\n/** Optional repository setup selected for policy initialization. */\nexport interface PolicyInitPlanOptions {\n /** Selected setup features. */\n features: readonly PolicySetupFeatureType[];\n /** Exact released Transcend CLI version for generated CI. */\n cliVersion: string;\n}\n\n/**\n * Build the copyable policy lint command for one target.\n *\n * @param state - Discovered project state\n * @returns Raw one-line command\n */\nexport function buildPolicyLintCommand(state: PolicyProjectState): string {\n const directory = displayProjectPath(state.invocationDirectory, state.targetDirectory);\n return `transcend policy lint --dir ${quoteShellArgument(directory)} --noInteractive`;\n}\n\n/**\n * Enumerate all core starter paths that could be created.\n *\n * @param state - Policy project state\n * @param options - Selected repository setup\n * @returns Absolute candidate paths\n */\nexport function getPolicyInitPlanningCandidatePaths(\n state: PolicyProjectState,\n options: Pick<PolicyInitPlanOptions, 'features'>,\n): string[] {\n const paths = new Set(\n generatePolicyStarterFiles().map(({ path }) => join(state.targetDirectory, path)),\n );\n const selected = new Set(options.features);\n if (selected.has(PolicySetupFeature.Editor)) {\n paths.add(join(state.projectRoot, '.vscode', 'settings.json'));\n paths.add(join(state.projectRoot, '.vscode', 'extensions.json'));\n paths.add(join(state.projectRoot, '.vscode', 'tasks.json'));\n }\n if (selected.has(PolicySetupFeature.Skill)) {\n getManagedAgentSkillCandidatePaths(\n state.projectRoot,\n state.existingSkillDirectories,\n POLICY_MANAGED_SKILL,\n ).forEach((path) => paths.add(path));\n }\n if (selected.has(PolicySetupFeature.Ci) && state.repositoryRoot && state.usesGithub) {\n paths.add(join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH));\n }\n return [...paths].sort((left, right) => left.localeCompare(right));\n}\n\n/**\n * Ensure a destination stays below an approved project root.\n *\n * @param root - Approved root\n * @param path - Candidate path\n */\nfunction assertContained(root: string, path: string): void {\n const child = relative(root, path);\n if (child === '..' || child.startsWith(`..${sep}`) || isAbsolute(child)) {\n throw new Error(`Refusing to modify path outside project root: ${path}`);\n }\n}\n\n/**\n * Enumerate generated file and directory paths allowed in an exact starter.\n *\n * @param files - Starter files\n * @returns POSIX relative paths\n */\nfunction starterRelativePaths(files: readonly PolicyStarterFile[]): Set<string> {\n const paths = new Set<string>(['input.json']);\n files.forEach(({ path }) => {\n paths.add(path);\n let parent = posix.dirname(path);\n while (parent !== '.') {\n paths.add(parent);\n parent = posix.dirname(parent);\n }\n });\n return paths;\n}\n\n/**\n * Add or classify one regular-file mutation.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param options - Desired file\n */\nfunction addFileChange(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n options: {\n /** Absolute destination path. */\n path: string;\n /** Complete desired contents. */\n contents: string;\n /** Human-readable plan description. */\n description: string;\n /** Refuse existing contents. */\n createOnly?: boolean;\n },\n): void {\n const change = planFileChange({\n snapshot: getPlanningFileSnapshot(input.snapshots, options.path),\n after: options.contents,\n description: options.description,\n ...(options.createOnly === undefined ? {} : { createOnly: options.createOnly }),\n });\n if (change) {\n plan.changes.push(change);\n } else {\n plan.unchanged.push(options.path);\n }\n}\n\n/**\n * Add one safe editor merge and its preservation warnings.\n *\n * @param plan - Policy plan being assembled\n * @param input - Collected snapshots\n * @param path - Absolute editor artifact path\n * @param result - Pure JSONC merge result\n * @param description - Human-readable plan description\n * @param cwd - Invocation directory for portable warning paths\n */\nfunction addEditorMerge(\n plan: PolicyInitProjectPlan,\n input: PolicyInitPlanningInput,\n path: string,\n result: PolicyEditorMergeResult,\n description: string,\n cwd: string,\n): void {\n addFileChange(plan, input, {\n path,\n contents: result.contents,\n description,\n });\n plan.warnings.push(\n ...result.warnings.map((warning) => `${warning} (${displayProjectPath(cwd, path)})`),\n );\n}\n\n/**\n * Build a safe policy project plan without reading the filesystem.\n *\n * Empty targets receive the complete starter. Existing targets are classified\n * only; no domain file is added, merged, or overwritten.\n *\n * @param input - Collected project state and path snapshots\n * @param options - Selected setup and pinned CLI version\n * @returns Validated policy initialization plan\n */\nexport function buildPolicyInitPlan(\n input: PolicyInitPlanningInput,\n options: PolicyInitPlanOptions,\n): PolicyInitProjectPlan {\n const { state } = input;\n const files = generatePolicyStarterFiles();\n const manifestPath = getPolicyManifestPath(state);\n const lintCommand = buildPolicyLintCommand(state);\n const resultPath = join(state.targetDirectory, 'policy_engine', 'example', 'result.rego');\n const plan: PolicyInitProjectPlan = {\n version: POLICY_INIT_RESULT_VERSION,\n command: 'init',\n rootDirectory: state.projectRoot,\n targetDirectory: state.targetDirectory,\n manifestPath,\n changes: [],\n unchanged: [],\n warnings: [],\n nextSteps: [lintCommand],\n features: [...options.features],\n };\n\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, options);\n assertContained(state.projectRoot, state.targetDirectory);\n candidatePaths.forEach((path) => assertContained(state.projectRoot, path));\n\n let hasDisposableExample = false;\n if (state.relativeFilePaths.length === 0) {\n hasDisposableExample = true;\n plan.directoryPreconditions = [\n {\n path: state.targetDirectory,\n relativePaths: [...state.relativePaths],\n },\n ];\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent') {\n throw new Error(`Expected an empty policy target, but found an entry at: ${path}`);\n }\n addFileChange(plan, input, {\n path,\n contents: file.contents,\n description: file.description,\n createOnly: true,\n });\n });\n } else {\n let allStarterFilesMatch = true;\n files.forEach((file) => {\n const path = join(state.targetDirectory, file.path);\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind === 'file' && snapshot.contents === file.contents) {\n plan.unchanged.push(path);\n return;\n }\n allStarterFilesMatch = false;\n if (snapshot.kind !== 'absent') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing policy scaffold path was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n }\n });\n hasDisposableExample = allStarterFilesMatch;\n\n const allowedPaths = starterRelativePaths(files);\n const hasCustomPaths = state.relativeFilePaths.some((path) => !allowedPaths.has(path));\n if (!allStarterFilesMatch || hasCustomPaths) {\n plan.warnings.push(\n `Existing policy target contains custom or partial content, so no starter files were added or overwritten. ` +\n `Review ${displayProjectPath(\n state.invocationDirectory,\n state.targetDirectory,\n )} manually, then run \\`${lintCommand}\\`.`,\n );\n }\n }\n if (hasDisposableExample) {\n plan.disposableExamplePath = resultPath;\n plan.nextSteps.push(\n `Edit ${quoteShellArgument(displayProjectPath(state.invocationDirectory, resultPath))}`,\n );\n }\n\n const selected = new Set(options.features);\n const root = state.projectRoot;\n if (selected.has(PolicySetupFeature.Editor)) {\n const settingsPath = join(root, '.vscode', 'settings.json');\n const extensionsPath = join(root, '.vscode', 'extensions.json');\n const tasksPath = join(root, '.vscode', 'tasks.json');\n const editorArtifacts = [\n {\n path: settingsPath,\n description: 'Merge strict target-scoped OPA and Rego editor settings',\n merge: mergePolicyEditorSettings,\n },\n {\n path: extensionsPath,\n description: 'Recommend the OPA extension and discourage its syntax-only conflict',\n merge: (\n contents: string | null,\n _repositoryRoot: string,\n _targetDirectory: string,\n ): PolicyEditorMergeResult => mergePolicyEditorExtensions(contents),\n },\n {\n path: tasksPath,\n description: 'Add the default target-scoped policy lint task',\n merge: mergePolicyEditorTasks,\n },\n ];\n editorArtifacts.forEach(({ path, description, merge }) => {\n const snapshot = getPlanningPathSnapshot(input.snapshots, path);\n if (snapshot.kind !== 'absent' && snapshot.kind !== 'file') {\n plan.unchanged.push(path);\n plan.warnings.push(\n `Existing VS Code artifact is not a regular file and was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n path,\n )}`,\n );\n return;\n }\n addEditorMerge(\n plan,\n input,\n path,\n merge(snapshot.kind === 'file' ? snapshot.contents : null, root, state.targetDirectory),\n description,\n state.invocationDirectory,\n );\n });\n }\n\n if (selected.has(PolicySetupFeature.Skill)) {\n const skillPlan = planManagedAgentSkill({\n rootDirectory: root,\n existingDirectories: state.existingSkillDirectories,\n snapshots: input.snapshots,\n skill: POLICY_MANAGED_SKILL,\n preserveModified: true,\n });\n plan.changes.push(...skillPlan.changes);\n plan.unchanged.push(...skillPlan.unchanged);\n plan.warnings.push(\n ...skillPlan.warnings.map((warning) => {\n return skillPlan.unchanged.reduce(\n (rendered, path) =>\n rendered.replace(path, displayProjectPath(state.invocationDirectory, path)),\n warning,\n );\n }),\n );\n }\n\n if (selected.has(PolicySetupFeature.Ci)) {\n if (!state.repositoryRoot || !state.usesGithub) {\n plan.warnings.push(\n 'GitHub Actions setup was selected, but this target is not inside a detected GitHub repository.',\n );\n } else {\n const workflowPath = join(state.repositoryRoot, POLICY_CI_WORKFLOW_PATH);\n const target =\n relative(state.repositoryRoot, state.targetDirectory).split(sep).join('/') || '.';\n const workflowContents = generatePolicyGithubActionsWorkflow({\n cliVersion: options.cliVersion,\n targetDirectory: target,\n });\n const workflowSnapshot = getPlanningPathSnapshot(input.snapshots, workflowPath);\n if (workflowSnapshot.kind === 'absent') {\n addFileChange(plan, input, {\n path: workflowPath,\n contents: workflowContents,\n description: 'Add credential-free Policy Engine validation',\n createOnly: true,\n });\n } else if (\n workflowSnapshot.kind === 'file' &&\n workflowSnapshot.contents === workflowContents\n ) {\n plan.unchanged.push(workflowPath);\n } else {\n plan.unchanged.push(workflowPath);\n plan.warnings.push(\n `Existing GitHub Actions workflow was left unchanged: ${displayProjectPath(\n state.invocationDirectory,\n workflowPath,\n )}. Adapt it manually to run \\`${lintCommand}\\`.`,\n );\n }\n }\n }\n\n plan.changes.forEach(({ path }) => assertContained(state.projectRoot, path));\n return plan;\n}\n","import colors from 'colors';\n\nimport { version as CLI_VERSION } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n runCapturedProcess,\n type CapturedProcessResult,\n type CapturedProcessRunner,\n} from '../../../lib/cli/run-captured-process.js';\nimport {\n DEFAULT_POLICY_PROJECT_DIRECTORY,\n discoverPolicyProject,\n} from '../../../lib/policy/policy-project-discovery.js';\nimport {\n OPA_INSTALL_URL,\n OPA_MISSING_MESSAGE,\n parsePolicyToolVersion,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n REGAL_INSTALL_URL,\n REGAL_MISSING_MESSAGE,\n unsupportedOpaVersionMessage,\n unsupportedRegalVersionMessage,\n} from '../../../lib/policy/policy-runtime.js';\nimport {\n PolicySetupFeature,\n type PolicySetupFeature as PolicySetupFeatureType,\n} from '../../../lib/policy/policy-scaffold-model.js';\nimport {\n buildPolicyInitAiHandoff,\n buildPolicyInitPlanResult,\n type PolicyInitToolVersions,\n} from '../../../lib/policy/policy-scaffold-output.js';\nimport {\n buildPolicyInitPlan,\n getPolicyInitPlanningCandidatePaths,\n} from '../../../lib/policy/policy-scaffold-planning.js';\nimport { collectPlanningSnapshots } from '../../../lib/scaffolding/project-discovery.js';\nimport { applyProjectPlan } from '../../../lib/scaffolding/project-plan-apply.js';\nimport {\n displayProjectPath,\n quoteShellArgument,\n renderProjectPlan,\n} from '../../../lib/scaffolding/project-plan-output.js';\nimport {\n PromptCancelledError,\n type PromptChoice,\n ScaffoldPrompts,\n} from '../../../lib/scaffolding/prompts.js';\n\n/** Flags for `transcend policy init`. */\nexport interface PolicyInitFlags {\n /** Install repository-level VS Code setup. */\n editor?: boolean;\n /** Install the Policy Engine Agent Skill. */\n skill?: boolean;\n /** Install validation-only GitHub Actions CI. */\n ci?: boolean;\n /** Disable prompts. */\n noInteractive: boolean;\n /** Render but do not apply the plan. */\n dryRun: boolean;\n /** Approve the final displayed plan. */\n yes: boolean;\n /** Emit one stable JSON result on stdout. */\n json: boolean;\n}\n\n/** User-facing optional setup labels. */\nconst SETUP_LABELS: Readonly<Record<PolicySetupFeatureType, string>> = {\n [PolicySetupFeature.Editor]: 'VS Code settings and lint task',\n [PolicySetupFeature.Skill]: 'Policy Engine Agent Skill',\n [PolicySetupFeature.Ci]: 'Validation-only GitHub Actions',\n};\n\n/** All optional setup features in stable prompt order. */\nconst ALL_SETUP_FEATURES = Object.values(PolicySetupFeature);\n\n/** Runtime compatibility detected before policy planning. */\ninterface PolicyRuntimeProbe {\n /** Compatible tool versions. */\n tools: PolicyInitToolVersions;\n /** Missing or incompatible runtime guidance. */\n warnings: string[];\n}\n\n/**\n * Whether this invocation can ask questions.\n *\n * @param flags - Interaction flags\n * @param stdinIsTTY - Whether standard input is interactive\n * @param stderrIsTTY - Whether prompt output is interactive\n * @returns Whether prompts are enabled\n */\nfunction isInteractiveInvocation(\n flags: Pick<PolicyInitFlags, '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 * Resolve setup from explicit flags or one default-selected checklist.\n *\n * @param prompts - Prompt adapters\n * @param flags - Setup flags\n * @param options - Interaction state\n * @returns Explicitly selected setup features\n */\nasync function resolveFeatures(\n prompts: ScaffoldPrompts,\n flags: PolicyInitFlags,\n options: {\n /** Whether prompts are available. */\n interactive: boolean;\n },\n): Promise<PolicySetupFeatureType[]> {\n const enabled: Readonly<Record<PolicySetupFeatureType, boolean | undefined>> = {\n [PolicySetupFeature.Editor]: flags.editor,\n [PolicySetupFeature.Skill]: flags.skill,\n [PolicySetupFeature.Ci]: flags.ci,\n };\n if (!options.interactive) {\n return ALL_SETUP_FEATURES.filter((feature) => enabled[feature] === true);\n }\n const choices: PromptChoice<PolicySetupFeatureType>[] = ALL_SETUP_FEATURES.map((feature) => ({\n name: SETUP_LABELS[feature],\n value: feature,\n checked: enabled[feature] !== false,\n }));\n return prompts.checkbox('Choose repository setup:', choices);\n}\n\n/**\n * Explain a failed version subprocess with official installation guidance.\n *\n * @param tool - Policy tool name\n * @param result - Failed captured process\n * @returns Actionable warning\n */\nfunction failedVersionProbeMessage(tool: 'OPA' | 'Regal', result: CapturedProcessResult): string {\n const detail = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join('\\n');\n const url = tool === 'OPA' ? OPA_INSTALL_URL : REGAL_INSTALL_URL;\n const requirement =\n tool === 'OPA' ? 'OPA 1.x' : `Regal ${MINIMUM_POLICY_STARTER_REGAL_VERSION} or newer`;\n return (\n `${requirement} is required, but \\`${tool.toLowerCase()} version\\` exited with code ` +\n `${result.code}${detail ? `: ${detail}` : '.'} ` +\n `Install or upgrade it using the official instructions: ${url}`\n );\n}\n\n/**\n * Probe both local policy runtimes without installing or modifying them.\n *\n * @param context - CLI context\n * @param cwd - Invocation working directory\n * @param runner - Captured subprocess runner\n * @returns Compatible versions and exact runtime guidance\n */\nasync function probePolicyRuntimes(\n context: LocalContext,\n cwd: string,\n runner: CapturedProcessRunner,\n): Promise<PolicyRuntimeProbe> {\n const tools: PolicyInitToolVersions = { opa: null, regal: null };\n const warnings: string[] = [];\n\n const opaResult = await runner('opa', ['version'], { cwd }, context);\n if (opaResult.error?.code === 'ENOENT') {\n warnings.push(OPA_MISSING_MESSAGE);\n } else {\n const output = `${opaResult.stdout}\\n${opaResult.stderr}`;\n const unsupported = unsupportedOpaVersionMessage(output);\n if (opaResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('OPA', opaResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.opa = parsePolicyToolVersion(output)!.version;\n }\n }\n\n const regalResult = await runner('regal', ['version'], { cwd }, context);\n if (regalResult.error?.code === 'ENOENT') {\n warnings.push(REGAL_MISSING_MESSAGE);\n } else {\n const output = `${regalResult.stdout}\\n${regalResult.stderr}`;\n const unsupported = unsupportedRegalVersionMessage(\n output,\n MINIMUM_POLICY_STARTER_REGAL_VERSION,\n 'the generated OPA 1.13.1 capabilities configuration',\n );\n if (regalResult.code !== 0) {\n warnings.push(unsupported ?? failedVersionProbeMessage('Regal', regalResult));\n } else if (unsupported) {\n warnings.push(unsupported);\n } else {\n tools.regal = parsePolicyToolVersion(output)!.version;\n }\n }\n\n return { tools, warnings };\n}\n\n/**\n * Initialize a credential-free local Policy Engine project.\n *\n * @param this - CLI context\n * @param flags - Scaffold and interaction flags\n * @param directory - Target policy directory\n * @param runner - Captured policy tool runner\n */\nexport async function init(\n this: LocalContext,\n flags: PolicyInitFlags,\n directory: string = DEFAULT_POLICY_PROJECT_DIRECTORY,\n runner: CapturedProcessRunner = runCapturedProcess,\n): Promise<void> {\n doneInputValidation(this.process);\n try {\n const runtime = await probePolicyRuntimes(this, this.process.cwd(), runner);\n const state = discoverPolicyProject(this, directory);\n const prompts = new ScaffoldPrompts(this);\n const interactive = isInteractiveInvocation(\n flags,\n this.process.stdin.isTTY,\n this.process.stderr.isTTY,\n );\n const features = await resolveFeatures(prompts, flags, { interactive });\n const candidatePaths = getPolicyInitPlanningCandidatePaths(state, { features });\n const snapshots = collectPlanningSnapshots(this, state.projectRoot, candidatePaths);\n\n const plan = buildPolicyInitPlan(\n { state, snapshots },\n {\n features,\n cliVersion: CLI_VERSION,\n },\n );\n plan.warnings.push(...runtime.warnings);\n\n if (!flags.json) {\n this.logger.info(\n renderProjectPlan(plan, {\n cwd: this.process.cwd(),\n title: 'Policy initialization plan',\n details: [\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 setupAvailable = approved && !flags.dryRun;\n const aiHandoff = buildPolicyInitAiHandoff({\n projectPath: quoteShellArgument(\n displayProjectPath(this.process.cwd(), state.targetDirectory),\n ),\n ...(plan.disposableExamplePath\n ? {\n examplePath: quoteShellArgument(\n displayProjectPath(this.process.cwd(), plan.disposableExamplePath),\n ),\n }\n : {}),\n hasSkill: setupAvailable && features.includes(PolicySetupFeature.Skill),\n lintCommand: plan.nextSteps[0]!,\n });\n const result = buildPolicyInitPlanResult(plan, {\n applied,\n dryRun: flags.dryRun,\n cwd: this.process.cwd(),\n aiHandoff,\n tools: runtime.tools,\n });\n if (flags.json) {\n this.process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n if (flags.dryRun) {\n this.logger.info(colors.yellow('Dry run complete. No changes were written.'));\n return;\n }\n if (!approved) {\n this.logger.info(colors.yellow('No changes applied.'));\n return;\n }\n if (plan.changes.length === 0) {\n const message =\n plan.warnings.length === runtime.warnings.length\n ? 'Policy project is already initialized.'\n : 'Existing policy project was left unchanged.';\n this.logger.info(colors.green(message));\n } else {\n this.logger.info(colors.green('Policy project initialized.'));\n }\n if (plan.nextSteps.length > 0) {\n this.logger.info(`\\n${colors.bold('Next steps')}`);\n plan.nextSteps.forEach((step) => this.logger.info(step));\n }\n this.logger.info(`\\n${colors.bold('AI handoff — paste into your coding agent')}`);\n this.logger.info(aiHandoff);\n } catch (error) {\n if (error instanceof PromptCancelledError) {\n return this.process.exit(130);\n }\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{t as e}from"./buildExamples-DLDlrgWE.mjs";import{r as t}from"./policyEngineCliError-DY8V-qkK.mjs";import{r as n,t as r}from"./runOpa-CswzJxIs.mjs";import{t as i}from"./policy-bundle-manifest-D6dkbjNi.mjs";import{a,i as o,n as s,o as c,t as l}from"./printResult-CHe3nRN4.mjs";import{t as u}from"./formatPolicyBundleVersionSummary-CJmMCLtJ.mjs";import{n as d}from"./resolveBundleIdByName-qXZBrUz_.mjs";import{n as f}from"./inquirer-BeaBetMO.mjs";import{t as p}from"./done-input-validation-BUz-aVC5.mjs";import{spawnSync as m}from"node:child_process";import h from"node:fs";import g from"node:os";import _ from"node:path";import{gunzipSync as v}from"node:zlib";import y from"fast-glob";import b from"colors";function x(e){let t=y.sync(`**/*.rego`,{cwd:e,onlyFiles:!0,dot:!1}).sort(),n=_.join(e,`manifest.json`),{publishableRegoPaths:r}=i(h.existsSync(n)?h.readFileSync(n,`utf8`):void 0,t.map(t=>({path:t,contents:h.readFileSync(_.join(e,t),`utf8`)})));return{entries:[`manifest.json`,...r]}}async function S(e){let t=_.join(g.tmpdir(),`transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`);try{let{code:n,stderr:i}=await r([`build`,`--v0-compatible`,`--ignore`,`*_test.rego`,`-o`,t,`.`],{cwd:e});if(n!==0)throw Error(i.trim()||`opa build failed with exit code ${n}`)}finally{h.existsSync(t)&&h.unlinkSync(t)}}function C(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${t%1==0?t.toFixed(0):t.toFixed(1)} KiB`;let n=t/1024;return`${n%1==0?n.toFixed(0):n.toFixed(1)} MiB`}async function w(e){n();let t=_.resolve(e);if(!h.existsSync(t)||!h.statSync(t).isDirectory())throw Error(`Policy directory does not exist or is not a directory: ${t}`);let{entries:i}=x(t),{code:o,stderr:s}=await r([`check`,`--strict`,`--v0-compatible`,t]);if(o!==0)throw Error(s.trim()||`opa check failed with exit code ${o}`);await S(t);let l=_.join(g.tmpdir(),`transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`),u=m(`tar`,[`-czf`,l,`-C`,t,...i],{env:{...process.env,COPYFILE_DISABLE:`1`},encoding:`utf8`});if(u.status!==0)throw Error(`Failed to create policy bundle archive: ${u.stderr.trim()||`tar failed`}`);let d=h.readFileSync(l);if(d.byteLength>5120)throw h.unlinkSync(l),Error(`Policy bundle exceeds the ${C(a)} compressed upload limit (bundle is ${C(d.byteLength)}). The server also rejects decompressed bundles larger than ${C(c)}.`);let f=v(d);if(f.byteLength>51200)throw h.unlinkSync(l),Error(`Policy bundle exceeds the ${C(c)} decompressed upload limit (bundle is ${C(f.byteLength)} decompressed).`);return l}function T(e){let t=h.readFileSync(e.bundlePath),n=new FormData;return n.append(`bundle`,new Blob([t],{type:`application/gzip`}),_.basename(e.bundlePath)),n.append(`version`,e.version),e.description&&n.append(`description`,e.description),e.bundleName&&n.append(`bundleName`,e.bundleName),n}function E(e){return e.toISOString().slice(0,19).replace(/[T:]/g,`-`)}function D(e,t=new Date){return`${e}-${E(t)}`}async function O({dir:n,"bundle-name":r,auth:i,"transcend-url":a,version:c,description:m,json:h,yes:g,debug:v=!1}){p(this.process),t(v);let y=_.resolve(n),x=c??D(r),S=o(a,i),C;try{this.logger.info(b.green(`Building policy bundle from ${y}...`)),C=await w(y);let t=await d(S,r),n;if(t){this.logger.info(b.green(`Uploading new version for bundle "${r}"...`));let e=T({bundlePath:C,version:x,description:m});n=await s(S.post(`v1/policy-engine/policy-bundles/${t}/versions`,{body:e}).json())}else{if(!this.process.stdin.isTTY&&!g){this.logger.error(b.red(`Cannot create a new bundle in a non-interactive environment; pass --yes to confirm.`)),this.process.exit(1);return}if(!g&&(this.logger.warn(b.yellow(`No policy bundle named "${r}" exists for this organization.`)),!await f({message:`No policy bundle named "${r}" exists. Create a new bundle and upload its first version?`}))){this.logger.info(b.yellow(`Publish cancelled.`));return}this.logger.info(b.green(`Creating bundle "${r}" and uploading first version...`));let e=T({bundlePath:C,version:x,description:m,bundleName:r});n=await s(S.post(`v1/policy-engine/policy-bundles`,{body:e}).json())}l(this.process.stdout,{json:h,data:n,renderTable:()=>u(n.version)}),this.logger.info(b.green(`Policy bundle version uploaded successfully.`));let i=e([`policy`,`activate`],{version:n.version.version,"bundle-name":r});this.logger.info(b.yellow(`Publishing a policy does not activate it. To activate this version, run:\n ${i}`))}finally{C&&this.fs.existsSync(C)&&this.fs.unlinkSync(C)}}export{O as publish};
2
- //# sourceMappingURL=impl-C8sWVJUG.mjs.map
1
+ import{t as e}from"./buildExamples-COM0o0UR.mjs";import{r as t}from"./policyEngineCliError-DY8V-qkK.mjs";import{r as n,t as r}from"./runOpa-CswzJxIs.mjs";import{t as i}from"./policy-bundle-manifest-D6dkbjNi.mjs";import{a,i as o,n as s,o as c,t as l}from"./printResult-CHe3nRN4.mjs";import{t as u}from"./formatPolicyBundleVersionSummary-CJmMCLtJ.mjs";import{n as d}from"./resolveBundleIdByName-qXZBrUz_.mjs";import{n as f}from"./inquirer-BeaBetMO.mjs";import{t as p}from"./done-input-validation-BUz-aVC5.mjs";import{spawnSync as m}from"node:child_process";import h from"node:fs";import g from"node:os";import _ from"node:path";import{gunzipSync as v}from"node:zlib";import y from"fast-glob";import b from"colors";function x(e){let t=y.sync(`**/*.rego`,{cwd:e,onlyFiles:!0,dot:!1}).sort(),n=_.join(e,`manifest.json`),{publishableRegoPaths:r}=i(h.existsSync(n)?h.readFileSync(n,`utf8`):void 0,t.map(t=>({path:t,contents:h.readFileSync(_.join(e,t),`utf8`)})));return{entries:[`manifest.json`,...r]}}async function S(e){let t=_.join(g.tmpdir(),`transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`);try{let{code:n,stderr:i}=await r([`build`,`--v0-compatible`,`--ignore`,`*_test.rego`,`-o`,t,`.`],{cwd:e});if(n!==0)throw Error(i.trim()||`opa build failed with exit code ${n}`)}finally{h.existsSync(t)&&h.unlinkSync(t)}}function C(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${t%1==0?t.toFixed(0):t.toFixed(1)} KiB`;let n=t/1024;return`${n%1==0?n.toFixed(0):n.toFixed(1)} MiB`}async function w(e){n();let t=_.resolve(e);if(!h.existsSync(t)||!h.statSync(t).isDirectory())throw Error(`Policy directory does not exist or is not a directory: ${t}`);let{entries:i}=x(t),{code:o,stderr:s}=await r([`check`,`--strict`,`--v0-compatible`,t]);if(o!==0)throw Error(s.trim()||`opa check failed with exit code ${o}`);await S(t);let l=_.join(g.tmpdir(),`transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`),u=m(`tar`,[`-czf`,l,`-C`,t,...i],{env:{...process.env,COPYFILE_DISABLE:`1`},encoding:`utf8`});if(u.status!==0)throw Error(`Failed to create policy bundle archive: ${u.stderr.trim()||`tar failed`}`);let d=h.readFileSync(l);if(d.byteLength>5120)throw h.unlinkSync(l),Error(`Policy bundle exceeds the ${C(a)} compressed upload limit (bundle is ${C(d.byteLength)}). The server also rejects decompressed bundles larger than ${C(c)}.`);let f=v(d);if(f.byteLength>51200)throw h.unlinkSync(l),Error(`Policy bundle exceeds the ${C(c)} decompressed upload limit (bundle is ${C(f.byteLength)} decompressed).`);return l}function T(e){let t=h.readFileSync(e.bundlePath),n=new FormData;return n.append(`bundle`,new Blob([t],{type:`application/gzip`}),_.basename(e.bundlePath)),n.append(`version`,e.version),e.description&&n.append(`description`,e.description),e.bundleName&&n.append(`bundleName`,e.bundleName),n}function E(e){return e.toISOString().slice(0,19).replace(/[T:]/g,`-`)}function D(e,t=new Date){return`${e}-${E(t)}`}async function O({dir:n,"bundle-name":r,auth:i,"transcend-url":a,version:c,description:m,json:h,yes:g,debug:v=!1}){p(this.process),t(v);let y=_.resolve(n),x=c??D(r),S=o(a,i),C;try{this.logger.info(b.green(`Building policy bundle from ${y}...`)),C=await w(y);let t=await d(S,r),n;if(t){this.logger.info(b.green(`Uploading new version for bundle "${r}"...`));let e=T({bundlePath:C,version:x,description:m});n=await s(S.post(`v1/policy-engine/policy-bundles/${t}/versions`,{body:e}).json())}else{if(!this.process.stdin.isTTY&&!g){this.logger.error(b.red(`Cannot create a new bundle in a non-interactive environment; pass --yes to confirm.`)),this.process.exit(1);return}if(!g&&(this.logger.warn(b.yellow(`No policy bundle named "${r}" exists for this organization.`)),!await f({message:`No policy bundle named "${r}" exists. Create a new bundle and upload its first version?`}))){this.logger.info(b.yellow(`Publish cancelled.`));return}this.logger.info(b.green(`Creating bundle "${r}" and uploading first version...`));let e=T({bundlePath:C,version:x,description:m,bundleName:r});n=await s(S.post(`v1/policy-engine/policy-bundles`,{body:e}).json())}l(this.process.stdout,{json:h,data:n,renderTable:()=>u(n.version)}),this.logger.info(b.green(`Policy bundle version uploaded successfully.`));let i=e([`policy`,`activate`],{version:n.version.version,"bundle-name":r});this.logger.info(b.yellow(`Publishing a policy does not activate it. To activate this version, run:\n ${i}`))}finally{C&&this.fs.existsSync(C)&&this.fs.unlinkSync(C)}}export{O as publish};
2
+ //# sourceMappingURL=impl-DN6CgOI6.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"impl-C8sWVJUG.mjs","names":["fg"],"sources":["../src/commands/policy/helpers/buildOpaBundleTarball.ts","../src/commands/policy/helpers/buildPolicyBundleFormData.ts","../src/commands/policy/helpers/defaultPolicyVersionLabel.ts","../src/commands/policy/publish/impl.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { gunzipSync } from 'node:zlib';\n\nimport fg from 'fast-glob';\n\nimport { validatePolicyBundleContents } from '../../../lib/policy/policy-bundle-manifest.js';\nimport { MAX_BUNDLE_COMPRESSED_BYTES, MAX_BUNDLE_DECOMPRESSED_BYTES } from '../constants.js';\nimport { assertOpaInstalled } from './assertOpaInstalled.js';\nimport { runOPACapture } from './runOpa.js';\n\n/** Result of collecting publishable entries from a policy bundle directory. */\ninterface PolicyBundleArchiveContents {\n /** Relative paths to include in the upload tarball (manifest first, then rego) */\n entries: string[];\n}\n\n/**\n * Collects `manifest.json` and publishable `.rego` files from a policy directory.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @returns Validated archive entries\n */\nfunction collectPolicyBundleArchiveEntries(dir: string): PolicyBundleArchiveContents {\n const regoFiles = fg\n .sync('**/*.rego', {\n cwd: dir,\n onlyFiles: true,\n dot: false,\n })\n .sort();\n const manifestPath = path.join(dir, 'manifest.json');\n const { publishableRegoPaths } = validatePolicyBundleContents(\n fs.existsSync(manifestPath) ? fs.readFileSync(manifestPath, 'utf8') : undefined,\n regoFiles.map((relativePath) => ({\n path: relativePath,\n contents: fs.readFileSync(path.join(dir, relativePath), 'utf8'),\n })),\n );\n\n return {\n entries: ['manifest.json', ...publishableRegoPaths],\n };\n}\n\n/**\n * Verifies that a policy directory compiles end-to-end with `opa build`.\n *\n * The compiled output is discarded — the server receives the `manifest.json` +\n * `.rego` archive produced by {@link buildOpaBundleTarball}, not the OPA bundle\n * — but a successful build guarantees the policies compile and link, surfacing\n * errors (syntax, missing imports, undefined references, etc.) before upload.\n *\n * @param dir - Absolute path to the policy bundle directory\n */\nasync function assertBundleCompiles(dir: string): Promise<void> {\n const buildOutputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n try {\n // Run with `cwd` set to the bundle directory and pass `.` so `opa build`\n // resolves the bundle root correctly. `*_test.rego` files are local-only.\n const { code, stderr } = await runOPACapture(\n ['build', '--v0-compatible', '--ignore', '*_test.rego', '-o', buildOutputPath, '.'],\n { cwd: dir },\n );\n if (code !== 0) {\n throw new Error(stderr.trim() || `opa build failed with exit code ${code}`);\n }\n } finally {\n if (fs.existsSync(buildOutputPath)) {\n fs.unlinkSync(buildOutputPath);\n }\n }\n}\n\n/**\n * Formats a byte count as a human-readable size with binary units.\n *\n * @param bytes - Number of bytes\n * @returns Human-readable size, e.g. `14 MiB` or `4 KiB`\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const kib = bytes / 1024;\n if (kib < 1024) {\n return `${kib % 1 === 0 ? kib.toFixed(0) : kib.toFixed(1)} KiB`;\n }\n const mib = kib / 1024;\n return `${mib % 1 === 0 ? mib.toFixed(0) : mib.toFixed(1)} MiB`;\n}\n\n/**\n * Builds a gzip-compressed policy bundle tarball for upload to Transcend.\n *\n * The Policy Engine API expects a plain archive containing `manifest.json` and\n * one or more `.rego` files. This differs from `opa build` output, which embeds\n * `.manifest`, `data.json`, and other OPA bundle metadata that the server\n * rejects. Before packaging, the manifest is validated (shape + root coverage)\n * and the bundle is validated with `opa check` (strict Rego linting) and\n * `opa build` (full compilation) so failures surface client-side rather than\n * after upload.\n *\n * @param dir - Directory containing `manifest.json` and `.rego` policy files\n * @returns Absolute path to the generated `.tar.gz` bundle\n */\nexport async function buildOpaBundleTarball(dir: string): Promise<string> {\n assertOpaInstalled();\n\n const resolvedDir = path.resolve(dir);\n if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {\n throw new Error(`Policy directory does not exist or is not a directory: ${resolvedDir}`);\n }\n\n // Validate the manifest shape and that roots cover every Rego package before\n // invoking OPA, so invalid manifests surface a clear error instead of an\n // opaque `opa build failed with exit code 1`.\n const { entries: archiveEntries } = collectPolicyBundleArchiveEntries(resolvedDir);\n\n // Match the Rego v1 validation the Policy Engine API runs on upload.\n const { code: checkCode, stderr: checkStderr } = await runOPACapture([\n 'check',\n '--strict',\n '--v0-compatible',\n resolvedDir,\n ]);\n if (checkCode !== 0) {\n throw new Error(checkStderr.trim() || `opa check failed with exit code ${checkCode}`);\n }\n\n // Ensure the bundle compiles end-to-end before packaging for upload.\n await assertBundleCompiles(resolvedDir);\n\n const outputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n\n const tarResult = spawnSync('tar', ['-czf', outputPath, '-C', resolvedDir, ...archiveEntries], {\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n encoding: 'utf8',\n });\n if (tarResult.status !== 0) {\n throw new Error(\n `Failed to create policy bundle archive: ${tarResult.stderr.trim() || 'tar failed'}`,\n );\n }\n\n const compressedBytes = fs.readFileSync(outputPath);\n if (compressedBytes.byteLength > MAX_BUNDLE_COMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_COMPRESSED_BYTES)} compressed upload limit ` +\n `(bundle is ${formatBytes(compressedBytes.byteLength)}). ` +\n `The server also rejects decompressed bundles larger than ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)}.`,\n );\n }\n\n const decompressedBytes = gunzipSync(compressedBytes);\n if (decompressedBytes.byteLength > MAX_BUNDLE_DECOMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)} decompressed upload limit ` +\n `(bundle is ${formatBytes(decompressedBytes.byteLength)} decompressed).`,\n );\n }\n\n return outputPath;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Fields for building a policy bundle upload form. */\nexport interface BuildPolicyBundleFormDataOptions {\n /** Absolute path to the bundle tarball */\n bundlePath: string;\n /** Version label */\n version: string;\n /** Optional description */\n description?: string;\n /** Bundle name (only for create) */\n bundleName?: string;\n}\n\n/**\n * Builds multipart form data for a policy bundle upload.\n *\n * @param options - Upload fields\n * @returns FormData ready for POST\n */\nexport function buildPolicyBundleFormData(options: BuildPolicyBundleFormDataOptions): FormData {\n const bundleBytes = fs.readFileSync(options.bundlePath);\n const form = new FormData();\n form.append(\n 'bundle',\n new Blob([bundleBytes], { type: 'application/gzip' }),\n path.basename(options.bundlePath),\n );\n form.append('version', options.version);\n if (options.description) {\n form.append('description', options.description);\n }\n if (options.bundleName) {\n form.append('bundleName', options.bundleName);\n }\n return form;\n}\n","/**\n * Formats a date as `yyyy-mm-dd-hh-mm-ss` in UTC.\n *\n * @param date - Date to format\n * @returns Timestamp label\n */\nfunction formatPolicyVersionTimestamp(date: Date): string {\n return date.toISOString().slice(0, 19).replace(/[T:]/g, '-');\n}\n\n/**\n * Returns a default version label from the bundle name and current UTC timestamp.\n *\n * @param bundleName - Tenant-unique policy bundle name\n * @param now - Current time (for testing)\n * @returns Version label in `{bundleName}-yyyy-mm-dd-hh-mm-ss` form\n */\nexport function defaultPolicyVersionLabel(bundleName: string, now: Date = new Date()): string {\n return `${bundleName}-${formatPolicyVersionTimestamp(now)}`;\n}\n","import path from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildExampleCommand } from '../../../lib/docgen/buildExamples.js';\nimport { inquirerConfirmBoolean } from '../../../lib/helpers/inquirer.js';\nimport type { ActivateCommandFlags } from '../activate/impl.js';\nimport {\n buildPolicyBundleFormData,\n buildPolicyEngineClient,\n buildOpaBundleTarball,\n defaultPolicyVersionLabel,\n formatPolicyBundleVersionSummary,\n policyEngineRequest,\n printResult,\n resolveBundleIdByName,\n setPolicyEngineCliDebug,\n} from '../helpers/index.js';\nimport type { CreatePolicyBundleResponse, CreatePolicyBundleVersionResponse } from '../types.js';\n\n/** CLI flags for `transcend policy publish`. */\nexport interface PublishCommandFlags {\n /** Directory containing Rego policy files */\n dir: string;\n /** Tenant-unique bundle name */\n 'bundle-name': string;\n /** Transcend API key */\n auth: string;\n /** Transcend API URL */\n 'transcend-url': string;\n /** Version label (defaults to `{bundleName}-yyyy-mm-dd-hh-mm-ss`) */\n version?: string;\n /** Optional version description */\n description?: string;\n /** Print raw JSON response */\n json: boolean;\n /** Skip the \"create new bundle\" confirmation */\n yes: boolean;\n /** Include technical error details when a command fails */\n debug?: boolean;\n}\n\n/**\n * Build and upload a new immutable policy bundle version.\n *\n * @param this - CLI context\n * @param flags - Command flags\n */\nexport async function publish(\n this: LocalContext,\n {\n dir,\n 'bundle-name': bundleName,\n auth,\n 'transcend-url': transcendUrl,\n version,\n description,\n json,\n yes,\n debug = false,\n }: PublishCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n setPolicyEngineCliDebug(debug);\n\n const resolvedDir = path.resolve(dir);\n const versionLabel = version ?? defaultPolicyVersionLabel(bundleName);\n const client = buildPolicyEngineClient(transcendUrl, auth);\n\n let bundlePath: string | undefined;\n try {\n this.logger.info(colors.green(`Building policy bundle from ${resolvedDir}...`));\n bundlePath = await buildOpaBundleTarball(resolvedDir);\n\n const existingBundleId = await resolveBundleIdByName(client, bundleName);\n\n let responseBody: CreatePolicyBundleResponse | CreatePolicyBundleVersionResponse;\n\n if (existingBundleId) {\n this.logger.info(colors.green(`Uploading new version for bundle \"${bundleName}\"...`));\n const form = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n });\n responseBody = await policyEngineRequest(\n client\n .post(`v1/policy-engine/policy-bundles/${existingBundleId}/versions`, { body: form })\n .json<CreatePolicyBundleVersionResponse>(),\n );\n } else {\n if (!this.process.stdin.isTTY && !yes) {\n this.logger.error(\n colors.red(\n 'Cannot create a new bundle in a non-interactive environment; pass --yes to confirm.',\n ),\n );\n this.process.exit(1);\n return;\n }\n\n if (!yes) {\n this.logger.warn(\n colors.yellow(`No policy bundle named \"${bundleName}\" exists for this organization.`),\n );\n const shouldCreate = await inquirerConfirmBoolean({\n message: `No policy bundle named \"${bundleName}\" exists. Create a new bundle and upload its first version?`,\n });\n if (!shouldCreate) {\n this.logger.info(colors.yellow('Publish cancelled.'));\n return;\n }\n }\n\n this.logger.info(\n colors.green(`Creating bundle \"${bundleName}\" and uploading first version...`),\n );\n const createForm = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n bundleName,\n });\n responseBody = await policyEngineRequest(\n client\n .post('v1/policy-engine/policy-bundles', {\n body: createForm,\n })\n .json<CreatePolicyBundleResponse>(),\n );\n }\n\n printResult(this.process.stdout, {\n json,\n data: responseBody,\n renderTable: () => formatPolicyBundleVersionSummary(responseBody.version),\n });\n\n this.logger.info(colors.green('Policy bundle version uploaded successfully.'));\n\n const activateCommand = buildExampleCommand<ActivateCommandFlags>(['policy', 'activate'], {\n version: responseBody.version.version,\n 'bundle-name': bundleName,\n });\n this.logger.info(\n colors.yellow(\n `Publishing a policy does not activate it. To activate this version, run:\\n ${activateCommand}`,\n ),\n );\n } finally {\n if (bundlePath && this.fs.existsSync(bundlePath)) {\n this.fs.unlinkSync(bundlePath);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"impl-DN6CgOI6.mjs","names":["fg"],"sources":["../src/commands/policy/helpers/buildOpaBundleTarball.ts","../src/commands/policy/helpers/buildPolicyBundleFormData.ts","../src/commands/policy/helpers/defaultPolicyVersionLabel.ts","../src/commands/policy/publish/impl.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { gunzipSync } from 'node:zlib';\n\nimport fg from 'fast-glob';\n\nimport { validatePolicyBundleContents } from '../../../lib/policy/policy-bundle-manifest.js';\nimport { MAX_BUNDLE_COMPRESSED_BYTES, MAX_BUNDLE_DECOMPRESSED_BYTES } from '../constants.js';\nimport { assertOpaInstalled } from './assertOpaInstalled.js';\nimport { runOPACapture } from './runOpa.js';\n\n/** Result of collecting publishable entries from a policy bundle directory. */\ninterface PolicyBundleArchiveContents {\n /** Relative paths to include in the upload tarball (manifest first, then rego) */\n entries: string[];\n}\n\n/**\n * Collects `manifest.json` and publishable `.rego` files from a policy directory.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @returns Validated archive entries\n */\nfunction collectPolicyBundleArchiveEntries(dir: string): PolicyBundleArchiveContents {\n const regoFiles = fg\n .sync('**/*.rego', {\n cwd: dir,\n onlyFiles: true,\n dot: false,\n })\n .sort();\n const manifestPath = path.join(dir, 'manifest.json');\n const { publishableRegoPaths } = validatePolicyBundleContents(\n fs.existsSync(manifestPath) ? fs.readFileSync(manifestPath, 'utf8') : undefined,\n regoFiles.map((relativePath) => ({\n path: relativePath,\n contents: fs.readFileSync(path.join(dir, relativePath), 'utf8'),\n })),\n );\n\n return {\n entries: ['manifest.json', ...publishableRegoPaths],\n };\n}\n\n/**\n * Verifies that a policy directory compiles end-to-end with `opa build`.\n *\n * The compiled output is discarded — the server receives the `manifest.json` +\n * `.rego` archive produced by {@link buildOpaBundleTarball}, not the OPA bundle\n * — but a successful build guarantees the policies compile and link, surfacing\n * errors (syntax, missing imports, undefined references, etc.) before upload.\n *\n * @param dir - Absolute path to the policy bundle directory\n */\nasync function assertBundleCompiles(dir: string): Promise<void> {\n const buildOutputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n try {\n // Run with `cwd` set to the bundle directory and pass `.` so `opa build`\n // resolves the bundle root correctly. `*_test.rego` files are local-only.\n const { code, stderr } = await runOPACapture(\n ['build', '--v0-compatible', '--ignore', '*_test.rego', '-o', buildOutputPath, '.'],\n { cwd: dir },\n );\n if (code !== 0) {\n throw new Error(stderr.trim() || `opa build failed with exit code ${code}`);\n }\n } finally {\n if (fs.existsSync(buildOutputPath)) {\n fs.unlinkSync(buildOutputPath);\n }\n }\n}\n\n/**\n * Formats a byte count as a human-readable size with binary units.\n *\n * @param bytes - Number of bytes\n * @returns Human-readable size, e.g. `14 MiB` or `4 KiB`\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const kib = bytes / 1024;\n if (kib < 1024) {\n return `${kib % 1 === 0 ? kib.toFixed(0) : kib.toFixed(1)} KiB`;\n }\n const mib = kib / 1024;\n return `${mib % 1 === 0 ? mib.toFixed(0) : mib.toFixed(1)} MiB`;\n}\n\n/**\n * Builds a gzip-compressed policy bundle tarball for upload to Transcend.\n *\n * The Policy Engine API expects a plain archive containing `manifest.json` and\n * one or more `.rego` files. This differs from `opa build` output, which embeds\n * `.manifest`, `data.json`, and other OPA bundle metadata that the server\n * rejects. Before packaging, the manifest is validated (shape + root coverage)\n * and the bundle is validated with `opa check` (strict Rego linting) and\n * `opa build` (full compilation) so failures surface client-side rather than\n * after upload.\n *\n * @param dir - Directory containing `manifest.json` and `.rego` policy files\n * @returns Absolute path to the generated `.tar.gz` bundle\n */\nexport async function buildOpaBundleTarball(dir: string): Promise<string> {\n assertOpaInstalled();\n\n const resolvedDir = path.resolve(dir);\n if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {\n throw new Error(`Policy directory does not exist or is not a directory: ${resolvedDir}`);\n }\n\n // Validate the manifest shape and that roots cover every Rego package before\n // invoking OPA, so invalid manifests surface a clear error instead of an\n // opaque `opa build failed with exit code 1`.\n const { entries: archiveEntries } = collectPolicyBundleArchiveEntries(resolvedDir);\n\n // Match the Rego v1 validation the Policy Engine API runs on upload.\n const { code: checkCode, stderr: checkStderr } = await runOPACapture([\n 'check',\n '--strict',\n '--v0-compatible',\n resolvedDir,\n ]);\n if (checkCode !== 0) {\n throw new Error(checkStderr.trim() || `opa check failed with exit code ${checkCode}`);\n }\n\n // Ensure the bundle compiles end-to-end before packaging for upload.\n await assertBundleCompiles(resolvedDir);\n\n const outputPath = path.join(\n os.tmpdir(),\n `transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n );\n\n const tarResult = spawnSync('tar', ['-czf', outputPath, '-C', resolvedDir, ...archiveEntries], {\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n encoding: 'utf8',\n });\n if (tarResult.status !== 0) {\n throw new Error(\n `Failed to create policy bundle archive: ${tarResult.stderr.trim() || 'tar failed'}`,\n );\n }\n\n const compressedBytes = fs.readFileSync(outputPath);\n if (compressedBytes.byteLength > MAX_BUNDLE_COMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_COMPRESSED_BYTES)} compressed upload limit ` +\n `(bundle is ${formatBytes(compressedBytes.byteLength)}). ` +\n `The server also rejects decompressed bundles larger than ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)}.`,\n );\n }\n\n const decompressedBytes = gunzipSync(compressedBytes);\n if (decompressedBytes.byteLength > MAX_BUNDLE_DECOMPRESSED_BYTES) {\n fs.unlinkSync(outputPath);\n throw new Error(\n `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)} decompressed upload limit ` +\n `(bundle is ${formatBytes(decompressedBytes.byteLength)} decompressed).`,\n );\n }\n\n return outputPath;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Fields for building a policy bundle upload form. */\nexport interface BuildPolicyBundleFormDataOptions {\n /** Absolute path to the bundle tarball */\n bundlePath: string;\n /** Version label */\n version: string;\n /** Optional description */\n description?: string;\n /** Bundle name (only for create) */\n bundleName?: string;\n}\n\n/**\n * Builds multipart form data for a policy bundle upload.\n *\n * @param options - Upload fields\n * @returns FormData ready for POST\n */\nexport function buildPolicyBundleFormData(options: BuildPolicyBundleFormDataOptions): FormData {\n const bundleBytes = fs.readFileSync(options.bundlePath);\n const form = new FormData();\n form.append(\n 'bundle',\n new Blob([bundleBytes], { type: 'application/gzip' }),\n path.basename(options.bundlePath),\n );\n form.append('version', options.version);\n if (options.description) {\n form.append('description', options.description);\n }\n if (options.bundleName) {\n form.append('bundleName', options.bundleName);\n }\n return form;\n}\n","/**\n * Formats a date as `yyyy-mm-dd-hh-mm-ss` in UTC.\n *\n * @param date - Date to format\n * @returns Timestamp label\n */\nfunction formatPolicyVersionTimestamp(date: Date): string {\n return date.toISOString().slice(0, 19).replace(/[T:]/g, '-');\n}\n\n/**\n * Returns a default version label from the bundle name and current UTC timestamp.\n *\n * @param bundleName - Tenant-unique policy bundle name\n * @param now - Current time (for testing)\n * @returns Version label in `{bundleName}-yyyy-mm-dd-hh-mm-ss` form\n */\nexport function defaultPolicyVersionLabel(bundleName: string, now: Date = new Date()): string {\n return `${bundleName}-${formatPolicyVersionTimestamp(now)}`;\n}\n","import path from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildExampleCommand } from '../../../lib/docgen/buildExamples.js';\nimport { inquirerConfirmBoolean } from '../../../lib/helpers/inquirer.js';\nimport type { ActivateCommandFlags } from '../activate/impl.js';\nimport {\n buildPolicyBundleFormData,\n buildPolicyEngineClient,\n buildOpaBundleTarball,\n defaultPolicyVersionLabel,\n formatPolicyBundleVersionSummary,\n policyEngineRequest,\n printResult,\n resolveBundleIdByName,\n setPolicyEngineCliDebug,\n} from '../helpers/index.js';\nimport type { CreatePolicyBundleResponse, CreatePolicyBundleVersionResponse } from '../types.js';\n\n/** CLI flags for `transcend policy publish`. */\nexport interface PublishCommandFlags {\n /** Directory containing Rego policy files */\n dir: string;\n /** Tenant-unique bundle name */\n 'bundle-name': string;\n /** Transcend API key */\n auth: string;\n /** Transcend API URL */\n 'transcend-url': string;\n /** Version label (defaults to `{bundleName}-yyyy-mm-dd-hh-mm-ss`) */\n version?: string;\n /** Optional version description */\n description?: string;\n /** Print raw JSON response */\n json: boolean;\n /** Skip the \"create new bundle\" confirmation */\n yes: boolean;\n /** Include technical error details when a command fails */\n debug?: boolean;\n}\n\n/**\n * Build and upload a new immutable policy bundle version.\n *\n * @param this - CLI context\n * @param flags - Command flags\n */\nexport async function publish(\n this: LocalContext,\n {\n dir,\n 'bundle-name': bundleName,\n auth,\n 'transcend-url': transcendUrl,\n version,\n description,\n json,\n yes,\n debug = false,\n }: PublishCommandFlags,\n): Promise<void> {\n doneInputValidation(this.process);\n setPolicyEngineCliDebug(debug);\n\n const resolvedDir = path.resolve(dir);\n const versionLabel = version ?? defaultPolicyVersionLabel(bundleName);\n const client = buildPolicyEngineClient(transcendUrl, auth);\n\n let bundlePath: string | undefined;\n try {\n this.logger.info(colors.green(`Building policy bundle from ${resolvedDir}...`));\n bundlePath = await buildOpaBundleTarball(resolvedDir);\n\n const existingBundleId = await resolveBundleIdByName(client, bundleName);\n\n let responseBody: CreatePolicyBundleResponse | CreatePolicyBundleVersionResponse;\n\n if (existingBundleId) {\n this.logger.info(colors.green(`Uploading new version for bundle \"${bundleName}\"...`));\n const form = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n });\n responseBody = await policyEngineRequest(\n client\n .post(`v1/policy-engine/policy-bundles/${existingBundleId}/versions`, { body: form })\n .json<CreatePolicyBundleVersionResponse>(),\n );\n } else {\n if (!this.process.stdin.isTTY && !yes) {\n this.logger.error(\n colors.red(\n 'Cannot create a new bundle in a non-interactive environment; pass --yes to confirm.',\n ),\n );\n this.process.exit(1);\n return;\n }\n\n if (!yes) {\n this.logger.warn(\n colors.yellow(`No policy bundle named \"${bundleName}\" exists for this organization.`),\n );\n const shouldCreate = await inquirerConfirmBoolean({\n message: `No policy bundle named \"${bundleName}\" exists. Create a new bundle and upload its first version?`,\n });\n if (!shouldCreate) {\n this.logger.info(colors.yellow('Publish cancelled.'));\n return;\n }\n }\n\n this.logger.info(\n colors.green(`Creating bundle \"${bundleName}\" and uploading first version...`),\n );\n const createForm = buildPolicyBundleFormData({\n bundlePath,\n version: versionLabel,\n description,\n bundleName,\n });\n responseBody = await policyEngineRequest(\n client\n .post('v1/policy-engine/policy-bundles', {\n body: createForm,\n })\n .json<CreatePolicyBundleResponse>(),\n );\n }\n\n printResult(this.process.stdout, {\n json,\n data: responseBody,\n renderTable: () => formatPolicyBundleVersionSummary(responseBody.version),\n });\n\n this.logger.info(colors.green('Policy bundle version uploaded successfully.'));\n\n const activateCommand = buildExampleCommand<ActivateCommandFlags>(['policy', 'activate'], {\n version: responseBody.version.version,\n 'bundle-name': bundleName,\n });\n this.logger.info(\n colors.yellow(\n `Publishing a policy does not activate it. To activate this version, run:\\n ${activateCommand}`,\n ),\n );\n } finally {\n if (bundlePath && this.fs.existsSync(bundlePath)) {\n this.fs.unlinkSync(bundlePath);\n }\n }\n}\n"],"mappings":"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"}