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

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 (509) 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-23VFQHFQ.js +827 -0
  6. package/dist/chunk-26DBAGOP.js +315 -0
  7. package/dist/chunk-27EDZN52.js +115 -0
  8. package/dist/chunk-2K2ZEJVR.js +252 -0
  9. package/dist/chunk-3DDJLI7N.js +1081 -0
  10. package/dist/chunk-3G4YI4ZU.js +16 -0
  11. package/dist/chunk-3LU6YCSQ.js +3507 -0
  12. package/dist/chunk-3WU7LVTL.js +203 -0
  13. package/dist/chunk-4AYZQ3SY.js +285 -0
  14. package/dist/chunk-4ONORLK5.js +234 -0
  15. package/dist/chunk-4Q3NN7VF.js +32 -0
  16. package/dist/chunk-4SKZDI62.js +22 -0
  17. package/dist/chunk-4URR24DD.js +189 -0
  18. package/dist/chunk-4UZJOQYK.js +70 -0
  19. package/dist/chunk-4Y4FY34K.js +34 -0
  20. package/dist/chunk-4YWRU7JK.js +80 -0
  21. package/dist/chunk-52WCHTVZ.js +41 -0
  22. package/dist/chunk-55TBYJF2.js +36 -0
  23. package/dist/chunk-5ACUW753.js +240 -0
  24. package/dist/chunk-5BJFMAQU.js +32 -0
  25. package/dist/chunk-5ICB2BXH.js +33 -0
  26. package/dist/chunk-5NZSJ5ZG.js +60 -0
  27. package/dist/chunk-5P5BGG5L.js +307 -0
  28. package/dist/chunk-5RUMHLIS.js +104 -0
  29. package/dist/chunk-5TY4DTHQ.js +242 -0
  30. package/dist/chunk-5V5BJACL.js +2929 -0
  31. package/dist/chunk-6E2GJANQ.js +52 -0
  32. package/dist/chunk-6N2GUZMZ.js +471 -0
  33. package/dist/chunk-6RGIM2ZH.js +2069 -0
  34. package/dist/chunk-6V3DTQWK.js +391 -0
  35. package/dist/chunk-76WKMA4J.js +14 -0
  36. package/dist/chunk-77RSRG3A.js +104 -0
  37. package/dist/chunk-7A7IG7OA.js +2007 -0
  38. package/dist/chunk-7EFILTCI.js +67 -0
  39. package/dist/chunk-7HQOZALR.js +180 -0
  40. package/dist/chunk-7HWXYP4H.js +1217 -0
  41. package/dist/chunk-7J7UY46S.js +688 -0
  42. package/dist/chunk-7KXYMC2P.js +38 -0
  43. package/dist/chunk-7LCQ7JAM.js +55 -0
  44. package/dist/chunk-7RGCQ4VZ.js +22 -0
  45. package/dist/chunk-7RUMD56V.js +26 -0
  46. package/dist/chunk-7S3XFWOU.js +251 -0
  47. package/dist/chunk-7SZPENUP.js +32 -0
  48. package/dist/chunk-7VFVQX5K.js +105 -0
  49. package/dist/chunk-ACWQDL6T.js +37 -0
  50. package/dist/chunk-ANCI3LFS.js +25 -0
  51. package/dist/chunk-ASKDCMW5.js +275 -0
  52. package/dist/chunk-ATNG5VOZ.js +122 -0
  53. package/dist/chunk-B3QOYE74.js +58 -0
  54. package/dist/chunk-B3UHYXHU.js +41 -0
  55. package/dist/chunk-BA5DTXHQ.js +250 -0
  56. package/dist/chunk-BKFGGJKA.js +2743 -0
  57. package/dist/chunk-BQNEHB5U.js +212 -0
  58. package/dist/chunk-BUWSOQLU.js +131 -0
  59. package/dist/chunk-BX52REMA.js +134 -0
  60. package/dist/chunk-BXBCMGIQ.js +82 -0
  61. package/dist/chunk-C2YGYTU6.js +408 -0
  62. package/dist/chunk-C5JFMAXX.js +102 -0
  63. package/dist/chunk-C75W7VXX.js +42 -0
  64. package/dist/chunk-CAN3EBE5.js +1726 -0
  65. package/dist/chunk-CE4S5ZY3.js +182 -0
  66. package/dist/chunk-CRQ73DIF.js +25 -0
  67. package/dist/chunk-CZI2ACNT.js +36 -0
  68. package/dist/chunk-D7MWYJZF.js +43 -0
  69. package/dist/chunk-DDAEAZEV.js +54 -0
  70. package/dist/chunk-DGKNOPSE.js +549 -0
  71. package/dist/chunk-DQNKG4HY.js +906 -0
  72. package/dist/chunk-DS3ZEJVN.js +22 -0
  73. package/dist/chunk-DYWTQXP4.js +108 -0
  74. package/dist/chunk-E25G46RW.js +54 -0
  75. package/dist/chunk-EADP3PEN.js +450 -0
  76. package/dist/chunk-EAQFRD2B.js +430 -0
  77. package/dist/chunk-EATSD7YD.js +41 -0
  78. package/dist/chunk-EBWIOODZ.js +339 -0
  79. package/dist/chunk-EHUYLNLC.js +282 -0
  80. package/dist/chunk-EI4KQYJ3.js +1496 -0
  81. package/dist/chunk-EQOSXLK3.js +49 -0
  82. package/dist/chunk-EV4TEFOD.js +16667 -0
  83. package/dist/chunk-EW7MRMD5.js +312 -0
  84. package/dist/chunk-EZSZFI54.js +531 -0
  85. package/dist/chunk-FMRMTI7W.js +1142 -0
  86. package/dist/chunk-FOQXYMOR.js +46 -0
  87. package/dist/chunk-G3PBLW4K.js +246 -0
  88. package/dist/chunk-G7WZH54P.js +221 -0
  89. package/dist/chunk-GG6HIU74.js +211 -0
  90. package/dist/chunk-GMJXC5AL.js +27809 -0
  91. package/dist/chunk-GPLFYLGH.js +130 -0
  92. package/dist/chunk-GVFUEGGM.js +19943 -0
  93. package/dist/chunk-GWSWS264.js +130 -0
  94. package/dist/chunk-H4VJO3M2.js +229 -0
  95. package/dist/chunk-HGQZTUAC.js +415 -0
  96. package/dist/chunk-HOUUBE74.js +166 -0
  97. package/dist/chunk-HQMCHHY5.js +155 -0
  98. package/dist/chunk-HR4DVO6X.js +374 -0
  99. package/dist/chunk-HZYFLEWO.js +39 -0
  100. package/dist/chunk-IA2RKC6I.js +279 -0
  101. package/dist/chunk-IILZ7J3L.js +5548 -0
  102. package/dist/chunk-IRW64JFF.js +247 -0
  103. package/dist/chunk-IVHN2VYG.js +1526 -0
  104. package/dist/chunk-IWZPGIGT.js +856 -0
  105. package/dist/chunk-IY4PHPHT.js +15 -0
  106. package/dist/chunk-J27QGXO4.js +1247 -0
  107. package/dist/chunk-JBSD57N7.js +324 -0
  108. package/dist/chunk-JEUXCIRD.js +120 -0
  109. package/dist/chunk-JMOLB347.js +46388 -0
  110. package/dist/chunk-JQX6BSE4.js +130 -0
  111. package/dist/chunk-JRPQX2EK.js +376 -0
  112. package/dist/chunk-JUQHYTXN.js +45 -0
  113. package/dist/chunk-JUZ75OG4.js +344 -0
  114. package/dist/chunk-KIWEBM6G.js +378 -0
  115. package/dist/chunk-KLKENMWQ.js +891 -0
  116. package/dist/chunk-KQDZXGNR.js +14 -0
  117. package/dist/chunk-KQK6SQPE.js +48 -0
  118. package/dist/chunk-KQRYW7OS.js +4108 -0
  119. package/dist/chunk-KU4T2CXJ.js +116 -0
  120. package/dist/chunk-KXZR2BLL.js +53 -0
  121. package/dist/chunk-L7I5PKGD.js +915 -0
  122. package/dist/chunk-LDIARP6F.js +31 -0
  123. package/dist/chunk-LEHZTKB3.js +34 -0
  124. package/dist/chunk-LS3WR2RF.js +1071 -0
  125. package/dist/chunk-LUPW4WLK.js +526 -0
  126. package/dist/chunk-LVBPY2M6.js +406 -0
  127. package/dist/chunk-LZWVK4YY.js +169 -0
  128. package/dist/chunk-MCWWMMLN.js +48 -0
  129. package/dist/chunk-MKC7P5LD.js +32 -0
  130. package/dist/chunk-MKFYQQ5Q.js +36 -0
  131. package/dist/chunk-MKIULIUQ.js +273 -0
  132. package/dist/chunk-MMB2OHUY.js +263 -0
  133. package/dist/chunk-MQNBEO3N.js +2610 -0
  134. package/dist/chunk-MSL3CLHX.js +545 -0
  135. package/dist/chunk-MV4637YA.js +174 -0
  136. package/dist/chunk-MYKQVS5W.js +296 -0
  137. package/dist/chunk-MYOW3RPC.js +143 -0
  138. package/dist/chunk-NBGBMRIS.js +25 -0
  139. package/dist/chunk-NBQO75XT.js +287 -0
  140. package/dist/chunk-NCR24CPV.js +41 -0
  141. package/dist/chunk-NDW4ROST.js +38 -0
  142. package/dist/chunk-NELU7LSL.js +3208 -0
  143. package/dist/chunk-NG5R2WIY.js +2919 -0
  144. package/dist/chunk-NH5QH3WS.js +119 -0
  145. package/dist/chunk-NIYB5K5B.js +583 -0
  146. package/dist/chunk-NR5T46ZY.js +49 -0
  147. package/dist/chunk-NX6QEEOA.js +163 -0
  148. package/dist/chunk-O6ILVBYB.js +18 -0
  149. package/dist/chunk-OFWYZH6B.js +230 -0
  150. package/dist/chunk-OHXTB6CO.js +50 -0
  151. package/dist/chunk-OJN7WME4.js +34 -0
  152. package/dist/chunk-OR5VRULZ.js +226 -0
  153. package/dist/chunk-ORZSD2KD.js +55 -0
  154. package/dist/chunk-OXVVRJDQ.js +66 -0
  155. package/dist/chunk-PQW7PYUR.js +2522 -0
  156. package/dist/chunk-Q32Y5T2U.js +27 -0
  157. package/dist/chunk-QWHTTA2X.js +130 -0
  158. package/dist/chunk-R3RVFCJ2.js +76 -0
  159. package/dist/chunk-R3VFLYZZ.js +400 -0
  160. package/dist/chunk-R6RY4Q5T.js +51 -0
  161. package/dist/chunk-R6UTCLH5.js +166 -0
  162. package/dist/chunk-RB2VSED2.js +231 -0
  163. package/dist/chunk-REWZE2XI.js +53 -0
  164. package/dist/chunk-RIEFYHXI.js +162 -0
  165. package/dist/chunk-RJDP642F.js +101 -0
  166. package/dist/chunk-RWMSJP7H.js +279 -0
  167. package/dist/chunk-S2FDPN32.js +41 -0
  168. package/dist/chunk-S5LSDXV4.js +40 -0
  169. package/dist/chunk-S7ZWCMDO.js +192 -0
  170. package/dist/chunk-SG5KY4VB.js +69 -0
  171. package/dist/chunk-SH7AZZDA.js +69 -0
  172. package/dist/chunk-SILY6ZEZ.js +104 -0
  173. package/dist/chunk-SINJKQSI.js +34 -0
  174. package/dist/chunk-SIUDWWKS.js +47 -0
  175. package/dist/chunk-SKMHS4CL.js +766 -0
  176. package/dist/chunk-SNHOLLGN.js +280 -0
  177. package/dist/chunk-SUQZGPVG.js +119 -0
  178. package/dist/chunk-T6ESD5KM.js +6115 -0
  179. package/dist/chunk-TC3KTG33.js +221 -0
  180. package/dist/chunk-TCADP67G.js +101 -0
  181. package/dist/chunk-TEBBD4XH.js +7923 -0
  182. package/dist/chunk-TGEOLIAK.js +149 -0
  183. package/dist/chunk-TQYBXDVH.js +133 -0
  184. package/dist/chunk-TV45EUGM.js +51 -0
  185. package/dist/chunk-TZXHUDI6.js +233 -0
  186. package/dist/chunk-U5PDQTLA.js +50 -0
  187. package/dist/chunk-U6YKL7SI.js +334 -0
  188. package/dist/chunk-UABFFMWH.js +2078 -0
  189. package/dist/chunk-UFBKJOWB.js +325 -0
  190. package/dist/chunk-UFTQIK2J.js +43 -0
  191. package/dist/chunk-UNFCFJMF.js +95 -0
  192. package/dist/chunk-UTR67XU2.js +164 -0
  193. package/dist/chunk-V4XKYGLK.js +405 -0
  194. package/dist/chunk-VOGCSYOI.js +16 -0
  195. package/dist/chunk-VYNZED7B.js +53 -0
  196. package/dist/chunk-WCLAOKCH.js +540 -0
  197. package/dist/chunk-WFYHOXTB.js +29 -0
  198. package/dist/chunk-WGU6NIUV.js +113 -0
  199. package/dist/chunk-WIMOJMAK.js +3702 -0
  200. package/dist/chunk-WKXOEIOY.js +184 -0
  201. package/dist/chunk-WUE6HKIU.js +790 -0
  202. package/dist/chunk-WUP77GG2.js +56 -0
  203. package/dist/chunk-XF3DATVU.js +150 -0
  204. package/dist/chunk-XJAJQGXJ.js +18 -0
  205. package/dist/chunk-XKJRPVJO.js +3898 -0
  206. package/dist/chunk-XNRPCI23.js +3851 -0
  207. package/dist/chunk-XOVLGBKI.js +214 -0
  208. package/dist/chunk-XPJR74MA.js +562 -0
  209. package/dist/chunk-XPWSNKF3.js +5619 -0
  210. package/dist/chunk-XR5DD5DQ.js +104 -0
  211. package/dist/chunk-XZJE6WIT.js +706 -0
  212. package/dist/chunk-XZRON6IV.js +131 -0
  213. package/dist/chunk-Y5AYBGLB.js +368 -0
  214. package/dist/chunk-YLAM4HZH.js +95 -0
  215. package/dist/chunk-YVCOQ5TZ.js +47 -0
  216. package/dist/chunk-YWOMGMZB.js +94 -0
  217. package/dist/chunk-YWZDAZMA.js +18 -0
  218. package/dist/chunk-Z2EYRUOH.js +172 -0
  219. package/dist/chunk-Z46OXTBE.js +1611 -0
  220. package/dist/chunk-ZHWSL6SR.js +45 -0
  221. package/dist/chunk-ZJQUIG3A.js +87 -0
  222. package/dist/chunk-ZKUDS7JG.js +310 -0
  223. package/dist/chunk-ZTNS3L5Z.js +1019 -0
  224. package/dist/files.json +2024 -0
  225. package/dist/fixtures/forge/README.md +19 -0
  226. package/dist/fixtures/forge/expected/discrepancies.yaml +54 -0
  227. package/dist/fixtures/forge/expected/inputs.yaml +38 -0
  228. package/dist/fixtures/forge/expected/scan.yaml +342 -0
  229. package/dist/fixtures/forge/inputs/diagrams/forge-context.drawio +23 -0
  230. package/dist/fixtures/forge/inputs/partner-specs/northwind-pay-openapi.yaml +11 -0
  231. package/dist/fixtures/forge/inputs/tickets/ado-stories.json +4 -0
  232. package/dist/fixtures/forge/inputs/tickets/closed-service-requests.json +5 -0
  233. package/dist/fixtures/forge/inputs/wiki/integration-patterns.md +11 -0
  234. package/dist/fixtures/forge/inputs/wiki/ledger-solution-spec.md +9 -0
  235. package/dist/fixtures/forge/inputs/wiki/snow-firewall-request.md +4 -0
  236. package/dist/fixtures/forge/metarepo/judgments/reaches/84af5b6af24f7ca8c23013f3.yaml +17 -0
  237. package/dist/fixtures/forge/metarepo/judgments/reaches/c3917555edebddce8cecb647.yaml +17 -0
  238. package/dist/fixtures/forge/metarepo/judgments/reaches/c5fafd6601f8ca9e34e0bbd0.yaml +17 -0
  239. package/dist/fixtures/forge/metarepo/org-pack/agents/architecture-critic.yaml +9 -0
  240. package/dist/fixtures/forge/metarepo/org-pack/agents/story-writer.yaml +10 -0
  241. package/dist/fixtures/forge/metarepo/org-pack/checklists/architecture.yaml +115 -0
  242. package/dist/fixtures/forge/metarepo/org-pack/dialects/forge.yaml +111 -0
  243. package/dist/fixtures/forge/metarepo/org-pack/gates.yaml +22 -0
  244. package/dist/fixtures/forge/metarepo/org-pack/pack.yaml +11 -0
  245. package/dist/fixtures/forge/metarepo/org-pack/patterns/A.EB.PUB.yaml +12 -0
  246. package/dist/fixtures/forge/metarepo/org-pack/patterns/D.JDBC.yaml +12 -0
  247. package/dist/fixtures/forge/metarepo/org-pack/patterns/S.DIR.BFF.yaml +12 -0
  248. package/dist/fixtures/forge/metarepo/org-pack/patterns/S.GW.SOR.yaml +13 -0
  249. package/dist/fixtures/forge/metarepo/org-pack/patterns/S.GW.VND.yaml +14 -0
  250. package/dist/fixtures/forge/metarepo/org-pack/process/change-templates/feature.md +37 -0
  251. package/dist/fixtures/forge/metarepo/org-pack/process/skills/add-forge-endpoint/SKILL.md +17 -0
  252. package/dist/fixtures/forge/metarepo/org-pack/process/snow/firewall-rule.yaml +14 -0
  253. package/dist/fixtures/forge/metarepo/org-pack/process/snow/gateway-route.yaml +13 -0
  254. package/dist/fixtures/forge/metarepo/org-pack/profiles/forge/profile.yaml +12 -0
  255. package/dist/fixtures/forge/metarepo/org-pack/profiles/forge/repos.manifest.yaml +44 -0
  256. package/dist/fixtures/forge/metarepo/org-pack/roles.yaml +14 -0
  257. package/dist/fixtures/forge/metarepo/org-pack/runtime.yaml +14 -0
  258. package/dist/fixtures/forge/metarepo/org-pack/sources.yaml +3 -0
  259. package/dist/fixtures/forge/repos/forge-events/topics/payments.initiated.yaml +4 -0
  260. package/dist/fixtures/forge/repos/forge-events/topics/transfers.completed.yaml +4 -0
  261. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/ledger-v1.xml +3 -0
  262. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/policies/SpikeArrest.xml +3 -0
  263. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/policies/VerifyOAuth.xml +4 -0
  264. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/proxies/default.xml +14 -0
  265. package/dist/fixtures/forge/repos/forge-gateway/proxies/ledger-v1/apiproxy/targets/ledger.xml +5 -0
  266. package/dist/fixtures/forge/repos/forge-infra/alerts/ledger-api.yaml +5 -0
  267. package/dist/fixtures/forge/repos/forge-infra/k8s/ledger-api.yaml +15 -0
  268. package/dist/fixtures/forge/repos/forge-infra/k8s/portal-bff.yaml +7 -0
  269. package/dist/fixtures/forge/repos/forge-infra/terraform/ledger-db.tf +9 -0
  270. package/dist/fixtures/forge/repos/forge-ledger/api/ledger-openapi.yaml +31 -0
  271. package/dist/fixtures/forge/repos/forge-ledger/forge.yaml +4 -0
  272. package/dist/fixtures/forge/repos/forge-ledger/src/main/java/forge/ledger/LedgerEndpoints.java +13 -0
  273. package/dist/fixtures/forge/repos/forge-ledger/src/main/java/forge/ledger/LedgerEvents.java +11 -0
  274. package/dist/fixtures/forge/repos/forge-ledger/src/main/java/forge/ledger/NorthwindClient.java +10 -0
  275. package/dist/fixtures/forge/repos/forge-ledger/src/main/resources/application.yml +3 -0
  276. package/dist/fixtures/forge/repos/forge-ledger/src/main/resources/db/migration/V1__create_account.sql +5 -0
  277. package/dist/fixtures/forge/repos/forge-ledger/src/main/resources/db/migration/V2__create_entry.sql +7 -0
  278. package/dist/fixtures/forge/repos/forge-portal-bff/pom.xml +1 -0
  279. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/AuditPublisher.java +12 -0
  280. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/BalanceController.java +16 -0
  281. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/LedgerClient.java +13 -0
  282. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/java/forge/portal/PaymentEvents.java +13 -0
  283. package/dist/fixtures/forge/repos/forge-portal-bff/src/main/resources/application.yml +8 -0
  284. package/dist/fixtures/forge/repos/forge-portal-ui/package.json +1 -0
  285. package/dist/fixtures/forge/repos/forge-portal-ui/src/api/balance.ts +5 -0
  286. package/dist/fixtures/forge/repos/forge-reports-job/src/main/java/forge/reports/DailyEntriesJob.java +19 -0
  287. package/dist/fixtures/forge/repos/forge-reports-job/src/main/resources/application.yml +3 -0
  288. package/dist/fixtures/forge-change/README.md +41 -0
  289. package/dist/fixtures/forge-change/expected/findings.yaml +301 -0
  290. package/dist/fixtures/forge-change/expected/stories.yaml +101 -0
  291. package/dist/fixtures/forge-change/judgments/personal-data/0b5f3dbf5257a22275d8c74b.yaml +18 -0
  292. package/dist/fixtures/forge-change/judgments/personal-data/2759a66770134c417440bf2d.yaml +18 -0
  293. package/dist/fixtures/forge-change/judgments/personal-data/31b1ea2f14d0737f1aca79fd.yaml +18 -0
  294. package/dist/fixtures/forge-change/judgments/personal-data/49afd70c08228e65ad6ca1ed.yaml +18 -0
  295. package/dist/fixtures/forge-change/judgments/personal-data/761cabcb8a39f5e5866d2dd6.yaml +18 -0
  296. package/dist/fixtures/forge-change/judgments/personal-data/adae902b90cc8ffa0c765145.yaml +18 -0
  297. package/dist/fixtures/forge-change/judgments/personal-data/ba11bb933105ec9493e065dd.yaml +18 -0
  298. package/dist/fixtures/forge-change/judgments/personal-data/bdbcd1cdac3021c68063c3e7.yaml +18 -0
  299. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/brief.md +35 -0
  300. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/change.yaml +120 -0
  301. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/data.md +18 -0
  302. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/design.md +29 -0
  303. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/interfaces.md +17 -0
  304. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/mappings.md +26 -0
  305. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/proposal.md +35 -0
  306. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/snow.md +12 -0
  307. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/specs/transfer-limits/spec.md +19 -0
  308. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s1-refuse-over-limit.md +17 -0
  309. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s2-show-remaining.md +16 -0
  310. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s3-audit-refusals.md +18 -0
  311. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories/s4-velocity-check.md +16 -0
  312. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/stories.md +8 -0
  313. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/tasks.md +12 -0
  314. package/dist/fixtures/forge-change/openspec/changes/add-transfer-limit/ux.md +7 -0
  315. package/dist/fixtures/forge-change/org-pack/agents/code-and-test-critic.yaml +13 -0
  316. package/dist/fixtures/forge-change/org-pack/agents/complete-critic.yaml +12 -0
  317. package/dist/fixtures/forge-change/org-pack/agents/safe-critic.yaml +12 -0
  318. package/dist/fixtures/forge-change/org-pack/agents/ship-critic.yaml +11 -0
  319. package/dist/fixtures/forge-change/org-pack/agents/true-critic.yaml +11 -0
  320. package/dist/fixtures/forge-change/org-pack/checklists/review.yaml +54 -0
  321. package/dist/fixtures/forge-change/org-pack/gates.yaml +25 -0
  322. package/dist/fixtures/forge-change/org-pack/teams/team-ledger/checklists/ledger-team.yaml +227 -0
  323. package/dist/fixtures/forge-change/recordings/complete-critic/2ad84f84bf39c1d5412697e69fe23034d6983ec45a00314bf0975e627589a3c5.json +12 -0
  324. package/dist/fixtures/forge-change/recordings/complete-critic/417c98d8e54a4387d0fd93441c49f44c2868958739070d855c1dce0c41e24db3.json +12 -0
  325. package/dist/fixtures/forge-change/recordings/complete-critic/50203ee22e9cb3ef047295edb6538fe7d5695e1e4b139f3c929013dc6ce47021.json +12 -0
  326. package/dist/fixtures/forge-change/recordings/complete-critic/89f18d67f5d9c325bf35e2a9e020f9ddb6ee13b8523315037f0905cc57c040b1.json +12 -0
  327. package/dist/fixtures/forge-change/recordings/complete-critic/b4097867d26ae8eadc8b9efa8cdd86897013358035f0b40086c299a59c4ba121.json +12 -0
  328. package/dist/fixtures/forge-change/recordings/safe-critic/302d06f49664dd67ad2e21ab9cf74c1b0f7d3f750709c6ed8eff2b70983274e2.json +12 -0
  329. package/dist/fixtures/forge-change/recordings/safe-critic/32f1049c9a5ab4a759543290db4644ec6e221cc45fdfdcf06193837c6a8ce0b9.json +12 -0
  330. package/dist/fixtures/forge-change/recordings/safe-critic/4e4a84bfc04b9f26ca4250319a879901ff7a1c081c71e46a117675fee05026b0.json +12 -0
  331. package/dist/fixtures/forge-change/recordings/safe-critic/604af0fcdd6df6b76208fa88305fdc15c37606c2a4d1ae816477e46ac8c2dd04.json +12 -0
  332. package/dist/fixtures/forge-change/recordings/safe-critic/f0bf50af11f14c50d07904f0dffe1c8c20fb0cd89770645a8824c1d30a443955.json +12 -0
  333. package/dist/fixtures/forge-change/recordings/ship-critic/350954b58833b2c04880c67db45a1b328b7fd541d9f0d943b63905b8875488a6.json +12 -0
  334. package/dist/fixtures/forge-change/recordings/ship-critic/4af95c6c96a206777cec9de1f9c2d8c55a36ddc9b8db2f81d6eb83217b835efa.json +12 -0
  335. package/dist/fixtures/forge-change/recordings/ship-critic/76c34522a49cf7587a4e5689a5030d384603fa780b8aba97d27815cbc829683e.json +12 -0
  336. package/dist/fixtures/forge-change/recordings/ship-critic/a3b2cd1ace48587e5994333db03b34c3a0f9dec4f1932f1730ddfb687f6918c8.json +12 -0
  337. package/dist/fixtures/forge-change/recordings/ship-critic/de288a4fa64d0fc20890f9a787080ce6eac5203b7b9b72d884df11e8cf111835.json +12 -0
  338. package/dist/fixtures/forge-change/recordings/story-writer/1ddb00eac2aaf91a5ec5d9dfd220116be9f75aec6546a4a3a3b050ed89af2864.json +12 -0
  339. package/dist/packages/assistant-kit/frameworks-kit/README.md +86 -0
  340. package/dist/packages/assistant-kit/frameworks-kit/checklist.md +11 -0
  341. package/dist/packages/assistant-kit/frameworks-kit/examples/tide-lantern.yaml +56 -0
  342. package/dist/packages/assistant-kit/frameworks-kit/examples/tide-platform.yaml +43 -0
  343. package/dist/packages/assistant-kit/frameworks-kit/prompts/write-framework-model.md +12 -0
  344. package/dist/packages/assistant-kit/kit/README.md +98 -0
  345. package/dist/packages/assistant-kit/kit/c2-reference.md +334 -0
  346. package/dist/packages/assistant-kit/kit/checklist.md +39 -0
  347. package/dist/packages/assistant-kit/kit/examples/house-http-client.yaml +102 -0
  348. package/dist/packages/assistant-kit/kit/examples/tide-apigee.yaml +56 -0
  349. package/dist/packages/assistant-kit/kit/examples/tide-apim.yaml +32 -0
  350. package/dist/packages/assistant-kit/kit/examples/tide-kong.yaml +44 -0
  351. package/dist/packages/assistant-kit/kit/prompts/write-dialect.md +34 -0
  352. package/dist/packages/assistant-kit/kit/worked-example.md +198 -0
  353. package/dist/packages/conformance/sample/README.md +4 -0
  354. package/dist/packages/conformance/sample/inputs/notes.md +3 -0
  355. package/dist/packages/conformance/sample/inputs/systems.csv +3 -0
  356. package/dist/packages/conformance/sample/repo/api/greeter.proto +6 -0
  357. package/dist/packages/conformance/sample/repo/api/openapi.yaml +10 -0
  358. package/dist/packages/conformance/sample/repo/api/schema.graphql +3 -0
  359. package/dist/packages/conformance/sample/repo/db/V1__create_greeting.sql +4 -0
  360. package/dist/packages/conformance/sample/repo/package.json +7 -0
  361. package/dist/packages/conformance/sample/repo/src/main/java/sample/HelloController.java +10 -0
  362. package/dist/packages/conformance/sample/repo/web/app.ts +4 -0
  363. package/dist/packages/evals/datasets/critic-lenses.yaml +62 -0
  364. package/dist/packages/evals/datasets/dialect-writer.yaml +14 -0
  365. package/dist/packages/evals/datasets/feature-namer.yaml +34 -0
  366. package/dist/packages/evals/datasets/glossary-definer.yaml +25 -0
  367. package/dist/packages/evals/datasets/story-writer.yaml +13 -0
  368. package/dist/packages/evals/datasets/template-writer.yaml +16 -0
  369. package/dist/packages/evals/datasets/test-writer.yaml +18 -0
  370. package/dist/packages/executors/reference/reference-executor.mjs +233 -0
  371. package/dist/packages/extractors/dialects/argocd.yaml +45 -0
  372. package/dist/packages/extractors/dialects/fixtures/jaxrs/accounts-service/src/main/java/forge/accounts/AccountResource.java +47 -0
  373. package/dist/packages/extractors/dialects/fixtures/jaxrs/accounts-service/src/main/java/forge/accounts/AuditClient.java +12 -0
  374. package/dist/packages/extractors/dialects/fixtures/jaxrs/accounts-service/src/main/java/forge/accounts/LedgerClient.java +17 -0
  375. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/java/forge/statements/LedgerClient.java +14 -0
  376. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/java/forge/statements/RatesClient.java +11 -0
  377. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/java/forge/statements/StatementController.java +36 -0
  378. package/dist/packages/extractors/dialects/fixtures/micronaut/statements-service/src/main/resources/application.yml +7 -0
  379. package/dist/packages/extractors/dialects/fixtures/quarkus-reactive-messaging/fraud-service/src/main/java/forge/fraud/FraudScorer.java +27 -0
  380. package/dist/packages/extractors/dialects/fixtures/quarkus-reactive-messaging/fraud-service/src/main/resources/application.properties +4 -0
  381. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/api.tf +38 -0
  382. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/main.tf +95 -0
  383. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/terraform.tfvars +1 -0
  384. package/dist/packages/extractors/dialects/fixtures/terraform-aws/forge-aws-infra/envs/prod/variables.tf +4 -0
  385. package/dist/packages/extractors/dialects/fixtures/terraform-azure/forge-azure-infra/main.tf +102 -0
  386. package/dist/packages/extractors/dialects/fixtures/terraform-gcp/forge-gcp-infra/main.tf +51 -0
  387. package/dist/packages/extractors/dialects/harness.yaml +101 -0
  388. package/dist/packages/extractors/dialects/jaxrs.yaml +155 -0
  389. package/dist/packages/extractors/dialects/micronaut.yaml +207 -0
  390. package/dist/packages/extractors/dialects/quarkus-reactive-messaging.yaml +158 -0
  391. package/dist/packages/extractors/dialects/tekton.yaml +71 -0
  392. package/dist/packages/extractors/dialects/terraform-aws.yaml +267 -0
  393. package/dist/packages/extractors/dialects/terraform-azure.yaml +212 -0
  394. package/dist/packages/extractors/dialects/terraform-gcp.yaml +109 -0
  395. package/dist/packages/extractors/grammars/README.md +11 -0
  396. package/dist/packages/extractors/grammars/tree-sitter-groovy.LICENSE +21 -0
  397. package/dist/packages/extractors/grammars/tree-sitter-groovy.wasm +0 -0
  398. package/dist/packages/extractors/grammars/vendored.json +11 -0
  399. package/dist/packages/learn/lessons/architect-diagrams-and-code.yaml +69 -0
  400. package/dist/packages/learn/lessons/business-analyst-story-bar.yaml +94 -0
  401. package/dist/packages/learn/lessons/delivery-lead-release-readiness.yaml +44 -0
  402. package/dist/packages/learn/lessons/designer-features-in-user-words.yaml +57 -0
  403. package/dist/packages/learn/lessons/developer-find-your-way.yaml +60 -0
  404. package/dist/packages/learn/lessons/everyone-first-hour.yaml +74 -0
  405. package/dist/packages/learn/lessons/platform-lead-coverage-and-defences.yaml +58 -0
  406. package/dist/packages/learn/lessons/product-owner-first-change.yaml +167 -0
  407. package/dist/packages/learn/lessons/qa-tests-and-trace.yaml +53 -0
  408. package/dist/packages/learn/lessons/team-lead-initiative.yaml +146 -0
  409. package/dist/packages/naysayer/constitution/constitution.yaml +305 -0
  410. package/dist/packages/naysayer/starter/review.yaml +256 -0
  411. package/dist/packages/sdk/npm/index.js +10097 -0
  412. package/dist/packages/speckit/rules/drift.yaml +78 -0
  413. package/dist/packages/taskrun/rules/conform.yaml +38 -0
  414. package/dist/packages/testgen/rules/trace.yaml +49 -0
  415. package/dist/packages/ui/dist/assets/elk-api-DDup23Us.js +2 -0
  416. package/dist/packages/ui/dist/assets/elk-worker.min--dAJroGl.js +6401 -0
  417. package/dist/packages/ui/dist/assets/elk-worker.min-DdYmS5kP.js +2 -0
  418. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-400-normal-BTotfTJu.woff +0 -0
  419. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-400-normal-DZqxrq2p.woff2 +0 -0
  420. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-500-normal-ByOcLdNv.woff +0 -0
  421. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-500-normal-CocWQlwt.woff2 +0 -0
  422. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-600-normal-71GNu3SW.woff2 +0 -0
  423. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-600-normal-BGq0mW3O.woff +0 -0
  424. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-400-normal-Dsrv2Tcn.woff +0 -0
  425. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-400-normal-g30qAdWV.woff2 +0 -0
  426. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-500-normal-Cs5J6C77.woff2 +0 -0
  427. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-500-normal-DB5PtV2g.woff +0 -0
  428. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-600-normal-Bz0x94Yp.woff +0 -0
  429. package/dist/packages/ui/dist/assets/ibm-plex-sans-cyrillic-ext-600-normal-DUMzJB7m.woff2 +0 -0
  430. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-400-normal-D9ESIMu3.woff +0 -0
  431. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-400-normal-_efipK4i.woff2 +0 -0
  432. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-500-normal-CuWXN6rf.woff +0 -0
  433. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-500-normal-JMMifIXV.woff2 +0 -0
  434. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-600-normal-D-CqTdkO.woff +0 -0
  435. package/dist/packages/ui/dist/assets/ibm-plex-sans-greek-600-normal-DzTrcv_p.woff2 +0 -0
  436. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  437. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  438. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  439. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  440. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  441. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  442. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-400-normal-C5H60-Va.woff2 +0 -0
  443. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-400-normal-RBey6euL.woff +0 -0
  444. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-500-normal-D0aIdm-b.woff +0 -0
  445. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-500-normal-DakdToA3.woff2 +0 -0
  446. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-600-normal-DIrixKbi.woff +0 -0
  447. package/dist/packages/ui/dist/assets/ibm-plex-sans-latin-ext-600-normal-DOrvGEcy.woff2 +0 -0
  448. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-400-normal-DG4YqDda.woff2 +0 -0
  449. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-400-normal-fK1oJ5dG.woff +0 -0
  450. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-500-normal-BEb3_waV.woff +0 -0
  451. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-500-normal-e4dixQRQ.woff2 +0 -0
  452. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-600-normal-DgdngZtN.woff +0 -0
  453. package/dist/packages/ui/dist/assets/ibm-plex-sans-vietnamese-600-normal-DpPYBSTl.woff2 +0 -0
  454. package/dist/packages/ui/dist/assets/index-C0JEkXyN.css +1 -0
  455. package/dist/packages/ui/dist/assets/index-mTOWhQZm.js +29 -0
  456. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  457. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  458. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  459. package/dist/packages/ui/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  460. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  461. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  462. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  463. package/dist/packages/ui/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  464. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  465. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  466. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  467. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  468. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  469. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  470. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  471. package/dist/packages/ui/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  472. package/dist/packages/ui/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  473. package/dist/packages/ui/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  474. package/dist/packages/ui/dist/assets/rajdhani-devanagari-600-normal-BtY48IV_.woff +0 -0
  475. package/dist/packages/ui/dist/assets/rajdhani-devanagari-600-normal-DhS7ScYx.woff2 +0 -0
  476. package/dist/packages/ui/dist/assets/rajdhani-devanagari-700-normal-BQQOj9BB.woff2 +0 -0
  477. package/dist/packages/ui/dist/assets/rajdhani-devanagari-700-normal-DBRwWuxA.woff +0 -0
  478. package/dist/packages/ui/dist/assets/rajdhani-latin-600-normal-CXCVEoA9.woff2 +0 -0
  479. package/dist/packages/ui/dist/assets/rajdhani-latin-600-normal-Dx02qI2_.woff +0 -0
  480. package/dist/packages/ui/dist/assets/rajdhani-latin-700-normal-BPDUZo87.woff2 +0 -0
  481. package/dist/packages/ui/dist/assets/rajdhani-latin-700-normal-e0Uj8ZlN.woff +0 -0
  482. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-600-normal-BleIgkPp.woff +0 -0
  483. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-600-normal-C9ZjJQAt.woff2 +0 -0
  484. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-700-normal-BPaQ7tlD.woff +0 -0
  485. package/dist/packages/ui/dist/assets/rajdhani-latin-ext-700-normal-S6aYESQK.woff2 +0 -0
  486. package/dist/packages/ui/dist/favicon.svg +1 -0
  487. package/dist/packages/ui/dist/index.html +15 -0
  488. package/dist/third-party.json +575 -0
  489. package/dist/vendor/@fission-ai/openspec/bin/openspec.js +85986 -0
  490. package/dist/vendor/@fission-ai/openspec/package.json +82 -0
  491. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/schema.yaml +248 -0
  492. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/design.md +21 -0
  493. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/proposal.md +34 -0
  494. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/spec.md +13 -0
  495. package/dist/vendor/@fission-ai/openspec/schemas/spec-driven/templates/tasks.md +11 -0
  496. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-c_sharp.wasm +0 -0
  497. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-go.wasm +0 -0
  498. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-java.wasm +0 -0
  499. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-javascript.wasm +0 -0
  500. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-kotlin.wasm +0 -0
  501. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-php.wasm +0 -0
  502. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-python.wasm +0 -0
  503. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-ruby.wasm +0 -0
  504. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-rust.wasm +0 -0
  505. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-scala.wasm +0 -0
  506. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-tsx.wasm +0 -0
  507. package/dist/vendor/tree-sitter-wasms/out/tree-sitter-typescript.wasm +0 -0
  508. package/dist/vendor/web-tree-sitter/tree-sitter.wasm +0 -0
  509. package/package.json +36 -3
@@ -0,0 +1,1726 @@
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
+ ManualStep,
8
+ changesDirOf,
9
+ external_exports,
10
+ require_dist,
11
+ toCanonicalYaml
12
+ } from "./chunk-JMOLB347.js";
13
+ import {
14
+ __toESM
15
+ } from "./chunk-TV45EUGM.js";
16
+
17
+ // packages/adapters/dist/work-item-csv.js
18
+ var ADO_COLUMNS = [
19
+ "ID",
20
+ "Work Item Type",
21
+ "Title 1",
22
+ "Title 2",
23
+ "Description",
24
+ "Acceptance Criteria",
25
+ "Tags",
26
+ "Area Path",
27
+ "Iteration Path"
28
+ ];
29
+ var JIRA_COLUMNS = [
30
+ "Issue Id",
31
+ "Issue Type",
32
+ "Summary",
33
+ "Description",
34
+ "Acceptance Criteria",
35
+ "Parent",
36
+ "Labels"
37
+ ];
38
+ var html = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
39
+ var ul = (xs) => xs.length ? `<ul>${xs.map((x) => `<li>${html(x)}</li>`).join("")}</ul>` : "";
40
+ var p = (s) => `<p>${html(s)}</p>`;
41
+ var csvCell = (v) => /[",\r\n]/.test(v) ? `"${v.replace(/"/g, '""')}"` : v;
42
+ var csvRow = (cells) => cells.map(csvCell).join(",");
43
+ var storyRef = (s) => `Change ${s.change}, repo ${s.repo}, flow ${s.flow}. The story in full: ${s.file}.`;
44
+ var promptRef = (t) => `Prompt for Copilot or Claude Code: ${t.prompt}; run it with ${t.run}.`;
45
+ function workItemRows(stories, o = {}) {
46
+ const rows = [];
47
+ let issue = 0;
48
+ for (const s of stories) {
49
+ const tags = [s.change, s.repo, ...o.tags ?? []];
50
+ const parent = ++issue;
51
+ if ((o.format ?? "ado") === "ado") {
52
+ const common = {
53
+ ID: "",
54
+ Tags: tags.join("; "),
55
+ "Area Path": o.areaPath ?? "",
56
+ "Iteration Path": o.iterationPath ?? ""
57
+ };
58
+ rows.push({
59
+ ...common,
60
+ "Work Item Type": "User Story",
61
+ "Title 1": s.title,
62
+ "Title 2": "",
63
+ Description: [p(s.statement), ...s.context ? [p(s.context)] : [], p(storyRef(s))].join(""),
64
+ "Acceptance Criteria": ul(s.criteria)
65
+ });
66
+ for (const t of s.tasks)
67
+ rows.push({
68
+ ...common,
69
+ "Work Item Type": "Task",
70
+ "Title 1": "",
71
+ "Title 2": `${t.label} ${t.title}`,
72
+ Description: [
73
+ ul(t.steps),
74
+ ...t.places.length ? [p(`Where: ${t.places.join(", ")}.`)] : [],
75
+ ...t.fields.length ? [p(`Fields: ${t.fields.join(", ")}.`)] : [],
76
+ p(promptRef(t))
77
+ ].join(""),
78
+ "Acceptance Criteria": ul(t.criteria)
79
+ });
80
+ } else {
81
+ const labels = tags.map((x) => x.replace(/\s+/g, "-")).join(" ");
82
+ rows.push({
83
+ "Issue Id": String(parent),
84
+ "Issue Type": "Story",
85
+ Summary: s.title,
86
+ Description: [s.statement, s.context, storyRef(s)].filter(Boolean).join("\n\n"),
87
+ "Acceptance Criteria": s.criteria.map((c) => `* ${c}`).join("\n"),
88
+ Parent: "",
89
+ Labels: labels
90
+ });
91
+ for (const t of s.tasks)
92
+ rows.push({
93
+ "Issue Id": String(++issue),
94
+ "Issue Type": "Sub-task",
95
+ Summary: `${t.label} ${t.title}`,
96
+ Description: [
97
+ t.steps.map((x) => `* ${x}`).join("\n"),
98
+ t.places.length ? `Where: ${t.places.join(", ")}.` : "",
99
+ t.fields.length ? `Fields: ${t.fields.join(", ")}.` : "",
100
+ promptRef(t)
101
+ ].filter(Boolean).join("\n\n"),
102
+ "Acceptance Criteria": t.criteria.map((c) => `* ${c}`).join("\n"),
103
+ Parent: String(parent),
104
+ Labels: labels
105
+ });
106
+ }
107
+ }
108
+ return rows;
109
+ }
110
+ function workItemsCsv(stories, o = {}) {
111
+ const columns = (o.format ?? "ado") === "ado" ? ADO_COLUMNS : JIRA_COLUMNS;
112
+ return [
113
+ csvRow([...columns]),
114
+ ...workItemRows(stories, o).map((r) => csvRow(columns.map((c) => r[c] ?? "")))
115
+ ].map((l) => `${l}\r
116
+ `).join("");
117
+ }
118
+
119
+ // packages/adapters/dist/manual/steps.js
120
+ var import_yaml = __toESM(require_dist(), 1);
121
+ import { createHash } from "node:crypto";
122
+ import { mkdir, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
123
+ import { dirname, join } from "node:path";
124
+ var LEADING = [
125
+ "schemaVersion",
126
+ "id",
127
+ "change",
128
+ "system",
129
+ "action",
130
+ "state",
131
+ "title",
132
+ "where",
133
+ "key",
134
+ "name",
135
+ "label",
136
+ "value",
137
+ "format"
138
+ ];
139
+ function serializeStep(step) {
140
+ return toCanonicalYaml(ManualStep.parse(step), LEADING);
141
+ }
142
+ var slugify = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/, "") || "step";
143
+ var shortHash = (s) => createHash("sha256").update(s, "utf8").digest("hex").slice(0, 8);
144
+ var nowIso = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
145
+ function matches(s, f = {}) {
146
+ return (!f.change || s.change === f.change) && (!f.state || s.state === f.state) && (!f.system || s.system === f.system) && (!f.action || s.action === f.action);
147
+ }
148
+ var byCreated = (a, b) => a.createdAt === b.createdAt ? a.id < b.id ? -1 : 1 : a.createdAt < b.createdAt ? -1 : 1;
149
+ function build(step, id) {
150
+ const { slug: _slug, createdAt, ...rest } = step;
151
+ return ManualStep.parse({
152
+ schemaVersion: 1,
153
+ ...rest,
154
+ id,
155
+ createdAt: createdAt ?? nowIso(),
156
+ state: "open",
157
+ runs: []
158
+ });
159
+ }
160
+ function uniqueId(slug, taken) {
161
+ const base = slugify(slug);
162
+ if (!taken.has(base))
163
+ return base;
164
+ for (let n = 2; ; n++)
165
+ if (!taken.has(`${base}-${n}`))
166
+ return `${base}-${n}`;
167
+ }
168
+ async function writeAtomic(path, text) {
169
+ await mkdir(dirname(path), { recursive: true });
170
+ const tmp = `${path}.tmp`;
171
+ try {
172
+ await writeFile(tmp, text, "utf8");
173
+ await rename(tmp, path);
174
+ } catch (e) {
175
+ await rm(tmp, { force: true });
176
+ throw e;
177
+ }
178
+ }
179
+ var StepFileError = class extends Error {
180
+ path;
181
+ constructor(message, path) {
182
+ super(message);
183
+ this.path = path;
184
+ this.name = "StepFileError";
185
+ }
186
+ };
187
+ function fileStepStore(root) {
188
+ const dirFor = (change) => change ? join(changesDirOf(root), change, "steps") : join(root, "steps");
189
+ const pathOf = (s) => join(dirFor(s.change), `${s.id}.yaml`);
190
+ async function folders() {
191
+ const out = [join(root, "steps")];
192
+ try {
193
+ for (const d of await readdir(changesDirOf(root), { withFileTypes: true }))
194
+ if (d.isDirectory() && d.name !== "archive")
195
+ out.push(join(changesDirOf(root), d.name, "steps"));
196
+ } catch {
197
+ }
198
+ return out;
199
+ }
200
+ const cache = /* @__PURE__ */ new Map();
201
+ async function readAll() {
202
+ const out = [];
203
+ for (const dir of await folders()) {
204
+ let names;
205
+ try {
206
+ names = (await readdir(dir)).filter((n) => n.endsWith(".yaml")).sort();
207
+ } catch {
208
+ continue;
209
+ }
210
+ for (const n of names) {
211
+ const path = join(dir, n);
212
+ const st = await stat(path);
213
+ const hit = cache.get(path);
214
+ if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {
215
+ out.push(structuredClone(hit.step));
216
+ continue;
217
+ }
218
+ let data;
219
+ try {
220
+ data = (0, import_yaml.parse)(await readFile(path, "utf8"));
221
+ } catch (e) {
222
+ throw new StepFileError(`${path}: invalid YAML: ${e.message}`, path);
223
+ }
224
+ const r = ManualStep.safeParse(data);
225
+ if (!r.success)
226
+ throw new StepFileError(`${path}: ${r.error.issues.map((i) => `${i.path.join(".") || "(file)"}: ${i.message}`).join("; ")}`, path);
227
+ cache.set(path, { mtimeMs: st.mtimeMs, size: st.size, step: r.data });
228
+ out.push(structuredClone(r.data));
229
+ }
230
+ }
231
+ return out.sort(byCreated);
232
+ }
233
+ return {
234
+ pathOf,
235
+ async create(step) {
236
+ const all = await readAll();
237
+ const found = all.find((s2) => s2.key === step.key);
238
+ if (found)
239
+ return found;
240
+ const s = build(step, uniqueId(step.slug, new Set(all.map((x) => x.id))));
241
+ await writeAtomic(pathOf(s), serializeStep(s));
242
+ cache.delete(pathOf(s));
243
+ return s;
244
+ },
245
+ async get(id) {
246
+ return (await readAll()).find((s) => s.id === id);
247
+ },
248
+ async byKey(key) {
249
+ return (await readAll()).find((s) => s.key === key);
250
+ },
251
+ async list(filter) {
252
+ return (await readAll()).filter((s) => matches(s, filter));
253
+ },
254
+ async save(step) {
255
+ const s = ManualStep.parse(step);
256
+ await writeAtomic(pathOf(s), serializeStep(s));
257
+ cache.delete(pathOf(s));
258
+ return s;
259
+ }
260
+ };
261
+ }
262
+ var HANDLE = /^@?[A-Za-z0-9][A-Za-z0-9._/-]*$/;
263
+ function checkValue(field, raw) {
264
+ const bad = (problem) => ({ ok: false, problem: `${field.label}: ${problem}` });
265
+ if (field.format === "handles") {
266
+ const list = Array.isArray(raw) ? raw.map(String) : String(raw ?? "").split(/[\s,;]+/).filter(Boolean);
267
+ const wrong = list.filter((h) => !HANDLE.test(h));
268
+ if (wrong.length)
269
+ return bad(`${wrong.join(", ")} isn't a handle such as pat`);
270
+ return { ok: true, value: list.map((h) => h.replace(/^@/, "")) };
271
+ }
272
+ if (typeof raw === "boolean" && field.format === "yes-no")
273
+ return { ok: true, value: raw };
274
+ if (typeof raw === "number" && (field.format === "number" || field.format === "integer")) {
275
+ if (field.format === "integer" && !Number.isInteger(raw))
276
+ return bad("a whole number");
277
+ return { ok: true, value: raw };
278
+ }
279
+ const s = String(raw ?? "").trim();
280
+ if (!s)
281
+ return bad("empty");
282
+ switch (field.format) {
283
+ case "text":
284
+ return { ok: true, value: s };
285
+ case "url":
286
+ try {
287
+ const u = new URL(s);
288
+ if (u.protocol !== "https:" && u.protocol !== "http:")
289
+ return bad("an http(s) link");
290
+ return { ok: true, value: s };
291
+ } catch {
292
+ return bad(`${s} isn't a link`);
293
+ }
294
+ case "number":
295
+ case "integer": {
296
+ const n = Number(s);
297
+ if (!Number.isFinite(n))
298
+ return bad(`${s} isn't a number`);
299
+ if (field.format === "integer" && !Number.isInteger(n))
300
+ return bad(`${s} isn't a whole number`);
301
+ return { ok: true, value: n };
302
+ }
303
+ case "date":
304
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(s) || Number.isNaN(Date.parse(s)))
305
+ return bad(`${s} isn't a date such as 2026-10-21`);
306
+ return { ok: true, value: s };
307
+ case "yes-no": {
308
+ const k = s.toLowerCase();
309
+ if (["yes", "y", "true"].includes(k))
310
+ return { ok: true, value: true };
311
+ if (["no", "n", "false"].includes(k))
312
+ return { ok: true, value: false };
313
+ return bad("yes or no");
314
+ }
315
+ case "pattern":
316
+ return new RegExp(`^(?:${field.pattern})$`).test(s) ? { ok: true, value: s } : bad(`${s} doesn't look right (expected ${field.help ?? field.pattern})`);
317
+ case "choice":
318
+ return field.choices?.includes(s) ? { ok: true, value: s } : bad(`one of ${field.choices?.join(", ")}`);
319
+ }
320
+ }
321
+ function checkResult(step, values) {
322
+ const out = {};
323
+ const problems = [];
324
+ const known = new Set(step.result.map((f) => f.name));
325
+ for (const k of Object.keys(values))
326
+ if (!known.has(k))
327
+ problems.push(`${k} isn't asked for here${known.size ? ` (record ${[...known].join(", ")})` : ""}`);
328
+ for (const f of step.result) {
329
+ const raw = values[f.name];
330
+ if (raw === void 0 || raw === "") {
331
+ if (f.required)
332
+ problems.push(`${f.label}: required`);
333
+ continue;
334
+ }
335
+ const r = checkValue(f, raw);
336
+ if (r.ok)
337
+ out[f.name] = r.value;
338
+ else
339
+ problems.push(r.problem);
340
+ }
341
+ return { values: out, problems };
342
+ }
343
+ var StepError = class extends Error {
344
+ code;
345
+ problems;
346
+ constructor(code, message, problems = []) {
347
+ super(message);
348
+ this.code = code;
349
+ this.problems = problems;
350
+ this.name = "StepError";
351
+ }
352
+ };
353
+ async function recordStep(store, id, o) {
354
+ const step = await store.get(id);
355
+ if (!step)
356
+ throw new StepError("not-found", `There is no step ${id}.`);
357
+ if (step.state !== "open")
358
+ throw new StepError("refused", `Step ${id} is already ${step.state}.`);
359
+ if (o.skip) {
360
+ if (!o.note?.trim())
361
+ throw new StepError("invalid", `Say why step ${id} is skipped.`);
362
+ return store.save({
363
+ ...step,
364
+ state: "skipped",
365
+ recorded: {
366
+ at: o.at ?? nowIso(),
367
+ by: o.by.replace(/^@/, ""),
368
+ values: {},
369
+ via: "person",
370
+ evidence: [],
371
+ note: o.note
372
+ }
373
+ });
374
+ }
375
+ for (const d of step.dependsOn) {
376
+ const dep = await store.get(d);
377
+ if (dep && dep.state === "open")
378
+ throw new StepError("refused", `Do step ${d} first: step ${id} depends on it.`);
379
+ }
380
+ const r = checkResult(step, o.values ?? {});
381
+ if (r.problems.length)
382
+ throw new StepError("invalid", `The result for step ${id} isn't valid.`, r.problems);
383
+ return store.save({
384
+ ...step,
385
+ state: "done",
386
+ recorded: {
387
+ at: o.at ?? nowIso(),
388
+ by: o.by.replace(/^@/, ""),
389
+ values: r.values,
390
+ via: o.via ?? "person",
391
+ ...o.executor ? { executor: o.executor } : {},
392
+ evidence: o.evidence ?? [],
393
+ ...o.note ? { note: o.note } : {}
394
+ }
395
+ });
396
+ }
397
+ var stepApproval = (a) => ({
398
+ by: a.by.replace(/^@/, ""),
399
+ at: a.at,
400
+ ref: a.ref
401
+ });
402
+ var csvCell2 = (s) => /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
403
+ var csvRow2 = (cells) => cells.map(csvCell2).join(",");
404
+ var WORK_ITEM_COLUMNS = [
405
+ ["Work Item Type", "Work item type"],
406
+ ["Title", "Title"],
407
+ ["Description", "Description"],
408
+ ["Acceptance Criteria", "Acceptance criteria"],
409
+ ["Parent", "Parent"],
410
+ ["Tags", "Tags"],
411
+ ["Assigned To", "Assigned to"]
412
+ ];
413
+ function exportStep(step, format) {
414
+ const field = (n) => step.fields.find((f) => f.name.toLowerCase() === n.toLowerCase())?.value ?? "";
415
+ if (format === "csv")
416
+ return {
417
+ format: "csv",
418
+ fileName: `${step.id}.csv`,
419
+ text: [csvRow2(["Field", "Value"]), ...step.fields.map((f) => csvRow2([f.name, f.value]))].join("\n") + "\n"
420
+ };
421
+ if (format === "import" && step.system === "work-tracker" && step.action === "create-work-item")
422
+ return {
423
+ format: "work-item-csv",
424
+ fileName: `${step.id}.csv`,
425
+ text: [
426
+ csvRow2(WORK_ITEM_COLUMNS.map(([c]) => c)),
427
+ csvRow2(WORK_ITEM_COLUMNS.map(([, f]) => field(f)))
428
+ ].join("\n") + "\n"
429
+ };
430
+ if (format === "import" && step.system === "service-desk" && step.action === "submit-request")
431
+ return {
432
+ format: "request-json",
433
+ fileName: `${step.id}.json`,
434
+ text: JSON.stringify({
435
+ requestType: field("Request type"),
436
+ fields: Object.fromEntries(step.fields.filter((f) => f.name !== "Request type").map((f) => [f.name, f.value]))
437
+ }, null, 2) + "\n"
438
+ };
439
+ const lines = [
440
+ `Step ${step.id}: ${step.title}`,
441
+ `Where: ${step.where}`,
442
+ ...step.reason ? [`Why it is manual: ${step.reason}`] : [],
443
+ ...step.dependsOn.length ? [`Do first: ${step.dependsOn.join(", ")}`] : [],
444
+ "",
445
+ ...step.instructions.length ? ["Steps:", ...step.instructions.map((s, i) => `${i + 1}. ${s}`), ""] : [],
446
+ ...step.fields.length ? ["Fields:", ...step.fields.map((f) => `${f.name}: ${f.value}`), ""] : [],
447
+ ...step.result.length ? [
448
+ "Record back:",
449
+ ...step.result.map((f) => `- ${f.label}${f.required ? "" : " (optional)"}: atticus todo done ${step.id} --result ${f.name}=\u2026`)
450
+ ] : [`When done: atticus todo done ${step.id}`]
451
+ ];
452
+ return {
453
+ format: "text",
454
+ fileName: `${step.id}.txt`,
455
+ text: lines.join("\n").replace(/\n+$/, "") + "\n"
456
+ };
457
+ }
458
+
459
+ // packages/adapters/dist/common.js
460
+ var Approval = external_exports.strictObject({
461
+ /** The person who approved: a handle from the Git host or directory. */
462
+ by: external_exports.string().min(1),
463
+ at: external_exports.iso.datetime({ offset: true }),
464
+ scope: external_exports.enum(["once", "standing"]).default("once"),
465
+ /** What was approved, e.g. a finding, hand-off PR or artifact path. */
466
+ ref: external_exports.string().min(1)
467
+ });
468
+ var AdapterError = class extends Error {
469
+ adapter;
470
+ code;
471
+ retryable;
472
+ constructor(adapter, code, message, retryable = code === "rate-limited" || code === "unavailable") {
473
+ super(`${adapter}: ${message}`);
474
+ this.adapter = adapter;
475
+ this.code = code;
476
+ this.retryable = retryable;
477
+ this.name = "AdapterError";
478
+ }
479
+ };
480
+ function requireApproval(adapter, approval, opts = {}) {
481
+ const r = Approval.safeParse(approval);
482
+ if (!r.success) {
483
+ throw new AdapterError(adapter, "not-approved", "this write needs a person's approval (by, at, ref)");
484
+ }
485
+ if (r.data.scope === "standing" && !opts.allowStanding) {
486
+ throw new AdapterError(adapter, "not-approved", "a standing approval can't cover this write; it needs approval each time");
487
+ }
488
+ return r.data;
489
+ }
490
+ var MockBase = class {
491
+ name;
492
+ journal = [];
493
+ failures = [];
494
+ constructor(name) {
495
+ this.name = name;
496
+ }
497
+ failNext(code, method) {
498
+ this.failures.push(method === void 0 ? { code } : { code, method });
499
+ }
500
+ /** Record a call and raise an injected failure if one is due. */
501
+ call(method, args, approval) {
502
+ const i = this.failures.findIndex((f) => f.method === void 0 || f.method === method);
503
+ if (i !== -1) {
504
+ const [f] = this.failures.splice(i, 1);
505
+ throw new AdapterError(this.name, f.code, `injected ${f.code} on ${method}`);
506
+ }
507
+ this.journal.push(approval ? { adapter: this.name, method, args, approval } : { adapter: this.name, method, args });
508
+ }
509
+ notFound(what) {
510
+ throw new AdapterError(this.name, "not-found", `${what} not found`);
511
+ }
512
+ };
513
+
514
+ // packages/adapters/dist/git-host.js
515
+ function mergeBlockers(pr) {
516
+ const out = [];
517
+ if (pr.state === "merged" || pr.state === "closed")
518
+ out.push(`the PR is ${pr.state}`);
519
+ if (pr.state === "draft")
520
+ out.push("the PR is a draft");
521
+ const latest = /* @__PURE__ */ new Map();
522
+ for (const r of pr.reviews)
523
+ if (r.state !== "commented")
524
+ latest.set(r.by, r.state);
525
+ if ([...latest.values()].includes("changes-requested"))
526
+ out.push("changes are requested");
527
+ const missing = pr.requiredReviewers.filter((r) => latest.get(r) !== "approved");
528
+ if (pr.requiredReviewers.length > 0 && missing.length === pr.requiredReviewers.length) {
529
+ out.push(`needs approval from ${pr.requiredReviewers.join(" or ")}`);
530
+ }
531
+ if (pr.requiredReviewers.length === 0 && ![...latest.values()].includes("approved"))
532
+ out.push("needs at least one approval");
533
+ const failing = pr.checks.filter((c) => c.status !== "passed").map((c) => `${c.name} ${c.status}`);
534
+ if (failing.length > 0)
535
+ out.push(`checks not passing: ${failing.join(", ")}`);
536
+ return out;
537
+ }
538
+ var MockGitHost = class extends MockBase {
539
+ repos = /* @__PURE__ */ new Map();
540
+ prs = /* @__PURE__ */ new Map();
541
+ numbers = /* @__PURE__ */ new Map();
542
+ constructor(repos = []) {
543
+ super("git-host");
544
+ for (const r of repos) {
545
+ const defaultBranch = r.defaultBranch ?? "main";
546
+ this.repos.set(r.repo, {
547
+ repo: r.repo,
548
+ defaultBranch,
549
+ protectedBranches: r.protectedBranches ?? [defaultBranch]
550
+ });
551
+ }
552
+ }
553
+ key = (repo, n) => `${repo}#${n}`;
554
+ async getRepo(repo) {
555
+ this.call("getRepo", [repo]);
556
+ return { ...this.repos.get(repo) ?? this.notFound(`repo ${repo}`) };
557
+ }
558
+ async getPullRequest(repo, number) {
559
+ this.call("getPullRequest", [repo, number]);
560
+ return structuredClone(this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`));
561
+ }
562
+ async listPullRequests(repo, q) {
563
+ this.call("listPullRequests", [repo, q]);
564
+ return [...this.prs.values()].filter((p2) => p2.repo === repo && (!q.head || p2.head === q.head) && (!q.state || p2.state === q.state)).map((p2) => structuredClone(p2));
565
+ }
566
+ async createPullRequest(input, approval) {
567
+ const a = requireApproval(this.name, approval);
568
+ this.call("createPullRequest", [input], a);
569
+ const info = this.repos.get(input.repo) ?? this.notFound(`repo ${input.repo}`);
570
+ if (info.protectedBranches.includes(input.head)) {
571
+ throw new AdapterError(this.name, "invalid", `${input.head} is protected and can't be a PR's source branch`);
572
+ }
573
+ if ([...this.prs.values()].some((p2) => p2.repo === input.repo && p2.head === input.head && (p2.state === "open" || p2.state === "draft"))) {
574
+ throw new AdapterError(this.name, "conflict", `an open PR from ${input.head} already exists`);
575
+ }
576
+ const n = (this.numbers.get(input.repo) ?? 0) + 1;
577
+ this.numbers.set(input.repo, n);
578
+ const pr = {
579
+ repo: input.repo,
580
+ number: n,
581
+ url: `https://git.example.com/${input.repo}/pull/${n}`,
582
+ title: input.title,
583
+ body: input.body,
584
+ head: input.head,
585
+ base: input.base,
586
+ state: input.draft ? "draft" : "open",
587
+ reviews: [],
588
+ checks: [],
589
+ requiredReviewers: []
590
+ };
591
+ this.prs.set(this.key(input.repo, n), pr);
592
+ return structuredClone(pr);
593
+ }
594
+ async comment(repo, number, body, approval) {
595
+ const a = requireApproval(this.name, approval);
596
+ this.call("comment", [repo, number, body], a);
597
+ if (!this.prs.has(this.key(repo, number)))
598
+ this.notFound(`PR ${repo}#${number}`);
599
+ }
600
+ async merge(repo, number, approval) {
601
+ const a = requireApproval(this.name, approval);
602
+ this.call("merge", [repo, number], a);
603
+ const pr = this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`);
604
+ const blockers = mergeBlockers(pr);
605
+ if (blockers.length > 0)
606
+ throw new AdapterError(this.name, "conflict", `can't merge: ${blockers.join("; ")}`);
607
+ pr.state = "merged";
608
+ return structuredClone(pr);
609
+ }
610
+ async closePullRequest(repo, number, approval) {
611
+ const a = requireApproval(this.name, approval);
612
+ this.call("closePullRequest", [repo, number], a);
613
+ const pr = this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`);
614
+ if (pr.state === "merged")
615
+ throw new AdapterError(this.name, "conflict", `PR ${number} is merged and can't be closed`);
616
+ pr.state = "closed";
617
+ return structuredClone(pr);
618
+ }
619
+ /** Test helpers: what reviewers and CI would do on the host. */
620
+ review(repo, number, by, state) {
621
+ (this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`)).reviews.push({
622
+ by,
623
+ state
624
+ });
625
+ }
626
+ setChecks(repo, number, checks) {
627
+ (this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`)).checks = checks;
628
+ }
629
+ requireReviewers(repo, number, reviewers) {
630
+ (this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`)).requiredReviewers = reviewers;
631
+ }
632
+ markReady(repo, number) {
633
+ const pr = this.prs.get(this.key(repo, number)) ?? this.notFound(`PR ${repo}#${number}`);
634
+ if (pr.state === "draft")
635
+ pr.state = "open";
636
+ }
637
+ };
638
+
639
+ // packages/adapters/dist/read-only.js
640
+ var MockWiki = class extends MockBase {
641
+ pages = /* @__PURE__ */ new Map();
642
+ constructor(seed = []) {
643
+ super("wiki");
644
+ for (const p2 of seed)
645
+ this.pages.set(p2.id, { ...p2 });
646
+ }
647
+ head = ({ body: _b, ...rest }) => rest;
648
+ async listPages(space) {
649
+ this.call("listPages", [space]);
650
+ return [...this.pages.values()].filter((p2) => p2.space === space).map(this.head);
651
+ }
652
+ async getPage(id) {
653
+ this.call("getPage", [id]);
654
+ return { ...this.pages.get(id) ?? this.notFound(`page ${id}`) };
655
+ }
656
+ async search(text) {
657
+ this.call("search", [text]);
658
+ const t = text.toLowerCase();
659
+ return [...this.pages.values()].filter((p2) => p2.title.toLowerCase().includes(t) || p2.body.toLowerCase().includes(t)).map(this.head);
660
+ }
661
+ };
662
+ var MockDesignTool = class extends MockBase {
663
+ files = /* @__PURE__ */ new Map();
664
+ constructor(seed = []) {
665
+ super("design-tool");
666
+ for (const f of seed)
667
+ this.files.set(f.key, structuredClone(f));
668
+ }
669
+ async getFile(key) {
670
+ this.call("getFile", [key]);
671
+ return structuredClone(this.files.get(key) ?? this.notFound(`design file ${key}`));
672
+ }
673
+ async renderFrame(key, frameId) {
674
+ this.call("renderFrame", [key, frameId]);
675
+ const file = this.files.get(key) ?? this.notFound(`design file ${key}`);
676
+ if (!file.pages.some((p2) => p2.frames.some((f) => f.id === frameId)))
677
+ this.notFound(`frame ${frameId}`);
678
+ return new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
679
+ }
680
+ };
681
+ var MockNotifier = class extends MockBase {
682
+ channels;
683
+ sent = [];
684
+ constructor(channels = []) {
685
+ super("notify");
686
+ this.channels = channels;
687
+ }
688
+ async send(n, approval) {
689
+ const a = requireApproval(this.name, approval, { allowStanding: true });
690
+ this.call("send", [n], a);
691
+ if (this.channels.length > 0 && !this.channels.includes(n.channel)) {
692
+ throw new AdapterError(this.name, "invalid", `unknown channel ${n.channel}`);
693
+ }
694
+ const id = `msg-${this.sent.length + 1}`;
695
+ this.sent.push({ ...n, id });
696
+ return { id };
697
+ }
698
+ };
699
+
700
+ // packages/adapters/dist/service-desk.js
701
+ var MockServiceDesk = class _MockServiceDesk extends MockBase {
702
+ requests = /* @__PURE__ */ new Map();
703
+ next = 1;
704
+ constructor(seed = []) {
705
+ super("service-desk");
706
+ for (const r of seed)
707
+ this.requests.set(r.id, { ...r });
708
+ this.next = seed.length + 1;
709
+ }
710
+ /** Load the shape the fixture's closed-requests export uses. */
711
+ static fromExport(rows) {
712
+ return new _MockServiceDesk(rows.map((r) => ({
713
+ id: r.number,
714
+ type: r.type,
715
+ state: r.closed ? "done" : "submitted",
716
+ fields: r.fields,
717
+ ...r.approvalGroup ? { approvalGroup: r.approvalGroup } : {},
718
+ ...r.opened ? { openedAt: r.opened } : {},
719
+ ...r.closed ? { closedAt: r.closed } : {},
720
+ url: `https://desk.example.com/requests/${r.number}`
721
+ })));
722
+ }
723
+ async getRequest(id) {
724
+ this.call("getRequest", [id]);
725
+ return { ...this.requests.get(id) ?? this.notFound(`request ${id}`) };
726
+ }
727
+ async listRequests(q) {
728
+ this.call("listRequests", [q]);
729
+ return [...this.requests.values()].filter((r) => (!q.changeId || r.changeId === q.changeId) && (!q.state || r.state === q.state) && (!q.type || r.type === q.type)).map((r) => ({ ...r }));
730
+ }
731
+ async submitRequest(draft, approval) {
732
+ const a = requireApproval(this.name, approval);
733
+ this.call("submitRequest", [draft], a);
734
+ const empty = Object.entries(draft.fields).filter(([, v]) => v === "").map(([k]) => k);
735
+ if (empty.length > 0)
736
+ throw new AdapterError(this.name, "invalid", `required fields are empty: ${empty.join(", ")}`);
737
+ const id = `SR-${String(this.next++).padStart(4, "0")}`;
738
+ const r = {
739
+ id,
740
+ type: draft.type,
741
+ state: "submitted",
742
+ fields: { ...draft.fields },
743
+ changeId: draft.changeId,
744
+ openedAt: a.at.slice(0, 10),
745
+ url: `https://desk.example.com/requests/${id}`
746
+ };
747
+ this.requests.set(id, r);
748
+ return { ...r };
749
+ }
750
+ /** Test helper: move a request along as the service desk would. */
751
+ setState(id, state, closedAt) {
752
+ const r = this.requests.get(id) ?? this.notFound(`request ${id}`);
753
+ r.state = state;
754
+ if (closedAt)
755
+ r.closedAt = closedAt;
756
+ }
757
+ };
758
+
759
+ // packages/adapters/dist/work-tracker.js
760
+ var MockWorkTracker = class _MockWorkTracker extends MockBase {
761
+ items = /* @__PURE__ */ new Map();
762
+ links = [];
763
+ next = 1e3;
764
+ constructor(seed = []) {
765
+ super("work-tracker");
766
+ for (const i of seed)
767
+ this.items.set(i.id, { ...i });
768
+ }
769
+ /** Load the shape the fixture's ticket export uses. */
770
+ static fromExport(rows) {
771
+ const type = (t) => {
772
+ const k = t.toLowerCase();
773
+ if (k.includes("story"))
774
+ return "story";
775
+ if (k.includes("epic"))
776
+ return "epic";
777
+ if (k.includes("feature"))
778
+ return "feature";
779
+ if (k.includes("bug"))
780
+ return "bug";
781
+ return "task";
782
+ };
783
+ return new _MockWorkTracker(rows.map((r) => ({
784
+ id: String(r.id),
785
+ type: type(r.type),
786
+ title: r.title,
787
+ description: r.description ?? "",
788
+ acceptanceCriteria: r.acceptanceCriteria ?? "",
789
+ state: r.state ?? "New",
790
+ tags: [],
791
+ url: `https://work.example.com/items/${r.id}`
792
+ })));
793
+ }
794
+ async getItem(id) {
795
+ this.call("getItem", [id]);
796
+ return { ...this.items.get(id) ?? this.notFound(`work item ${id}`) };
797
+ }
798
+ async query(q) {
799
+ this.call("query", [q]);
800
+ const text = q.text?.toLowerCase();
801
+ return [...this.items.values()].filter((i) => (!q.type || i.type === q.type) && (!q.parent || i.parent === q.parent) && (!q.state || i.state === q.state) && (!q.tag || i.tags.includes(q.tag)) && (!text || i.title.toLowerCase().includes(text) || i.description.toLowerCase().includes(text))).map((i) => ({ ...i }));
802
+ }
803
+ async createItem(input, approval) {
804
+ const a = requireApproval(this.name, approval);
805
+ this.call("createItem", [input], a);
806
+ if (input.parent && !this.items.has(input.parent))
807
+ this.notFound(`parent ${input.parent}`);
808
+ const id = String(this.next++);
809
+ const item = {
810
+ id,
811
+ type: input.type,
812
+ title: input.title,
813
+ description: input.description ?? "",
814
+ acceptanceCriteria: input.acceptanceCriteria ?? "",
815
+ state: "New",
816
+ ...input.parent ? { parent: input.parent } : {},
817
+ ...input.assignee ? { assignee: input.assignee } : {},
818
+ tags: input.tags ?? [],
819
+ url: `https://work.example.com/items/${id}`
820
+ };
821
+ this.items.set(id, item);
822
+ return { ...item };
823
+ }
824
+ async updateItem(id, patch, approval) {
825
+ const a = requireApproval(this.name, approval);
826
+ this.call("updateItem", [id, patch], a);
827
+ const item = this.items.get(id) ?? this.notFound(`work item ${id}`);
828
+ const updated = {
829
+ ...item,
830
+ ...Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== void 0))
831
+ };
832
+ this.items.set(id, updated);
833
+ return { ...updated };
834
+ }
835
+ async link(from, to, kind, approval) {
836
+ const a = requireApproval(this.name, approval);
837
+ this.call("link", [from, to, kind], a);
838
+ if (!this.items.has(from))
839
+ this.notFound(`work item ${from}`);
840
+ if (!this.items.has(to))
841
+ this.notFound(`work item ${to}`);
842
+ this.links.push({ from, to, kind });
843
+ if (kind === "parent")
844
+ this.items.get(from).parent = to;
845
+ }
846
+ };
847
+
848
+ // packages/adapters/dist/manual/base.js
849
+ var nowIso2 = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
850
+ var PROVISIONAL = "manual:";
851
+ var provisionalId = (stepId) => `${PROVISIONAL}${stepId}`;
852
+ var stepOfProvisional = (id) => id.startsWith(PROVISIONAL) ? id.slice(PROVISIONAL.length) : void 0;
853
+ var ManualBase = class {
854
+ name;
855
+ system;
856
+ opts;
857
+ /** Set by the fallback wrapper while it hands one call to this adapter. */
858
+ reason;
859
+ journal = [];
860
+ constructor(name, system, opts) {
861
+ this.name = name;
862
+ this.system = system;
863
+ this.opts = opts;
864
+ }
865
+ now() {
866
+ return this.opts.now?.() ?? nowIso2();
867
+ }
868
+ setting(key) {
869
+ const v = this.opts.settings?.[key];
870
+ return typeof v === "string" ? v : void 0;
871
+ }
872
+ settingList(key) {
873
+ const v = this.opts.settings?.[key];
874
+ return Array.isArray(v) ? v : typeof v === "string" ? [v] : void 0;
875
+ }
876
+ approve(approval, o = {}) {
877
+ return requireApproval(this.name, approval, o);
878
+ }
879
+ /** The procedure (and step) for a kind of write, if the org pack has one. */
880
+ procedureFor(kind, o = {}) {
881
+ for (const p2 of this.opts.procedures ?? []) {
882
+ if (p2.status === "retired")
883
+ continue;
884
+ if (o.template && p2.template !== o.template)
885
+ continue;
886
+ if (!o.template && p2.system !== this.system)
887
+ continue;
888
+ const s = p2.steps.find((x) => x.kind === kind);
889
+ if (s)
890
+ return { procedure: p2.id, procedureStep: s.id };
891
+ }
892
+ return void 0;
893
+ }
894
+ async step(method, s, approval) {
895
+ const created = await this.opts.store.create({
896
+ ...s,
897
+ system: this.system,
898
+ createdBy: (s.createdBy ?? approval?.by ?? "atticus").replace(/^@/, ""),
899
+ createdAt: this.now(),
900
+ ...approval ? { approval: stepApproval(approval) } : {},
901
+ ...s.change ?? this.opts.change ? { change: s.change ?? this.opts.change } : {},
902
+ ...this.reason ? { reason: this.reason } : {}
903
+ });
904
+ this.journal.push({ method, step: created.id });
905
+ return created;
906
+ }
907
+ notFound(what, hint) {
908
+ throw new AdapterError(this.name, "not-found", `${what} not found: ${hint}`);
909
+ }
910
+ };
911
+
912
+ // packages/adapters/dist/manual/git-host.js
913
+ function changeOfBranch(branch) {
914
+ const m = /^(?:handoff|task|change)\/([a-z0-9][a-z0-9._-]*)(?:\/|$)/.exec(branch);
915
+ return m?.[1];
916
+ }
917
+ var ManualGitHost = class extends ManualBase {
918
+ constructor(opts) {
919
+ super("git-host", "git-host", opts);
920
+ }
921
+ async getRepo(repo) {
922
+ this.journal.push({ method: "getRepo" });
923
+ const defaultBranch = this.setting("defaultBranch") ?? "main";
924
+ return {
925
+ repo,
926
+ defaultBranch,
927
+ protectedBranches: this.settingList("protectedBranches") ?? [defaultBranch]
928
+ };
929
+ }
930
+ async prSteps(repo) {
931
+ return (await this.opts.store.list({ system: "git-host", action: "open-pull-request" })).filter((s) => !repo || s.inputs.repo === repo);
932
+ }
933
+ async related(repo, number, action) {
934
+ return (await this.opts.store.list({ system: "git-host", action })).filter((s) => s.inputs.repo === repo && s.inputs.number === number);
935
+ }
936
+ async toPr(open) {
937
+ const repo = String(open.inputs.repo);
938
+ const number = Number(open.inputs.number);
939
+ const rec = open.state === "done" ? open.recorded?.values : void 0;
940
+ const merged = (await this.related(repo, number, "merge-pull-request")).some((s) => s.state === "done");
941
+ const reports = (await this.related(repo, number, "report-pull-request")).filter((s) => s.state === "done").sort((a, b) => a.recorded.at < b.recorded.at ? -1 : 1);
942
+ const last = reports.at(-1)?.recorded?.values;
943
+ const list = (v) => Array.isArray(v) ? v.map(String) : [];
944
+ const reviews = [
945
+ ...list(last?.approvers).map((by) => ({ by, state: "approved" })),
946
+ ...list(last?.changesRequestedBy).map((by) => ({ by, state: "changes-requested" }))
947
+ ];
948
+ const closed = (await this.related(repo, number, "close-pull-request")).some((s) => s.state === "done");
949
+ let state = open.state === "done" ? open.inputs.draft ? "draft" : "open" : "draft";
950
+ if (open.state === "skipped" || closed)
951
+ state = "closed";
952
+ if (merged)
953
+ state = "merged";
954
+ return {
955
+ repo,
956
+ number,
957
+ url: typeof rec?.url === "string" ? rec.url : `manual://git-host/${repo}/pull/${number}`,
958
+ title: String(open.inputs.title ?? ""),
959
+ body: open.fields.find((f) => f.name === "Description")?.value ?? "",
960
+ head: String(open.inputs.head),
961
+ base: String(open.inputs.base),
962
+ state,
963
+ reviews,
964
+ checks: last?.checksPassing === void 0 ? [] : [{ name: "reported by a person", status: last.checksPassing ? "passed" : "failed" }],
965
+ requiredReviewers: []
966
+ };
967
+ }
968
+ async find(repo, number) {
969
+ const s = (await this.prSteps(repo)).find((x) => x.inputs.number === number);
970
+ return s ?? this.notFound(`PR ${repo}#${number}`, "no manual step opened it");
971
+ }
972
+ async getPullRequest(repo, number) {
973
+ this.journal.push({ method: "getPullRequest" });
974
+ return this.toPr(await this.find(repo, number));
975
+ }
976
+ async listPullRequests(repo, q) {
977
+ this.journal.push({ method: "listPullRequests" });
978
+ const out = [];
979
+ for (const s of await this.prSteps(repo)) {
980
+ const pr = await this.toPr(s);
981
+ if ((!q.head || pr.head === q.head) && (!q.state || pr.state === q.state))
982
+ out.push(pr);
983
+ }
984
+ return out;
985
+ }
986
+ /** A report step for the PR's reviews and checks, unless one is still open. */
987
+ async askForReviews(open, change) {
988
+ const repo = String(open.inputs.repo);
989
+ const number = Number(open.inputs.number);
990
+ const reports = await this.related(repo, number, "report-pull-request");
991
+ if (reports.some((s) => s.state === "open"))
992
+ return;
993
+ await this.step("report", {
994
+ slug: `report-pr-${number}`,
995
+ action: "report-pull-request",
996
+ key: `git-host|report|${repo}|${number}|${reports.length}`,
997
+ title: `Record the reviews and checks on PR ${number} (${open.inputs.title})`,
998
+ where: `Git host: ${repo}, the pull request opened for step ${open.id}`,
999
+ ...change ? { change } : {},
1000
+ inputs: { repo, number },
1001
+ fields: [
1002
+ { name: "Repository", value: repo },
1003
+ { name: "From branch", value: String(open.inputs.head) }
1004
+ ],
1005
+ instructions: [
1006
+ "Once reviewers have acted, record who approved, who asked for changes and whether the checks pass.",
1007
+ "Name people by their handle on the Git host. Only what is recorded here counts for approval."
1008
+ ],
1009
+ result: [
1010
+ { name: "approvers", label: "Approved by", format: "handles", required: false },
1011
+ {
1012
+ name: "changesRequestedBy",
1013
+ label: "Changes requested by",
1014
+ format: "handles",
1015
+ required: false
1016
+ },
1017
+ { name: "checksPassing", label: "All checks pass", format: "yes-no", required: true }
1018
+ ],
1019
+ dependsOn: [open.id]
1020
+ });
1021
+ }
1022
+ async createPullRequest(input, approval) {
1023
+ const a = this.approve(approval);
1024
+ const info = await this.getRepo(input.repo);
1025
+ if (info.protectedBranches.includes(input.head))
1026
+ throw new AdapterError(this.name, "invalid", `${input.head} is protected and can't be a PR's source branch`);
1027
+ const existing = await this.prSteps(input.repo);
1028
+ for (const s of existing) {
1029
+ if (s.inputs.head !== input.head)
1030
+ continue;
1031
+ const pr = await this.toPr(s);
1032
+ if (pr.state === "open" || pr.state === "draft")
1033
+ throw new AdapterError(this.name, "conflict", `an open PR from ${input.head} already exists`);
1034
+ }
1035
+ const number = existing.reduce((n, s) => Math.max(n, Number(s.inputs.number)), 0) + 1;
1036
+ const change = this.opts.change ?? changeOfBranch(input.head);
1037
+ const proc = this.procedureFor("open-pull-request");
1038
+ const open = await this.step("createPullRequest", {
1039
+ slug: `open-pr-${input.head}`,
1040
+ action: "open-pull-request",
1041
+ key: `git-host|pr|${input.repo}|${input.head}|${number}`,
1042
+ title: `Open a pull request from ${input.head} into ${input.base}`,
1043
+ where: `Git host: ${input.repo}, new pull request`,
1044
+ ...change ? { change } : {},
1045
+ ...proc ?? {},
1046
+ inputs: {
1047
+ repo: input.repo,
1048
+ number,
1049
+ head: input.head,
1050
+ base: input.base,
1051
+ title: input.title,
1052
+ ...input.draft ? { draft: true } : {}
1053
+ },
1054
+ fields: [
1055
+ { name: "Repository", value: input.repo },
1056
+ { name: "From branch", value: input.head },
1057
+ { name: "Into branch", value: input.base },
1058
+ { name: "Title", value: input.title },
1059
+ { name: "Description", value: input.body },
1060
+ ...input.draft ? [{ name: "Draft", value: "yes" }] : []
1061
+ ],
1062
+ instructions: [
1063
+ `Make sure ${input.head} is on the Git host (Atticus pushes it when it can reach the remote; otherwise push it yourself).`,
1064
+ `Open a pull request from ${input.head} into ${input.base} with the title and description below.`,
1065
+ "Record the pull request's link and number here."
1066
+ ],
1067
+ result: [
1068
+ { name: "url", label: "Pull request link", format: "url", required: true },
1069
+ { name: "number", label: "Pull request number", format: "integer", required: true }
1070
+ ]
1071
+ }, a);
1072
+ await this.askForReviews(open, change);
1073
+ return this.toPr(open);
1074
+ }
1075
+ async comment(repo, number, body, approval) {
1076
+ const a = this.approve(approval);
1077
+ const open = await this.find(repo, number);
1078
+ const change = open.change;
1079
+ await this.step("comment", {
1080
+ slug: `comment-pr-${number}`,
1081
+ action: "comment-pull-request",
1082
+ key: `git-host|comment|${repo}|${number}|${shortHash(body)}`,
1083
+ title: `Post a comment on PR ${number} (${open.inputs.title})`,
1084
+ where: `Git host: ${repo}, the pull request opened for step ${open.id}`,
1085
+ ...change ? { change } : {},
1086
+ inputs: { repo, number },
1087
+ fields: [{ name: "Comment", value: body }],
1088
+ instructions: ["Post the comment below on the pull request."],
1089
+ dependsOn: [open.id]
1090
+ }, a);
1091
+ if ((await this.toPr(open)).state !== "merged")
1092
+ await this.askForReviews(open, change);
1093
+ }
1094
+ /**
1095
+ * Closing is a step for a person (once per PR); the PR reads closed when they have done
1096
+ * it, so until then it is returned as it is.
1097
+ */
1098
+ async closePullRequest(repo, number, approval) {
1099
+ const a = this.approve(approval);
1100
+ const open = await this.find(repo, number);
1101
+ const pr = await this.toPr(open);
1102
+ if (pr.state === "merged")
1103
+ throw new AdapterError(this.name, "conflict", `PR ${number} is merged and can't be closed`);
1104
+ if (pr.state === "closed")
1105
+ return pr;
1106
+ await this.step("closePullRequest", {
1107
+ slug: `close-pr-${number}`,
1108
+ action: "close-pull-request",
1109
+ key: `git-host|close|${repo}|${number}`,
1110
+ title: `Close PR ${number} (${open.inputs.title}) without merging`,
1111
+ where: `Git host: ${repo}, ${pr.url}`,
1112
+ ...open.change ? { change: open.change } : {},
1113
+ inputs: { repo, number },
1114
+ fields: [{ name: "Pull request", value: pr.url }],
1115
+ instructions: [
1116
+ "The change went back to the product owner: close the pull request on the Git host without merging it, then mark this step done."
1117
+ ],
1118
+ dependsOn: [open.id]
1119
+ }, a);
1120
+ return this.toPr(open);
1121
+ }
1122
+ async merge(repo, number, approval) {
1123
+ const a = this.approve(approval);
1124
+ const open = await this.find(repo, number);
1125
+ const pr = await this.toPr(open);
1126
+ if (pr.state === "merged")
1127
+ return pr;
1128
+ const blockers = mergeBlockers(pr);
1129
+ if (blockers.length > 0)
1130
+ throw new AdapterError(this.name, "conflict", `can't merge: ${blockers.join("; ")}`);
1131
+ const step = await this.step("merge", {
1132
+ slug: `merge-pr-${number}`,
1133
+ action: "merge-pull-request",
1134
+ key: `git-host|merge|${repo}|${number}`,
1135
+ title: `Merge PR ${number} (${open.inputs.title}) on the Git host`,
1136
+ where: `Git host: ${repo}, ${pr.url}`,
1137
+ ...open.change ? { change: open.change } : {},
1138
+ inputs: { repo, number },
1139
+ fields: [
1140
+ { name: "Pull request", value: pr.url },
1141
+ {
1142
+ name: "Approved by",
1143
+ value: pr.reviews.filter((r) => r.state === "approved").map((r) => r.by).join(", ")
1144
+ }
1145
+ ],
1146
+ instructions: [
1147
+ "Atticus checked the recorded approvals and checks: the pull request may merge.",
1148
+ "Merge it on the Git host, then mark this step done."
1149
+ ],
1150
+ result: [{ name: "mergedBy", label: "Merged by", format: "handles", required: false }],
1151
+ dependsOn: [open.id]
1152
+ }, a);
1153
+ throw new AdapterError(this.name, "unavailable", `a person merges PR ${number} on the Git host: do step ${step.id} (atticus todo), then sync again`, false);
1154
+ }
1155
+ };
1156
+
1157
+ // packages/adapters/dist/manual/read-only.js
1158
+ import { readdir as readdir2, readFile as readFile2, stat as stat2 } from "node:fs/promises";
1159
+ import { isAbsolute, join as join2, relative, sep } from "node:path";
1160
+ function folder(opts, value, fallback) {
1161
+ const v = value ?? fallback;
1162
+ return isAbsolute(v) ? v : join2(opts.root ?? ".", v);
1163
+ }
1164
+ var ManualWiki = class extends ManualBase {
1165
+ constructor(opts) {
1166
+ super("wiki", "wiki", opts);
1167
+ }
1168
+ dir() {
1169
+ return folder(this.opts, this.setting("exportDir"), "inputs/wiki");
1170
+ }
1171
+ async pages() {
1172
+ const root = this.dir();
1173
+ const out = [];
1174
+ const walk = async (d) => {
1175
+ let entries;
1176
+ try {
1177
+ entries = await readdir2(d, { withFileTypes: true });
1178
+ } catch {
1179
+ return;
1180
+ }
1181
+ for (const e of entries.sort((a, b) => a.name < b.name ? -1 : 1)) {
1182
+ if (e.name.startsWith("."))
1183
+ continue;
1184
+ const full = join2(d, e.name);
1185
+ if (e.isDirectory())
1186
+ await walk(full);
1187
+ else if (/\.(md|markdown)$/i.test(e.name)) {
1188
+ const id = relative(root, full).split(sep).join("/");
1189
+ const body = await readFile2(full, "utf8");
1190
+ const title = /^#\s+(.+)$/m.exec(body)?.[1]?.trim() ?? e.name.replace(/\.(md|markdown)$/i, "");
1191
+ out.push({
1192
+ id,
1193
+ space: id.includes("/") ? id.split("/")[0] : "default",
1194
+ title,
1195
+ body,
1196
+ version: 1,
1197
+ updatedAt: (await stat2(full)).mtime.toISOString(),
1198
+ url: `file:${id}`
1199
+ });
1200
+ }
1201
+ }
1202
+ };
1203
+ await walk(root);
1204
+ return out;
1205
+ }
1206
+ async listPages(space) {
1207
+ this.journal.push({ method: "listPages" });
1208
+ return (await this.pages()).filter((p2) => p2.space === space).map(({ body: _b, ...h }) => h);
1209
+ }
1210
+ async getPage(id) {
1211
+ this.journal.push({ method: "getPage" });
1212
+ return (await this.pages()).find((p2) => p2.id === id) ?? this.notFound(`page ${id}`, `export the page into ${this.dir()}`);
1213
+ }
1214
+ async search(text) {
1215
+ this.journal.push({ method: "search" });
1216
+ const t = text.toLowerCase();
1217
+ return (await this.pages()).filter((p2) => p2.title.toLowerCase().includes(t) || p2.body.toLowerCase().includes(t)).map(({ body: _b, ...h }) => h);
1218
+ }
1219
+ };
1220
+ var ManualDesignTool = class extends ManualBase {
1221
+ constructor(opts) {
1222
+ super("design-tool", "design", opts);
1223
+ }
1224
+ dir() {
1225
+ return folder(this.opts, this.setting("exportDir"), "inputs/design");
1226
+ }
1227
+ async getFile(key) {
1228
+ this.journal.push({ method: "getFile" });
1229
+ try {
1230
+ return JSON.parse(await readFile2(join2(this.dir(), `${key}.json`), "utf8"));
1231
+ } catch {
1232
+ return this.notFound(`design file ${key}`, `export it as ${key}.json into ${this.dir()}`);
1233
+ }
1234
+ }
1235
+ async renderFrame(key, frameId) {
1236
+ this.journal.push({ method: "renderFrame" });
1237
+ try {
1238
+ return new Uint8Array(await readFile2(join2(this.dir(), key, `${frameId}.png`)));
1239
+ } catch {
1240
+ return this.notFound(`frame ${frameId}`, `export it as ${key}/${frameId}.png into ${this.dir()}`);
1241
+ }
1242
+ }
1243
+ };
1244
+ var ManualNotifier = class extends ManualBase {
1245
+ constructor(opts) {
1246
+ super("notify", "notify", opts);
1247
+ }
1248
+ async send(n, approval) {
1249
+ const a = this.approve(approval, { allowStanding: true });
1250
+ const step = await this.step("send", {
1251
+ slug: `message-${n.channel}`,
1252
+ action: "send-notification",
1253
+ key: `notify|${n.channel}|${shortHash(`${n.title}
1254
+ ${n.body}
1255
+ ${n.link ?? ""}`)}`,
1256
+ title: `Send "${n.title}" to ${n.channel}`,
1257
+ where: `Messages: ${n.channel}`,
1258
+ inputs: { channel: n.channel },
1259
+ fields: [
1260
+ { name: "Channel", value: n.channel },
1261
+ { name: "Title", value: n.title },
1262
+ { name: "Message", value: n.body },
1263
+ ...n.link ? [{ name: "Link", value: n.link }] : [],
1264
+ ...n.mentions?.length ? [{ name: "Mention", value: n.mentions.join(", ") }] : []
1265
+ ],
1266
+ instructions: ["Send the message below to the channel, mentioning the people named."]
1267
+ }, a);
1268
+ return { id: provisionalId(step.id) };
1269
+ }
1270
+ };
1271
+
1272
+ // packages/adapters/dist/manual/service-desk.js
1273
+ var STATES = ["draft", "submitted", "in-progress", "done", "rejected"];
1274
+ var FINAL = /* @__PURE__ */ new Set(["done", "rejected"]);
1275
+ var fieldKey = (name) => name.toLowerCase().replace(/[^a-z0-9]+(.)?/g, (_m, c) => c ? c.toUpperCase() : "").replace(/^[^a-z]+/, "");
1276
+ var ManualServiceDesk = class extends ManualBase {
1277
+ exports;
1278
+ constructor(opts, exports = async () => []) {
1279
+ super("service-desk", "service-desk", opts);
1280
+ this.exports = exports;
1281
+ }
1282
+ numberPattern() {
1283
+ return this.setting("numberPattern") ?? "[A-Z]{2,10}-?\\d{3,}";
1284
+ }
1285
+ /** The request number once its step is recorded, else the id as given. */
1286
+ async resolveId(id) {
1287
+ const stepId = stepOfProvisional(id);
1288
+ if (!stepId)
1289
+ return id;
1290
+ const s = await this.opts.store.get(stepId);
1291
+ const real = s?.state === "done" ? s.recorded?.values.requestNumber : void 0;
1292
+ return typeof real === "string" ? real : id;
1293
+ }
1294
+ async stateAnswers(number) {
1295
+ return (await this.opts.store.list({ system: "service-desk", action: "report-request-state" })).filter((s) => s.inputs.request === number && s.state === "done").sort((a, b) => a.recorded.at < b.recorded.at ? -1 : 1);
1296
+ }
1297
+ async fromStep(step) {
1298
+ const rec = step.state === "done" ? step.recorded?.values : void 0;
1299
+ const number = typeof rec?.requestNumber === "string" ? rec.requestNumber : void 0;
1300
+ const fields = Object.fromEntries(step.fields.filter((f) => f.name !== "Request type").map((f) => [f.name, f.value]));
1301
+ let state = number ? "submitted" : "draft";
1302
+ let closedAt;
1303
+ if (number) {
1304
+ const last = (await this.stateAnswers(number)).at(-1);
1305
+ const s = last?.recorded?.values.state;
1306
+ if (typeof s === "string" && STATES.includes(s))
1307
+ state = s;
1308
+ const c = last?.recorded?.values.closedAt;
1309
+ if (typeof c === "string")
1310
+ closedAt = c;
1311
+ }
1312
+ return {
1313
+ id: number ?? provisionalId(step.id),
1314
+ type: String(step.inputs.requestType ?? ""),
1315
+ state,
1316
+ fields,
1317
+ ...step.change ? { changeId: step.change } : {},
1318
+ ...step.recorded?.at && number ? { openedAt: step.recorded.at.slice(0, 10) } : {},
1319
+ ...closedAt ? { closedAt } : {},
1320
+ url: typeof rec?.url === "string" ? rec.url : ""
1321
+ };
1322
+ }
1323
+ async submitted() {
1324
+ const steps = await this.opts.store.list({ system: "service-desk", action: "submit-request" });
1325
+ return Promise.all(steps.map((s) => this.fromStep(s)));
1326
+ }
1327
+ /** Ask a person where an unfinished request is; one open question per request at a time. */
1328
+ async ask(r) {
1329
+ const answered = (await this.stateAnswers(r.id)).length;
1330
+ await this.step("getRequest", {
1331
+ slug: `state-${r.id}`,
1332
+ action: "report-request-state",
1333
+ key: `service-desk|state|${r.id}|${answered}`,
1334
+ title: `Report where request ${r.id} is in the service desk`,
1335
+ where: `Service desk: request ${r.id}`,
1336
+ ...r.changeId ? { change: r.changeId } : {},
1337
+ inputs: { request: r.id },
1338
+ fields: [
1339
+ { name: "Request", value: r.id },
1340
+ { name: "Request type", value: r.type }
1341
+ ],
1342
+ instructions: [
1343
+ "Open the request and record its state; give the closing date once it is done or rejected."
1344
+ ],
1345
+ result: [
1346
+ { name: "state", label: "State", format: "choice", choices: STATES, required: true },
1347
+ { name: "closedAt", label: "Closed on", format: "date", required: false }
1348
+ ]
1349
+ });
1350
+ }
1351
+ async getRequest(id) {
1352
+ this.journal.push({ method: "getRequest" });
1353
+ const stepId = stepOfProvisional(id);
1354
+ const mine = stepId ? await this.opts.store.get(stepId).then((s) => s ? this.fromStep(s) : void 0) : (await this.submitted()).find((r) => r.id === id);
1355
+ if (mine) {
1356
+ if (mine.state !== "draft" && !FINAL.has(mine.state))
1357
+ await this.ask(mine);
1358
+ return mine;
1359
+ }
1360
+ const exported = (await this.exports()).find((r) => r.id === id);
1361
+ return exported ?? this.notFound(`request ${id}`, "export the requests from the service desk into inputs/ so Atticus can read them");
1362
+ }
1363
+ async listRequests(q) {
1364
+ this.journal.push({ method: "listRequests" });
1365
+ const mine = await this.submitted();
1366
+ const ids = new Set(mine.map((r) => r.id));
1367
+ return [...mine, ...(await this.exports()).filter((r) => !ids.has(r.id))].filter((r) => (!q.changeId || r.changeId === q.changeId) && (!q.state || r.state === q.state) && (!q.type || r.type === q.type));
1368
+ }
1369
+ async submitRequest(draft, approval) {
1370
+ const a = this.approve(approval);
1371
+ const empty = Object.entries(draft.fields).filter(([, v]) => v === "").map(([k]) => k);
1372
+ if (empty.length > 0)
1373
+ throw new AdapterError(this.name, "invalid", `required fields are empty: ${empty.join(", ")}`);
1374
+ const proc = this.procedureFor("submit-request", { template: draft.templateId });
1375
+ const step = await this.step("submitRequest", {
1376
+ slug: `request-${draft.templateId}`,
1377
+ action: "submit-request",
1378
+ key: `service-desk|${draft.changeId}|${draft.templateId}|${shortHash(JSON.stringify(draft.fields))}`,
1379
+ title: `Raise a "${draft.type}" request in the service desk`,
1380
+ where: `Service desk: "${draft.type}" request`,
1381
+ change: draft.changeId,
1382
+ ...proc ?? {},
1383
+ inputs: {
1384
+ template: draft.templateId,
1385
+ requestType: draft.type,
1386
+ ...Object.fromEntries(Object.entries(draft.fields).map(([k, v]) => [fieldKey(k), v]))
1387
+ },
1388
+ fields: [
1389
+ { name: "Request type", value: draft.type },
1390
+ ...Object.entries(draft.fields).map(([name, v]) => ({ name, value: String(v) }))
1391
+ ],
1392
+ instructions: [
1393
+ `Open a new "${draft.type}" request and copy the fields below.`,
1394
+ "Submit it and record the request number here."
1395
+ ],
1396
+ result: [
1397
+ {
1398
+ name: "requestNumber",
1399
+ label: "Request number",
1400
+ format: "pattern",
1401
+ pattern: this.numberPattern(),
1402
+ help: "the number the service desk gave the request, such as SR-0042",
1403
+ required: true
1404
+ },
1405
+ { name: "url", label: "Link to the request", format: "url", required: false }
1406
+ ]
1407
+ }, a);
1408
+ return this.fromStep(step);
1409
+ }
1410
+ };
1411
+
1412
+ // packages/adapters/dist/manual/work-tracker.js
1413
+ var TYPE_NAME = {
1414
+ epic: "Epic",
1415
+ feature: "Feature",
1416
+ story: "User Story",
1417
+ task: "Task",
1418
+ bug: "Bug"
1419
+ };
1420
+ var ManualWorkTracker = class extends ManualBase {
1421
+ exports;
1422
+ constructor(opts, exports = async () => []) {
1423
+ super("work-tracker", "work-tracker", opts);
1424
+ this.exports = exports;
1425
+ }
1426
+ idPattern() {
1427
+ return this.setting("idPattern") ?? "[A-Za-z]*-?\\d+";
1428
+ }
1429
+ /** The real id once its step is recorded, else the id as given. */
1430
+ async resolveId(id) {
1431
+ const stepId = stepOfProvisional(id);
1432
+ if (!stepId)
1433
+ return id;
1434
+ const s = await this.opts.store.get(stepId);
1435
+ const real = s?.state === "done" ? s.recorded?.values.id : void 0;
1436
+ return typeof real === "string" ? real : id;
1437
+ }
1438
+ parentField(parent, deps) {
1439
+ if (!parent)
1440
+ return "";
1441
+ const stepId = stepOfProvisional(parent);
1442
+ if (!stepId)
1443
+ return parent;
1444
+ deps.push(stepId);
1445
+ return `the id you record for step ${stepId}`;
1446
+ }
1447
+ itemFrom(step) {
1448
+ const f = (n) => step.fields.find((x) => x.name === n)?.value ?? "";
1449
+ const rec = step.state === "done" ? step.recorded?.values : void 0;
1450
+ const type = Object.entries(TYPE_NAME).find(([, v]) => v === f("Work item type"))?.[0] ?? "task";
1451
+ const parent = step.inputs.parent ?? void 0;
1452
+ return {
1453
+ id: typeof rec?.id === "string" ? rec.id : provisionalId(step.id),
1454
+ type,
1455
+ title: f("Title"),
1456
+ description: f("Description"),
1457
+ acceptanceCriteria: f("Acceptance criteria"),
1458
+ state: rec ? "New" : "Not created yet",
1459
+ ...parent ? { parent } : {},
1460
+ ...f("Assigned to") ? { assignee: f("Assigned to") } : {},
1461
+ tags: f("Tags").split(";").map((t) => t.trim()).filter(Boolean),
1462
+ url: typeof rec?.url === "string" ? rec.url : ""
1463
+ };
1464
+ }
1465
+ async known() {
1466
+ const created = await this.opts.store.list({
1467
+ system: "work-tracker",
1468
+ action: "create-work-item"
1469
+ });
1470
+ const fromSteps = created.map((s) => this.itemFrom(s));
1471
+ const exported = await this.exports();
1472
+ const ids = new Set(fromSteps.map((i) => i.id));
1473
+ return [...fromSteps, ...exported.filter((i) => !ids.has(i.id))];
1474
+ }
1475
+ async getItem(id) {
1476
+ this.journal.push({ method: "getItem" });
1477
+ const real = await this.resolveId(id);
1478
+ const item = (await this.known()).find((i) => i.id === real || i.id === id);
1479
+ return item ?? this.notFound(`work item ${id}`, "export the work items from the tracker into inputs/ (CSV or JSON) so Atticus can read them");
1480
+ }
1481
+ async query(q) {
1482
+ this.journal.push({ method: "query" });
1483
+ const text = q.text?.toLowerCase();
1484
+ return (await this.known()).filter((i) => (!q.type || i.type === q.type) && (!q.parent || i.parent === q.parent) && (!q.state || i.state === q.state) && (!q.tag || i.tags.includes(q.tag)) && (!text || i.title.toLowerCase().includes(text) || i.description.toLowerCase().includes(text)));
1485
+ }
1486
+ async createItem(input, approval) {
1487
+ const a = this.approve(approval);
1488
+ const deps = [];
1489
+ const parent = input.parent ? await this.resolveId(input.parent) : void 0;
1490
+ const keyTag = input.tags?.find((t) => t.startsWith("atticus:"));
1491
+ const proc = this.procedureFor("create-work-item");
1492
+ const step = await this.step("createItem", {
1493
+ slug: `create-${input.type}-${input.title}`,
1494
+ action: "create-work-item",
1495
+ key: `work-tracker|create|${keyTag ?? `${input.type}|${input.title}`}`,
1496
+ title: `Create the ${TYPE_NAME[input.type].toLowerCase()} "${input.title}" in the work tracker`,
1497
+ where: `Work tracker${this.setting("project") ? `, project ${this.setting("project")}` : ""}: new ${TYPE_NAME[input.type]}`,
1498
+ ...proc ?? {},
1499
+ inputs: {
1500
+ type: input.type,
1501
+ title: input.title,
1502
+ ...parent ? { parent } : {}
1503
+ },
1504
+ fields: [
1505
+ { name: "Work item type", value: TYPE_NAME[input.type] },
1506
+ { name: "Title", value: input.title },
1507
+ { name: "Description", value: input.description ?? "" },
1508
+ { name: "Acceptance criteria", value: input.acceptanceCriteria ?? "" },
1509
+ { name: "Parent", value: this.parentField(parent, deps) },
1510
+ { name: "Tags", value: (input.tags ?? []).join("; ") },
1511
+ { name: "Assigned to", value: input.assignee ?? "" }
1512
+ ].filter((f) => f.value !== "" || ["Title", "Work item type"].includes(f.name)),
1513
+ instructions: [
1514
+ `Create a new ${TYPE_NAME[input.type]} with the fields below (or import the CSV export).`,
1515
+ ...deps.length ? [`Set its parent to the id recorded for step ${deps[0]}.`] : [],
1516
+ "Record the new item's id (and its link) here."
1517
+ ],
1518
+ result: [
1519
+ {
1520
+ name: "id",
1521
+ label: "Work item id",
1522
+ format: "pattern",
1523
+ pattern: this.idPattern(),
1524
+ help: "the id the tracker gave the new item, such as 4711",
1525
+ required: true
1526
+ },
1527
+ { name: "url", label: "Link to the item", format: "url", required: false }
1528
+ ],
1529
+ dependsOn: deps
1530
+ }, a);
1531
+ return this.itemFrom(step);
1532
+ }
1533
+ async updateItem(id, patch, approval) {
1534
+ const a = this.approve(approval);
1535
+ const real = await this.resolveId(id);
1536
+ const deps = [];
1537
+ const target = stepOfProvisional(real);
1538
+ if (target)
1539
+ deps.push(target);
1540
+ const changes = Object.entries(patch).filter(([, v]) => v !== void 0);
1541
+ const label = {
1542
+ type: "Work item type",
1543
+ title: "Title",
1544
+ description: "Description",
1545
+ acceptanceCriteria: "Acceptance criteria",
1546
+ parent: "Parent",
1547
+ assignee: "Assigned to",
1548
+ tags: "Tags",
1549
+ state: "State"
1550
+ };
1551
+ await this.step("updateItem", {
1552
+ slug: `update-${real}`,
1553
+ action: "update-work-item",
1554
+ key: `work-tracker|update|${real}|${shortHash(JSON.stringify(changes))}`,
1555
+ title: `Update work item ${target ? `from step ${target}` : real} in the work tracker`,
1556
+ where: `Work tracker: item ${target ? `recorded for step ${target}` : real}`,
1557
+ inputs: { id: real, ...Object.fromEntries(changes) },
1558
+ fields: changes.map(([k, v]) => ({
1559
+ name: label[k] ?? k,
1560
+ value: Array.isArray(v) ? v.join("; ") : k === "parent" ? this.parentField(String(v), deps) : String(v)
1561
+ })),
1562
+ instructions: ["Open the item and set the fields below to these values."],
1563
+ dependsOn: [...new Set(deps)]
1564
+ }, a);
1565
+ const base = await this.getItem(real).catch(() => void 0);
1566
+ return {
1567
+ ...base ?? {
1568
+ id: real,
1569
+ type: patch.type ?? "task",
1570
+ title: patch.title ?? "",
1571
+ description: "",
1572
+ acceptanceCriteria: "",
1573
+ state: "New",
1574
+ tags: [],
1575
+ url: ""
1576
+ },
1577
+ ...Object.fromEntries(changes)
1578
+ };
1579
+ }
1580
+ async link(from, to, kind, approval) {
1581
+ const a = this.approve(approval);
1582
+ const deps = [];
1583
+ const show = async (id) => {
1584
+ const real = await this.resolveId(id);
1585
+ return this.parentField(real, deps) || real;
1586
+ };
1587
+ const f = await show(from);
1588
+ const t = await show(to);
1589
+ await this.step("link", {
1590
+ slug: `link-${kind}`,
1591
+ action: "link-work-items",
1592
+ key: `work-tracker|link|${from}|${to}|${kind}`,
1593
+ title: `Link two work items (${kind}) in the work tracker`,
1594
+ where: "Work tracker: the item's links",
1595
+ inputs: { from, to, kind },
1596
+ fields: [
1597
+ { name: "From item", value: f },
1598
+ { name: "To item", value: t },
1599
+ {
1600
+ name: "Link type",
1601
+ value: kind === "parent" ? "Parent" : kind === "blocks" ? "Blocks" : "Related"
1602
+ }
1603
+ ],
1604
+ instructions: ["Open the first item and add the link to the second."],
1605
+ dependsOn: [...new Set(deps)]
1606
+ }, a);
1607
+ }
1608
+ };
1609
+
1610
+ // packages/adapters/dist/manual/fallback.js
1611
+ function manualAdapter(kind, ctx, settings = {}) {
1612
+ const opts = {
1613
+ store: ctx.store,
1614
+ settings,
1615
+ ...ctx.root ? { root: ctx.root } : {},
1616
+ ...ctx.change ? { change: ctx.change } : {},
1617
+ ...ctx.procedures ? { procedures: ctx.procedures } : {},
1618
+ ...ctx.now ? { now: ctx.now } : {}
1619
+ };
1620
+ switch (kind) {
1621
+ case "workTracker":
1622
+ return new ManualWorkTracker(opts, ctx.readers?.workItems);
1623
+ case "serviceDesk":
1624
+ return new ManualServiceDesk(opts, ctx.readers?.requests);
1625
+ case "gitHost":
1626
+ return new ManualGitHost(opts);
1627
+ case "wiki":
1628
+ return new ManualWiki(opts);
1629
+ case "notify":
1630
+ return new ManualNotifier(opts);
1631
+ case "design":
1632
+ return new ManualDesignTool(opts);
1633
+ }
1634
+ }
1635
+ var FALLBACK_CODES = /* @__PURE__ */ new Set(["unavailable", "unauthorized"]);
1636
+ function withManualFallback(kind, live, manual, onFallback) {
1637
+ return new Proxy(live, {
1638
+ get(target, prop, receiver) {
1639
+ const v = Reflect.get(target, prop, receiver);
1640
+ if (typeof v !== "function")
1641
+ return v;
1642
+ return async (...args) => {
1643
+ try {
1644
+ return await v.apply(target, args);
1645
+ } catch (e) {
1646
+ if (!(e instanceof AdapterError) || !FALLBACK_CODES.has(e.code))
1647
+ throw e;
1648
+ const m = manual[prop];
1649
+ if (typeof m !== "function")
1650
+ throw e;
1651
+ const reason = `the ${kind} adapter failed (${e.code}): ${e.message}`;
1652
+ onFallback?.({ kind, method: String(prop), code: e.code, message: e.message });
1653
+ manual.reason = reason;
1654
+ try {
1655
+ return await m.apply(manual, args);
1656
+ } finally {
1657
+ manual.reason = void 0;
1658
+ }
1659
+ }
1660
+ };
1661
+ }
1662
+ });
1663
+ }
1664
+
1665
+ // packages/adapters/dist/registry.js
1666
+ var MOCKS = {
1667
+ workTracker: { mock: () => new MockWorkTracker() },
1668
+ serviceDesk: { mock: () => new MockServiceDesk() },
1669
+ gitHost: { mock: () => new MockGitHost() },
1670
+ wiki: { mock: () => new MockWiki() },
1671
+ notify: { mock: () => new MockNotifier() },
1672
+ design: { mock: () => new MockDesignTool() }
1673
+ };
1674
+ function createAdapters(runtime, factories = {}, manual) {
1675
+ const out = {};
1676
+ const kinds = ["workTracker", "serviceDesk", "gitHost", "wiki", "notify", "design"];
1677
+ for (const kind of kinds) {
1678
+ const cfg = runtime.adapters[kind];
1679
+ if (!cfg)
1680
+ continue;
1681
+ if (cfg.type === "manual") {
1682
+ if (!manual)
1683
+ throw new AdapterError(kind, "invalid", "a manual adapter writes steps into the metarepo; build adapters with the metarepo's step store");
1684
+ out[kind] = manualAdapter(kind, manual, cfg.settings);
1685
+ continue;
1686
+ }
1687
+ const make = factories[kind]?.[cfg.type] ?? MOCKS[kind][cfg.type];
1688
+ if (!make) {
1689
+ throw new AdapterError(kind, "invalid", `no ${cfg.type} adapter is installed; add its plugin or set type: mock for tests`);
1690
+ }
1691
+ if (!manual || manual.fallback === false) {
1692
+ out[kind] = make(cfg.settings);
1693
+ continue;
1694
+ }
1695
+ const fallback = manualAdapter(kind, manual, cfg.settings);
1696
+ let live;
1697
+ try {
1698
+ live = make(cfg.settings);
1699
+ } catch (e) {
1700
+ if (!(e instanceof AdapterError) || !FALLBACK_CODES.has(e.code))
1701
+ throw e;
1702
+ manual.onFallback?.({ kind, method: "connect", code: e.code, message: e.message });
1703
+ fallback.reason = `the ${kind} adapter couldn't start (${e.code}): ${e.message}`;
1704
+ out[kind] = fallback;
1705
+ continue;
1706
+ }
1707
+ out[kind] = withManualFallback(kind, live, fallback, manual.onFallback);
1708
+ }
1709
+ return out;
1710
+ }
1711
+
1712
+ export {
1713
+ AdapterError,
1714
+ requireApproval,
1715
+ workItemsCsv,
1716
+ mergeBlockers,
1717
+ fileStepStore,
1718
+ checkResult,
1719
+ StepError,
1720
+ recordStep,
1721
+ exportStep,
1722
+ stepOfProvisional,
1723
+ ManualNotifier,
1724
+ manualAdapter,
1725
+ createAdapters
1726
+ };