@maycombhq/atticus 0.0.0-stage → 2.0.0-beta.2

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 (475) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +17 -2
  3. package/THIRD-PARTY-LICENSES.txt +2607 -0
  4. package/dist/bin.js +47 -0
  5. package/dist/chunk-23W7VWKR.js +2609 -0
  6. package/dist/chunk-27NKUS3X.js +4330 -0
  7. package/dist/chunk-2ANOROX3.js +2522 -0
  8. package/dist/chunk-2BF2EYJV.js +174 -0
  9. package/dist/chunk-2BFCZ3RK.js +315 -0
  10. package/dist/chunk-2DIQQJCB.js +378 -0
  11. package/dist/chunk-2RMYG36Q.js +1227 -0
  12. package/dist/chunk-2VHF7OXM.js +55 -0
  13. package/dist/chunk-3ALD2W2A.js +95 -0
  14. package/dist/chunk-3C7EYRFZ.js +41 -0
  15. package/dist/chunk-3G4YI4ZU.js +16 -0
  16. package/dist/chunk-3HI6Z55Y.js +5949 -0
  17. package/dist/chunk-3USYZGRF.js +324 -0
  18. package/dist/chunk-42EVSKME.js +37 -0
  19. package/dist/chunk-4AK7IBVP.js +915 -0
  20. package/dist/chunk-4BKGMUIK.js +53 -0
  21. package/dist/chunk-4BN53TG3.js +343 -0
  22. package/dist/chunk-4NDAAFQT.js +103 -0
  23. package/dist/chunk-4Q3NN7VF.js +32 -0
  24. package/dist/chunk-4RS5KZQD.js +25 -0
  25. package/dist/chunk-4SKZDI62.js +22 -0
  26. package/dist/chunk-4WBVUHXN.js +69 -0
  27. package/dist/chunk-5GDRCDQB.js +32 -0
  28. package/dist/chunk-5GGOLAKC.js +856 -0
  29. package/dist/chunk-5KLGBXG5.js +48 -0
  30. package/dist/chunk-5WG5YP4T.js +34 -0
  31. package/dist/chunk-64EQYWCA.js +180 -0
  32. package/dist/chunk-652QWTLZ.js +242 -0
  33. package/dist/chunk-65NYPGRC.js +766 -0
  34. package/dist/chunk-66YVAGGM.js +46 -0
  35. package/dist/chunk-6BNC6EQ4.js +41 -0
  36. package/dist/chunk-6BVONWJ7.js +50 -0
  37. package/dist/chunk-6D2CQ5II.js +41 -0
  38. package/dist/chunk-6IU67AEK.js +325 -0
  39. package/dist/chunk-6J5OKA4Y.js +49 -0
  40. package/dist/chunk-6JCPI55B.js +92 -0
  41. package/dist/chunk-6JUBZBMW.js +56 -0
  42. package/dist/chunk-6M5NK3K3.js +415 -0
  43. package/dist/chunk-6QSERWXH.js +53 -0
  44. package/dist/chunk-6TACQN3N.js +41 -0
  45. package/dist/chunk-76WKMA4J.js +14 -0
  46. package/dist/chunk-7AVHLZGD.js +45 -0
  47. package/dist/chunk-7EFILTCI.js +67 -0
  48. package/dist/chunk-7EKXJZ2Y.js +2902 -0
  49. package/dist/chunk-7EOBHUMC.js +133 -0
  50. package/dist/chunk-7FBGJFEE.js +66 -0
  51. package/dist/chunk-7JUKDRSZ.js +1726 -0
  52. package/dist/chunk-7SW2QWLU.js +212 -0
  53. package/dist/chunk-7WD63HU2.js +143 -0
  54. package/dist/chunk-7ZUIMTOU.js +108 -0
  55. package/dist/chunk-A3GY6SOA.js +95 -0
  56. package/dist/chunk-A7UPUQFY.js +2356 -0
  57. package/dist/chunk-AA6YULYB.js +376 -0
  58. package/dist/chunk-ABWHYWNI.js +101 -0
  59. package/dist/chunk-AIOQPLA5.js +540 -0
  60. package/dist/chunk-AVJDSJ2F.js +18 -0
  61. package/dist/chunk-B2WLAWNJ.js +374 -0
  62. package/dist/chunk-BKVWTZ6A.js +211 -0
  63. package/dist/chunk-BOHJZTEQ.js +1991 -0
  64. package/dist/chunk-BWZ77RQT.js +25 -0
  65. package/dist/chunk-C6EKFH7J.js +169 -0
  66. package/dist/chunk-CAQZUNOH.js +1150 -0
  67. package/dist/chunk-CEXSU4S6.js +1217 -0
  68. package/dist/chunk-CKSITVS4.js +16101 -0
  69. package/dist/chunk-CNUKCS2T.js +2741 -0
  70. package/dist/chunk-CPA6HPVR.js +3206 -0
  71. package/dist/chunk-CR3MTH32.js +207 -0
  72. package/dist/chunk-CSZ4C5N6.js +307 -0
  73. package/dist/chunk-D3PO4DOZ.js +261 -0
  74. package/dist/chunk-D46WUV3T.js +33 -0
  75. package/dist/chunk-DE76JROX.js +80 -0
  76. package/dist/chunk-DFBCSHVT.js +69 -0
  77. package/dist/chunk-DHPACDG7.js +104 -0
  78. package/dist/chunk-DKJA76CJ.js +113 -0
  79. package/dist/chunk-DPUYDDQG.js +164 -0
  80. package/dist/chunk-DPZHZQKE.js +285 -0
  81. package/dist/chunk-E36QOJMD.js +47 -0
  82. package/dist/chunk-EADP3PEN.js +450 -0
  83. package/dist/chunk-EBEW3XXQ.js +166 -0
  84. package/dist/chunk-EDS2L2LD.js +106 -0
  85. package/dist/chunk-EFHQ3TWP.js +637 -0
  86. package/dist/chunk-EPTBZ3GP.js +101 -0
  87. package/dist/chunk-EYWIDJFU.js +130 -0
  88. package/dist/chunk-F7HYOUFF.js +287 -0
  89. package/dist/chunk-FHH4I4ZV.js +128 -0
  90. package/dist/chunk-FITWGOJ2.js +131 -0
  91. package/dist/chunk-FQXYPF7E.js +147 -0
  92. package/dist/chunk-G2B4ZQGH.js +240 -0
  93. package/dist/chunk-GBRFVT63.js +45 -0
  94. package/dist/chunk-GDLULHTC.js +2919 -0
  95. package/dist/chunk-GLUX4EEP.js +583 -0
  96. package/dist/chunk-GQ4N4WKF.js +1142 -0
  97. package/dist/chunk-GT4I4ZWM.js +38 -0
  98. package/dist/chunk-HFQCFSJR.js +60 -0
  99. package/dist/chunk-HITVBIJS.js +1247 -0
  100. package/dist/chunk-HLJAXMM4.js +233 -0
  101. package/dist/chunk-HVUPKCGJ.js +162 -0
  102. package/dist/chunk-I3E7CX4H.js +155 -0
  103. package/dist/chunk-I4JRCD6M.js +184 -0
  104. package/dist/chunk-ICY36XCH.js +34 -0
  105. package/dist/chunk-IHMLFRVV.js +228 -0
  106. package/dist/chunk-IPKHE5D6.js +1963 -0
  107. package/dist/chunk-J4K3KVLD.js +131 -0
  108. package/dist/chunk-JBTK5OP2.js +55 -0
  109. package/dist/chunk-JCZIKA4C.js +163 -0
  110. package/dist/chunk-JGZCG5VM.js +189 -0
  111. package/dist/chunk-JIITQXFB.js +4087 -0
  112. package/dist/chunk-JMSCMUCA.js +271 -0
  113. package/dist/chunk-JZU3H6UQ.js +54 -0
  114. package/dist/chunk-K65BJIMT.js +49 -0
  115. package/dist/chunk-KEM4SDDP.js +3898 -0
  116. package/dist/chunk-KQDZXGNR.js +14 -0
  117. package/dist/chunk-L24C55VN.js +7923 -0
  118. package/dist/chunk-L6SGQIR3.js +471 -0
  119. package/dist/chunk-LR3R6Z2A.js +400 -0
  120. package/dist/chunk-M766ZJ6W.js +119 -0
  121. package/dist/chunk-MC3H7736.js +19910 -0
  122. package/dist/chunk-MGYZM27B.js +205 -0
  123. package/dist/chunk-MMOSZPWJ.js +273 -0
  124. package/dist/chunk-MVZVGYXH.js +1611 -0
  125. package/dist/chunk-N7IXEHK3.js +549 -0
  126. package/dist/chunk-NE2W3OO7.js +230 -0
  127. package/dist/chunk-NN2ZQEB4.js +38 -0
  128. package/dist/chunk-NXFPS2LR.js +182 -0
  129. package/dist/chunk-O3WI5KWW.js +31 -0
  130. package/dist/chunk-OLQJTJJU.js +76 -0
  131. package/dist/chunk-ONLS5QA5.js +102 -0
  132. package/dist/chunk-OT2O76OS.js +1496 -0
  133. package/dist/chunk-PAMPPUR6.js +4500 -0
  134. package/dist/chunk-PCOCACY3.js +385 -0
  135. package/dist/chunk-PCVDV3UZ.js +430 -0
  136. package/dist/chunk-PRPPGYZG.js +104 -0
  137. package/dist/chunk-Q4D5X7QB.js +264 -0
  138. package/dist/chunk-Q5AMFEWD.js +119 -0
  139. package/dist/chunk-QRAOANID.js +214 -0
  140. package/dist/chunk-QSXK2RGH.js +688 -0
  141. package/dist/chunk-QZSX3F7C.js +389 -0
  142. package/dist/chunk-R6RY4Q5T.js +51 -0
  143. package/dist/chunk-R6XF6UR3.js +149 -0
  144. package/dist/chunk-R77KLRB3.js +166 -0
  145. package/dist/chunk-RRTKKSLQ.js +251 -0
  146. package/dist/chunk-RTEYOSJY.js +29 -0
  147. package/dist/chunk-RUVFXE2L.js +666 -0
  148. package/dist/chunk-RVH5SUW5.js +69 -0
  149. package/dist/chunk-RZPYKDWS.js +26 -0
  150. package/dist/chunk-S2A7YC3Q.js +41433 -0
  151. package/dist/chunk-S3QNRWYR.js +25 -0
  152. package/dist/chunk-SJRGMG6A.js +174 -0
  153. package/dist/chunk-SP2I63OO.js +252 -0
  154. package/dist/chunk-T2UYZSCQ.js +545 -0
  155. package/dist/chunk-T6AIP7H5.js +3851 -0
  156. package/dist/chunk-T6XQL73F.js +94 -0
  157. package/dist/chunk-TANFV3MZ.js +531 -0
  158. package/dist/chunk-TDD55CJH.js +119 -0
  159. package/dist/chunk-TV45EUGM.js +51 -0
  160. package/dist/chunk-TXLH6WHQ.js +2078 -0
  161. package/dist/chunk-TYAID7B7.js +408 -0
  162. package/dist/chunk-UBBC2XSG.js +873 -0
  163. package/dist/chunk-UGLN7QHV.js +27 -0
  164. package/dist/chunk-UNM6ZOKP.js +878 -0
  165. package/dist/chunk-V2YTAIQO.js +1075 -0
  166. package/dist/chunk-VN3DP4LQ.js +43 -0
  167. package/dist/chunk-VOGCSYOI.js +16 -0
  168. package/dist/chunk-VYDBJ73M.js +32 -0
  169. package/dist/chunk-W3BQAZ3Q.js +34 -0
  170. package/dist/chunk-W5BVQF44.js +36 -0
  171. package/dist/chunk-WVPJSRRJ.js +52 -0
  172. package/dist/chunk-WY6PP6AA.js +53 -0
  173. package/dist/chunk-XAKWMCXI.js +285 -0
  174. package/dist/chunk-XPCM366L.js +70 -0
  175. package/dist/chunk-XPTOBS2D.js +48 -0
  176. package/dist/chunk-XY3P7JW7.js +3479 -0
  177. package/dist/chunk-XZRON6IV.js +131 -0
  178. package/dist/chunk-YEDDOYSC.js +27809 -0
  179. package/dist/chunk-YISXLPHN.js +496 -0
  180. package/dist/chunk-YMZ3TNYB.js +18 -0
  181. package/dist/chunk-YY6ZQQBP.js +203 -0
  182. package/dist/chunk-YYQN46FY.js +334 -0
  183. package/dist/chunk-Z6LF7HQN.js +22 -0
  184. package/dist/chunk-ZCJDOK2S.js +116 -0
  185. package/dist/chunk-ZDPAS56H.js +76 -0
  186. package/dist/chunk-ZMAINWBW.js +18 -0
  187. package/dist/chunk-ZMFPW66A.js +22 -0
  188. package/dist/chunk-ZNCEKR4J.js +296 -0
  189. package/dist/chunk-ZVM6AKKM.js +47 -0
  190. package/dist/files.json +1888 -0
  191. package/dist/fixtures/forge/README.md +19 -0
  192. package/dist/fixtures/forge/expected/discrepancies.yaml +54 -0
  193. package/dist/fixtures/forge/expected/inputs.yaml +38 -0
  194. package/dist/fixtures/forge/expected/scan.yaml +342 -0
  195. package/dist/fixtures/forge/inputs/diagrams/forge-context.drawio +23 -0
  196. package/dist/fixtures/forge/inputs/partner-specs/northwind-pay-openapi.yaml +11 -0
  197. package/dist/fixtures/forge/inputs/tickets/ado-stories.json +4 -0
  198. package/dist/fixtures/forge/inputs/tickets/closed-service-requests.json +5 -0
  199. package/dist/fixtures/forge/inputs/wiki/integration-patterns.md +11 -0
  200. package/dist/fixtures/forge/inputs/wiki/ledger-solution-spec.md +9 -0
  201. package/dist/fixtures/forge/inputs/wiki/snow-firewall-request.md +4 -0
  202. package/dist/fixtures/forge/metarepo/judgments/reaches/84af5b6af24f7ca8c23013f3.yaml +17 -0
  203. package/dist/fixtures/forge/metarepo/judgments/reaches/c3917555edebddce8cecb647.yaml +17 -0
  204. package/dist/fixtures/forge/metarepo/judgments/reaches/c5fafd6601f8ca9e34e0bbd0.yaml +17 -0
  205. package/dist/fixtures/forge/metarepo/org-pack/agents/architecture-critic.yaml +9 -0
  206. package/dist/fixtures/forge/metarepo/org-pack/agents/story-writer.yaml +10 -0
  207. package/dist/fixtures/forge/metarepo/org-pack/checklists/architecture.yaml +115 -0
  208. package/dist/fixtures/forge/metarepo/org-pack/dialects/forge.yaml +111 -0
  209. package/dist/fixtures/forge/metarepo/org-pack/gates.yaml +22 -0
  210. package/dist/fixtures/forge/metarepo/org-pack/pack.yaml +11 -0
  211. package/dist/fixtures/forge/metarepo/org-pack/patterns/A.EB.PUB.yaml +12 -0
  212. package/dist/fixtures/forge/metarepo/org-pack/patterns/D.JDBC.yaml +12 -0
  213. package/dist/fixtures/forge/metarepo/org-pack/patterns/S.DIR.BFF.yaml +12 -0
  214. package/dist/fixtures/forge/metarepo/org-pack/patterns/S.GW.SOR.yaml +13 -0
  215. package/dist/fixtures/forge/metarepo/org-pack/patterns/S.GW.VND.yaml +14 -0
  216. package/dist/fixtures/forge/metarepo/org-pack/process/change-templates/feature.md +37 -0
  217. package/dist/fixtures/forge/metarepo/org-pack/process/skills/add-forge-endpoint/SKILL.md +17 -0
  218. package/dist/fixtures/forge/metarepo/org-pack/process/snow/firewall-rule.yaml +14 -0
  219. package/dist/fixtures/forge/metarepo/org-pack/process/snow/gateway-route.yaml +13 -0
  220. package/dist/fixtures/forge/metarepo/org-pack/profiles/forge/profile.yaml +12 -0
  221. package/dist/fixtures/forge/metarepo/org-pack/profiles/forge/repos.manifest.yaml +44 -0
  222. package/dist/fixtures/forge/metarepo/org-pack/roles.yaml +14 -0
  223. package/dist/fixtures/forge/metarepo/org-pack/runtime.yaml +14 -0
  224. package/dist/fixtures/forge/metarepo/org-pack/sources.yaml +3 -0
  225. package/dist/fixtures/forge/repos/forge-events/topics/payments.initiated.yaml +4 -0
  226. package/dist/fixtures/forge/repos/forge-events/topics/transfers.completed.yaml +4 -0
  227. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/ledger-v1.xml +3 -0
  228. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/policies/SpikeArrest.xml +3 -0
  229. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/policies/VerifyOAuth.xml +4 -0
  230. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/proxies/default.xml +14 -0
  231. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/targets/ledger.xml +5 -0
  232. package/dist/fixtures/forge/repos/forge-infra/alerts/ledger-api.yaml +5 -0
  233. package/dist/fixtures/forge/repos/forge-infra/k8s/ledger-api.yaml +15 -0
  234. package/dist/fixtures/forge/repos/forge-infra/k8s/portal-bff.yaml +7 -0
  235. package/dist/fixtures/forge/repos/forge-infra/terraform/ledger-db.tf +9 -0
  236. package/dist/fixtures/forge/repos/forge-ledger/api/ledger-openapi.yaml +31 -0
  237. package/dist/fixtures/forge/repos/forge-ledger/forge.yaml +4 -0
  238. package/dist/fixtures/forge/repos/forge-ledger/src/main/java/forge/ledger/LedgerEndpoints.java +13 -0
  239. package/dist/fixtures/forge/repos/forge-ledger/src/main/java/forge/ledger/LedgerEvents.java +11 -0
  240. package/dist/fixtures/forge/repos/forge-ledger/src/main/java/forge/ledger/NorthwindClient.java +10 -0
  241. package/dist/fixtures/forge/repos/forge-ledger/src/main/resources/application.yml +3 -0
  242. package/dist/fixtures/forge/repos/forge-ledger/src/main/resources/db/migration/V1__create_account.sql +5 -0
  243. package/dist/fixtures/forge/repos/forge-ledger/src/main/resources/db/migration/V2__create_entry.sql +7 -0
  244. package/dist/fixtures/forge/repos/forge-portal-bff/pom.xml +1 -0
  245. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/AuditPublisher.java +12 -0
  246. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/BalanceController.java +16 -0
  247. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/LedgerClient.java +13 -0
  248. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/PaymentEvents.java +13 -0
  249. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/resources/application.yml +8 -0
  250. package/dist/fixtures/forge/repos/forge-portal-ui/package.json +1 -0
  251. package/dist/fixtures/forge/repos/forge-portal-ui/src/api/balance.ts +5 -0
  252. package/dist/fixtures/forge/repos/forge-reports-job/src/main/java/forge/reports/DailyEntriesJob.java +19 -0
  253. package/dist/fixtures/forge/repos/forge-reports-job/src/main/resources/application.yml +3 -0
  254. package/dist/fixtures/forge-change/README.md +41 -0
  255. package/dist/fixtures/forge-change/expected/findings.yaml +301 -0
  256. package/dist/fixtures/forge-change/expected/stories.yaml +101 -0
  257. package/dist/fixtures/forge-change/judgments/personal-data/0b5f3dbf5257a22275d8c74b.yaml +18 -0
  258. package/dist/fixtures/forge-change/judgments/personal-data/2759a66770134c417440bf2d.yaml +18 -0
  259. package/dist/fixtures/forge-change/judgments/personal-data/31b1ea2f14d0737f1aca79fd.yaml +18 -0
  260. package/dist/fixtures/forge-change/judgments/personal-data/49afd70c08228e65ad6ca1ed.yaml +18 -0
  261. package/dist/fixtures/forge-change/judgments/personal-data/761cabcb8a39f5e5866d2dd6.yaml +18 -0
  262. package/dist/fixtures/forge-change/judgments/personal-data/adae902b90cc8ffa0c765145.yaml +18 -0
  263. package/dist/fixtures/forge-change/judgments/personal-data/ba11bb933105ec9493e065dd.yaml +18 -0
  264. package/dist/fixtures/forge-change/judgments/personal-data/bdbcd1cdac3021c68063c3e7.yaml +18 -0
  265. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/brief.md +35 -0
  266. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/change.yaml +120 -0
  267. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/data.md +18 -0
  268. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/design.md +29 -0
  269. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/interfaces.md +17 -0
  270. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/mappings.md +26 -0
  271. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/proposal.md +35 -0
  272. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/snow.md +12 -0
  273. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/specs/transfer-limits/spec.md +19 -0
  274. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s1-refuse-over-limit.md +17 -0
  275. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s2-show-remaining.md +16 -0
  276. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s3-audit-refusals.md +18 -0
  277. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s4-velocity-check.md +16 -0
  278. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories.md +8 -0
  279. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/tasks.md +12 -0
  280. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/ux.md +7 -0
  281. package/dist/fixtures/forge-change/org-pack/agents/code-and-test-critic.yaml +13 -0
  282. package/dist/fixtures/forge-change/org-pack/agents/complete-critic.yaml +12 -0
  283. package/dist/fixtures/forge-change/org-pack/agents/safe-critic.yaml +12 -0
  284. package/dist/fixtures/forge-change/org-pack/agents/ship-critic.yaml +11 -0
  285. package/dist/fixtures/forge-change/org-pack/agents/true-critic.yaml +11 -0
  286. package/dist/fixtures/forge-change/org-pack/checklists/review.yaml +54 -0
  287. package/dist/fixtures/forge-change/org-pack/gates.yaml +25 -0
  288. package/dist/fixtures/forge-change/org-pack/teams/team-ledger/checklists/ledger-team.yaml +227 -0
  289. package/dist/fixtures/forge-change/recordings/complete-critic/2ad84f84bf39c1d5412697e69fe23034d6983ec45a00314bf0975e627589a3c5.json +12 -0
  290. package/dist/fixtures/forge-change/recordings/complete-critic/417c98d8e54a4387d0fd93441c49f44c2868958739070d855c1dce0c41e24db3.json +12 -0
  291. package/dist/fixtures/forge-change/recordings/complete-critic/50203ee22e9cb3ef047295edb6538fe7d5695e1e4b139f3c929013dc6ce47021.json +12 -0
  292. package/dist/fixtures/forge-change/recordings/complete-critic/89f18d67f5d9c325bf35e2a9e020f9ddb6ee13b8523315037f0905cc57c040b1.json +12 -0
  293. package/dist/fixtures/forge-change/recordings/complete-critic/b4097867d26ae8eadc8b9efa8cdd86897013358035f0b40086c299a59c4ba121.json +12 -0
  294. package/dist/fixtures/forge-change/recordings/safe-critic/302d06f49664dd67ad2e21ab9cf74c1b0f7d3f750709c6ed8eff2b70983274e2.json +12 -0
  295. package/dist/fixtures/forge-change/recordings/safe-critic/32f1049c9a5ab4a759543290db4644ec6e221cc45fdfdcf06193837c6a8ce0b9.json +12 -0
  296. package/dist/fixtures/forge-change/recordings/safe-critic/4e4a84bfc04b9f26ca4250319a879901ff7a1c081c71e46a117675fee05026b0.json +12 -0
  297. package/dist/fixtures/forge-change/recordings/safe-critic/604af0fcdd6df6b76208fa88305fdc15c37606c2a4d1ae816477e46ac8c2dd04.json +12 -0
  298. package/dist/fixtures/forge-change/recordings/safe-critic/f0bf50af11f14c50d07904f0dffe1c8c20fb0cd89770645a8824c1d30a443955.json +12 -0
  299. package/dist/fixtures/forge-change/recordings/ship-critic/350954b58833b2c04880c67db45a1b328b7fd541d9f0d943b63905b8875488a6.json +12 -0
  300. package/dist/fixtures/forge-change/recordings/ship-critic/4af95c6c96a206777cec9de1f9c2d8c55a36ddc9b8db2f81d6eb83217b835efa.json +12 -0
  301. package/dist/fixtures/forge-change/recordings/ship-critic/76c34522a49cf7587a4e5689a5030d384603fa780b8aba97d27815cbc829683e.json +12 -0
  302. package/dist/fixtures/forge-change/recordings/ship-critic/a3b2cd1ace48587e5994333db03b34c3a0f9dec4f1932f1730ddfb687f6918c8.json +12 -0
  303. package/dist/fixtures/forge-change/recordings/ship-critic/de288a4fa64d0fc20890f9a787080ce6eac5203b7b9b72d884df11e8cf111835.json +12 -0
  304. package/dist/fixtures/forge-change/recordings/story-writer/1ddb00eac2aaf91a5ec5d9dfd220116be9f75aec6546a4a3a3b050ed89af2864.json +12 -0
  305. package/dist/packages/assistant-kit/frameworks-kit/README.md +86 -0
  306. package/dist/packages/assistant-kit/frameworks-kit/checklist.md +11 -0
  307. package/dist/packages/assistant-kit/frameworks-kit/examples/tide-lantern.yaml +56 -0
  308. package/dist/packages/assistant-kit/frameworks-kit/examples/tide-platform.yaml +43 -0
  309. package/dist/packages/assistant-kit/frameworks-kit/prompts/write-framework-model.md +12 -0
  310. package/dist/packages/assistant-kit/kit/README.md +98 -0
  311. package/dist/packages/assistant-kit/kit/c2-reference.md +334 -0
  312. package/dist/packages/assistant-kit/kit/checklist.md +39 -0
  313. package/dist/packages/assistant-kit/kit/examples/house-http-client.yaml +102 -0
  314. package/dist/packages/assistant-kit/kit/examples/tide-apigee.yaml +56 -0
  315. package/dist/packages/assistant-kit/kit/examples/tide-apim.yaml +32 -0
  316. package/dist/packages/assistant-kit/kit/examples/tide-kong.yaml +44 -0
  317. package/dist/packages/assistant-kit/kit/prompts/write-dialect.md +34 -0
  318. package/dist/packages/assistant-kit/kit/worked-example.md +198 -0
  319. package/dist/packages/conformance/sample/README.md +4 -0
  320. package/dist/packages/conformance/sample/inputs/notes.md +3 -0
  321. package/dist/packages/conformance/sample/inputs/systems.csv +3 -0
  322. package/dist/packages/conformance/sample/repo/api/greeter.proto +6 -0
  323. package/dist/packages/conformance/sample/repo/api/openapi.yaml +10 -0
  324. package/dist/packages/conformance/sample/repo/api/schema.graphql +3 -0
  325. package/dist/packages/conformance/sample/repo/db/V1__create_greeting.sql +4 -0
  326. package/dist/packages/conformance/sample/repo/package.json +7 -0
  327. package/dist/packages/conformance/sample/repo/src/main/java/sample/HelloController.java +10 -0
  328. package/dist/packages/conformance/sample/repo/web/app.ts +4 -0
  329. package/dist/packages/evals/datasets/critic-lenses.yaml +62 -0
  330. package/dist/packages/evals/datasets/dialect-writer.yaml +14 -0
  331. package/dist/packages/evals/datasets/feature-namer.yaml +34 -0
  332. package/dist/packages/evals/datasets/glossary-definer.yaml +25 -0
  333. package/dist/packages/evals/datasets/story-writer.yaml +13 -0
  334. package/dist/packages/evals/datasets/template-writer.yaml +16 -0
  335. package/dist/packages/evals/datasets/test-writer.yaml +18 -0
  336. package/dist/packages/executors/reference/reference-executor.mjs +233 -0
  337. package/dist/packages/extractors/dialects/argocd.yaml +45 -0
  338. package/dist/packages/extractors/dialects/fixtures/jaxrs/accounts-service/src/main/java/forge/accounts/AccountResource.java +47 -0
  339. package/dist/packages/extractors/dialects/fixtures/jaxrs/accounts-service/src/main/java/forge/accounts/AuditClient.java +12 -0
  340. package/dist/packages/extractors/dialects/fixtures/jaxrs/accounts-service/src/main/java/forge/accounts/LedgerClient.java +17 -0
  341. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/java/forge/statements/LedgerClient.java +14 -0
  342. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/java/forge/statements/RatesClient.java +11 -0
  343. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/java/forge/statements/StatementController.java +36 -0
  344. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/resources/application.yml +7 -0
  345. package/dist/packages/extractors/dialects/fixtures/quarkus-reactive-messaging/fraud-service/src/main/java/forge/fraud/FraudScorer.java +27 -0
  346. package/dist/packages/extractors/dialects/fixtures/quarkus-reactive-messaging/fraud-service/src/main/resources/application.properties +4 -0
  347. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/api.tf +38 -0
  348. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/main.tf +95 -0
  349. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/terraform.tfvars +1 -0
  350. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/variables.tf +4 -0
  351. package/dist/packages/extractors/dialects/fixtures/terraform-azure/forge-azure-infra/main.tf +102 -0
  352. package/dist/packages/extractors/dialects/fixtures/terraform-gcp/forge-gcp-infra/main.tf +51 -0
  353. package/dist/packages/extractors/dialects/harness.yaml +101 -0
  354. package/dist/packages/extractors/dialects/jaxrs.yaml +155 -0
  355. package/dist/packages/extractors/dialects/micronaut.yaml +207 -0
  356. package/dist/packages/extractors/dialects/quarkus-reactive-messaging.yaml +158 -0
  357. package/dist/packages/extractors/dialects/tekton.yaml +71 -0
  358. package/dist/packages/extractors/dialects/terraform-aws.yaml +267 -0
  359. package/dist/packages/extractors/dialects/terraform-azure.yaml +212 -0
  360. package/dist/packages/extractors/dialects/terraform-gcp.yaml +109 -0
  361. package/dist/packages/extractors/grammars/README.md +11 -0
  362. package/dist/packages/extractors/grammars/tree-sitter-groovy.LICENSE +21 -0
  363. package/dist/packages/extractors/grammars/tree-sitter-groovy.wasm +0 -0
  364. package/dist/packages/extractors/grammars/vendored.json +11 -0
  365. package/dist/packages/learn/lessons/architect-diagrams-and-code.yaml +69 -0
  366. package/dist/packages/learn/lessons/business-analyst-story-bar.yaml +94 -0
  367. package/dist/packages/learn/lessons/delivery-lead-release-readiness.yaml +44 -0
  368. package/dist/packages/learn/lessons/designer-features-in-user-words.yaml +57 -0
  369. package/dist/packages/learn/lessons/developer-find-your-way.yaml +60 -0
  370. package/dist/packages/learn/lessons/everyone-first-hour.yaml +74 -0
  371. package/dist/packages/learn/lessons/platform-lead-coverage-and-defences.yaml +58 -0
  372. package/dist/packages/learn/lessons/product-owner-first-change.yaml +167 -0
  373. package/dist/packages/learn/lessons/qa-tests-and-trace.yaml +53 -0
  374. package/dist/packages/learn/lessons/team-lead-initiative.yaml +146 -0
  375. package/dist/packages/naysayer/constitution/constitution.yaml +286 -0
  376. package/dist/packages/naysayer/starter/review.yaml +256 -0
  377. package/dist/packages/sdk/npm/index.js +8892 -0
  378. package/dist/packages/speckit/rules/drift.yaml +78 -0
  379. package/dist/packages/taskrun/rules/conform.yaml +38 -0
  380. package/dist/packages/testgen/rules/trace.yaml +49 -0
  381. package/dist/packages/ui/dist/assets/elk-api-tma0MCuh.js +2 -0
  382. package/dist/packages/ui/dist/assets/elk-worker.min--dAJroGl.js +6401 -0
  383. package/dist/packages/ui/dist/assets/elk-worker.min-DdYmS5kP.js +2 -0
  384. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-400-normal-BTotfTJu.woff +0 -0
  385. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-400-normal-DZqxrq2p.woff2 +0 -0
  386. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-500-normal-ByOcLdNv.woff +0 -0
  387. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-500-normal-CocWQlwt.woff2 +0 -0
  388. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-600-normal-71GNu3SW.woff2 +0 -0
  389. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-600-normal-BGq0mW3O.woff +0 -0
  390. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-400-normal-Dsrv2Tcn.woff +0 -0
  391. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-400-normal-g30qAdWV.woff2 +0 -0
  392. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-500-normal-Cs5J6C77.woff2 +0 -0
  393. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-500-normal-DB5PtV2g.woff +0 -0
  394. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-600-normal-Bz0x94Yp.woff +0 -0
  395. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-600-normal-DUMzJB7m.woff2 +0 -0
  396. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-400-normal-D9ESIMu3.woff +0 -0
  397. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-400-normal-_efipK4i.woff2 +0 -0
  398. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-500-normal-CuWXN6rf.woff +0 -0
  399. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-500-normal-JMMifIXV.woff2 +0 -0
  400. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-600-normal-D-CqTdkO.woff +0 -0
  401. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-600-normal-DzTrcv_p.woff2 +0 -0
  402. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  403. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  404. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  405. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  406. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  407. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  408. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-400-normal-C5H60-Va.woff2 +0 -0
  409. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-400-normal-RBey6euL.woff +0 -0
  410. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-500-normal-D0aIdm-b.woff +0 -0
  411. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-500-normal-DakdToA3.woff2 +0 -0
  412. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-600-normal-DIrixKbi.woff +0 -0
  413. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-600-normal-DOrvGEcy.woff2 +0 -0
  414. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-400-normal-DG4YqDda.woff2 +0 -0
  415. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-400-normal-fK1oJ5dG.woff +0 -0
  416. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-500-normal-BEb3_waV.woff +0 -0
  417. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-500-normal-e4dixQRQ.woff2 +0 -0
  418. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-600-normal-DgdngZtN.woff +0 -0
  419. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-600-normal-DpPYBSTl.woff2 +0 -0
  420. package/dist/packages/ui/dist/assets/index-B54fm9FQ.js +29 -0
  421. package/dist/packages/ui/dist/assets/index-DD_hufQz.css +1 -0
  422. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  423. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  424. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  425. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  426. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  427. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  428. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  429. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  430. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  431. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  432. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  433. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  434. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  435. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  436. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  437. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  438. package/dist/packages/ui/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  439. package/dist/packages/ui/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  440. package/dist/packages/ui/dist/assets/rajdhani-devanagari-600-normal-BtY48IV_.woff +0 -0
  441. package/dist/packages/ui/dist/assets/rajdhani-devanagari-600-normal-DhS7ScYx.woff2 +0 -0
  442. package/dist/packages/ui/dist/assets/rajdhani-devanagari-700-normal-BQQOj9BB.woff2 +0 -0
  443. package/dist/packages/ui/dist/assets/rajdhani-devanagari-700-normal-DBRwWuxA.woff +0 -0
  444. package/dist/packages/ui/dist/assets/rajdhani-latin-600-normal-CXCVEoA9.woff2 +0 -0
  445. package/dist/packages/ui/dist/assets/rajdhani-latin-600-normal-Dx02qI2_.woff +0 -0
  446. package/dist/packages/ui/dist/assets/rajdhani-latin-700-normal-BPDUZo87.woff2 +0 -0
  447. package/dist/packages/ui/dist/assets/rajdhani-latin-700-normal-e0Uj8ZlN.woff +0 -0
  448. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-600-normal-BleIgkPp.woff +0 -0
  449. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-600-normal-C9ZjJQAt.woff2 +0 -0
  450. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-700-normal-BPaQ7tlD.woff +0 -0
  451. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-700-normal-S6aYESQK.woff2 +0 -0
  452. package/dist/packages/ui/dist/favicon.svg +1 -0
  453. package/dist/packages/ui/dist/index.html +15 -0
  454. package/dist/third-party.json +575 -0
  455. package/dist/vendor/@fission-ai/openspec/bin/openspec.js +85986 -0
  456. package/dist/vendor/@fission-ai/openspec/package.json +82 -0
  457. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/schema.yaml +248 -0
  458. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/design.md +21 -0
  459. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/proposal.md +34 -0
  460. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/spec.md +13 -0
  461. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/tasks.md +11 -0
  462. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-c_sharp.wasm +0 -0
  463. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-go.wasm +0 -0
  464. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-java.wasm +0 -0
  465. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-javascript.wasm +0 -0
  466. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-kotlin.wasm +0 -0
  467. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-php.wasm +0 -0
  468. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-python.wasm +0 -0
  469. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-ruby.wasm +0 -0
  470. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-rust.wasm +0 -0
  471. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-scala.wasm +0 -0
  472. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-tsx.wasm +0 -0
  473. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-typescript.wasm +0 -0
  474. package/dist/vendor/web-tree-sitter/tree-sitter.wasm +0 -0
  475. package/package.json +36 -3
@@ -0,0 +1,1247 @@
1
+ import { createRequire as __atticusCreateRequire } from "node:module";
2
+ import { fileURLToPath as __atticusFileURLToPath } from "node:url";
3
+ var require = __atticusCreateRequire(import.meta.url);
4
+ var __atticusUrl = (p) => new URL("./" + p, import.meta.url).href;
5
+ var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
6
+ import {
7
+ generateTests,
8
+ matrixCsv,
9
+ matrixMarkdown,
10
+ traceMatrix,
11
+ writeTraceFindings
12
+ } from "./chunk-2ANOROX3.js";
13
+ import {
14
+ table
15
+ } from "./chunk-VOGCSYOI.js";
16
+ import {
17
+ readChangeFiles,
18
+ readDataChanges,
19
+ readHops,
20
+ reviewedGates
21
+ } from "./chunk-3HI6Z55Y.js";
22
+ import {
23
+ assess,
24
+ changeFolder,
25
+ changeStore,
26
+ checkFindings,
27
+ loadChangeContext
28
+ } from "./chunk-XY3P7JW7.js";
29
+ import {
30
+ GlossaryError,
31
+ aliasDecision,
32
+ completeGlossaryDefinitions,
33
+ defineDecision,
34
+ linkDecision,
35
+ loadGlossary,
36
+ readCatalog,
37
+ resolveTermId,
38
+ scanGlossary,
39
+ writeDecisions
40
+ } from "./chunk-27NKUS3X.js";
41
+ import {
42
+ BUILT_IN_EXTRACTORS,
43
+ SHIPPED_DIALECTS_DIR,
44
+ dialectExtractor,
45
+ loadShippedDialects,
46
+ runDialectTests
47
+ } from "./chunk-MC3H7736.js";
48
+ import {
49
+ baseClonePath,
50
+ checkoutState,
51
+ createGit,
52
+ readChangeRepos
53
+ } from "./chunk-EFHQ3TWP.js";
54
+ import {
55
+ DEFAULT_IGNORES,
56
+ fsRepo,
57
+ scanRepo
58
+ } from "./chunk-GQ4N4WKF.js";
59
+ import {
60
+ runtimeForCli
61
+ } from "./chunk-CNUKCS2T.js";
62
+ import {
63
+ catalogDirOf,
64
+ external_exports,
65
+ loadOrgPack,
66
+ mergeCatalog,
67
+ normalizePath,
68
+ orgPackDirOf,
69
+ require_dist
70
+ } from "./chunk-S2A7YC3Q.js";
71
+ import {
72
+ __toESM
73
+ } from "./chunk-TV45EUGM.js";
74
+
75
+ // packages/cli/dist/quality-commands.js
76
+ import { appendFile, mkdir, writeFile } from "node:fs/promises";
77
+ import { dirname, join as join4 } from "node:path";
78
+
79
+ // packages/ci/dist/config.js
80
+ var import_yaml = __toESM(require_dist(), 1);
81
+ import { readFile } from "node:fs/promises";
82
+ import { join } from "node:path";
83
+ var CiConfig = external_exports.strictObject({
84
+ schemaVersion: external_exports.literal(1),
85
+ drift: external_exports.strictObject({
86
+ mode: external_exports.enum(["block", "warn"]).default("block"),
87
+ ignore: external_exports.array(external_exports.string().min(1)).default([])
88
+ }).default({ mode: "block", ignore: [] }),
89
+ archive: external_exports.strictObject({ requireMergedPrs: external_exports.boolean().default(true) }).default({ requireMergedPrs: true })
90
+ });
91
+ var DEFAULT_CI_CONFIG = CiConfig.parse({ schemaVersion: 1 });
92
+ async function loadCiConfig(orgPackDir) {
93
+ if (!orgPackDir)
94
+ return { config: DEFAULT_CI_CONFIG, problems: [] };
95
+ let text;
96
+ try {
97
+ text = await readFile(join(orgPackDir, "process", "ci.yaml"), "utf8");
98
+ } catch {
99
+ return { config: DEFAULT_CI_CONFIG, problems: [] };
100
+ }
101
+ let data;
102
+ try {
103
+ data = (0, import_yaml.parse)(text);
104
+ } catch (e) {
105
+ return {
106
+ config: DEFAULT_CI_CONFIG,
107
+ problems: [
108
+ `org-pack/process/ci.yaml: can't read YAML: ${e.message.split("\n")[0]}`
109
+ ]
110
+ };
111
+ }
112
+ const r = CiConfig.safeParse(data);
113
+ if (!r.success)
114
+ return {
115
+ config: DEFAULT_CI_CONFIG,
116
+ problems: r.error.issues.map((i) => `org-pack/process/ci.yaml: ${i.path.join(".") || "(file)"}: ${i.message}`)
117
+ };
118
+ return { config: r.data, problems: [] };
119
+ }
120
+ function ignored(id, patterns) {
121
+ return patterns.some((p) => p.endsWith("*") ? id.startsWith(p.slice(0, -1)) : id === p);
122
+ }
123
+
124
+ // packages/ci/dist/drift.js
125
+ import { createHash } from "node:crypto";
126
+ import { existsSync, statSync } from "node:fs";
127
+ import { basename, isAbsolute, join as join2, relative, resolve } from "node:path";
128
+ var DRIFT_SCHEMA_VERSION = 1;
129
+ var DriftError = class extends Error {
130
+ constructor(message) {
131
+ super(message);
132
+ this.name = "DriftError";
133
+ }
134
+ };
135
+ var isDir = (p) => {
136
+ try {
137
+ return statSync(p).isDirectory();
138
+ } catch {
139
+ return false;
140
+ }
141
+ };
142
+ function resolveCatalog(p) {
143
+ const abs = resolve(p);
144
+ if (isDir(join2(abs, "org-pack")) || isDir(join2(abs, ".atticus", "org-pack")))
145
+ return { root: abs, generated: join2(catalogDirOf(abs), "generated") };
146
+ if (isDir(join2(abs, "generated")))
147
+ return { generated: join2(abs, "generated") };
148
+ return { generated: abs };
149
+ }
150
+ async function usableDialects(op, orgPackDir, problems) {
151
+ const own = new Set(op.dialects.map((d) => d.name));
152
+ const shipped = (await loadShippedDialects().catch(() => [])).filter((d) => !own.has(d.name));
153
+ const all = [
154
+ ...shipped.map((d) => ({ d, dir: SHIPPED_DIALECTS_DIR })),
155
+ ...op.dialects.map((d) => ({ d, dir: join2(orgPackDir ?? ".", "dialects") }))
156
+ ];
157
+ const byName = new Map(all.map(({ d }) => [d.name, d]));
158
+ const ok = [];
159
+ for (const { d, dir } of all) {
160
+ const failures = await runDialectTests(d, dir, byName).catch((e) => [
161
+ { test: "(load)", message: e.message }
162
+ ]);
163
+ if (failures.length) {
164
+ for (const f of failures)
165
+ problems.push(`dialect ${d.name}: test "${f.test}": ${f.message}`);
166
+ continue;
167
+ }
168
+ ok.push(d);
169
+ }
170
+ return ok;
171
+ }
172
+ var fromRepo = (r, repo, side) => r.evidence.some((e) => e.repo === repo && (!side || side(e.side)));
173
+ var evOf = (r, repo) => r.evidence.filter((e) => e.repo === repo && e.path).slice(0, 3).map((e) => ({ path: e.path, ...e.line ? { line: e.line } : {} }));
174
+ function surface(records, repo, components) {
175
+ const out = /* @__PURE__ */ new Map();
176
+ const add = (s) => out.set(`${s.subject}|${s.id}`, s);
177
+ for (const r of records) {
178
+ if (r.status === "retired")
179
+ continue;
180
+ if (r.kind === "Endpoint") {
181
+ const e = r;
182
+ if (!fromRepo(e, repo, (s) => s !== "caller"))
183
+ continue;
184
+ if (e.endpointType === "event-topic")
185
+ add({
186
+ subject: "topic",
187
+ id: e.id,
188
+ label: `topic ${e.pathOrTopic}`,
189
+ fields: { owner: e.component },
190
+ record: e
191
+ });
192
+ else
193
+ add({
194
+ subject: "endpoint",
195
+ id: e.id,
196
+ label: `${e.method ? `${e.method} ` : ""}${e.pathOrTopic} on ${e.component}`,
197
+ fields: {
198
+ method: e.method,
199
+ path: e.normalizedPath ?? normalizePath(e.pathOrTopic),
200
+ auth: e.auth
201
+ },
202
+ pair: `${e.component}|${e.method ?? ""}`,
203
+ record: e
204
+ });
205
+ } else if (r.kind === "Interface") {
206
+ const i = r;
207
+ if (fromRepo(i, repo, (s) => s === "caller"))
208
+ add({
209
+ subject: "call",
210
+ id: i.id,
211
+ label: i.sync === "async" ? `${i.from} publishes ${i.normalizedPath} to ${i.to}` : `${i.from} calls ${i.to} ${i.method ? `${i.method} ` : ""}${i.normalizedPath}`,
212
+ fields: {
213
+ to: i.to,
214
+ via: i.via,
215
+ route: i.route,
216
+ method: i.method,
217
+ path: i.normalizedPath,
218
+ auth: i.auth,
219
+ pattern: i.pattern?.code
220
+ },
221
+ pair: `${i.from}|${i.to}|${i.sync}`,
222
+ record: i
223
+ });
224
+ else if (i.sync === "async" && fromRepo(i, repo, (s) => s === "callee"))
225
+ add({
226
+ subject: "subscription",
227
+ id: i.id,
228
+ label: `${i.to} subscribes to ${i.normalizedPath} from ${i.from}`,
229
+ fields: { from: i.from, topic: i.normalizedPath },
230
+ record: i
231
+ });
232
+ } else if (r.kind === "Table") {
233
+ const t = r;
234
+ if (!fromRepo(t, repo))
235
+ continue;
236
+ const mine = (l) => l.filter((c) => components.has(c)).sort().join(",") || void 0;
237
+ add({
238
+ subject: "table",
239
+ id: t.id,
240
+ label: `table ${t.id}`,
241
+ fields: { readers: mine(t.readers), writers: mine(t.writers) },
242
+ record: t
243
+ });
244
+ } else if (r.kind === "Column") {
245
+ const c = r;
246
+ if (!fromRepo(c, repo))
247
+ continue;
248
+ add({
249
+ subject: "column",
250
+ id: c.id,
251
+ label: `column ${c.id}`,
252
+ fields: {
253
+ type: c.type.toLowerCase().replace(/\s+/g, ""),
254
+ nullable: c.nullable === void 0 ? void 0 : String(c.nullable)
255
+ },
256
+ record: c
257
+ });
258
+ } else if (r.kind === "Migration") {
259
+ const m = r;
260
+ if (!fromRepo(m, repo))
261
+ continue;
262
+ add({
263
+ subject: "migration",
264
+ id: m.id,
265
+ label: `migration ${m.file.split("/").pop()}`,
266
+ fields: { operations: m.operations.join("; ") || void 0 },
267
+ record: m
268
+ });
269
+ } else if (r.kind === "Unresolved") {
270
+ const u = r;
271
+ if (!fromRepo(u, repo) && !(u.owner && components.has(u.owner)))
272
+ continue;
273
+ add({
274
+ subject: "loose-end",
275
+ id: u.id,
276
+ label: `${u.unresolvedKind} ${u.raw}${u.owner ? ` from ${u.owner}` : ""}`,
277
+ fields: {},
278
+ record: u
279
+ });
280
+ }
281
+ }
282
+ return out;
283
+ }
284
+ var APPROVED = /* @__PURE__ */ new Set([
285
+ "plan",
286
+ "build",
287
+ "qa",
288
+ "release-ready",
289
+ "released",
290
+ "post-release-review"
291
+ ]);
292
+ async function approvedDesigns(root) {
293
+ const hops = [];
294
+ const data = [];
295
+ const changes = [];
296
+ if (!root)
297
+ return { hops, data, changes };
298
+ let list;
299
+ try {
300
+ list = await changeStore(root).list();
301
+ } catch {
302
+ return { hops, data, changes };
303
+ }
304
+ for (const c of list.filter((x) => APPROVED.has(x.state))) {
305
+ changes.push(c.id);
306
+ const files = await readChangeFiles(changeFolder(root, c.id));
307
+ for (const h of readHops(files)) {
308
+ const topic = /^(publish|subscribe|send|receive)\s+(\S+)/i.exec(h.operation.trim())?.[2];
309
+ hops.push({
310
+ change: c.id,
311
+ caller: h.caller,
312
+ callee: h.callee,
313
+ ...h.method ? { method: h.method } : {},
314
+ ...h.path ? { path: normalizePath(h.path) } : {},
315
+ ...topic ? { topic } : {},
316
+ status: h.status
317
+ });
318
+ }
319
+ for (const d of readDataChanges(files))
320
+ data.push({
321
+ change: c.id,
322
+ table: d.tableId,
323
+ store: d.store,
324
+ columns: d.newColumns.map((x) => x.name.toLowerCase()),
325
+ newTable: d.newTable,
326
+ migration: d.migration.replace(/[`*]/g, "").trim()
327
+ });
328
+ }
329
+ return { hops, data, changes };
330
+ }
331
+ var NEW = /* @__PURE__ */ new Set(["planned-new", "planned-modify"]);
332
+ function plannedBy(item, kind, d) {
333
+ const ok = (h) => kind === "removed" ? h.status === "planned-retire" : NEW.has(h.status);
334
+ const r = item.record;
335
+ switch (item.subject) {
336
+ case "call": {
337
+ const i = item.record;
338
+ return d.hops.find((h) => ok(h) && h.caller === i.from && h.callee === i.to && (i.sync === "async" ? h.topic === i.normalizedPath : h.method === i.method && h.path === normalizePath(i.normalizedPath)))?.change;
339
+ }
340
+ case "subscription": {
341
+ const i = item.record;
342
+ return d.hops.find((h) => ok(h) && h.topic === i.normalizedPath && (h.callee === i.to || h.caller === i.from))?.change;
343
+ }
344
+ case "endpoint": {
345
+ const e = item.record;
346
+ const path = e.normalizedPath ?? normalizePath(e.pathOrTopic);
347
+ return d.hops.find((h) => ok(h) && h.callee === e.component && h.method === e.method && h.path === path)?.change;
348
+ }
349
+ case "topic": {
350
+ const e = item.record;
351
+ return d.hops.find((h) => ok(h) && h.topic === e.pathOrTopic)?.change;
352
+ }
353
+ case "table":
354
+ return kind === "removed" ? void 0 : d.data.find((x) => x.table === item.id && (x.newTable || kind === "changed"))?.change;
355
+ case "column": {
356
+ const c = item.record;
357
+ return kind === "removed" ? void 0 : d.data.find((x) => x.table === c.table && x.columns.includes(c.name.toLowerCase()))?.change;
358
+ }
359
+ case "migration": {
360
+ if (kind === "removed")
361
+ return void 0;
362
+ const m = item.record;
363
+ const file = m.file.split("/").pop() ?? "";
364
+ return d.data.find((x) => x.migration && x.migration === file || x.store === m.dataStore && m.operations.some((op) => {
365
+ const t = /^(?:create|alter) table (\S+)/.exec(op)?.[1];
366
+ return !!t && x.table === `${m.dataStore}.${t.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
367
+ }))?.change;
368
+ }
369
+ case "loose-end": {
370
+ const raw = String(r.raw ?? "");
371
+ const m = /^([A-Z]+)\s+(\S+)/.exec(raw);
372
+ const owner = String(r.owner ?? "");
373
+ return d.hops.find((h) => {
374
+ if (!ok(h) || owner && h.caller !== owner)
375
+ return false;
376
+ if (m && h.method && h.path) {
377
+ const url = normalizePath(m[2].replace(/^[a-z]+:\/\/[^/]+/i, ""));
378
+ return h.method === m[1] && (url === h.path || url.endsWith(h.path));
379
+ }
380
+ return !!h.topic && raw.trim() === h.topic;
381
+ })?.change;
382
+ }
383
+ }
384
+ }
385
+ function strip(r, repo, components) {
386
+ const evidence = r.evidence.filter((e) => e.repo !== repo);
387
+ if (!evidence.length)
388
+ return void 0;
389
+ if (r.kind === "Table")
390
+ return {
391
+ ...r,
392
+ evidence,
393
+ readers: r.readers.filter((c) => !components.has(c)),
394
+ writers: r.writers.filter((c) => !components.has(c))
395
+ };
396
+ return { ...r, evidence };
397
+ }
398
+ function otherEnds(records, repo, components) {
399
+ const out = [];
400
+ for (const r of records) {
401
+ if (r.kind !== "Interface" || r.sync !== "async")
402
+ continue;
403
+ const ends = [
404
+ { kind: "event-publish", owner: r.from, side: "caller" },
405
+ { kind: "event-subscribe", owner: r.to, side: "callee" }
406
+ ];
407
+ for (const e of ends) {
408
+ if (components.has(e.owner))
409
+ continue;
410
+ const evidence = r.evidence.filter((x) => x.side === e.side && x.repo !== repo && x.source === "code");
411
+ if (!evidence.length)
412
+ continue;
413
+ const hash = createHash("sha256").update(`${r.id}|${e.kind}`).digest("hex").slice(0, 10);
414
+ out.push({
415
+ kind: "Unresolved",
416
+ schemaVersion: 2,
417
+ id: `${e.owner}.${e.kind}.ctx-${hash}`.slice(0, 120),
418
+ status: "current",
419
+ confidence: "inferred",
420
+ unresolvedKind: e.kind,
421
+ raw: r.normalizedPath,
422
+ owner: e.owner,
423
+ evidence
424
+ });
425
+ }
426
+ }
427
+ return out;
428
+ }
429
+ var CONTEXT_SKIP = /* @__PURE__ */ new Set([
430
+ "Interface",
431
+ "Unresolved",
432
+ "Capability",
433
+ "GlossaryTerm",
434
+ "OwnerQuestion"
435
+ ]);
436
+ async function repoDrift(o) {
437
+ const repoDir = resolve(o.repoDir);
438
+ if (!isDir(repoDir))
439
+ throw new DriftError(`There is no folder ${o.repoDir} to check.`);
440
+ const where2 = resolveCatalog(o.catalog);
441
+ if (!isDir(where2.generated))
442
+ throw new DriftError(`There is no catalog at ${o.catalog}. Give the metarepo checkout or its catalog folder with --catalog.`);
443
+ const problems = [];
444
+ const orgPackDir = where2.root ? orgPackDirOf(where2.root) : void 0;
445
+ const op = await loadOrgPack(orgPackDir ?? join2(where2.generated, "__no-org-pack__"));
446
+ if (orgPackDir)
447
+ for (const p of op.problems)
448
+ problems.push(`org-pack/${p.file}: ${p.path ? `${p.path}: ` : ""}${p.message}`);
449
+ const loaded = await loadCiConfig(orgPackDir);
450
+ problems.push(...loaded.problems);
451
+ const cfg = loaded.config;
452
+ const catalog = await readCatalog(where2.generated, where2.root ? { cacheRoot: where2.root } : {});
453
+ for (const p of catalog.problems)
454
+ problems.push(`catalog ${p.file}: ${p.message}`);
455
+ if (catalog.records.length === 0)
456
+ throw new DriftError(`The catalog at ${o.catalog} has no records; scan the estate first.`);
457
+ const manifest = op.profiles.flatMap((p) => p.repos?.repos ?? []);
458
+ const repoId = o.repo ?? basename(repoDir);
459
+ const listed = manifest.find((r) => r.id === repoId);
460
+ if (!listed && manifest.length && o.repo)
461
+ problems.push(`${repoId} isn't in the repos manifest; checking it without its type and dialects.`);
462
+ const fromCatalog = catalog.records.filter((r) => r.kind === "Component" && r.repo === repoId);
463
+ const entry = listed ?? (fromCatalog.length === 1 ? { component: fromCatalog[0].id, system: fromCatalog[0].system, dialects: [] } : void 0);
464
+ let commit = o.commit;
465
+ if (!commit) {
466
+ try {
467
+ commit = existsSync(join2(repoDir, ".git")) ? (await checkoutState(repoDir, o.git)).commit : "0".repeat(40);
468
+ } catch {
469
+ commit = "0".repeat(40);
470
+ }
471
+ }
472
+ if (!/^[0-9a-f]{7,64}$/.test(commit))
473
+ commit = "0".repeat(40);
474
+ const dialects = await usableDialects(op, orgPackDir, problems);
475
+ const byName = new Map(dialects.map((d) => [d.name, d]));
476
+ const extractors = [
477
+ ...BUILT_IN_EXTRACTORS,
478
+ ...dialects.filter((d) => (entry?.dialects ?? []).includes(d.name) || d.appliesTo.repoTypes.includes("*") || (entry?.type ? d.appliesTo.repoTypes.includes(entry.type) : false)).map((d) => dialectExtractor(d, byName))
479
+ ];
480
+ const inside = relative(repoDir, resolve(o.catalog)).split(/[\\/]/);
481
+ const skip = inside[0] && inside[0] !== ".." && !isAbsolute(inside.join("/")) ? [inside[0]] : [];
482
+ const scan = await scanRepo({
483
+ repo: fsRepo(repoId, repoDir, commit, { ignore: [...DEFAULT_IGNORES, ".atticus", ...skip] }),
484
+ extractors,
485
+ dialects: entry?.dialects ?? [],
486
+ scannedAt: o.scannedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
487
+ repoInfo: {
488
+ ...entry?.component ? { component: entry.component } : {},
489
+ ...entry?.system ? { system: entry.system } : {},
490
+ ...entry?.type ? { repoType: entry.type } : {}
491
+ }
492
+ });
493
+ for (const run of scan.runs.filter((x) => x.status === "failed"))
494
+ problems.push(`${run.extractor} failed on ${repoId}`);
495
+ const components = /* @__PURE__ */ new Set([
496
+ ...entry?.component ? [entry.component] : [],
497
+ ...scan.records.filter((r) => r.kind === "Component").map((r) => r.id),
498
+ ...catalog.records.filter((r) => r.kind === "Component" && r.repo === repoId).map((r) => r.id)
499
+ ]);
500
+ const context = catalog.records.filter((r) => !CONTEXT_SKIP.has(r.kind)).map((r) => strip(r, repoId, components)).filter((r) => !!r);
501
+ const merged = mergeCatalog({
502
+ // A fetched copy of the catalog has no manifest, so no declared hosts: route by basepath.
503
+ ...orgPackDir ? {} : { gatewayByBasepath: true },
504
+ records: [...context, ...otherEnds(catalog.records, repoId, components), ...scan.records],
505
+ repos: manifest.map((r) => ({
506
+ id: r.id,
507
+ type: r.type,
508
+ ...r.component ? { component: r.component } : {},
509
+ ...r.system ? { system: r.system } : {},
510
+ hosts: r.hosts
511
+ })),
512
+ // Without the org pack (a fetched copy of the catalog), the catalog's systems stand in for
513
+ // the profile's.
514
+ systems: orgPackDir ? op.profiles.flatMap((p) => p.profile?.systems ?? []) : catalog.records.filter((r) => r.kind === "System").map((x) => ({
515
+ id: x.id,
516
+ name: x.name,
517
+ boundary: x.boundary,
518
+ ...x.owner ? { owner: x.owner } : {},
519
+ aliases: []
520
+ })),
521
+ patterns: op.patterns
522
+ });
523
+ if (!orgPackDir)
524
+ problems.push("There is no org pack with this catalog, so patterns (inferred from the org pack) aren't compared.");
525
+ const before = surface(catalog.records, repoId, components);
526
+ const after = surface(merged.records, repoId, components);
527
+ if (!orgPackDir)
528
+ for (const m of [before, after])
529
+ for (const s of m.values())
530
+ delete s.fields.pattern;
531
+ const designs = await approvedDesigns(where2.root);
532
+ const items = [];
533
+ const push = (kind, s, summary, extra = {}) => {
534
+ if (ignored(s.id, cfg.drift.ignore))
535
+ return;
536
+ const planned = kind === "planned" ? void 0 : plannedBy(s, kind, designs);
537
+ items.push({
538
+ kind: planned ? "planned" : kind,
539
+ subject: s.subject,
540
+ id: s.id,
541
+ summary: planned ? `${summary} (planned by ${planned})` : summary,
542
+ ...extra,
543
+ ...planned ? { change: planned } : {},
544
+ evidence: evOf(s.record, repoId)
545
+ });
546
+ };
547
+ const diff = (a, b) => Object.keys({ ...a.fields, ...b.fields }).sort().filter((f) => (a.fields[f] ?? "") !== (b.fields[f] ?? "")).map((f) => ({
548
+ field: f,
549
+ ...a.fields[f] !== void 0 ? { catalog: a.fields[f] } : {},
550
+ ...b.fields[f] !== void 0 ? { code: b.fields[f] } : {}
551
+ }));
552
+ const describe = (ch) => ch.map((c) => `${c.field} ${c.catalog ?? "(none)"} \u2192 ${c.code ?? "(none)"}`).join(", ");
553
+ const gone = [];
554
+ const fresh = [];
555
+ for (const [k, a] of before) {
556
+ const b = after.get(k);
557
+ if (!b)
558
+ gone.push(a);
559
+ else {
560
+ const ch = diff(a, b);
561
+ if (ch.length)
562
+ push("changed", b, `${b.label} changed: ${describe(ch)}.`, { changes: ch });
563
+ }
564
+ }
565
+ for (const [k, b] of after)
566
+ if (!before.has(k))
567
+ fresh.push(b);
568
+ const pairs = (l) => {
569
+ const m = /* @__PURE__ */ new Map();
570
+ for (const s of l)
571
+ if (s.pair)
572
+ m.set(`${s.subject}|${s.pair}`, [...m.get(`${s.subject}|${s.pair}`) ?? [], s]);
573
+ return m;
574
+ };
575
+ const gp = pairs(gone);
576
+ const fp = pairs(fresh);
577
+ const paired = /* @__PURE__ */ new Set();
578
+ for (const [k, olds] of gp) {
579
+ const news = fp.get(k);
580
+ if (olds.length !== 1 || news?.length !== 1)
581
+ continue;
582
+ const ch = diff(olds[0], news[0]);
583
+ push("changed", news[0], `${olds[0].label} changed: ${describe(ch)}.`, { changes: ch });
584
+ paired.add(olds[0]).add(news[0]);
585
+ }
586
+ for (const a of gone.filter((x) => !paired.has(x)))
587
+ push("removed", a, `${a.label} is in the catalog but no longer in the code.`);
588
+ for (const b of fresh.filter((x) => !paired.has(x)))
589
+ push(b.subject === "loose-end" ? "unknown" : "added", b, b.subject === "loose-end" ? `${b.label}: Atticus can't tell where it goes.` : `${b.label} is in the code but not in the catalog.`);
590
+ const ORDER = ["added", "changed", "removed", "unknown", "planned"];
591
+ items.sort((a, b) => ORDER.indexOf(a.kind) - ORDER.indexOf(b.kind) || a.subject.localeCompare(b.subject) || a.id.localeCompare(b.id));
592
+ const counts = Object.fromEntries(ORDER.map((k) => [k, items.filter((i) => i.kind === k).length]));
593
+ return {
594
+ schemaVersion: DRIFT_SCHEMA_VERSION,
595
+ repo: repoId,
596
+ components: [...components].sort(),
597
+ mode: o.warnOnly ? "warn" : cfg.drift.mode,
598
+ drift: items.some((i) => i.kind !== "planned"),
599
+ counts,
600
+ items,
601
+ changes: designs.changes,
602
+ scanned: {
603
+ commit,
604
+ records: scan.records.length,
605
+ extractors: extractors.map((x) => x.id).sort()
606
+ },
607
+ problems
608
+ };
609
+ }
610
+ var driftExitCode = (r) => r.drift && r.mode === "block" ? 1 : 0;
611
+
612
+ // packages/ci/dist/report.js
613
+ var driftJson = (r) => `${JSON.stringify(r, null, 2)}
614
+ `;
615
+ var xml = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
616
+ var where = (i) => i.evidence.map((e) => `${e.path ?? ""}${e.line ? `:${e.line}` : ""}`).filter(Boolean);
617
+ function driftJUnit(r) {
618
+ const cases = r.items.map((i) => {
619
+ const name = `${i.kind} ${i.subject} ${i.id}`;
620
+ const open = ` <testcase classname="atticus.drift.${i.subject}" name="${xml(name)}">`;
621
+ const detail = [i.summary, ...where(i).map((w) => `at ${w}`)].join("\n");
622
+ if (i.kind === "planned")
623
+ return `${open}
624
+ <system-out>${xml(detail)}</system-out>
625
+ </testcase>`;
626
+ if (r.mode === "warn")
627
+ return `${open}
628
+ <skipped message="${xml(`warn-only: ${i.summary}`)}"/>
629
+ </testcase>`;
630
+ return `${open}
631
+ <failure message="${xml(i.summary)}" type="${i.kind}">${xml(detail)}</failure>
632
+ </testcase>`;
633
+ });
634
+ if (!cases.length)
635
+ cases.push(` <testcase classname="atticus.drift" name="${xml(`${r.repo} matches the catalog`)}"/>`);
636
+ const failures = r.mode === "block" ? r.items.filter((i) => i.kind !== "planned").length : 0;
637
+ const skipped = r.mode === "warn" ? r.items.filter((i) => i.kind !== "planned").length : 0;
638
+ return [
639
+ `<?xml version="1.0" encoding="UTF-8"?>`,
640
+ `<testsuites name="atticus drift" tests="${cases.length}" failures="${failures}" skipped="${skipped}">`,
641
+ ` <testsuite name="${xml(`atticus drift ${r.repo}`)}" tests="${cases.length}" failures="${failures}" errors="0" skipped="${skipped}">`,
642
+ ...cases,
643
+ ` </testsuite>`,
644
+ `</testsuites>`,
645
+ ""
646
+ ].join("\n");
647
+ }
648
+ var KIND_WORD = {
649
+ added: "Not in the catalog",
650
+ changed: "Changed",
651
+ removed: "Gone from the code",
652
+ unknown: "Unknown loose end",
653
+ planned: "Planned"
654
+ };
655
+ var cell = (s) => s.replace(/\|/g, "\\|").replace(/\n/g, " ");
656
+ function driftMarkdown(r) {
657
+ const n = r.items.filter((i) => i.kind !== "planned").length;
658
+ const planned = r.counts.planned;
659
+ const head = !r.drift ? `No drift: ${r.repo} matches the catalog${planned ? ` (${planned} planned by approved changes)` : ""}.` : `${n} drift ${n === 1 ? "finding" : "findings"} in ${r.repo}${r.mode === "warn" ? " (warn-only: the pipeline passes)" : ""}.`;
660
+ const lines2 = [`## Atticus drift check: ${r.repo}`, "", head];
661
+ if (r.items.length) {
662
+ lines2.push("", "| What | Kind | Id | Details |", "| --- | --- | --- | --- |");
663
+ for (const i of r.items)
664
+ lines2.push(`| ${KIND_WORD[i.kind]} | ${i.subject} | ${cell(i.id)} | ${cell(i.summary)}${where(i).length ? ` (${where(i).join(", ")})` : ""} |`);
665
+ }
666
+ if (r.drift && r.mode === "block")
667
+ lines2.push("", "Fix the code, or record the change in the catalog: plan it in an approved change's design, or rescan the estate once it is merged.");
668
+ if (r.problems.length)
669
+ lines2.push("", "Problems:", ...r.problems.map((p) => `- ${p}`));
670
+ return `${lines2.join("\n")}
671
+ `;
672
+ }
673
+
674
+ // packages/ci/dist/snippets.js
675
+ var SNIPPET_KINDS = ["github", "azure", "gitlab", "jenkins"];
676
+ var CLI = "npx --yes @maycombhq/atticus@${ATTICUS_VERSION:-latest}";
677
+ var ARGS = "--json atticus-drift.json --junit atticus-drift.xml";
678
+ var GITHUB = `# Generated by Atticus (atticus ci snippet github): the catalog drift check.
679
+ # Set the repository variable ATTICUS_METAREPO (owner/name of the metarepo) and, for a private
680
+ # metarepo, the secret ATTICUS_METAREPO_TOKEN (read-only). ATTICUS_VERSION pins the CLI.
681
+ name: atticus-drift
682
+ on:
683
+ pull_request:
684
+ push:
685
+ branches: [main]
686
+ jobs:
687
+ drift:
688
+ runs-on: ubuntu-latest
689
+ env:
690
+ ATTICUS_VERSION: \${{ vars.ATTICUS_VERSION || 'latest' }}
691
+ steps:
692
+ - uses: actions/checkout@v4
693
+ with:
694
+ path: repo
695
+ - name: Check out the metarepo
696
+ uses: actions/checkout@v4
697
+ with:
698
+ repository: \${{ vars.ATTICUS_METAREPO }}
699
+ token: \${{ secrets.ATTICUS_METAREPO_TOKEN || github.token }}
700
+ path: atticus-metarepo
701
+ - uses: actions/setup-node@v4
702
+ with:
703
+ node-version: 22
704
+ - name: Atticus drift check
705
+ run: ${CLI} ci drift repo --catalog atticus-metarepo --repo \${{ github.event.repository.name }} ${ARGS} --summary "$GITHUB_STEP_SUMMARY"
706
+ - name: Keep the drift report
707
+ if: always()
708
+ uses: actions/upload-artifact@v4
709
+ with:
710
+ name: atticus-drift
711
+ path: |
712
+ atticus-drift.json
713
+ atticus-drift.xml
714
+ `;
715
+ var AZURE = `# Generated by Atticus (atticus ci snippet azure): the catalog drift check.
716
+ # Declare the metarepo as a repository resource named atticus_metarepo; ATTICUS_VERSION pins the CLI.
717
+ resources:
718
+ repositories:
719
+ - repository: atticus_metarepo
720
+ type: git
721
+ name: $(ATTICUS_METAREPO)
722
+
723
+ trigger:
724
+ - main
725
+ pr:
726
+ - "*"
727
+
728
+ pool:
729
+ vmImage: ubuntu-latest
730
+
731
+ steps:
732
+ - checkout: self
733
+ path: s/repo
734
+ - checkout: atticus_metarepo
735
+ path: s/atticus-metarepo
736
+ - task: NodeTool@0
737
+ inputs:
738
+ versionSpec: "22.x"
739
+ - script: ${CLI} ci drift repo --catalog atticus-metarepo --repo $(Build.Repository.Name) ${ARGS} --summary atticus-drift.md
740
+ displayName: Atticus drift check
741
+ workingDirectory: $(Pipeline.Workspace)/s
742
+ - task: PublishTestResults@2
743
+ condition: always()
744
+ inputs:
745
+ testResultsFormat: JUnit
746
+ testResultsFiles: $(Pipeline.Workspace)/s/atticus-drift.xml
747
+ testRunTitle: Atticus drift
748
+ - task: PublishBuildArtifacts@1
749
+ condition: always()
750
+ inputs:
751
+ PathtoPublish: $(Pipeline.Workspace)/s/atticus-drift.json
752
+ ArtifactName: atticus-drift
753
+ `;
754
+ var GITLAB = `# Generated by Atticus (atticus ci snippet gitlab): the catalog drift check.
755
+ # Set the CI/CD variable ATTICUS_METAREPO_URL (an https clone URL the job token can read);
756
+ # ATTICUS_VERSION pins the CLI.
757
+ atticus-drift:
758
+ image: node:22
759
+ stage: test
760
+ rules:
761
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
762
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
763
+ script:
764
+ - git clone --depth 1 "$ATTICUS_METAREPO_URL" ../atticus-metarepo
765
+ - ${CLI} ci drift . --catalog ../atticus-metarepo --repo "$CI_PROJECT_NAME" ${ARGS} --summary atticus-drift.md
766
+ artifacts:
767
+ when: always
768
+ paths:
769
+ - atticus-drift.json
770
+ - atticus-drift.md
771
+ reports:
772
+ junit: atticus-drift.xml
773
+ `;
774
+ var JENKINS = `// Generated by Atticus (atticus ci snippet jenkins): the catalog drift check.
775
+ // Set ATTICUS_METAREPO_URL and, for a private metarepo, the credentials id
776
+ // ATTICUS_METAREPO_CREDENTIALS; ATTICUS_VERSION pins the CLI.
777
+ pipeline {
778
+ agent any
779
+ stages {
780
+ stage('Atticus drift check') {
781
+ steps {
782
+ dir('repo') {
783
+ checkout scm
784
+ }
785
+ dir('atticus-metarepo') {
786
+ git url: env.ATTICUS_METAREPO_URL, credentialsId: env.ATTICUS_METAREPO_CREDENTIALS
787
+ }
788
+ sh '${CLI} ci drift repo --catalog atticus-metarepo --repo "$(basename "$GIT_URL" .git)" ${ARGS} --summary atticus-drift.md'
789
+ }
790
+ }
791
+ }
792
+ post {
793
+ always {
794
+ junit allowEmptyResults: false, testResults: 'atticus-drift.xml'
795
+ archiveArtifacts artifacts: 'atticus-drift.json,atticus-drift.md', allowEmptyArchive: true
796
+ }
797
+ }
798
+ }
799
+ `;
800
+ var SNIPPETS = {
801
+ github: { kind: "github", path: ".github/workflows/atticus-drift.yml", content: GITHUB },
802
+ azure: { kind: "azure", path: "azure-pipelines.atticus-drift.yml", content: AZURE },
803
+ gitlab: { kind: "gitlab", path: ".gitlab-ci.atticus-drift.yml", content: GITLAB },
804
+ jenkins: { kind: "jenkins", path: "Jenkinsfile.atticus-drift", content: JENKINS }
805
+ };
806
+ function pipelineSnippet(kind) {
807
+ const k = kind.toLowerCase().replace(/[-_ ]?(actions|pipelines|ci)$/, "");
808
+ return SNIPPETS[k];
809
+ }
810
+
811
+ // packages/ci/dist/archive.js
812
+ import { existsSync as existsSync2 } from "node:fs";
813
+ import { readFile as readFile2 } from "node:fs/promises";
814
+ import { join as join3 } from "node:path";
815
+ async function archiveGate(root, changeId, o = {}) {
816
+ const change = await changeStore(root).read(changeId);
817
+ const blockers = [];
818
+ const notes = [];
819
+ const { config } = await loadCiConfig(orgPackDirOf(root));
820
+ if (change.state === "post-release-review") {
821
+ const ctx = await loadChangeContext(root);
822
+ const a = await assess(ctx, change);
823
+ for (const r of a.blockers)
824
+ blockers.push({ code: "finding", message: r.message });
825
+ } else if (change.state !== "released") {
826
+ blockers.push({
827
+ code: "wrong-state",
828
+ message: change.state === "archived" ? `${change.id} is already archived.` : `${change.id} is ${change.state}; a change is archived once it is released (go/no-go merged).`
829
+ });
830
+ }
831
+ const gates = await reviewedGates(root, change.id);
832
+ for (const r of await checkFindings(root, change, gates))
833
+ blockers.push({ code: "finding", message: r.message });
834
+ const repos = (await readChangeRepos(root, change.id))?.repos ?? [];
835
+ for (const r of repos) {
836
+ if (r.pr && config.archive.requireMergedPrs && r.pr.state !== "merged" && r.pr.state !== "closed")
837
+ blockers.push({
838
+ code: "pr-open",
839
+ message: `${r.id}: PR #${r.pr.number} is ${r.pr.state}; merge it before archiving.`
840
+ });
841
+ if (r.build.status === "failed")
842
+ blockers.push({
843
+ code: "build-failed",
844
+ message: `${r.id}: the build failed${r.build.sha ? ` on ${r.build.sha.slice(0, 7)}` : ""}${r.build.log ? ` (log ${r.build.log})` : ""}.`
845
+ });
846
+ else if (r.build.status === "running")
847
+ blockers.push({ code: "build-running", message: `${r.id}: the build is still running.` });
848
+ else if (r.build.status === "not-run" && r.pr)
849
+ blockers.push({
850
+ code: "build-not-run",
851
+ message: `${r.id}: PR #${r.pr.number} changed code but no build has run.`
852
+ });
853
+ }
854
+ const drift = [];
855
+ if (o.driftReports?.length) {
856
+ for (const f of o.driftReports) {
857
+ try {
858
+ drift.push(JSON.parse(await readFile2(f, "utf8")));
859
+ } catch (e) {
860
+ blockers.push({
861
+ code: "drift-error",
862
+ message: `Can't read the drift report ${f}: ${e.message.split("\n")[0]}.`
863
+ });
864
+ }
865
+ }
866
+ } else {
867
+ for (const r of repos) {
868
+ const dir = o.repoDir?.(r.id) ?? [join3(root, r.worktree), baseClonePath(root, r.id)].find((d) => existsSync2(d));
869
+ if (!dir || !existsSync2(dir)) {
870
+ notes.push(`No checkout of ${r.id} here, so its drift wasn't checked; pass its pipeline's drift report.`);
871
+ continue;
872
+ }
873
+ try {
874
+ drift.push(await repoDrift({
875
+ repoDir: dir,
876
+ catalog: root,
877
+ repo: r.id,
878
+ ...o.commit ? { commit: o.commit } : {}
879
+ }));
880
+ } catch (e) {
881
+ if (!(e instanceof DriftError))
882
+ throw e;
883
+ blockers.push({ code: "drift-error", message: `${r.id}: ${e.message}` });
884
+ }
885
+ }
886
+ if (!repos.length)
887
+ notes.push("The change has no repos (repos.yaml), so there was no code to check for drift.");
888
+ }
889
+ for (const d of drift) {
890
+ const items = d.items.filter((i) => i.kind !== "planned");
891
+ if (!items.length)
892
+ continue;
893
+ blockers.push({
894
+ code: "drift",
895
+ message: `${d.repo}: ${items.length} catalog drift ${items.length === 1 ? "finding" : "findings"} (${items.slice(0, 3).map((i) => i.summary.replace(/\.$/, "")).join("; ")}${items.length > 3 ? "; ..." : ""}).`
896
+ });
897
+ }
898
+ const unique = [...new Map(blockers.map((b) => [b.message, b])).values()];
899
+ return {
900
+ change: change.id,
901
+ state: change.state,
902
+ pass: unique.length === 0,
903
+ blockers: unique,
904
+ notes,
905
+ drift
906
+ };
907
+ }
908
+
909
+ // packages/cli/dist/quality-commands.js
910
+ var KNOWN = /* @__PURE__ */ new Set([
911
+ "TestgenError",
912
+ "PlannerError",
913
+ "ChangeError",
914
+ "ChangeFileError",
915
+ "GlossaryError",
916
+ "RuntimeConfigError"
917
+ ]);
918
+ function fail(io, e) {
919
+ if (e instanceof Error && KNOWN.has(e.name)) {
920
+ io.err(e.message);
921
+ return e.code === "invalid" ? 2 : 1;
922
+ }
923
+ throw e;
924
+ }
925
+ var iso = (d) => d.toISOString().replace(/\.\d{3}Z$/, "Z");
926
+ var lines = (io, text) => {
927
+ for (const l of text.trimEnd().split("\n"))
928
+ io.out(l);
929
+ };
930
+ var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
931
+ async function runtimeOf(root, mode, deps) {
932
+ if (deps.runtime)
933
+ return deps.runtime;
934
+ if (!mode && !process.env.ATTICUS_RUNTIME)
935
+ return void 0;
936
+ return (await runtimeForCli(root, mode ? { mode } : {})).runtime;
937
+ }
938
+ async function testsGenerate(root, changeId, storyId, o, io, deps = {}) {
939
+ if (!changeId || !storyId) {
940
+ io.err("Usage: atticus tests generate <change> <story> [--framework <id>] [--force] [--check] [--mode <mode>] [--json]");
941
+ return 2;
942
+ }
943
+ try {
944
+ const runtime = await runtimeOf(root, o.mode, deps);
945
+ const r = await generateTests(root, changeId, storyId, {
946
+ ...o.framework ? { framework: o.framework } : {},
947
+ ...o.force ? { force: true } : {},
948
+ ...o.check ? { check: true } : {},
949
+ ...o.resume ? { resume: o.resume } : {},
950
+ ...runtime ? { runtime } : {},
951
+ now: deps.now?.() ?? /* @__PURE__ */ new Date()
952
+ });
953
+ const kept = r.files.filter((f) => f.action === "kept-edited" || f.action === "kept-not-generated");
954
+ if (o.json) {
955
+ io.out(JSON.stringify({
956
+ change: r.change,
957
+ story: r.story,
958
+ strategy: r.model.strategy,
959
+ kinds: r.model.kinds,
960
+ names: r.names.by,
961
+ ...r.names.waiting ? { waiting: r.names.waiting } : {},
962
+ files: r.files,
963
+ manifest: r.manifest,
964
+ notes: r.notes,
965
+ gaps: r.gaps
966
+ }, null, 2));
967
+ return kept.length ? 1 : 0;
968
+ }
969
+ const count = (a) => r.files.filter((f) => f.action === a).length;
970
+ const cases = r.model.repos.reduce((n, x) => n + x.cases.length, 0);
971
+ io.out(`${o.check ? "Would write" : "Generated"} ${plural(cases, "test case")} for ${r.story} in ${plural(r.files.length, "file")}: ${count("created")} new, ${count("updated")} updated, ${count("unchanged")} unchanged${kept.length ? `, ${kept.length} kept` : ""}.`);
972
+ for (const l of table(["ACTION", "REPO", "FRAMEWORK", "FILE"], r.files.map((f) => [f.action, f.repo || "-", f.generator, f.path])))
973
+ io.out(l);
974
+ for (const k of r.model.kinds.filter((x) => !x.generated))
975
+ io.out(`No ${k.type} tests: ${k.why}`);
976
+ for (const n of r.notes)
977
+ io.out(n);
978
+ for (const g of r.gaps)
979
+ io.out(`Gap: ${g}`);
980
+ if (r.names.waiting)
981
+ io.out(`The test writer is with your assistant (run ${r.names.waiting}); the files use plain names until you run: atticus tests generate ${changeId} ${storyId} --resume ${r.names.waiting}`);
982
+ if (!o.check)
983
+ io.out(`Manifest: ${r.manifest}`);
984
+ return kept.length ? 1 : 0;
985
+ } catch (e) {
986
+ return fail(io, e);
987
+ }
988
+ }
989
+ async function traceCommand(root, changeId, o, io, deps = {}) {
990
+ if (!changeId) {
991
+ io.err("Usage: atticus trace <change> [--json | --csv] [--no-write]");
992
+ return 2;
993
+ }
994
+ try {
995
+ const m = await traceMatrix(root, changeId, { git: deps.git ?? createGit() });
996
+ for (const p of m.problems)
997
+ io.err(p);
998
+ const w = o.write === false ? void 0 : await writeTraceFindings(root, m, iso(deps.now?.() ?? /* @__PURE__ */ new Date()));
999
+ if (o.json)
1000
+ io.out(JSON.stringify({ ...m, ...w ? { round: w.round ?? null } : {} }, null, 2));
1001
+ else if (o.csv)
1002
+ lines(io, matrixCsv(m));
1003
+ else {
1004
+ lines(io, matrixMarkdown(m));
1005
+ if (w)
1006
+ io.out(w.unchanged ? `Findings on the trace gate are unchanged (round ${w.round ?? "none"}).` : `Wrote ${plural(w.findings.length, "finding")} to review/trace/${w.round}/.`);
1007
+ }
1008
+ return m.gaps.some((g) => g.kind !== "test-without-requirement") ? 1 : 0;
1009
+ } catch (e) {
1010
+ return fail(io, e);
1011
+ }
1012
+ }
1013
+ async function ciDrift(repoDir, o, io, deps = {}) {
1014
+ if (!o.catalog) {
1015
+ io.err("Usage: atticus ci drift [repo-dir] --catalog <metarepo or catalog folder> [--repo <id>] [--json [file]] [--junit <file>] [--summary <file>] [--warn-only]");
1016
+ return 2;
1017
+ }
1018
+ try {
1019
+ const r = await repoDrift({
1020
+ repoDir,
1021
+ catalog: o.catalog,
1022
+ ...o.repo ? { repo: o.repo } : {},
1023
+ ...o.warnOnly ? { warnOnly: true } : {},
1024
+ ...deps.commit ? { commit: deps.commit } : {},
1025
+ ...deps.git ? { git: deps.git } : {}
1026
+ });
1027
+ const put = async (file, text) => {
1028
+ await mkdir(dirname(file), { recursive: true });
1029
+ await writeFile(file, text, "utf8");
1030
+ };
1031
+ if (typeof o.json === "string")
1032
+ await put(o.json, driftJson(r));
1033
+ if (o.junit)
1034
+ await put(o.junit, driftJUnit(r));
1035
+ if (o.summary) {
1036
+ await mkdir(dirname(o.summary), { recursive: true });
1037
+ await appendFile(o.summary, driftMarkdown(r), "utf8");
1038
+ }
1039
+ if (o.json === true)
1040
+ io.out(driftJson(r).trimEnd());
1041
+ else
1042
+ lines(io, driftMarkdown(r));
1043
+ return driftExitCode(r);
1044
+ } catch (e) {
1045
+ if (e instanceof DriftError) {
1046
+ io.err(e.message);
1047
+ return 2;
1048
+ }
1049
+ throw e;
1050
+ }
1051
+ }
1052
+ async function ciSnippet(kind, io, o = {}) {
1053
+ const s = kind ? pipelineSnippet(kind) : void 0;
1054
+ if (!s) {
1055
+ io.err(`Usage: atticus ci snippet <${SNIPPET_KINDS.join("|")}> [--write <repo-dir>]`);
1056
+ return 2;
1057
+ }
1058
+ if (o.write) {
1059
+ const file = join4(o.write, ...s.path.split("/"));
1060
+ await mkdir(dirname(file), { recursive: true });
1061
+ await writeFile(file, s.content, "utf8");
1062
+ io.out(`Wrote ${s.path}. Set the variables its first lines name, then commit it.`);
1063
+ return 0;
1064
+ }
1065
+ lines(io, s.content);
1066
+ return 0;
1067
+ }
1068
+ async function ciArchiveGate(root, changeId, o, io, deps = {}) {
1069
+ if (!changeId) {
1070
+ io.err("Usage: atticus ci archive-gate <change> [--drift <report.json>...] [--json]");
1071
+ return 2;
1072
+ }
1073
+ let r;
1074
+ try {
1075
+ r = await archiveGate(root, changeId, {
1076
+ ...o.drift?.length ? { driftReports: o.drift } : {},
1077
+ ...deps.commit ? { commit: deps.commit } : {}
1078
+ });
1079
+ } catch (e) {
1080
+ if (e instanceof Error && e.name === "ChangeFileError") {
1081
+ io.err(e.message);
1082
+ return 2;
1083
+ }
1084
+ throw e;
1085
+ }
1086
+ if (o.json)
1087
+ io.out(JSON.stringify(r, null, 2));
1088
+ else {
1089
+ io.out(r.pass ? `${changeId} may be archived: no blockers, builds passed and the catalog matches its repos.` : `${changeId} can't be archived yet (${plural(r.blockers.length, "blocker")}):`);
1090
+ for (const b of r.blockers)
1091
+ io.out(`- ${b.message}`);
1092
+ for (const n of r.notes)
1093
+ io.out(n);
1094
+ }
1095
+ return r.pass ? 0 : 1;
1096
+ }
1097
+ var short = (s, n = 70) => s.length <= n ? s : `${s.slice(0, n - 3)}...`;
1098
+ var sourceOf = (flags, confidence) => confidence === "asserted" ? "person" : flags?.includes("ai-proposed") ? "ai" : flags?.includes("undefined") ? "code" : "wiki";
1099
+ async function glossaryList(root, o, io) {
1100
+ const g = await loadGlossary(root);
1101
+ for (const p of g.problems)
1102
+ io.err(p);
1103
+ if (o.json) {
1104
+ io.out(JSON.stringify({
1105
+ terms: g.terms,
1106
+ conflicts: g.build.conflicts,
1107
+ hints: g.build.hints,
1108
+ synonyms: Object.fromEntries(g.build.entries.filter((e) => e.aliases.length).map((e) => [e.id, e.aliases]))
1109
+ }, null, 2));
1110
+ return 0;
1111
+ }
1112
+ if (!g.terms.length) {
1113
+ io.out("The glossary is empty: no wiki page defines a term and the catalog has no domain words yet.");
1114
+ return 0;
1115
+ }
1116
+ for (const l of table(["TERM", "ID", "FROM", "FLAGS", "DEFINITION"], g.terms.map((t) => [
1117
+ t.term,
1118
+ t.id,
1119
+ sourceOf(t.flags, t.confidence),
1120
+ (t.flags ?? []).join(","),
1121
+ short(t.definition)
1122
+ ])))
1123
+ io.out(l);
1124
+ io.out(`${plural(g.terms.length, "term")}, ${plural(g.build.conflicts.filter((c) => !c.resolved).length, "conflict")}.`);
1125
+ return 0;
1126
+ }
1127
+ async function glossaryScan(root, o, io, deps = {}) {
1128
+ try {
1129
+ const runtime = await runtimeOf(root, o.mode, deps);
1130
+ const r = await scanGlossary(root, {
1131
+ ...runtime ? { runtime } : {},
1132
+ ...deps.now ? { now: deps.now() } : {}
1133
+ });
1134
+ if (o.json) {
1135
+ for (const p of r.problems)
1136
+ io.err(p);
1137
+ io.out(JSON.stringify({
1138
+ terms: r.terms.length,
1139
+ written: r.written,
1140
+ removed: r.removed,
1141
+ conflicts: r.build.conflicts,
1142
+ hints: r.build.hints,
1143
+ ...r.propose ? { proposals: r.propose.proposals.length, discarded: r.propose.discarded } : {}
1144
+ }, null, 2));
1145
+ return 0;
1146
+ }
1147
+ printGlossaryScan(r, io);
1148
+ return 0;
1149
+ } catch (e) {
1150
+ return fail(io, e);
1151
+ }
1152
+ }
1153
+ function printGlossaryScan(r, io) {
1154
+ for (const p of r.problems)
1155
+ io.err(p);
1156
+ const open = r.build.conflicts.filter((c) => !c.resolved);
1157
+ io.out(`The glossary has ${plural(r.terms.length, "term")}; ${plural(r.written.length, "file")} written and ${plural(r.removed.length, "file")} removed in catalog/generated.`);
1158
+ if (r.propose)
1159
+ io.out(r.propose.waiting ? `The glossary definer is with your assistant (run ${r.propose.waiting}). When it is done, run: atticus handoff done ${r.propose.waiting}` : `The glossary definer proposed ${plural(r.propose.proposals.length, "definition")} (kept inferred until a person defines the term).`);
1160
+ for (const d of r.propose?.discarded ?? [])
1161
+ if (d.term && !r.propose?.waiting)
1162
+ io.err(`Discarded ${d.term}: ${d.reason}`);
1163
+ for (const c of open)
1164
+ io.out(`Conflict: ${c.message}`);
1165
+ for (const h of r.build.hints)
1166
+ io.out(`Naming: ${h.message}`);
1167
+ }
1168
+ async function completeGlossaryScan(root, run, io, deps = {}) {
1169
+ try {
1170
+ const r = await completeGlossaryDefinitions(root, run, deps.now ? { now: deps.now } : {});
1171
+ printGlossaryScan(r, io);
1172
+ return 0;
1173
+ } catch (e) {
1174
+ return fail(io, e);
1175
+ }
1176
+ }
1177
+ async function decide(root, io, make, said) {
1178
+ try {
1179
+ const g = await loadGlossary(root);
1180
+ const ds = make(g);
1181
+ const files = await writeDecisions(join4(g.catalogDir, "curated"), ds);
1182
+ await scanGlossary(root);
1183
+ io.out(`Wrote ${files.map((f) => `catalog/curated/${f}`).join(" and ")}: ${said}. Commit it so every scan keeps it.`);
1184
+ return 0;
1185
+ } catch (e) {
1186
+ if (e instanceof GlossaryError) {
1187
+ io.err(e.message);
1188
+ return e.code === "invalid" ? 2 : 1;
1189
+ }
1190
+ throw e;
1191
+ }
1192
+ }
1193
+ async function glossaryDefine(root, term, definition, o, io) {
1194
+ if (!term || !definition || !o.by) {
1195
+ io.err('Usage: atticus glossary define <term> "<definition>" [--by <handle>] [--owner <team>]');
1196
+ return 2;
1197
+ }
1198
+ return decide(root, io, (g) => {
1199
+ const existing = g.terms.find((t) => t.id === resolveTermId(term));
1200
+ return [
1201
+ defineDecision(term, definition, {
1202
+ by: o.by,
1203
+ ...o.owner ? { owner: o.owner } : {},
1204
+ ...existing ? { existing } : {}
1205
+ })
1206
+ ];
1207
+ }, `${resolveTermId(term)} is defined and asserted`);
1208
+ }
1209
+ async function glossaryLink(root, term, recordId, o, io) {
1210
+ if (!term || !recordId || !o.by) {
1211
+ io.err("Usage: atticus glossary link <term> <record-id | schema#field> [--by <handle>]");
1212
+ return 2;
1213
+ }
1214
+ return decide(root, io, (g) => {
1215
+ const id = resolveTermId(term);
1216
+ const t = g.terms.find((x) => x.id === id);
1217
+ if (!t)
1218
+ throw new GlossaryError("not-found", `There is no term ${id}. Define it first: atticus glossary define`);
1219
+ return [linkDecision(t, recordId, g.base, { by: o.by })];
1220
+ }, `${recordId} is linked to ${resolveTermId(term)}`);
1221
+ }
1222
+ async function glossaryAlias(root, term, names, o, io) {
1223
+ if (!term || !names.length || !o.by) {
1224
+ io.err('Usage: atticus glossary alias <term> "<other name>"... [--by <handle>]');
1225
+ return 2;
1226
+ }
1227
+ return decide(root, io, (g) => {
1228
+ const id = resolveTermId(term);
1229
+ const before = g.build.entries.find((e) => e.id === id)?.aliases ?? [];
1230
+ return [aliasDecision(id, [...before, ...names], { by: o.by })];
1231
+ }, `${names.join(", ")} ${names.length === 1 ? "is another name" : "are other names"} for ${resolveTermId(term)}`);
1232
+ }
1233
+
1234
+ export {
1235
+ archiveGate,
1236
+ testsGenerate,
1237
+ traceCommand,
1238
+ ciDrift,
1239
+ ciSnippet,
1240
+ ciArchiveGate,
1241
+ glossaryList,
1242
+ glossaryScan,
1243
+ completeGlossaryScan,
1244
+ glossaryDefine,
1245
+ glossaryLink,
1246
+ glossaryAlias
1247
+ };