@runcofactor/cli 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/README.md +2 -0
  2. package/dist/{account-3ZG24MOE.js → account-MRZ54P5P.js} +5 -5
  3. package/dist/{alert-5G7PTAX2.js → alert-XBHELHEI.js} +8 -8
  4. package/dist/{api-catalog-IBYAFKKQ.js → api-catalog-GWYRX53L.js} +5 -5
  5. package/dist/{api-key-UXC44BDR.js → api-key-FH6JN447.js} +5 -5
  6. package/dist/{attachment-T6IRFQW3.js → attachment-J7GRVT5F.js} +5 -5
  7. package/dist/{auth-SHOCJE6Z.js → auth-VZZQXRDR.js} +3 -3
  8. package/dist/{benchmark-NJ2U6VTC.js → benchmark-A3SNDARF.js} +5 -5
  9. package/dist/{blackcat-RQJVFGXQ.js → blackcat-UM6TBQBN.js} +3 -3
  10. package/dist/{chunk-DHAGRM2F.js → chunk-33U56YGD.js} +14 -5
  11. package/dist/{chunk-DHAGRM2F.js.map → chunk-33U56YGD.js.map} +1 -1
  12. package/dist/{chunk-M752EUK3.js → chunk-3JU4UYYN.js} +5 -5
  13. package/dist/{chunk-G6BCST3G.js → chunk-3ZOUNCA5.js} +7 -7
  14. package/dist/{chunk-76Z6E7XX.js → chunk-4UZN6TVT.js} +74 -131
  15. package/dist/chunk-4UZN6TVT.js.map +1 -0
  16. package/dist/{chunk-ABT3BLRC.js → chunk-5TKXHS3X.js} +3 -3
  17. package/dist/{chunk-QCYSONXI.js → chunk-CRYHWO4M.js} +2 -2
  18. package/dist/{chunk-QTYUM4ZB.js → chunk-EJ3ZPH5U.js} +23 -187
  19. package/dist/chunk-EJ3ZPH5U.js.map +1 -0
  20. package/dist/{chunk-I5RHTCPY.js → chunk-EL6KJ4PO.js} +4 -4
  21. package/dist/{chunk-ZL4O6C42.js → chunk-HXBK3AGD.js} +2 -2
  22. package/dist/{chunk-PRERH4DN.js → chunk-I2SOHQ2C.js} +3 -3
  23. package/dist/{chunk-CYSPCGO6.js → chunk-JEHHEMUL.js} +5 -5
  24. package/dist/{chunk-LIEADTEF.js → chunk-LJFVRJCA.js} +2 -2
  25. package/dist/{chunk-UEJ2HTKU.js → chunk-MJVUMVLO.js} +19 -1
  26. package/dist/chunk-MJVUMVLO.js.map +1 -0
  27. package/dist/chunk-N55RKCGR.js +24 -0
  28. package/dist/chunk-N55RKCGR.js.map +1 -0
  29. package/dist/{chunk-PHNH3CEU.js → chunk-O4Z44BR7.js} +5 -5
  30. package/dist/{chunk-QA37WVF6.js → chunk-OQFCZERZ.js} +6 -6
  31. package/dist/{chunk-EUVB6Y3C.js → chunk-P7L5KELH.js} +8 -8
  32. package/dist/chunk-P7L5KELH.js.map +1 -0
  33. package/dist/{chunk-Z3MDQSZG.js → chunk-PJFFGQSB.js} +2 -2
  34. package/dist/{chunk-IY3ZK46I.js → chunk-QOVJUSSL.js} +2 -2
  35. package/dist/{chunk-RPJMQBB5.js → chunk-QXU4G4YN.js} +3 -3
  36. package/dist/{chunk-SZSTJIYU.js → chunk-RRSUKARV.js} +4 -4
  37. package/dist/{chunk-775FI436.js → chunk-RVD6J6IZ.js} +2 -2
  38. package/dist/{chunk-5UUIBY6E.js → chunk-TAVBFLCR.js} +3 -3
  39. package/dist/{chunk-ROX7N3RK.js → chunk-V7HB5LAU.js} +10 -7
  40. package/dist/chunk-V7HB5LAU.js.map +1 -0
  41. package/dist/{chunk-LL6TSQWV.js → chunk-VKZOHJCE.js} +3 -3
  42. package/dist/chunk-VKZOHJCE.js.map +1 -0
  43. package/dist/{chunk-3HI6QC4V.js → chunk-WRBU6TX7.js} +2 -2
  44. package/dist/{proofs-TXJGAP5F.js → chunk-X7SUSIY3.js} +118 -20
  45. package/dist/chunk-X7SUSIY3.js.map +1 -0
  46. package/dist/{chunk-BF3IPGMP.js → chunk-XSSZMG65.js} +4 -4
  47. package/dist/{credential-TWSWV64F.js → credential-4RFRU6OH.js} +5 -5
  48. package/dist/{credential-template-XO5D5AI3.js → credential-template-36PFUTBN.js} +5 -5
  49. package/dist/{digest-SLEFOLPV.js → digest-THMKFMP7.js} +8 -8
  50. package/dist/{docs-IDC4V4WQ.js → docs-ZGM53L67.js} +5 -5
  51. package/dist/{doctor-SDAYEA6C.js → doctor-Z2XBGBM3.js} +3 -3
  52. package/dist/{environment-VBUIBQ6O.js → environment-5YVZXBN7.js} +7 -7
  53. package/dist/eval-SO5TPD37.js +1177 -0
  54. package/dist/eval-SO5TPD37.js.map +1 -0
  55. package/dist/{exploration-IREIR5PO.js → exploration-GZ4WUJJH.js} +5 -5
  56. package/dist/{exploratory-test-4Q7BMEFT.js → exploratory-test-Y7P4ZDLD.js} +5 -5
  57. package/dist/{external-run-S7LULKPT.js → external-run-IJGGZOGI.js} +7 -7
  58. package/dist/{feature-flag-IASHTUGU.js → feature-flag-UH6Z7774.js} +5 -5
  59. package/dist/{flow-IBEZFZTU.js → flow-MRWAQYZZ.js} +5 -5
  60. package/dist/{github-HAEZRULP.js → github-VDJU3PU3.js} +6 -6
  61. package/dist/index.js +101 -82
  62. package/dist/index.js.map +1 -1
  63. package/dist/{init-LT2TZMQY.js → init-CROSTPA6.js} +5 -5
  64. package/dist/{install-RTEYH6TK.js → install-ECR7OLAY.js} +5 -5
  65. package/dist/{issues-5GE277R2.js → issues-K5TL2S4Z.js} +7 -7
  66. package/dist/{knobs-AMIWGYUZ.js → knobs-OKQFBQLK.js} +5 -5
  67. package/dist/{landing-3VLVVQL5.js → landing-XANIBPVM.js} +7 -7
  68. package/dist/{list-GDJR6UY6.js → list-64GX47Q4.js} +5 -5
  69. package/dist/{local-4R6GVW7U.js → local-QMQY2ZUX.js} +7 -7
  70. package/dist/{login-IXVAWTLO.js → login-I7UQ3GTM.js} +5 -5
  71. package/dist/{mcp-BM2MJWX4.js → mcp-XZV63DX5.js} +11 -11
  72. package/dist/{mcp-BM2MJWX4.js.map → mcp-XZV63DX5.js.map} +1 -1
  73. package/dist/{metrics-SSIP5CEB.js → metrics-KBTQ3KGZ.js} +5 -5
  74. package/dist/{monitor-ESZYHXT2.js → monitor-UGWY43IU.js} +5 -5
  75. package/dist/perf-CCHWHCSR.js +961 -0
  76. package/dist/perf-CCHWHCSR.js.map +1 -0
  77. package/dist/{product-VCGUV5TH.js → product-KLG2ZTHC.js} +5 -5
  78. package/dist/{product-map-AXKZNQDM.js → product-map-AMEZ76EQ.js} +5 -5
  79. package/dist/{prompts-FVPSON2N.js → prompts-ZVQNGL7X.js} +5 -5
  80. package/dist/proofs-QCNSQAPX.js +20 -0
  81. package/dist/{property-XEPCC7KQ.js → property-PJDQFHAL.js} +6 -6
  82. package/dist/{psql-JKF3OYYJ.js → psql-AURAN27C.js} +5 -5
  83. package/dist/{record-REQ37S54.js → record-SYWBTUOB.js} +6 -6
  84. package/dist/{redis-WGHT2GJB.js → redis-2H752SKO.js} +5 -5
  85. package/dist/{release-SNDIVIA6.js → release-OSIYUXSC.js} +5 -5
  86. package/dist/{runbook-XFJG2LFC.js → runbook-7LVHF6KV.js} +5 -5
  87. package/dist/{sandbox-DYCKLCMY.js → sandbox-TJQPMRGS.js} +18 -30
  88. package/dist/sandbox-TJQPMRGS.js.map +1 -0
  89. package/dist/{scenarios-PVHCKP55.js → scenarios-P2ABU4HK.js} +5 -5
  90. package/dist/{schedule-DGC7CX23.js → schedule-XLS56NP5.js} +8 -8
  91. package/dist/{session-ERGUFDDI.js → session-ACSFC3UB.js} +8 -8
  92. package/dist/{skill-6QO2E3TB.js → skill-F7I5P6AI.js} +43 -28
  93. package/dist/{skill-6QO2E3TB.js.map → skill-F7I5P6AI.js.map} +1 -1
  94. package/dist/{slack-WE7THLLH.js → slack-ZEK4GRND.js} +6 -6
  95. package/dist/{spec-SEOY7N3L.js → spec-XPIRRSV6.js} +5 -5
  96. package/dist/{src-CCK3TKBX.js → src-N7ZCYCXU.js} +4 -4
  97. package/dist/{src-AEWV5HYH.js → src-XSBBMVGW.js} +3 -3
  98. package/dist/{start-EPGLHTND.js → start-DKWLOQI6.js} +5 -5
  99. package/dist/{status-DTE2GXM2.js → status-K7KH5DI3.js} +5 -5
  100. package/dist/{tag-GIFEWGBL.js → tag-2Y3OMQQC.js} +6 -6
  101. package/dist/{task-VLJCHSFB.js → task-4PIOC4QV.js} +6 -6
  102. package/dist/{teams-J2OOJBL4.js → teams-KUM56BE2.js} +83 -47
  103. package/dist/teams-KUM56BE2.js.map +1 -0
  104. package/dist/{test-suite-CTACGIAZ.js → test-suite-SW25YGJV.js} +138 -96
  105. package/dist/test-suite-SW25YGJV.js.map +1 -0
  106. package/dist/{trace-RWQDYL4K.js → trace-QPXHYBLA.js} +7 -7
  107. package/dist/{triage-6UAXLCGU.js → triage-EZABRZZM.js} +6 -6
  108. package/dist/trigger-7C7KX5KH.js +137 -0
  109. package/dist/trigger-7C7KX5KH.js.map +1 -0
  110. package/dist/{update-check-QRREAM3N.js → update-check-E3X7UIY6.js} +3 -3
  111. package/dist/{upgrade-5Y655TQ6.js → upgrade-EJGTMW44.js} +4 -4
  112. package/dist/{usage-KCXFY46V.js → usage-GZCQDULF.js} +7 -7
  113. package/dist/{utilities-SUON2KZK.js → utilities-RIITD53A.js} +6 -6
  114. package/dist/{visual-GJZVJC32.js → visual-FH67OKS2.js} +5 -5
  115. package/dist/{workflow-R5QAXWBX.js → workflow-34YJZ2QQ.js} +38 -86
  116. package/dist/workflow-34YJZ2QQ.js.map +1 -0
  117. package/dist/{workflow-cache-PFBTWLGM.js → workflow-cache-YQ3BGJIG.js} +17 -17
  118. package/dist/{workflow-cache-convergence-resolve-UZGRPC3B.js → workflow-cache-convergence-resolve-SPLBRSNK.js} +5 -5
  119. package/dist/{workflow-debug-RACNWWOL.js → workflow-debug-HZB7TJGK.js} +10 -10
  120. package/dist/workflow-debug-HZB7TJGK.js.map +1 -0
  121. package/dist/{workflow-feedback-RJIQ5R3R.js → workflow-feedback-6UOTIWIQ.js} +5 -5
  122. package/dist/{workflow-fork-LINDCYJ3.js → workflow-fork-IDYHAHCX.js} +5 -5
  123. package/dist/workflow-promotion-U6WYFY5U.js +62 -0
  124. package/dist/workflow-promotion-U6WYFY5U.js.map +1 -0
  125. package/dist/{workflow-proposals-E4EXKAGM.js → workflow-proposals-MMVNIQT3.js} +5 -5
  126. package/dist/{workflow-revisions-5M6APN6R.js → workflow-revisions-BPUOLCZB.js} +5 -5
  127. package/dist/{workflow-status-7KL73WS2.js → workflow-status-RA3IEMEW.js} +5 -5
  128. package/package.json +3 -2
  129. package/dist/chat-target-IZ7YLLU3.js +0 -502
  130. package/dist/chat-target-IZ7YLLU3.js.map +0 -1
  131. package/dist/chunk-76Z6E7XX.js.map +0 -1
  132. package/dist/chunk-EUVB6Y3C.js.map +0 -1
  133. package/dist/chunk-LL6TSQWV.js.map +0 -1
  134. package/dist/chunk-QTYUM4ZB.js.map +0 -1
  135. package/dist/chunk-ROX7N3RK.js.map +0 -1
  136. package/dist/chunk-UEJ2HTKU.js.map +0 -1
  137. package/dist/proofs-TXJGAP5F.js.map +0 -1
  138. package/dist/sandbox-DYCKLCMY.js.map +0 -1
  139. package/dist/teams-J2OOJBL4.js.map +0 -1
  140. package/dist/test-suite-CTACGIAZ.js.map +0 -1
  141. package/dist/workflow-R5QAXWBX.js.map +0 -1
  142. /package/dist/{account-3ZG24MOE.js.map → account-MRZ54P5P.js.map} +0 -0
  143. /package/dist/{alert-5G7PTAX2.js.map → alert-XBHELHEI.js.map} +0 -0
  144. /package/dist/{api-catalog-IBYAFKKQ.js.map → api-catalog-GWYRX53L.js.map} +0 -0
  145. /package/dist/{api-key-UXC44BDR.js.map → api-key-FH6JN447.js.map} +0 -0
  146. /package/dist/{attachment-T6IRFQW3.js.map → attachment-J7GRVT5F.js.map} +0 -0
  147. /package/dist/{auth-SHOCJE6Z.js.map → auth-VZZQXRDR.js.map} +0 -0
  148. /package/dist/{benchmark-NJ2U6VTC.js.map → benchmark-A3SNDARF.js.map} +0 -0
  149. /package/dist/{blackcat-RQJVFGXQ.js.map → blackcat-UM6TBQBN.js.map} +0 -0
  150. /package/dist/{chunk-M752EUK3.js.map → chunk-3JU4UYYN.js.map} +0 -0
  151. /package/dist/{chunk-G6BCST3G.js.map → chunk-3ZOUNCA5.js.map} +0 -0
  152. /package/dist/{chunk-ABT3BLRC.js.map → chunk-5TKXHS3X.js.map} +0 -0
  153. /package/dist/{chunk-QCYSONXI.js.map → chunk-CRYHWO4M.js.map} +0 -0
  154. /package/dist/{chunk-I5RHTCPY.js.map → chunk-EL6KJ4PO.js.map} +0 -0
  155. /package/dist/{chunk-ZL4O6C42.js.map → chunk-HXBK3AGD.js.map} +0 -0
  156. /package/dist/{chunk-PRERH4DN.js.map → chunk-I2SOHQ2C.js.map} +0 -0
  157. /package/dist/{chunk-CYSPCGO6.js.map → chunk-JEHHEMUL.js.map} +0 -0
  158. /package/dist/{chunk-LIEADTEF.js.map → chunk-LJFVRJCA.js.map} +0 -0
  159. /package/dist/{chunk-PHNH3CEU.js.map → chunk-O4Z44BR7.js.map} +0 -0
  160. /package/dist/{chunk-QA37WVF6.js.map → chunk-OQFCZERZ.js.map} +0 -0
  161. /package/dist/{chunk-Z3MDQSZG.js.map → chunk-PJFFGQSB.js.map} +0 -0
  162. /package/dist/{chunk-IY3ZK46I.js.map → chunk-QOVJUSSL.js.map} +0 -0
  163. /package/dist/{chunk-RPJMQBB5.js.map → chunk-QXU4G4YN.js.map} +0 -0
  164. /package/dist/{chunk-SZSTJIYU.js.map → chunk-RRSUKARV.js.map} +0 -0
  165. /package/dist/{chunk-775FI436.js.map → chunk-RVD6J6IZ.js.map} +0 -0
  166. /package/dist/{chunk-5UUIBY6E.js.map → chunk-TAVBFLCR.js.map} +0 -0
  167. /package/dist/{chunk-3HI6QC4V.js.map → chunk-WRBU6TX7.js.map} +0 -0
  168. /package/dist/{chunk-BF3IPGMP.js.map → chunk-XSSZMG65.js.map} +0 -0
  169. /package/dist/{credential-TWSWV64F.js.map → credential-4RFRU6OH.js.map} +0 -0
  170. /package/dist/{credential-template-XO5D5AI3.js.map → credential-template-36PFUTBN.js.map} +0 -0
  171. /package/dist/{digest-SLEFOLPV.js.map → digest-THMKFMP7.js.map} +0 -0
  172. /package/dist/{docs-IDC4V4WQ.js.map → docs-ZGM53L67.js.map} +0 -0
  173. /package/dist/{doctor-SDAYEA6C.js.map → doctor-Z2XBGBM3.js.map} +0 -0
  174. /package/dist/{environment-VBUIBQ6O.js.map → environment-5YVZXBN7.js.map} +0 -0
  175. /package/dist/{exploration-IREIR5PO.js.map → exploration-GZ4WUJJH.js.map} +0 -0
  176. /package/dist/{exploratory-test-4Q7BMEFT.js.map → exploratory-test-Y7P4ZDLD.js.map} +0 -0
  177. /package/dist/{external-run-S7LULKPT.js.map → external-run-IJGGZOGI.js.map} +0 -0
  178. /package/dist/{feature-flag-IASHTUGU.js.map → feature-flag-UH6Z7774.js.map} +0 -0
  179. /package/dist/{flow-IBEZFZTU.js.map → flow-MRWAQYZZ.js.map} +0 -0
  180. /package/dist/{github-HAEZRULP.js.map → github-VDJU3PU3.js.map} +0 -0
  181. /package/dist/{init-LT2TZMQY.js.map → init-CROSTPA6.js.map} +0 -0
  182. /package/dist/{install-RTEYH6TK.js.map → install-ECR7OLAY.js.map} +0 -0
  183. /package/dist/{issues-5GE277R2.js.map → issues-K5TL2S4Z.js.map} +0 -0
  184. /package/dist/{knobs-AMIWGYUZ.js.map → knobs-OKQFBQLK.js.map} +0 -0
  185. /package/dist/{landing-3VLVVQL5.js.map → landing-XANIBPVM.js.map} +0 -0
  186. /package/dist/{list-GDJR6UY6.js.map → list-64GX47Q4.js.map} +0 -0
  187. /package/dist/{local-4R6GVW7U.js.map → local-QMQY2ZUX.js.map} +0 -0
  188. /package/dist/{login-IXVAWTLO.js.map → login-I7UQ3GTM.js.map} +0 -0
  189. /package/dist/{metrics-SSIP5CEB.js.map → metrics-KBTQ3KGZ.js.map} +0 -0
  190. /package/dist/{monitor-ESZYHXT2.js.map → monitor-UGWY43IU.js.map} +0 -0
  191. /package/dist/{product-VCGUV5TH.js.map → product-KLG2ZTHC.js.map} +0 -0
  192. /package/dist/{product-map-AXKZNQDM.js.map → product-map-AMEZ76EQ.js.map} +0 -0
  193. /package/dist/{prompts-FVPSON2N.js.map → prompts-ZVQNGL7X.js.map} +0 -0
  194. /package/dist/{src-AEWV5HYH.js.map → proofs-QCNSQAPX.js.map} +0 -0
  195. /package/dist/{property-XEPCC7KQ.js.map → property-PJDQFHAL.js.map} +0 -0
  196. /package/dist/{psql-JKF3OYYJ.js.map → psql-AURAN27C.js.map} +0 -0
  197. /package/dist/{record-REQ37S54.js.map → record-SYWBTUOB.js.map} +0 -0
  198. /package/dist/{redis-WGHT2GJB.js.map → redis-2H752SKO.js.map} +0 -0
  199. /package/dist/{release-SNDIVIA6.js.map → release-OSIYUXSC.js.map} +0 -0
  200. /package/dist/{runbook-XFJG2LFC.js.map → runbook-7LVHF6KV.js.map} +0 -0
  201. /package/dist/{scenarios-PVHCKP55.js.map → scenarios-P2ABU4HK.js.map} +0 -0
  202. /package/dist/{schedule-DGC7CX23.js.map → schedule-XLS56NP5.js.map} +0 -0
  203. /package/dist/{session-ERGUFDDI.js.map → session-ACSFC3UB.js.map} +0 -0
  204. /package/dist/{slack-WE7THLLH.js.map → slack-ZEK4GRND.js.map} +0 -0
  205. /package/dist/{spec-SEOY7N3L.js.map → spec-XPIRRSV6.js.map} +0 -0
  206. /package/dist/{src-CCK3TKBX.js.map → src-N7ZCYCXU.js.map} +0 -0
  207. /package/dist/{tag-GIFEWGBL.js.map → src-XSBBMVGW.js.map} +0 -0
  208. /package/dist/{start-EPGLHTND.js.map → start-DKWLOQI6.js.map} +0 -0
  209. /package/dist/{status-DTE2GXM2.js.map → status-K7KH5DI3.js.map} +0 -0
  210. /package/dist/{trace-RWQDYL4K.js.map → tag-2Y3OMQQC.js.map} +0 -0
  211. /package/dist/{task-VLJCHSFB.js.map → task-4PIOC4QV.js.map} +0 -0
  212. /package/dist/{triage-6UAXLCGU.js.map → trace-QPXHYBLA.js.map} +0 -0
  213. /package/dist/{update-check-QRREAM3N.js.map → triage-EZABRZZM.js.map} +0 -0
  214. /package/dist/{upgrade-5Y655TQ6.js.map → update-check-E3X7UIY6.js.map} +0 -0
  215. /package/dist/{utilities-SUON2KZK.js.map → upgrade-EJGTMW44.js.map} +0 -0
  216. /package/dist/{usage-KCXFY46V.js.map → usage-GZCQDULF.js.map} +0 -0
  217. /package/dist/{workflow-debug-RACNWWOL.js.map → utilities-RIITD53A.js.map} +0 -0
  218. /package/dist/{visual-GJZVJC32.js.map → visual-FH67OKS2.js.map} +0 -0
  219. /package/dist/{workflow-cache-PFBTWLGM.js.map → workflow-cache-YQ3BGJIG.js.map} +0 -0
  220. /package/dist/{workflow-cache-convergence-resolve-UZGRPC3B.js.map → workflow-cache-convergence-resolve-SPLBRSNK.js.map} +0 -0
  221. /package/dist/{workflow-feedback-RJIQ5R3R.js.map → workflow-feedback-6UOTIWIQ.js.map} +0 -0
  222. /package/dist/{workflow-fork-LINDCYJ3.js.map → workflow-fork-IDYHAHCX.js.map} +0 -0
  223. /package/dist/{workflow-proposals-E4EXKAGM.js.map → workflow-proposals-MMVNIQT3.js.map} +0 -0
  224. /package/dist/{workflow-revisions-5M6APN6R.js.map → workflow-revisions-BPUOLCZB.js.map} +0 -0
  225. /package/dist/{workflow-status-7KL73WS2.js.map → workflow-status-RA3IEMEW.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/skill.ts","../src/skill-identity.ts","../src/skill-install-helpers.ts","../src/skill-templates/cofactor-browser-testing.ts","../src/skill-templates/cofactor-debug-run.ts","../src/skill-templates/cofactor-onboarding.ts","../src/skill-templates/cofactor-prove-with-tests.ts","../src/skill-templates/cofactor-triage-issues.ts","../src/skill-templates/cofactor-triage-tests.ts","../src/skill-templates/cofactor-write-test.ts","../src/skill-templates/index.ts","../src/skill-version-commands.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { brandSkillContentFor, brandTextFor, command } from \"./brand.js\";\nimport { applyInstallIdentity, installedSourceKey } from \"./skill-identity.js\";\nimport {\n detectAgent,\n formatInstallWriteFailure,\n isAgentType,\n isValidInstallName,\n resolveInstallDir,\n SUPPORTED_AGENTS,\n} from \"./skill-install-helpers.js\";\nimport { SKILL_TEMPLATES } from \"./skill-templates/index.js\";\nimport { knownVersions, runDiff, runVersions } from \"./skill-version-commands.js\";\nimport type { AgentType } from \"./skill-install-helpers.js\";\n\nexport { applyInstallIdentity, installedSourceKey, SKILL_SOURCE_KEY } from \"./skill-identity.js\";\nexport {\n detectAgent,\n formatInstallWriteFailure,\n isInstallPermissionError,\n isValidInstallName,\n resolveInstallDir,\n} from \"./skill-install-helpers.js\";\nexport type { AgentType, InstallWriteFailureContext } from \"./skill-install-helpers.js\";\n\n/**\n * Render a skill template for the active brand. Install/output go through here\n * so a `cofactor` binary writes cofactor-branded skill files while `canary`\n * stays byte-for-byte identical. Authored-content tooling (`diff`, `versions`)\n * stays raw so it compares the source, not the per-brand presentation.\n */\nfunction renderForActiveBrand(template: { render: () => string }): string {\n return brandSkillContentFor(template.render(), command);\n}\n\nfunction printSkillHelp() {\n const lines = [\n \"Usage:\",\n \" canary skill <name> Output skill template to stdout\",\n \" canary skill install <name> Install skill (auto-detects agent)\",\n \" canary skill install <name> --agent codex Install for a specific agent\",\n \" canary skill install <name> --personal Install to ~/.<agent>/skills/\",\n \" canary skill install <name> --name <as> Install under a custom skill name\",\n \" canary skill install <name> --force Overwrite a name held by another skill\",\n \" canary skill list List available skill templates\",\n \" canary skill sync Print manifest + instructions for the\",\n \" agent to version-compare and update\",\n \" installed skills\",\n \" canary skill diff <name> [--from V] [--to V] Unified diff between two versions of\",\n \" a skill (defaults: previous → current)\",\n \" canary skill versions <name> List all known versions of a skill\",\n \"\",\n \"Agent auto-detection:\",\n \" The install command detects which AI agent is running and writes the\",\n \" SKILL.md to the correct location:\",\n \"\",\n \" Agent Project path Personal path\",\n \" ───── ──────────── ─────────────\",\n \" claude .claude/skills/<name>/ ~/.claude/skills/<name>/\",\n \" codex .codex/skills/<name>/ ~/.codex/skills/<name>/\",\n \" copilot .github/skills/<name>/ ~/.copilot/skills/<name>/\",\n \"\",\n \" Detection checks (in order):\",\n \" 1. CLAUDE env var → claude\",\n \" 2. CODEX_* env vars → codex\",\n \" 3. GITHUB_COPILOT env var → copilot\",\n \" 4. .claude/.codex/.github dirs → whichever single one exists\",\n \" 5. If ambiguous, use --agent to specify explicitly\",\n \"\",\n \"Custom skill names (--name):\",\n \" By default a skill installs under its template name. Pass --name to install\",\n \" it under a name of your choosing — useful when you want every Canary-provided\",\n \" skill namespaced (e.g. my-browser-testing) to avoid colliding with your\",\n \" own skills. --name sets both the install directory and the SKILL.md\",\n \" frontmatter name: (agents require those to match), and records the source\",\n \" template in a skill-source: field so `sync` and `diff` keep tracking updates\",\n \" even under the renamed install.\",\n \"\",\n \" canary skill install cofactor-browser-testing --name my-browser-testing\",\n \"\",\n \" Installing a different skill onto an existing custom name is refused unless\",\n \" you pass --force. When an agent installs skills on your behalf, it should\",\n \" follow your naming convention.\",\n \"\",\n \"Available templates:\",\n ];\n\n for (const [key, template] of Object.entries(SKILL_TEMPLATES)) {\n lines.push(` ${key.padEnd(24)} v${template.version.padEnd(7)} ${template.description}`);\n }\n\n console.log(lines.join(\"\\n\"));\n}\n\n/**\n * Skill names retired by the 2.0.0 trim, mapped to the skills that replace them.\n * Without this, installs under the old names would be orphaned (sync only\n * resolves names that are still in SKILL_TEMPLATES). Delete this map one major\n * version after 2.0.0.\n */\nconst RETIRED_SKILLS: Record<string, string[]> = {\n \"canary-basic\": [\"cofactor-triage-issues\", \"cofactor-triage-tests\"],\n \"agent-tasks\": [\"cofactor-triage-issues\"],\n \"issue-log-xref\": [\"cofactor-triage-issues\"],\n sandbox: [],\n \"optimize-cache\": [],\n \"test-cases\": [\"cofactor-write-test\"],\n \"browser-testing\": [\"cofactor-browser-testing\"],\n \"debug-run\": [\"cofactor-debug-run\"],\n};\n\nfunction retiredSkillHint(name: string): string | undefined {\n const replacements = RETIRED_SKILLS[name];\n if (!replacements) return undefined;\n return replacements.length > 0\n ? `\"${name}\" was retired in 2.0.0. Install ${replacements.join(\" and \")} instead.`\n : `\"${name}\" was retired in 2.0.0 and has no replacement.`;\n}\n\nfunction runSync() {\n const manifest = Object.entries(SKILL_TEMPLATES).map(([key, t]) => ({\n name: key,\n version: t.version,\n description: t.description,\n knownVersions: knownVersions(key),\n installedPaths: {\n claudeProject: `.claude/skills/${key}/SKILL.md`,\n claudePersonal: join(homedir(), \".claude\", \"skills\", key, \"SKILL.md\"),\n codexProject: `.codex/skills/${key}/SKILL.md`,\n codexPersonal: join(homedir(), \".codex\", \"skills\", key, \"SKILL.md\"),\n copilotProject: `.github/skills/${key}/SKILL.md`,\n copilotPersonal: join(homedir(), \".copilot\", \"skills\", key, \"SKILL.md\"),\n },\n }));\n\n const instructions = `# Canary Skill Sync — Instructions for the Agent\n\nYou are an AI coding agent (Claude, Codex, Copilot, etc.). The user ran \\`canary skill sync\\`\nto bring their installed Canary skill templates up to date. Follow these steps:\n\n## Step 1 — Discover installed skills (including renamed ones)\n\nSkills can be installed under a **custom name** (\\`canary skill install <name> --name <as>\\`),\nso do not rely only on the canonical \\`installedPaths\\` below. List every \\`SKILL.md\\`\nunder your agent's skills directory — both project and personal:\n\n .claude/skills/*/SKILL.md and ~/.claude/skills/*/SKILL.md (claude)\n .codex/skills/*/SKILL.md and ~/.codex/skills/*/SKILL.md (codex)\n .github/skills/*/SKILL.md and ~/.copilot/skills/*/SKILL.md (copilot)\n\nFor each file, read its frontmatter and resolve which manifest skill it came from:\n- If a \\`skill-source: <key>\\` line is present, that \\`<key>\\` is the template name\n (the skill was installed under a custom \\`--name\\`). The install directory is the\n custom name; remember it for Step 5.\n- Otherwise the \\`name:\\` value is the template name (a default install, where the\n install name equals the template key).\n\nMatch that resolved key against the manifest \\`name\\` field (current skills) and the\n\\`retiredSkills\\` keys. Ignore any \\`SKILL.md\\` whose resolved key is in neither (it isn't\na Canary skill).\n\n## Step 2 — Read the version of each installed skill\n\nSkills whose resolved key is in \\`retiredSkills\\` skip Steps 2–5; handle them in Step 6.\n\n\nThe \\`SKILL.md\\` frontmatter contains a \\`version: X.Y.Z\\` line. Parse that value.\nIf the frontmatter has no \\`version:\\` field, treat the installed version as \\`0.0.0\\`.\n\n## Step 3 — Compare semver\n\nFor each installed skill, compare \\`installedVersion\\` to the \\`version\\` in the manifest:\n- If \\`installedVersion < manifestVersion\\` → the skill is **outdated**, update it.\n- If equal or greater → leave it alone.\n\n## Step 4 — For each outdated skill, inspect what changed\n\nBefore overwriting, read the diff so you know what's new. Diff by the **template\nkey** you resolved in Step 1 (not the custom install name) — the diff compares\nsource renders and is independent of how the skill was named on disk:\n\n canary skill diff <templateKey> --from <installedVersion>\n\nThe CLI retains past renders of each skill in \\`previousVersions\\`, so this prints a\nunified diff from the user's installed version → the current version. Only versions\nlisted in \\`knownVersions\\` in the manifest can be diffed; if \\`installedVersion\\` is\nolder than the oldest known version, diff against the oldest known version instead\nand warn the user that the older content is no longer reproducible.\n\nUse the diff to:\n- Summarize what changed for the user (new sections, removed guidance, renamed commands).\n- Decide whether any user-local edits to the installed SKILL.md would be clobbered —\n if the user appears to have edited their local copy, surface that and ask before\n overwriting.\n\n## Step 5 — Update outdated skills\n\nRe-install with the template key, preserving both the location AND the custom name\nit was installed under (the install directory name from Step 1):\n\n canary skill install <templateKey> # default-named project install\n canary skill install <templateKey> --personal # default-named personal install\n canary skill install <templateKey> --name <installDir> # custom-named project install\n canary skill install <templateKey> --name <installDir> --personal\n\nPreserve whichever location and name it was already installed in — if it lived in\n\\`my-browser-testing/\\`, re-install with \\`--name my-browser-testing\\` so the\nupdate lands in place rather than creating a second default-named copy. Do NOT install\nskills that weren't already installed — sync only updates existing installs. When the\nuser has a naming convention, keep installing under their chosen names on their behalf.\n\n## Step 6 — Retire renamed skills\n\nAn installed skill whose resolved key (Step 1) is listed under \\`retiredSkills\\` no longer\nexists. Tell the user to remove its install directory and install each replacement in its\nvalue list with \\`canary skill install <replacement>\\` (same location; if it was installed\nunder a custom directory name and has a single replacement, pass \\`--name <installDir>\\`;\notherwise install under the default names).\nAn empty list means the skill was dropped with no replacement.\n\n## Step 7 — Report\n\nPrint a concise summary: which skills were updated (old → new version), which were\nalready current, which were retired (and what replaced them), and which were not\ninstalled (skipped).\n\n## Manifest\n\n\\`\\`\\`json\n${JSON.stringify({ skills: manifest, retiredSkills: RETIRED_SKILLS }, null, 2)}\n\\`\\`\\`\n`;\n\n // process.stdout bypasses the console branding patch, so brand explicitly.\n process.stdout.write(brandTextFor(instructions, command));\n}\n\nfunction parseInstallArgs(argv: string[]): {\n /** The registry/template key (positional argument). */\n templateName: string | undefined;\n /** Directory + frontmatter name to install under (defaults to templateName). */\n installName: string | undefined;\n agent: AgentType | undefined;\n personal: boolean;\n force: boolean;\n} {\n let templateName: string | undefined;\n let installName: string | undefined;\n let agent: AgentType | undefined;\n let personal = false;\n let force = false;\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--agent\" && i + 1 < argv.length) {\n const val = argv[++i];\n if (!isAgentType(val)) {\n console.error(`Unknown agent \"${val}\". Supported agents: ${SUPPORTED_AGENTS.join(\", \")}`);\n process.exit(1);\n }\n agent = val;\n } else if (arg === \"--name\" && i + 1 < argv.length) {\n const val = argv[++i];\n if (!isValidInstallName(val)) {\n console.error(\n `Invalid skill name \"${val}\". Use letters, digits, hyphens, or underscores (e.g. my-browser-testing).`\n );\n process.exit(1);\n }\n installName = val;\n } else if (arg === \"--personal\") {\n personal = true;\n } else if (arg === \"--force\" || arg === \"-f\") {\n force = true;\n } else if (!arg.startsWith(\"-\") && !templateName) {\n templateName = arg;\n }\n }\n\n return { templateName, installName: installName ?? templateName, agent, personal, force };\n}\n\nasync function runInstall(argv: string[]) {\n const {\n templateName,\n installName,\n agent: explicitAgent,\n personal,\n force,\n } = parseInstallArgs(argv);\n\n if (!templateName || !installName) {\n console.error(\"Missing skill name.\\n\");\n console.error(\n `Usage: canary skill install <name> [--name <install-name>] [--agent ${SUPPORTED_AGENTS.join(\"|\")}] [--personal] [--force]`\n );\n process.exit(1);\n }\n\n const template = SKILL_TEMPLATES[templateName];\n if (!template) {\n console.error(`Unknown skill template \"${templateName}\".\\n`);\n const hint = retiredSkillHint(templateName);\n if (hint) console.error(`${hint}\\n`);\n console.error(\"Available templates:\");\n for (const [key, t] of Object.entries(SKILL_TEMPLATES)) {\n console.error(` ${key.padEnd(24)} ${t.description}`);\n }\n process.exit(1);\n }\n\n // Resolve agent type\n const agent = explicitAgent ?? detectAgent();\n if (!agent) {\n console.error(\"Could not auto-detect the AI agent. Use --agent to specify:\\n\");\n console.error(\" canary skill install <name> --agent claude # Claude Code\");\n console.error(\" canary skill install <name> --agent codex # OpenAI Codex\");\n console.error(\" canary skill install <name> --agent copilot # GitHub Copilot\");\n process.exit(1);\n }\n\n const dir = resolveInstallDir(installName, agent, personal);\n const filePath = join(dir, \"SKILL.md\");\n\n // Collision guard: refuse to clobber a SKILL.md installed under this name from\n // a DIFFERENT template (e.g. collapsing multiple skills onto one name) unless\n // --force is passed. Updating the same skill in place is always allowed.\n if (existsSync(filePath) && !force) {\n const existingSource = installedSourceKey(readFileSync(filePath, \"utf-8\"));\n if (existingSource && existingSource !== templateName) {\n console.error(\n `✗ ${installName} already holds '${existingSource}'. Pass --force to overwrite.`\n );\n process.exit(1);\n }\n }\n\n // Write the file (brand-aware: cofactor binary writes cofactor-branded text),\n // rewriting the frontmatter identity when installing under a custom name.\n const content = applyInstallIdentity(renderForActiveBrand(template), installName, templateName);\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(filePath, content, \"utf-8\");\n } catch (error) {\n console.error(\n formatInstallWriteFailure({\n cwd: process.cwd(),\n templateName,\n installName,\n agent,\n personal,\n dir,\n filePath,\n error,\n })\n );\n process.exit(1);\n }\n\n const relPath = personal ? filePath : filePath.replace(process.cwd() + \"/\", \"\");\n const named = installName === templateName ? \"\" : ` as ${installName}`;\n console.log(`Installed ${templateName} skill for ${agent}${named} → ${relPath}`);\n}\n\nfunction runList() {\n for (const [key, template] of Object.entries(SKILL_TEMPLATES)) {\n console.log(`${key.padEnd(30)} ${brandTextFor(template.description, command)}`);\n }\n}\n\nexport async function runSkill(argv: string[]) {\n const [sub] = argv;\n\n // Anywhere in argv: `skill install <name> --help` must not install.\n if (sub === \"list\" && !argv.includes(\"--help\") && !argv.includes(\"-h\")) {\n runList();\n return;\n }\n\n if (!sub || sub === \"help\" || argv.includes(\"--help\") || argv.includes(\"-h\")) {\n printSkillHelp();\n return;\n }\n\n // canary skill install <name> [--agent ...]\n if (sub === \"install\") {\n await runInstall(argv.slice(1));\n return;\n }\n\n // canary skill sync — print instructions for the agent\n if (sub === \"sync\") {\n runSync();\n return;\n }\n\n if (sub === \"diff\") {\n runDiff(argv.slice(1));\n return;\n }\n\n if (sub === \"versions\") {\n runVersions(argv.slice(1));\n return;\n }\n\n // canary skill <name> — output to stdout (backward compatible)\n const template = SKILL_TEMPLATES[sub];\n if (!template) {\n console.error(`Unknown skill template \"${sub}\".\\n`);\n const hint = retiredSkillHint(sub);\n if (hint) console.error(`${hint}\\n`);\n printSkillHelp();\n process.exit(1);\n }\n\n process.stdout.write(renderForActiveBrand(template));\n}\n","/**\n * Skill frontmatter identity helpers.\n *\n * These helpers keep custom-named installs traceable to their source template\n * without coupling that parsing/writing logic to the skill command runner.\n */\n\n/**\n * Brand-neutral frontmatter key that records which template a SKILL.md was\n * rendered from. Stamped only when a skill is installed under a custom name\n * (`--name`), so `sync`/`diff` can map a renamed install back to its template\n * for version-compare and update.\n */\nexport const SKILL_SOURCE_KEY = \"skill-source\";\n\n/**\n * Split a SKILL.md into its leading YAML frontmatter block and the body. The\n * frontmatter is the block between the first `---` line and the next `---`\n * line. Returns `null` when the content has no recognizable frontmatter, so\n * callers can skip identity rewriting rather than corrupt the file.\n */\nfunction splitFrontmatter(\n content: string\n): { frontmatter: string; body: string } | null {\n const lines = content.split(\"\\n\");\n if (lines[0] !== \"---\") return null;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === \"---\") {\n return {\n frontmatter: lines.slice(1, i).join(\"\\n\"),\n // Keep the closing `---` and everything after it in the body so a\n // round-trip with `applyInstallIdentity` reproduces the file exactly.\n body: lines.slice(i).join(\"\\n\"),\n };\n }\n }\n return null;\n}\n\n/**\n * Read a single `key: value` field out of a frontmatter block. Returns `null`\n * when the key is absent. Used to recover an installed skill's `name:` /\n * `skill-source:` for the collision guard.\n */\nfunction readFrontmatterField(frontmatter: string, key: string): string | null {\n for (const line of frontmatter.split(\"\\n\")) {\n const match = line.match(/^([A-Za-z0-9_-]+):\\s*(.*)$/);\n if (match && match[1] === key) return match[2].trim();\n }\n return null;\n}\n\n/**\n * Derive the template key an already-installed SKILL.md was rendered from:\n * the `skill-source:` stamp when present (custom-named install), otherwise the\n * `name:` field (a default install, where name === template key). `null` when\n * neither is present.\n */\nexport function installedSourceKey(content: string): string | null {\n const parts = splitFrontmatter(content);\n if (!parts) return null;\n return (\n readFrontmatterField(parts.frontmatter, SKILL_SOURCE_KEY) ??\n readFrontmatterField(parts.frontmatter, \"name\")\n );\n}\n\n/**\n * Rewrite a rendered SKILL.md so it installs cleanly under `installName`:\n * the frontmatter `name:` is set to `installName` (agents require `name:` to\n * match the install directory), and — only when the name differs from the\n * template key — a `skill-source: <templateKey>` line is stamped so\n * `sync`/`diff` can still track the install.\n */\nexport function applyInstallIdentity(\n content: string,\n installName: string,\n templateKey: string\n): string {\n if (installName === templateKey) return content;\n\n const parts = splitFrontmatter(content);\n if (!parts) return content;\n\n const out: string[] = [];\n let wroteName = false;\n let wroteSource = false;\n for (const line of parts.frontmatter.split(\"\\n\")) {\n const match = line.match(/^([A-Za-z0-9_-]+):\\s*(.*)$/);\n const key = match?.[1];\n if (key === \"name\") {\n out.push(`name: ${installName}`);\n out.push(`${SKILL_SOURCE_KEY}: ${templateKey}`);\n wroteName = true;\n wroteSource = true;\n } else if (key === SKILL_SOURCE_KEY) {\n // Re-stamp from the template key rather than trusting a stale value.\n if (!wroteSource) {\n out.push(`${SKILL_SOURCE_KEY}: ${templateKey}`);\n wroteSource = true;\n }\n } else {\n out.push(line);\n }\n }\n // Defensive: frontmatter missing `name:` / `skill-source:` still gets them.\n if (!wroteName) out.unshift(`name: ${installName}`);\n if (!wroteSource) {\n const nameIdx = out.findIndex((l) => l.startsWith(\"name:\"));\n out.splice(nameIdx >= 0 ? nameIdx + 1 : 0, 0, `${SKILL_SOURCE_KEY}: ${templateKey}`);\n }\n\n // Reassemble: leading `---`, rewritten frontmatter, then the original body\n // (which already starts with its own closing `---` fence).\n return `---\\n${out.join(\"\\n\")}\\n${parts.body}`;\n}\n","/**\n * Skill install path, agent detection, and write-error helpers.\n *\n * The command runner performs template lookup and filesystem writes; this\n * module owns the pure-ish install support logic that is easiest to test in\n * isolation.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { command } from \"./brand.js\";\n\nexport type AgentType = \"claude\" | \"codex\" | \"copilot\";\n\nexport const SUPPORTED_AGENTS: AgentType[] = [\"claude\", \"codex\", \"copilot\"];\n\ntype DetectAgentOptions = {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n exists?: (path: string) => boolean;\n};\n\ntype InstallPathOptions = {\n cwd?: string;\n home?: string;\n};\n\nexport function isAgentType(value: string): value is AgentType {\n return value === \"claude\" || value === \"codex\" || value === \"copilot\";\n}\n\n/**\n * Detect which AI agent is currently running based on environment variables\n * and project directory structure.\n */\nexport function detectAgent(options: DetectAgentOptions = {}): AgentType | null {\n const env = options.env ?? process.env;\n const cwd = options.cwd ?? process.cwd();\n const pathExists = options.exists ?? existsSync;\n\n if (env.CLAUDE) return \"claude\";\n\n if (\n env.CODEX ||\n env.CODEX_CI ||\n env.CODEX_THREAD_ID ||\n env.CODEX_MANAGED_PACKAGE_ROOT ||\n env.AGENT_MODE === \"codex\"\n )\n return \"codex\";\n\n if (\n env.GITHUB_COPILOT ||\n env.COPILOT_AGENT ||\n env.AGENT_MODE === \"copilot\"\n )\n return \"copilot\";\n\n const foundAgents = SUPPORTED_AGENTS.filter((agent) =>\n pathExists(join(cwd, agent === \"copilot\" ? \".github\" : `.${agent}`))\n );\n\n if (foundAgents.length === 1) return foundAgents[0] ?? null;\n return null;\n}\n\n/**\n * Resolve the install directory for a skill based on agent type.\n */\nexport function resolveInstallDir(\n skillName: string,\n agent: AgentType,\n personal: boolean,\n options: InstallPathOptions = {}\n): string {\n const base = personal\n ? (options.home ?? homedir())\n : (options.cwd ?? process.cwd());\n\n switch (agent) {\n case \"claude\":\n return join(base, \".claude\", \"skills\", skillName);\n case \"codex\":\n return join(base, \".codex\", \"skills\", skillName);\n case \"copilot\":\n return personal\n ? join(base, \".copilot\", \"skills\", skillName)\n : join(base, \".github\", \"skills\", skillName);\n }\n}\n\nexport type InstallWriteFailureContext = {\n cwd: string;\n templateName: string;\n installName: string;\n agent: AgentType;\n personal: boolean;\n dir: string;\n filePath: string;\n error: unknown;\n};\n\nfunction errorField(error: unknown, key: string): string | undefined {\n if (typeof error !== \"object\" || error === null) return undefined;\n const value = (error as Record<string, unknown>)[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport function isInstallPermissionError(error: unknown): boolean {\n const code = errorField(error, \"code\");\n return code === \"EACCES\" || code === \"EPERM\" || code === \"EROFS\";\n}\n\nfunction formatErrorSummary(error: unknown): string {\n const code = errorField(error, \"code\");\n const message = errorField(error, \"message\");\n if (code && message) return `${code}: ${message}`;\n if (message) return message;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function formatInstallWriteFailure(\n context: InstallWriteFailureContext\n): string {\n const lines = [\n `Could not install ${context.templateName} skill for ${context.agent} at ${context.filePath}.`,\n \"\",\n isInstallPermissionError(context.error)\n ? \"The destination is not writable from the current shell.\"\n : \"The CLI could not create or write the destination file.\",\n `Failure: ${formatErrorSummary(context.error)}`,\n \"\",\n ];\n const nameFlag =\n context.installName === context.templateName\n ? \"\"\n : ` --name ${context.installName}`;\n\n if (context.personal) {\n lines.push(\n `Personal installs write under your home directory. Check permissions for ${context.dir}.`,\n \"\",\n \"Try again after fixing permissions:\",\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent} --personal`,\n \"\",\n \"Or run from a writable project directory and install without --personal.\"\n );\n } else {\n lines.push(\n `Project installs write under the current directory (${context.cwd}).`,\n \"Run from a writable project folder, or use --personal to install under your home directory.\",\n \"\",\n \"Try:\",\n \" cd <writable-project>\",\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent}`,\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent} --personal`\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * A custom install name becomes a directory segment and the frontmatter\n * `name:`, so it must be a single safe path component: word characters and\n * hyphens only, no separators, no `..`, no leading dot.\n */\nexport function isValidInstallName(value: string): boolean {\n return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value);\n}\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorBrowserTestingTemplate: SkillTemplate = {\n name: 'cofactor-browser-testing',\n description:\n 'Drive a real browser with the Cofactor CLI to explore, test or verify a web application. Use when the user asks to browse, click through, screenshot or check a page.',\n version: '2.1.0',\n render: () => `---\nname: cofactor-browser-testing\nversion: 2.1.0\ndescription: Drive a real browser with the Cofactor CLI to explore, test or verify a web application. Use when the user asks to browse, click through, screenshot or check a page.\nallowed-tools: Bash(cofactor session:*), Bash(cofactor login:*), Bash(cofactor exploratory-test:*), Read\n---\n\n# Browser Testing\n\nUse this to open a page, interact with it and report what you see.\n\nRun \\`cofactor session guide\\` first. It covers element discovery, waiting, credentials and what to do when the page is logged out.\n\nKey commands:\n\n\\`\\`\\`bash\ncofactor session start # open a browser session\ncofactor session navigate --url <url>\ncofactor session snapshot # list elements you can act on\ncofactor session click --ref <ref> # also: type, fill, press, scroll\ncofactor session screenshot\ncofactor session stop # always clean up\n\\`\\`\\`\n\n## Hand the exploring to an agent\n\nTo have a Cofactor agent explore an application from a prompt and report what it finds (an exploratory test), start one instead of driving the browser yourself:\n\n\\`\\`\\`bash\ncofactor exploratory-test run --application <name|id> --prompt \"Try the checkout flow as a new customer\" --wait\ncofactor exploratory-test run --application <name|id> --prompt @charter.md --sandbox-env <name> --wait # a Sandboxes v2 environment\ncofactor exploratory-test get <id> # status, summary, issues, video/trace availability, URL\ncofactor exploratory-test list --application <name|id>\n\\`\\`\\`\n\nRun \\`cofactor exploratory-test --help\\` for the options that pick a named live environment, a credential and a flavor. The sandbox environment option supports the functional flavor only. This is not \\`cofactor exploration\\`, which runs product-map cycles.\n\nRule: sign in with a \\`$CREDENTIAL\\` placeholder or \\`cofactor session load-credential\\` (see \\`cofactor session guide sign-in\\`), and never print or type a real password or token into the page or the transcript.\n`,\n};\n","/**\n * `cofactor-debug-run` skill template.\n *\n * Unlike the other entries in SKILL_TEMPLATES (which inline their content as\n * JS strings), the cofactor-debug-run skill is rendered from the Handlebars partials in\n * `@chatsdet/diagnostic-playbook`. Source of truth = the playbook partials.\n *\n * Versioning: each released version is a frozen snapshot file under\n * `packages/canary-cli/skills/cofactor-debug-run/history/<version>.md`. The current\n * version is stamped in `version.json` next to the history dir. To mint a new\n * version after editing partials, run:\n *\n * bun run --filter=@canaryai/cli bump-skill cofactor-debug-run [patch|minor|major]\n *\n * The drift test in `packages/canary-cli/src/skill-rendered.test.ts`\n * fails if the live `renderSkill()` output diverges from\n * `history/<currentVersion>.md`, forcing a bump rather than silent edits to a\n * previously-released version. `previousVersions` is auto-populated from the\n * history dir so `canary skill diff cofactor-debug-run` can replay any released version.\n */\n\nimport { readFileSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SkillTemplate } from './types.js';\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolve the on-disk location of the cofactor-debug-run skill assets.\n *\n * At runtime the assets live in one of two places depending on whether we\n * are running from the source tree (tests, dev), the bundled dist (npm\n * install), or from a published @canaryai/cli inside node_modules:\n *\n * - source: packages/canary-cli/src/skill-templates/cofactor-debug-run.ts\n * → ../../skills/cofactor-debug-run/\n * - dist: packages/canary-cli/dist/<chunk>.js\n * → ./skills/cofactor-debug-run/ (copied by `cp -r skills dist/`)\n *\n * The first candidate that has a readable `version.json` wins.\n */\nfunction resolveSkillDir(): string {\n const candidates = [\n join(HERE, '..', '..', 'skills', 'cofactor-debug-run'), // source tree\n join(HERE, 'skills', 'cofactor-debug-run'), // dist\n join(HERE, '..', 'skills', 'cofactor-debug-run'), // dist split-chunk variant\n ];\n for (const c of candidates) {\n try {\n readFileSync(join(c, 'version.json'), 'utf-8');\n return c;\n } catch {\n // try next\n }\n }\n throw new Error(\n `Could not locate cofactor-debug-run skill assets relative to ${HERE}. Tried: ${candidates.join(', ')}`,\n );\n}\n\nconst SKILL_DIR = resolveSkillDir();\nconst HISTORY_DIR = join(SKILL_DIR, 'history');\n\nconst versionMeta = JSON.parse(\n readFileSync(join(SKILL_DIR, 'version.json'), 'utf-8'),\n) as { current: string };\n\nfunction readVersion(version: string): string {\n return readFileSync(join(HISTORY_DIR, `${version}.md`), 'utf-8');\n}\n\nfunction listVersionsOnDisk(): string[] {\n return readdirSync(HISTORY_DIR)\n .filter((f) => f.endsWith('.md'))\n .map((f) => f.slice(0, -3));\n}\n\nconst previousVersions: Record<string, () => string> = {};\nfor (const v of listVersionsOnDisk()) {\n if (v !== versionMeta.current) {\n previousVersions[v] = () => readVersion(v);\n }\n}\n\nexport const cofactorDebugRunTemplate: SkillTemplate = {\n name: 'cofactor-debug-run',\n description:\n 'Diagnose why a workflow test failed — root-cause an end-to-end run from its materialised artifacts',\n version: versionMeta.current,\n render: () => readVersion(versionMeta.current),\n previousVersions,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorOnboardingTemplate: SkillTemplate = {\n name: 'cofactor-onboarding',\n description:\n \"Take a new Cofactor user from signup to their tests running nightly on Sandboxes v2 and a first report. Use when the user is new to Cofactor, asks to set it up or onboard, or has no sandbox or suite yet.\",\n version: '1.1.1',\n render: () => `---\nname: cofactor-onboarding\nversion: 1.1.1\ndescription: Take a new Cofactor user from signup to their tests running nightly on Sandboxes v2 and a first report. Use when the user is new to Cofactor, asks to set it up or onboard, or has no sandbox or suite yet.\nallowed-tools: Bash(cofactor:*), Read, Grep, Glob, Write, Edit\n---\n\n# Cofactor Onboarding\n\nGoal: within an hour, the user's tests run on Cofactor Sandboxes v2 every night and they have read a first report. You do the work through the CLI. **Each step asks the user exactly one thing** (in bold below); propose every other answer from their code and say what you assumed. Note the time when step 1 starts. Learn the platform from \\`cofactor sandbox guide v2\\` and its topics, never from memory.\n\n## 0. Sign in\n\\`cofactor --version\\` (missing: \\`npm install -g @runcofactor/cli\\`), then \\`cofactor orgs\\`. Ask, only if not signed in: **\"Approve the sign-in in your browser\"** while \\`cofactor login\\` runs.\nThen pick the application's name: an existing one from \\`cofactor application list\\`, or a new name from their code (the product's name). Don't create it: step 1's \\`connect\\` or \\`push\\` creates it, with its sandbox as its default environment.\n\n## 1. Connect the app to Sandboxes v2\nAsk: **\"Should Cofactor build from your GitHub repository, or will you push a built image?\"**\n- Read \\`cofactor sandbox guide v2\\`, then \\`definition\\`, \\`personas\\`, \\`seeds-and-actions\\`, \\`environments\\`, \\`secrets\\` (and \\`upload\\` for images). Read the app: how it starts, its database, sign-in, roles, outside services. Write \\`cofactor.sandbox.yaml\\` in the guide's \"WHAT TO BUILD FIRST\" order: a service with a health check, one persona per role, one seed through the app's own API.\n- GitHub: \\`cofactor github connect\\`, \\`cofactor sandbox validate\\`, merge the definition to the default branch (\\`connect\\` reads it from there; \\`--dir\\` if it isn't at the root), then \\`cofactor sandbox connect --application <app> --repo <owner/name>\\`.\n- Image: \\`cofactor sandbox validate --upload\\`, build for \\`linux/amd64\\`, then \\`cofactor sandbox push --application <app> <image> --definition cofactor.sandbox.yaml --tag nightly --wait\\`; it must say \\`Sync: syncable\\`. Then give the user the CI job for nightly pushes: the complete workflow file is \"NIGHTLY PUSH FROM GITHUB ACTIONS\" in \\`cofactor sandbox guide v2 upload\\` (its last step, the suite run, needs two more key scopes: \\`test-run:run\\` and \\`test-run:read\\`). CI signs in with an API key in \\`COFACTOR_API_TOKEN\\`; its secret is printed once, so never create it yourself. In the same handoff, give the user this to run in their own shell from the repository (an organization admin, with \\`jq\\` and \\`gh\\`; for other CI, store the secret in its secret store instead): \\`TOKEN=$(cofactor api-key create --name \"CI image push\" --scope sandbox:read --scope sandbox:publish --scope property:read --json | jq -er .secret) && printf %s \"$TOKEN\" | gh secret set COFACTOR_API_TOKEN\\`. If the key was created but not stored, revoke it (\\`cofactor api-key list\\`, then \\`cofactor api-key revoke <id>\\`) and run the command again.\nDone when \\`cofactor sandbox envs --application <app>\\` shows a current version.\n\n## 2a. Secrets (skip if the app needs none)\nAsk: **\"Run this in your own shell\"**, with the exact command and the provider's test key in an environment variable: \\`printf %s \"$KEY\" | cofactor sandbox secret set NAME --application <app>\\`. Never take a key in chat. Done when \\`cofactor sandbox secret list --application <app>\\` shows every name.\n\n## 2b. Preview and blockers\n- Find blockers yourself: scan the codebase for auth providers (Google, Auth0, Okta, Cognito, Clerk, SAML) and third-party services (email, payments, storage, Slack, Jira, AI). Compare each against \\`cofactor sandbox guide v2 emulation\\` and \\`cofactor sandbox guide v2 authentication\\`. Each one not emulated is a blocker; give options (emulate, stub in the app, use the provider's test mode, skip the journey).\n- \\`cofactor sandbox claim --application <app> --wait\\`: the app serves over https, the seed data is there, and each persona from \\`cofactor sandbox show <id>\\` signs in through the app's real login (check in a browser session, the \\`cofactor-browser-testing\\` skill). With several environments, also \\`cofactor sandbox verify-env --application <app>\\`.\nAsk: **\"Here is your app at <url> (sign in as <persona>). Which option for each blocker?\"** (no blockers: \"Does this look like your app?\"). Done when every persona signs in and each blocker has a decision; then \\`cofactor sandbox destroy <id>\\`.\n\n## 3. Existing tests or a new suite\nAsk: **\"Run your existing tests, or start a suite from scratch?\"** Find the sandbox environment's name in \\`cofactor environment list --application <app>\\` (type sandbox); it may differ from the definition's.\n\n**3a. Existing Playwright tests.** Copy how they run today: read their CI job and Playwright config for the base URL, env vars, global setup and sign-in. List what the sandbox can't give them (blockers from step 2b, fixed hosts, real third-party accounts, data from outside the app) and fix the config before scaling up. The tests must be in a GitHub repository. The runner sets \\`BASE_URL\\`, \\`APP_BASE_URL\\` and \\`PLAYWRIGHT_BASE_URL\\` to the copy's URL and passes each persona's login as \\`COFACTOR_PERSONAS\\` JSON: change their global setup to sign in from it (\\`cofactor sandbox guide v2 personas\\` and \\`authentication\\`). Requirements: the Cofactor GitHub App on that repository (\\`cofactor github connect\\`, already done if step 1 used GitHub); \\`@playwright/test\\` and \\`playwright\\` are exactly 1.62.1; one npm, pnpm or yarn lockfile; Node 22.16 on Linux amd64.\n\\`\\`\\`bash\ncofactor application repo link --application <app> --repo <owner/name>\ncofactor test-suite create --name \"<App> Playwright\" --kind external --provider playwright --repo <owner/name> --environment <sandbox environment>\ncofactor test-suite update <suite> --env-map <VAR>=<value> # only if the tests read variables: their CI's vars, never the base URLs; replaces the whole map\ncofactor test-suite run --suite <suite> --external-spec <one spec path> # one spec first, then the whole suite\n\\`\\`\\`\nA spec that needs a secret itself: ask the user to run, in their own shell with the value in an environment variable as in step 2a, \\`printf %s \"$VALUE\" | cofactor env set-var --application <app> --environment <sandbox environment> --sensitive --stdin NAME\\`, and map \\`NAME='$var.ENV.NAME'\\`, never the literal.\nDone when one spec passes on the sandbox, then the whole suite has run once.\n\n**3b. A new suite.** \\`cofactor skill install cofactor-write-test\\` and write 3 to 5 tests for the core journeys (sign-in, the main thing a user creates, the main thing they pay for). Before a test's first run, point it at the sandbox: \\`cofactor workflow patch <wf_...> --default-environment <sandbox environment>\\`; then \\`cofactor workflow run <wf_...>\\` runs it on a fresh copy. New map items default to in_dev; use \\`--stage <in_dev|alpha|beta|ga|deprecated>\\` on area/capability create|update and rule add|update only when instructed. Never set a child above its parent; promote parents first and deprecate children first. Record what each proves in the product map (\\`cofactor product-map guide\\`, \\`product-map area create <title>\\`, \\`product-map capability create <title> --area <CODE>\\`, \\`product-map link <CAP> <wf_...>\\`).\nDone when every test has passed once on the sandbox and is linked to a capability.\n\n## 4. Nightly schedule and alerts\nRecommend a nightly run with failure alerts. First run \\`cofactor teams status\\`: leave Teams out of the ask unless it shows Teams enabled. Ask: **\"Which Slack channel, Teams channel or email should failures go to? For Slack, approve the connection in the browser page I open; for Teams, run \\`cofactor teams install\\` in your own terminal and approve it.\"** Connecting is for organization admins:\n- Slack: run \\`cofactor slack connect\\` in the background: it opens Settings → Slack and waits up to 10 minutes for the user's approval. If it connected the wrong workspace, with the user's go-ahead run \\`cofactor slack disconnect --yes\\`, then connect again. A private channel must add the Cofactor app first (\\`/invite\\` in that channel).\n- Teams: the user's \\`cofactor teams install\\` opens the Microsoft consent page; they then add the Cofactor app to the channel, and \\`cofactor teams channels\\` lists the name to pass to \\`--teams\\`.\n\\`\\`\\`bash\ncofactor test-suite create --name \"<App> Nightly\" # 3b only\ncofactor test-suite set-members <suite> --layer <wf_...,wf_...> # 3b only\ncofactor test-suite suites # 3a: the suite's id (3b: printed by create)\ncofactor schedule suite create --name \"<App> Nightly\" --suite-id <id> --at 02:00 --timezone <their IANA zone>\ncofactor alert create --on-schedule <scheduleId> --slack \"#<channel>\" --when failure # or --teams \"<channel>\", or --email <addr>\n\\`\\`\\`\nDone when \\`cofactor schedule suite get <scheduleId>\\` shows the next run and the alert.\nOptional recurring summary of results: \\`cofactor digest config set daily --at 08:00 --timezone <their IANA zone> --slack \"#<channel>\"\\` (admins; Slack channels only), then \\`cofactor digest email daily on\\` for their own inbox.\n\n## 5. First report\n- \\`cofactor test-suite run --suite <suite>\\` now (don't wait for tonight); it streams results and prints the run URL. Read it with \\`cofactor test-suite get <executionId>\\` (3b) or \\`cofactor external-run get <run-id>\\` (3a). For failures: \\`cofactor skill install cofactor-triage-tests\\` (and \\`cofactor-debug-run\\` for 3b).\n- Something to share: the run's web URL, plus a short summary (what ran, passed, failed and why) published with \\`cofactor utilities gist create summary.md --title \"<App> first Cofactor run\"\\`.\n- Tell them the total time since step 1 started, and how to poke around: \\`cofactor sandbox claim --application <app> --wait\\` prints the URL and each persona's login; \\`cofactor sandbox destroy <id>\\` when done.\nAsk: **\"Who on your team should see this?\"** Invite each with \\`cofactor org invite <email>\\` (organization admins; \\`--role admin\\` for another admin); they get an email to join. The \\`link:\\` it prints lets anyone join: never repeat it; if the email did not send, the user shares it with the invitee themselves.\n\n## How cost works\nUse this when choosing what tests to write.\n- The base plan is $99/month and includes 10,000 test executions. One execution is any flow run (in design or draft mode, or in a suite) or any single Playwright test run: one test paired with one environment. Fully cached, deterministic executions (Playwright tests included) are plentiful and count within those.\n- Agent time is metered separately as **agent hours**: live healing, failure diagnosis and agent-only testing (MCP tests, exploratory tests). Plans include a free allotment; never quote a number.\n- Prefer deterministic tests for anything that runs every night. Before setting up an MCP or exploratory test, tell the user it spends agent hours on every run and weigh that against what it covers that a deterministic test cannot.\n\nRules: neutral example names (Acme, example.com) in tests; never real credentials in steps or chat. If something fails on Cofactor's side, stop and give the user the exact command, the error and the time.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorProveWithTestsTemplate: SkillTemplate = {\n name: 'cofactor-prove-with-tests',\n description:\n 'Prove a change with Cofactor tests. Find existing coverage, edit it through a fork (a new test only when none fits), run it on a sandbox of the change, and list the test with its passed run in the pull request so merging adds it to the regression suite. Use with every user-visible change.',\n version: '1.0.0',\n render: () => `---\nname: cofactor-prove-with-tests\nversion: 1.0.0\ndescription: Prove a change with Cofactor tests. Find existing coverage, edit it through a fork (a new test only when none fits), run it on a sandbox of the change, and list the test with its passed run in the pull request so merging adds it to the regression suite. Use with every user-visible change.\nallowed-tools: Bash(cofactor workflow:*), Bash(cofactor sandbox:*), Bash(cofactor proofs:*), Read\n---\n\n# Prove with Tests\n\nRun \\`cofactor workflow guide prove-changes\\` first. It has the whole loop and the rules.\n\nThe failure to avoid is flooding the suite with near-duplicates. **If a test already walks the journey, edit it. Never add a new test for a changed filter, column or field.**\n\n1. **Find coverage first.** \\`cofactor workflow list --search \"<words>\"\\`, then \\`cofactor workflow get <wf_...> --format markdown\\` and read its assertions.\n2. **Choose the change to the suite.**\n - A test covers the journey: fork it (\\`cofactor workflow fork fork <wf_...>\\`) and edit the fork, never the original. Add or change the assertion that proves your change.\n - Nothing covers it, or it needs its own data or role: write a new test (\\`cofactor workflow guide write-a-test\\`).\n - No test is possible (nothing a user or API can observe, or the sandbox cannot reach it): say so and say what would make it possible (step 5).\n3. **Prove it on a sandbox of your change.** \\`cofactor sandbox claim --application <app> --wait\\`, \\`cofactor sandbox sync <id> [--build]\\`, then \\`cofactor workflow run <fork> --sandbox <id> --stream\\`. Guide: \\`cofactor sandbox guide v2 local\\`. Iterate until it passes, then run it once more after your last change: that passing run is your proof, and the command prints its run id (a uuid or \\`wrun_...\\`; either works).\n4. **Open a draft pull request.**\n5. **List each test with its passed run in the pull request description** (update it once the pull request exists). \\`cofactor proofs block <wf_...> <wrun_...> [...]\\` checks each pair and prints the block; paste it in. No test possible: \\`cofactor proofs block --none \"<why; what would make a test possible>\"\\`.\n Cofactor does not run the tests again: it checks that each listed run exists, belongs to its test, passed and ran the test as it is now (edit it after the run and the run no longer counts), and reports the \\`cofactor / proofs\\` check (it does not check which commit the run was against, so run after your last change). When a human merges, new tests are approved and added to suite runs, and forks are merged into their originals, unless the original changed after the fork was taken; then the edit waits for a person. \\`cofactor proofs status --application <app> --pr <n>\\` shows what the pull request lists.\n6. **Record struggles.** In the pull request description add \\`## Proof notes\\`: each decision you were unsure about (fork or new, what to assert, what you left uncovered) and why you chose as you did. Tell the user about any missing command or misleading guide you hit.\n\nRules: use neutral example names in test copy, never a customer's, and never put real credentials in steps. Never approve a test yourself; the human merge is the approval.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorTriageIssuesTemplate: SkillTemplate = {\n name: 'cofactor-triage-issues',\n description:\n 'Triage Cofactor issues by listing, inspecting, deduping, tagging, closing and handing them off. Use when the user asks about open issues, what broke, or which issues to fix first.',\n version: '2.0.1',\n render: () => `---\nname: cofactor-triage-issues\nversion: 2.0.1\ndescription: Triage Cofactor issues by listing, inspecting, deduping, tagging, closing and handing them off. Use when the user asks about open issues, what broke, or which issues to fix first.\nallowed-tools: Bash(cofactor issues:*), Bash(cofactor login:*), Read, Grep\n---\n\n# Triage Issues\n\nUse this when the user wants to review, dedupe, prioritise or close issues Cofactor found.\n\nRun \\`cofactor issues guide\\` first. It explains triage order, dedupe, tagging and handing an issue to an engineer.\n\nKey commands:\n\n\\`\\`\\`bash\ncofactor issues list # open issues, newest first\ncofactor issues get <issueId> # evidence, steps, linked runs, comments\ncofactor issues comment <issueId> --body <text|@file> # leave a note for the team\ncofactor issues tag <issueId> --add <names> # label for routing\ncofactor issues merge <dupId> --into <canonicalId> # fold a duplicate\ncofactor issues close <issueId> [--not-a-bug --reason <text>]\n\\`\\`\\`\n\nRule: read an issue with \\`issues get\\` before closing or merging it, and never paste credentials or tokens from its evidence into tickets or chat.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorTriageTestsTemplate: SkillTemplate = {\n name: 'cofactor-triage-tests',\n description:\n 'Triage Cofactor test results by finding failing runs and suites, telling real failures from flakes, and deciding the next step. Use when the user asks what failed, whether a suite is healthy, or how to read test results.',\n version: '2.0.1',\n render: () => `---\nname: cofactor-triage-tests\nversion: 2.0.1\ndescription: Triage Cofactor test results by finding failing runs and suites, telling real failures from flakes, and deciding the next step. Use when the user asks what failed, whether a suite is healthy, or how to read test results.\nallowed-tools: Bash(cofactor test-suite:*), Bash(cofactor workflow list:*), Bash(cofactor workflow runs:*), Bash(cofactor workflow guide:*), Bash(cofactor external-run:*), Bash(cofactor login:*), Read\n---\n\n# Triage Tests\n\nUse this when the user wants to know what failed, whether a suite is healthy, or what to do about a red run.\n\nRun \\`cofactor external-run guide\\` first (and \\`cofactor workflow guide\\` for how tests are structured).\n\nKey commands:\n\n\\`\\`\\`bash\ncofactor test-suite executions # recent suite runs\ncofactor test-suite get <executionId> --failures-only\ncofactor test-suite diagnostics <workflowId> <runId>\ncofactor workflow runs list <workflowId> # run history for one test\ncofactor external-run guide # CI-triggered runs and artifacts\n\\`\\`\\`\n\nRule: a failure is real only when it reproduces with the same evidence; hand a single unexplained failure to \\`cofactor-debug-run\\` instead of guessing.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorWriteTestTemplate: SkillTemplate = {\n name: 'cofactor-write-test',\n description:\n 'Author a Cofactor end-to-end test directly through the CLI by picking the journey, creating or patching the workflow, running it and returning its URL. Use when the user asks to write, add, extend or fix a test.',\n version: '2.0.2',\n render: () => `---\nname: cofactor-write-test\nversion: 2.0.2\ndescription: Author a Cofactor end-to-end test directly through the CLI by picking the journey, creating or patching the workflow, running it and returning its URL. Use when the user asks to write, add, extend or fix a test.\nallowed-tools: Bash(cofactor workflow:*), Bash(cofactor session guide:*), Bash(cofactor login:*), Read\n---\n\n# Write a Test\n\nUse this when the user wants a new end-to-end test, or a change to an existing one.\n\nRun \\`cofactor workflow guide write-a-test\\` first. It covers journey altitude (one user goal per test), assertions that prove an outcome, and seed data.\n\nFor visual regression coverage, read \\`cofactor workflow guide visual-checkpoints\\` for checkpoint placement, severity, and Playwright attachments.\n\nAuthor directly in the CLI, with no spec files:\n\n\\`\\`\\`bash\ncofactor workflow list --search \"<topic>\" # never create a duplicate\ncofactor workflow create ... # new test (see the guide for the format)\ncofactor workflow patch <workflowId> ... # edit settings\ncofactor workflow node ... # edit a single step\ncofactor workflow sync <workflowId> --from-file state.json # replace all steps\ncofactor workflow run <workflowId> # prove it passes\n\\`\\`\\`\n\nFinish by giving the user the workflow URL and the run result.\n\nRule: never put real passwords or tokens in steps; use the credential placeholders the guide describes.\n`,\n};\n","import type { SkillTemplate } from './types.js';\nimport { cofactorBrowserTestingTemplate } from './cofactor-browser-testing.js';\nimport { cofactorDebugRunTemplate } from './cofactor-debug-run.js';\nimport { cofactorOnboardingTemplate } from './cofactor-onboarding.js';\nimport { cofactorProveWithTestsTemplate } from './cofactor-prove-with-tests.js';\nimport { cofactorTriageIssuesTemplate } from './cofactor-triage-issues.js';\nimport { cofactorTriageTestsTemplate } from './cofactor-triage-tests.js';\nimport { cofactorWriteTestTemplate } from './cofactor-write-test.js';\n\nexport type { SkillTemplate };\n\nexport const SKILL_TEMPLATES: Record<string, SkillTemplate> = {\n 'cofactor-triage-issues': cofactorTriageIssuesTemplate,\n 'cofactor-triage-tests': cofactorTriageTestsTemplate,\n 'cofactor-write-test': cofactorWriteTestTemplate,\n 'cofactor-browser-testing': cofactorBrowserTestingTemplate,\n 'cofactor-debug-run': cofactorDebugRunTemplate,\n 'cofactor-prove-with-tests': cofactorProveWithTestsTemplate,\n 'cofactor-onboarding': cofactorOnboardingTemplate,\n};\n","import { SKILL_TEMPLATES } from \"./skill-templates/index.js\";\n\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split(\".\").map((n) => parseInt(n, 10) || 0);\n const pb = b.split(\".\").map((n) => parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (d !== 0) return d < 0 ? -1 : 1;\n }\n return 0;\n}\n\nexport function knownVersions(name: string): string[] {\n const t = SKILL_TEMPLATES[name];\n if (!t) return [];\n const all = new Set<string>([t.version, ...Object.keys(t.previousVersions ?? {})]);\n return [...all].sort(compareSemver);\n}\n\nfunction renderAtVersion(name: string, version: string): string | null {\n const t = SKILL_TEMPLATES[name];\n if (!t) return null;\n if (version === t.version) return t.render();\n const prev = t.previousVersions?.[version];\n return prev ? prev() : null;\n}\n\nfunction parseFlagArgs(argv: string[]): {\n positional: string[];\n flags: Record<string, string | true>;\n} {\n const positional: string[] = [];\n const flags: Record<string, string | true> = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n const next = argv[i + 1];\n if (next !== undefined && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\nexport function runVersions(argv: string[]) {\n const [name] = argv;\n if (!name || !SKILL_TEMPLATES[name]) {\n console.error(`Usage: canary skill versions <name>`);\n process.exit(1);\n }\n const versions = knownVersions(name);\n const current = SKILL_TEMPLATES[name].version;\n for (const v of versions) {\n console.log(v === current ? `${v} (current)` : v);\n }\n}\n\nfunction jsUnifiedDiff(a: string, b: string, labelA: string, labelB: string): string {\n const aLines = a.split(\"\\n\");\n const bLines = b.split(\"\\n\");\n const n = aLines.length;\n const m = bLines.length;\n const dp: number[][] = Array.from({ length: n + 1 }, () =>\n Array.from<number>({ length: m + 1 }).fill(0)\n );\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n dp[i][j] =\n aLines[i] === bLines[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n const out: string[] = [`--- ${labelA}`, `+++ ${labelB}`];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (aLines[i] === bLines[j]) {\n out.push(` ${aLines[i]}`);\n i++;\n j++;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n out.push(`-${aLines[i++]}`);\n } else {\n out.push(`+${bLines[j++]}`);\n }\n }\n while (i < n) out.push(`-${aLines[i++]}`);\n while (j < m) out.push(`+${bLines[j++]}`);\n return out.join(\"\\n\") + \"\\n\";\n}\n\nexport function runDiff(argv: string[]) {\n const { positional, flags } = parseFlagArgs(argv);\n const [name] = positional;\n\n if (!name) {\n console.error(\"Usage: canary skill diff <name> [--from <version>] [--to <version>]\");\n process.exit(1);\n }\n\n const template = SKILL_TEMPLATES[name];\n if (!template) {\n console.error(`Unknown skill \"${name}\".`);\n process.exit(1);\n }\n\n const versions = knownVersions(name);\n const to = typeof flags.to === \"string\" ? flags.to : template.version;\n const from =\n typeof flags.from === \"string\" ? flags.from : versions.filter((v) => v !== to).slice(-1)[0];\n\n if (!from) {\n console.error(\n `No prior version of \"${name}\" to diff against. Only known version: ${template.version}.`\n );\n process.exit(1);\n }\n\n const fromContent = renderAtVersion(name, from);\n const toContent = renderAtVersion(name, to);\n\n if (fromContent === null) {\n console.error(\n `Version \"${from}\" of skill \"${name}\" is not in the CLI. Known: ${versions.join(\", \")}.`\n );\n process.exit(1);\n }\n if (toContent === null) {\n console.error(\n `Version \"${to}\" of skill \"${name}\" is not in the CLI. Known: ${versions.join(\", \")}.`\n );\n process.exit(1);\n }\n\n if (from === to) {\n console.log(`(no diff — both sides are v${from})`);\n return;\n }\n\n process.stdout.write(jsUnifiedDiff(fromContent, toContent, `${name}@${from}`, `${name}@${to}`));\n}\n"],"mappings":"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","names":["existsSync","readFileSync","homedir","join","join","i","j","join","homedir","existsSync","readFileSync"]}
1
+ {"version":3,"sources":["../src/skill.ts","../src/skill-identity.ts","../src/skill-install-helpers.ts","../src/skill-templates/cofactor-browser-testing.ts","../src/skill-templates/cofactor-debug-run.ts","../src/skill-templates/cofactor-onboarding.ts","../src/skill-templates/cofactor-prove-with-tests.ts","../src/skill-templates/cofactor-triage-issues.ts","../src/skill-templates/cofactor-triage-tests.ts","../src/skill-templates/cofactor-write-test.ts","../src/skill-templates/index.ts","../src/skill-version-commands.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { brandSkillContentFor, brandTextFor, command } from \"./brand.js\";\nimport { applyInstallIdentity, installedSourceKey } from \"./skill-identity.js\";\nimport {\n detectAgent,\n formatInstallWriteFailure,\n isAgentType,\n isValidInstallName,\n resolveInstallDir,\n SUPPORTED_AGENTS,\n} from \"./skill-install-helpers.js\";\nimport { SKILL_TEMPLATES } from \"./skill-templates/index.js\";\nimport { knownVersions, runDiff, runVersions } from \"./skill-version-commands.js\";\nimport type { AgentType } from \"./skill-install-helpers.js\";\n\nexport { applyInstallIdentity, installedSourceKey, SKILL_SOURCE_KEY } from \"./skill-identity.js\";\nexport {\n detectAgent,\n formatInstallWriteFailure,\n isInstallPermissionError,\n isValidInstallName,\n resolveInstallDir,\n} from \"./skill-install-helpers.js\";\nexport type { AgentType, InstallWriteFailureContext } from \"./skill-install-helpers.js\";\n\n/**\n * Render a skill template for the active brand. Install/output go through here\n * so a `cofactor` binary writes cofactor-branded skill files while `canary`\n * stays byte-for-byte identical. Authored-content tooling (`diff`, `versions`)\n * stays raw so it compares the source, not the per-brand presentation.\n */\nfunction renderForActiveBrand(template: { render: () => string }): string {\n return brandSkillContentFor(template.render(), command);\n}\n\nfunction printSkillHelp() {\n const lines = [\n \"Usage:\",\n \" canary skill <name> Output skill template to stdout\",\n \" canary skill install <name> Install skill (auto-detects agent)\",\n \" canary skill install <name> --agent codex Install for a specific agent\",\n \" canary skill install <name> --personal Install to ~/.<agent>/skills/\",\n \" canary skill install <name> --name <as> Install under a custom skill name\",\n \" canary skill install <name> --force Overwrite a name held by another skill\",\n \" canary skill list List available skill templates\",\n \" canary skill sync Print manifest + instructions for the\",\n \" agent to version-compare and update\",\n \" installed skills\",\n \" canary skill diff <name> [--from V] [--to V] Unified diff between two versions of\",\n \" a skill (defaults: previous → current)\",\n \" canary skill versions <name> List all known versions of a skill\",\n \"\",\n \"Agent auto-detection:\",\n \" The install command detects which AI agent is running and writes the\",\n \" SKILL.md to the correct location:\",\n \"\",\n \" Agent Project path Personal path\",\n \" ───── ──────────── ─────────────\",\n \" claude .claude/skills/<name>/ ~/.claude/skills/<name>/\",\n \" codex .codex/skills/<name>/ ~/.codex/skills/<name>/\",\n \" copilot .github/skills/<name>/ ~/.copilot/skills/<name>/\",\n \"\",\n \" Detection checks (in order):\",\n \" 1. CLAUDE env var → claude\",\n \" 2. CODEX_* env vars → codex\",\n \" 3. GITHUB_COPILOT env var → copilot\",\n \" 4. .claude/.codex/.github dirs → whichever single one exists\",\n \" 5. If ambiguous, use --agent to specify explicitly\",\n \"\",\n \"Custom skill names (--name):\",\n \" By default a skill installs under its template name. Pass --name to install\",\n \" it under a name of your choosing — useful when you want every Canary-provided\",\n \" skill namespaced (e.g. my-browser-testing) to avoid colliding with your\",\n \" own skills. --name sets both the install directory and the SKILL.md\",\n \" frontmatter name: (agents require those to match), and records the source\",\n \" template in a skill-source: field so `sync` and `diff` keep tracking updates\",\n \" even under the renamed install.\",\n \"\",\n \" canary skill install cofactor-browser-testing --name my-browser-testing\",\n \"\",\n \" Installing a different skill onto an existing custom name is refused unless\",\n \" you pass --force. When an agent installs skills on your behalf, it should\",\n \" follow your naming convention.\",\n \"\",\n \"Available templates:\",\n ];\n\n for (const [key, template] of Object.entries(SKILL_TEMPLATES)) {\n lines.push(` ${key.padEnd(24)} v${template.version.padEnd(7)} ${template.description}`);\n }\n\n console.log(lines.join(\"\\n\"));\n}\n\n/**\n * Skill names retired by the 2.0.0 trim, mapped to the skills that replace them.\n * Without this, installs under the old names would be orphaned (sync only\n * resolves names that are still in SKILL_TEMPLATES). Delete this map one major\n * version after 2.0.0.\n */\nconst RETIRED_SKILLS: Record<string, string[]> = {\n \"canary-basic\": [\"cofactor-triage-issues\", \"cofactor-triage-tests\"],\n \"agent-tasks\": [\"cofactor-triage-issues\"],\n \"issue-log-xref\": [\"cofactor-triage-issues\"],\n sandbox: [],\n \"optimize-cache\": [],\n \"test-cases\": [\"cofactor-write-test\"],\n \"browser-testing\": [\"cofactor-browser-testing\"],\n \"debug-run\": [\"cofactor-debug-run\"],\n};\n\nfunction retiredSkillHint(name: string): string | undefined {\n const replacements = RETIRED_SKILLS[name];\n if (!replacements) return undefined;\n return replacements.length > 0\n ? `\"${name}\" was retired in 2.0.0. Install ${replacements.join(\" and \")} instead.`\n : `\"${name}\" was retired in 2.0.0 and has no replacement.`;\n}\n\nfunction runSync() {\n const manifest = Object.entries(SKILL_TEMPLATES).map(([key, t]) => ({\n name: key,\n version: t.version,\n description: t.description,\n knownVersions: knownVersions(key),\n installedPaths: {\n claudeProject: `.claude/skills/${key}/SKILL.md`,\n claudePersonal: join(homedir(), \".claude\", \"skills\", key, \"SKILL.md\"),\n codexProject: `.codex/skills/${key}/SKILL.md`,\n codexPersonal: join(homedir(), \".codex\", \"skills\", key, \"SKILL.md\"),\n copilotProject: `.github/skills/${key}/SKILL.md`,\n copilotPersonal: join(homedir(), \".copilot\", \"skills\", key, \"SKILL.md\"),\n },\n }));\n\n const instructions = `# Canary Skill Sync — Instructions for the Agent\n\nYou are an AI coding agent (Claude, Codex, Copilot, etc.). The user ran \\`canary skill sync\\`\nto bring their installed Canary skill templates up to date. Follow these steps:\n\n## Step 1 — Discover installed skills (including renamed ones)\n\nSkills can be installed under a **custom name** (\\`canary skill install <name> --name <as>\\`),\nso do not rely only on the canonical \\`installedPaths\\` below. List every \\`SKILL.md\\`\nunder your agent's skills directory — both project and personal:\n\n .claude/skills/*/SKILL.md and ~/.claude/skills/*/SKILL.md (claude)\n .codex/skills/*/SKILL.md and ~/.codex/skills/*/SKILL.md (codex)\n .github/skills/*/SKILL.md and ~/.copilot/skills/*/SKILL.md (copilot)\n\nFor each file, read its frontmatter and resolve which manifest skill it came from:\n- If a \\`skill-source: <key>\\` line is present, that \\`<key>\\` is the template name\n (the skill was installed under a custom \\`--name\\`). The install directory is the\n custom name; remember it for Step 5.\n- Otherwise the \\`name:\\` value is the template name (a default install, where the\n install name equals the template key).\n\nMatch that resolved key against the manifest \\`name\\` field (current skills) and the\n\\`retiredSkills\\` keys. Ignore any \\`SKILL.md\\` whose resolved key is in neither (it isn't\na Canary skill).\n\n## Step 2 — Read the version of each installed skill\n\nSkills whose resolved key is in \\`retiredSkills\\` skip Steps 2–5; handle them in Step 6.\n\n\nThe \\`SKILL.md\\` frontmatter contains a \\`version: X.Y.Z\\` line. Parse that value.\nIf the frontmatter has no \\`version:\\` field, treat the installed version as \\`0.0.0\\`.\n\n## Step 3 — Compare semver\n\nFor each installed skill, compare \\`installedVersion\\` to the \\`version\\` in the manifest:\n- If \\`installedVersion < manifestVersion\\` → the skill is **outdated**, update it.\n- If equal or greater → leave it alone.\n\n## Step 4 — For each outdated skill, inspect what changed\n\nBefore overwriting, read the diff so you know what's new. Diff by the **template\nkey** you resolved in Step 1 (not the custom install name) — the diff compares\nsource renders and is independent of how the skill was named on disk:\n\n canary skill diff <templateKey> --from <installedVersion>\n\nThe CLI retains past renders of each skill in \\`previousVersions\\`, so this prints a\nunified diff from the user's installed version → the current version. Only versions\nlisted in \\`knownVersions\\` in the manifest can be diffed; if \\`installedVersion\\` is\nolder than the oldest known version, diff against the oldest known version instead\nand warn the user that the older content is no longer reproducible.\n\nUse the diff to:\n- Summarize what changed for the user (new sections, removed guidance, renamed commands).\n- Decide whether any user-local edits to the installed SKILL.md would be clobbered —\n if the user appears to have edited their local copy, surface that and ask before\n overwriting.\n\n## Step 5 — Update outdated skills\n\nRe-install with the template key, preserving both the location AND the custom name\nit was installed under (the install directory name from Step 1):\n\n canary skill install <templateKey> # default-named project install\n canary skill install <templateKey> --personal # default-named personal install\n canary skill install <templateKey> --name <installDir> # custom-named project install\n canary skill install <templateKey> --name <installDir> --personal\n\nPreserve whichever location and name it was already installed in — if it lived in\n\\`my-browser-testing/\\`, re-install with \\`--name my-browser-testing\\` so the\nupdate lands in place rather than creating a second default-named copy. Do NOT install\nskills that weren't already installed — sync only updates existing installs. When the\nuser has a naming convention, keep installing under their chosen names on their behalf.\n\n## Step 6 — Retire renamed skills\n\nAn installed skill whose resolved key (Step 1) is listed under \\`retiredSkills\\` no longer\nexists. Tell the user to remove its install directory and install each replacement in its\nvalue list with \\`canary skill install <replacement>\\` (same location; if it was installed\nunder a custom directory name and has a single replacement, pass \\`--name <installDir>\\`;\notherwise install under the default names).\nAn empty list means the skill was dropped with no replacement.\n\n## Step 7 — Report\n\nPrint a concise summary: which skills were updated (old → new version), which were\nalready current, which were retired (and what replaced them), and which were not\ninstalled (skipped).\n\n## Manifest\n\n\\`\\`\\`json\n${JSON.stringify({ skills: manifest, retiredSkills: RETIRED_SKILLS }, null, 2)}\n\\`\\`\\`\n`;\n\n // process.stdout bypasses the console branding patch, so brand explicitly.\n process.stdout.write(brandTextFor(instructions, command));\n}\n\nfunction parseInstallArgs(argv: string[]): {\n /** The registry/template key (positional argument). */\n templateName: string | undefined;\n /** Directory + frontmatter name to install under (defaults to templateName). */\n installName: string | undefined;\n agent: AgentType | undefined;\n personal: boolean;\n force: boolean;\n} {\n let templateName: string | undefined;\n let installName: string | undefined;\n let agent: AgentType | undefined;\n let personal = false;\n let force = false;\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--agent\" && i + 1 < argv.length) {\n const val = argv[++i];\n if (!isAgentType(val)) {\n console.error(`Unknown agent \"${val}\". Supported agents: ${SUPPORTED_AGENTS.join(\", \")}`);\n process.exit(1);\n }\n agent = val;\n } else if (arg === \"--name\" && i + 1 < argv.length) {\n const val = argv[++i];\n if (!isValidInstallName(val)) {\n console.error(\n `Invalid skill name \"${val}\". Use letters, digits, hyphens, or underscores (e.g. my-browser-testing).`\n );\n process.exit(1);\n }\n installName = val;\n } else if (arg === \"--personal\") {\n personal = true;\n } else if (arg === \"--force\" || arg === \"-f\") {\n force = true;\n } else if (!arg.startsWith(\"-\") && !templateName) {\n templateName = arg;\n }\n }\n\n return { templateName, installName: installName ?? templateName, agent, personal, force };\n}\n\nasync function runInstall(argv: string[]) {\n const {\n templateName,\n installName,\n agent: explicitAgent,\n personal,\n force,\n } = parseInstallArgs(argv);\n\n if (!templateName || !installName) {\n console.error(\"Missing skill name.\\n\");\n console.error(\n `Usage: canary skill install <name> [--name <install-name>] [--agent ${SUPPORTED_AGENTS.join(\"|\")}] [--personal] [--force]`\n );\n process.exit(1);\n }\n\n const template = SKILL_TEMPLATES[templateName];\n if (!template) {\n console.error(`Unknown skill template \"${templateName}\".\\n`);\n const hint = retiredSkillHint(templateName);\n if (hint) console.error(`${hint}\\n`);\n console.error(\"Available templates:\");\n for (const [key, t] of Object.entries(SKILL_TEMPLATES)) {\n console.error(` ${key.padEnd(24)} ${t.description}`);\n }\n process.exit(1);\n }\n\n // Resolve agent type\n const agent = explicitAgent ?? detectAgent();\n if (!agent) {\n console.error(\"Could not auto-detect the AI agent. Use --agent to specify:\\n\");\n console.error(\" canary skill install <name> --agent claude # Claude Code\");\n console.error(\" canary skill install <name> --agent codex # OpenAI Codex\");\n console.error(\" canary skill install <name> --agent copilot # GitHub Copilot\");\n process.exit(1);\n }\n\n const dir = resolveInstallDir(installName, agent, personal);\n const filePath = join(dir, \"SKILL.md\");\n\n // Collision guard: refuse to clobber a SKILL.md installed under this name from\n // a DIFFERENT template (e.g. collapsing multiple skills onto one name) unless\n // --force is passed. Updating the same skill in place is always allowed.\n if (existsSync(filePath) && !force) {\n const existingSource = installedSourceKey(readFileSync(filePath, \"utf-8\"));\n if (existingSource && existingSource !== templateName) {\n console.error(\n `✗ ${installName} already holds '${existingSource}'. Pass --force to overwrite.`\n );\n process.exit(1);\n }\n }\n\n // Write the file (brand-aware: cofactor binary writes cofactor-branded text),\n // rewriting the frontmatter identity when installing under a custom name.\n const content = applyInstallIdentity(renderForActiveBrand(template), installName, templateName);\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(filePath, content, \"utf-8\");\n } catch (error) {\n console.error(\n formatInstallWriteFailure({\n cwd: process.cwd(),\n templateName,\n installName,\n agent,\n personal,\n dir,\n filePath,\n error,\n })\n );\n process.exit(1);\n }\n\n const relPath = personal ? filePath : filePath.replace(process.cwd() + \"/\", \"\");\n const named = installName === templateName ? \"\" : ` as ${installName}`;\n console.log(`Installed ${templateName} skill for ${agent}${named} → ${relPath}`);\n}\n\nfunction runList() {\n for (const [key, template] of Object.entries(SKILL_TEMPLATES)) {\n console.log(`${key.padEnd(30)} ${brandTextFor(template.description, command)}`);\n }\n}\n\nexport async function runSkill(argv: string[]) {\n const [sub] = argv;\n\n // Anywhere in argv: `skill install <name> --help` must not install.\n if (sub === \"list\" && !argv.includes(\"--help\") && !argv.includes(\"-h\")) {\n runList();\n return;\n }\n\n if (!sub || sub === \"help\" || argv.includes(\"--help\") || argv.includes(\"-h\")) {\n printSkillHelp();\n return;\n }\n\n // canary skill install <name> [--agent ...]\n if (sub === \"install\") {\n await runInstall(argv.slice(1));\n return;\n }\n\n // canary skill sync — print instructions for the agent\n if (sub === \"sync\") {\n runSync();\n return;\n }\n\n if (sub === \"diff\") {\n runDiff(argv.slice(1));\n return;\n }\n\n if (sub === \"versions\") {\n runVersions(argv.slice(1));\n return;\n }\n\n // canary skill <name> — output to stdout (backward compatible)\n const template = SKILL_TEMPLATES[sub];\n if (!template) {\n console.error(`Unknown skill template \"${sub}\".\\n`);\n const hint = retiredSkillHint(sub);\n if (hint) console.error(`${hint}\\n`);\n printSkillHelp();\n process.exit(1);\n }\n\n process.stdout.write(renderForActiveBrand(template));\n}\n","/**\n * Skill frontmatter identity helpers.\n *\n * These helpers keep custom-named installs traceable to their source template\n * without coupling that parsing/writing logic to the skill command runner.\n */\n\n/**\n * Brand-neutral frontmatter key that records which template a SKILL.md was\n * rendered from. Stamped only when a skill is installed under a custom name\n * (`--name`), so `sync`/`diff` can map a renamed install back to its template\n * for version-compare and update.\n */\nexport const SKILL_SOURCE_KEY = \"skill-source\";\n\n/**\n * Split a SKILL.md into its leading YAML frontmatter block and the body. The\n * frontmatter is the block between the first `---` line and the next `---`\n * line. Returns `null` when the content has no recognizable frontmatter, so\n * callers can skip identity rewriting rather than corrupt the file.\n */\nfunction splitFrontmatter(\n content: string\n): { frontmatter: string; body: string } | null {\n const lines = content.split(\"\\n\");\n if (lines[0] !== \"---\") return null;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === \"---\") {\n return {\n frontmatter: lines.slice(1, i).join(\"\\n\"),\n // Keep the closing `---` and everything after it in the body so a\n // round-trip with `applyInstallIdentity` reproduces the file exactly.\n body: lines.slice(i).join(\"\\n\"),\n };\n }\n }\n return null;\n}\n\n/**\n * Read a single `key: value` field out of a frontmatter block. Returns `null`\n * when the key is absent. Used to recover an installed skill's `name:` /\n * `skill-source:` for the collision guard.\n */\nfunction readFrontmatterField(frontmatter: string, key: string): string | null {\n for (const line of frontmatter.split(\"\\n\")) {\n const match = line.match(/^([A-Za-z0-9_-]+):\\s*(.*)$/);\n if (match && match[1] === key) return match[2].trim();\n }\n return null;\n}\n\n/**\n * Derive the template key an already-installed SKILL.md was rendered from:\n * the `skill-source:` stamp when present (custom-named install), otherwise the\n * `name:` field (a default install, where name === template key). `null` when\n * neither is present.\n */\nexport function installedSourceKey(content: string): string | null {\n const parts = splitFrontmatter(content);\n if (!parts) return null;\n return (\n readFrontmatterField(parts.frontmatter, SKILL_SOURCE_KEY) ??\n readFrontmatterField(parts.frontmatter, \"name\")\n );\n}\n\n/**\n * Rewrite a rendered SKILL.md so it installs cleanly under `installName`:\n * the frontmatter `name:` is set to `installName` (agents require `name:` to\n * match the install directory), and — only when the name differs from the\n * template key — a `skill-source: <templateKey>` line is stamped so\n * `sync`/`diff` can still track the install.\n */\nexport function applyInstallIdentity(\n content: string,\n installName: string,\n templateKey: string\n): string {\n if (installName === templateKey) return content;\n\n const parts = splitFrontmatter(content);\n if (!parts) return content;\n\n const out: string[] = [];\n let wroteName = false;\n let wroteSource = false;\n for (const line of parts.frontmatter.split(\"\\n\")) {\n const match = line.match(/^([A-Za-z0-9_-]+):\\s*(.*)$/);\n const key = match?.[1];\n if (key === \"name\") {\n out.push(`name: ${installName}`);\n out.push(`${SKILL_SOURCE_KEY}: ${templateKey}`);\n wroteName = true;\n wroteSource = true;\n } else if (key === SKILL_SOURCE_KEY) {\n // Re-stamp from the template key rather than trusting a stale value.\n if (!wroteSource) {\n out.push(`${SKILL_SOURCE_KEY}: ${templateKey}`);\n wroteSource = true;\n }\n } else {\n out.push(line);\n }\n }\n // Defensive: frontmatter missing `name:` / `skill-source:` still gets them.\n if (!wroteName) out.unshift(`name: ${installName}`);\n if (!wroteSource) {\n const nameIdx = out.findIndex((l) => l.startsWith(\"name:\"));\n out.splice(nameIdx >= 0 ? nameIdx + 1 : 0, 0, `${SKILL_SOURCE_KEY}: ${templateKey}`);\n }\n\n // Reassemble: leading `---`, rewritten frontmatter, then the original body\n // (which already starts with its own closing `---` fence).\n return `---\\n${out.join(\"\\n\")}\\n${parts.body}`;\n}\n","/**\n * Skill install path, agent detection, and write-error helpers.\n *\n * The command runner performs template lookup and filesystem writes; this\n * module owns the pure-ish install support logic that is easiest to test in\n * isolation.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { command } from \"./brand.js\";\n\nexport type AgentType = \"claude\" | \"codex\" | \"copilot\";\n\nexport const SUPPORTED_AGENTS: AgentType[] = [\"claude\", \"codex\", \"copilot\"];\n\ntype DetectAgentOptions = {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n exists?: (path: string) => boolean;\n};\n\ntype InstallPathOptions = {\n cwd?: string;\n home?: string;\n};\n\nexport function isAgentType(value: string): value is AgentType {\n return value === \"claude\" || value === \"codex\" || value === \"copilot\";\n}\n\n/**\n * Detect which AI agent is currently running based on environment variables\n * and project directory structure.\n */\nexport function detectAgent(options: DetectAgentOptions = {}): AgentType | null {\n const env = options.env ?? process.env;\n const cwd = options.cwd ?? process.cwd();\n const pathExists = options.exists ?? existsSync;\n\n if (env.CLAUDE) return \"claude\";\n\n if (\n env.CODEX ||\n env.CODEX_CI ||\n env.CODEX_THREAD_ID ||\n env.CODEX_MANAGED_PACKAGE_ROOT ||\n env.AGENT_MODE === \"codex\"\n )\n return \"codex\";\n\n if (\n env.GITHUB_COPILOT ||\n env.COPILOT_AGENT ||\n env.AGENT_MODE === \"copilot\"\n )\n return \"copilot\";\n\n const foundAgents = SUPPORTED_AGENTS.filter((agent) =>\n pathExists(join(cwd, agent === \"copilot\" ? \".github\" : `.${agent}`))\n );\n\n if (foundAgents.length === 1) return foundAgents[0] ?? null;\n return null;\n}\n\n/**\n * Resolve the install directory for a skill based on agent type.\n */\nexport function resolveInstallDir(\n skillName: string,\n agent: AgentType,\n personal: boolean,\n options: InstallPathOptions = {}\n): string {\n const base = personal\n ? (options.home ?? homedir())\n : (options.cwd ?? process.cwd());\n\n switch (agent) {\n case \"claude\":\n return join(base, \".claude\", \"skills\", skillName);\n case \"codex\":\n return join(base, \".codex\", \"skills\", skillName);\n case \"copilot\":\n return personal\n ? join(base, \".copilot\", \"skills\", skillName)\n : join(base, \".github\", \"skills\", skillName);\n }\n}\n\nexport type InstallWriteFailureContext = {\n cwd: string;\n templateName: string;\n installName: string;\n agent: AgentType;\n personal: boolean;\n dir: string;\n filePath: string;\n error: unknown;\n};\n\nfunction errorField(error: unknown, key: string): string | undefined {\n if (typeof error !== \"object\" || error === null) return undefined;\n const value = (error as Record<string, unknown>)[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport function isInstallPermissionError(error: unknown): boolean {\n const code = errorField(error, \"code\");\n return code === \"EACCES\" || code === \"EPERM\" || code === \"EROFS\";\n}\n\nfunction formatErrorSummary(error: unknown): string {\n const code = errorField(error, \"code\");\n const message = errorField(error, \"message\");\n if (code && message) return `${code}: ${message}`;\n if (message) return message;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function formatInstallWriteFailure(\n context: InstallWriteFailureContext\n): string {\n const lines = [\n `Could not install ${context.templateName} skill for ${context.agent} at ${context.filePath}.`,\n \"\",\n isInstallPermissionError(context.error)\n ? \"The destination is not writable from the current shell.\"\n : \"The CLI could not create or write the destination file.\",\n `Failure: ${formatErrorSummary(context.error)}`,\n \"\",\n ];\n const nameFlag =\n context.installName === context.templateName\n ? \"\"\n : ` --name ${context.installName}`;\n\n if (context.personal) {\n lines.push(\n `Personal installs write under your home directory. Check permissions for ${context.dir}.`,\n \"\",\n \"Try again after fixing permissions:\",\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent} --personal`,\n \"\",\n \"Or run from a writable project directory and install without --personal.\"\n );\n } else {\n lines.push(\n `Project installs write under the current directory (${context.cwd}).`,\n \"Run from a writable project folder, or use --personal to install under your home directory.\",\n \"\",\n \"Try:\",\n \" cd <writable-project>\",\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent}`,\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent} --personal`\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * A custom install name becomes a directory segment and the frontmatter\n * `name:`, so it must be a single safe path component: word characters and\n * hyphens only, no separators, no `..`, no leading dot.\n */\nexport function isValidInstallName(value: string): boolean {\n return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value);\n}\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorBrowserTestingTemplate: SkillTemplate = {\n name: 'cofactor-browser-testing',\n description:\n 'Drive a real browser with the Cofactor CLI to explore, test or verify a web application. Use when the user asks to browse, click through, screenshot or check a page.',\n version: '2.1.0',\n render: () => `---\nname: cofactor-browser-testing\nversion: 2.1.0\ndescription: Drive a real browser with the Cofactor CLI to explore, test or verify a web application. Use when the user asks to browse, click through, screenshot or check a page.\nallowed-tools: Bash(cofactor session:*), Bash(cofactor login:*), Bash(cofactor exploratory-test:*), Read\n---\n\n# Browser Testing\n\nUse this to open a page, interact with it and report what you see.\n\nRun \\`cofactor session guide\\` first. It covers element discovery, waiting, credentials and what to do when the page is logged out.\n\nKey commands:\n\n\\`\\`\\`bash\ncofactor session start # open a browser session\ncofactor session navigate --url <url>\ncofactor session snapshot # list elements you can act on\ncofactor session click --ref <ref> # also: type, fill, press, scroll\ncofactor session screenshot\ncofactor session stop # always clean up\n\\`\\`\\`\n\n## Hand the exploring to an agent\n\nTo have a Cofactor agent explore an application from a prompt and report what it finds (an exploratory test), start one instead of driving the browser yourself:\n\n\\`\\`\\`bash\ncofactor exploratory-test run --application <name|id> --prompt \"Try the checkout flow as a new customer\" --wait\ncofactor exploratory-test run --application <name|id> --prompt @charter.md --sandbox-env <name> --wait # a Sandboxes v2 environment\ncofactor exploratory-test get <id> # status, summary, issues, video/trace availability, URL\ncofactor exploratory-test list --application <name|id>\n\\`\\`\\`\n\nRun \\`cofactor exploratory-test --help\\` for the options that pick a named live environment, a credential and a flavor. The sandbox environment option supports the functional flavor only. This is not \\`cofactor exploration\\`, which runs product-map cycles.\n\nRule: sign in with a \\`$CREDENTIAL\\` placeholder or \\`cofactor session load-credential\\` (see \\`cofactor session guide sign-in\\`), and never print or type a real password or token into the page or the transcript.\n`,\n};\n","/**\n * `cofactor-debug-run` skill template.\n *\n * Unlike the other entries in SKILL_TEMPLATES (which inline their content as\n * JS strings), the cofactor-debug-run skill is rendered from the Handlebars partials in\n * `@chatsdet/diagnostic-playbook`. Source of truth = the playbook partials.\n *\n * Versioning: each released version is a frozen snapshot file under\n * `packages/canary-cli/skills/cofactor-debug-run/history/<version>.md`. The current\n * version is stamped in `version.json` next to the history dir. To mint a new\n * version after editing partials, run:\n *\n * bun run --filter=@canaryai/cli bump-skill cofactor-debug-run [patch|minor|major]\n *\n * The drift test in `packages/canary-cli/src/skill-rendered.test.ts`\n * fails if the live `renderSkill()` output diverges from\n * `history/<currentVersion>.md`, forcing a bump rather than silent edits to a\n * previously-released version. `previousVersions` is auto-populated from the\n * history dir so `canary skill diff cofactor-debug-run` can replay any released version.\n */\n\nimport { readFileSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SkillTemplate } from './types.js';\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolve the on-disk location of the cofactor-debug-run skill assets.\n *\n * At runtime the assets live in one of two places depending on whether we\n * are running from the source tree (tests, dev), the bundled dist (npm\n * install), or from a published @canaryai/cli inside node_modules:\n *\n * - source: packages/canary-cli/src/skill-templates/cofactor-debug-run.ts\n * → ../../skills/cofactor-debug-run/\n * - dist: packages/canary-cli/dist/<chunk>.js\n * → ./skills/cofactor-debug-run/ (copied by `cp -r skills dist/`)\n *\n * The first candidate that has a readable `version.json` wins.\n */\nfunction resolveSkillDir(): string {\n const candidates = [\n join(HERE, '..', '..', 'skills', 'cofactor-debug-run'), // source tree\n join(HERE, 'skills', 'cofactor-debug-run'), // dist\n join(HERE, '..', 'skills', 'cofactor-debug-run'), // dist split-chunk variant\n ];\n for (const c of candidates) {\n try {\n readFileSync(join(c, 'version.json'), 'utf-8');\n return c;\n } catch {\n // try next\n }\n }\n throw new Error(\n `Could not locate cofactor-debug-run skill assets relative to ${HERE}. Tried: ${candidates.join(', ')}`,\n );\n}\n\nconst SKILL_DIR = resolveSkillDir();\nconst HISTORY_DIR = join(SKILL_DIR, 'history');\n\nconst versionMeta = JSON.parse(\n readFileSync(join(SKILL_DIR, 'version.json'), 'utf-8'),\n) as { current: string };\n\nfunction readVersion(version: string): string {\n return readFileSync(join(HISTORY_DIR, `${version}.md`), 'utf-8');\n}\n\nfunction listVersionsOnDisk(): string[] {\n return readdirSync(HISTORY_DIR)\n .filter((f) => f.endsWith('.md'))\n .map((f) => f.slice(0, -3));\n}\n\nconst previousVersions: Record<string, () => string> = {};\nfor (const v of listVersionsOnDisk()) {\n if (v !== versionMeta.current) {\n previousVersions[v] = () => readVersion(v);\n }\n}\n\nexport const cofactorDebugRunTemplate: SkillTemplate = {\n name: 'cofactor-debug-run',\n description:\n 'Diagnose why a workflow test failed — root-cause an end-to-end run from its materialised artifacts',\n version: versionMeta.current,\n render: () => readVersion(versionMeta.current),\n previousVersions,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorOnboardingTemplate: SkillTemplate = {\n name: 'cofactor-onboarding',\n description:\n \"Take a new Cofactor user from signup to their tests running nightly on Sandboxes v2 and a first report. Use when the user is new to Cofactor, asks to set it up or onboard, or has no sandbox or suite yet.\",\n version: '1.1.1',\n render: () => `---\nname: cofactor-onboarding\nversion: 1.1.1\ndescription: Take a new Cofactor user from signup to their tests running nightly on Sandboxes v2 and a first report. Use when the user is new to Cofactor, asks to set it up or onboard, or has no sandbox or suite yet.\nallowed-tools: Bash(cofactor:*), Read, Grep, Glob, Write, Edit\n---\n\n# Cofactor Onboarding\n\nGoal: within an hour, the user's tests run on Cofactor Sandboxes v2 every night and they have read a first report. You do the work through the CLI. **Each step asks the user exactly one thing** (in bold below); propose every other answer from their code and say what you assumed. Note the time when step 1 starts. Learn the platform from \\`cofactor sandbox guide v2\\` and its topics, never from memory.\n\n## 0. Sign in\n\\`cofactor --version\\` (missing: \\`npm install -g @runcofactor/cli\\`), then \\`cofactor orgs\\`. Ask, only if not signed in: **\"Approve the sign-in in your browser\"** while \\`cofactor login\\` runs.\nThen pick the application's name: an existing one from \\`cofactor application list\\`, or a new name from their code (the product's name). Don't create it: step 1's \\`connect\\` or \\`push\\` creates it, with its sandbox as its default environment.\n\n## 1. Connect the app to Sandboxes v2\nAsk: **\"Should Cofactor build from your GitHub repository, or will you push a built image?\"**\n- Read \\`cofactor sandbox guide v2\\`, then \\`definition\\`, \\`personas\\`, \\`seeds-and-actions\\`, \\`environments\\`, \\`secrets\\` (and \\`upload\\` for images). Read the app: how it starts, its database, sign-in, roles, outside services. Write \\`cofactor.sandbox.yaml\\` in the guide's \"WHAT TO BUILD FIRST\" order: a service with a health check, one persona per role, one seed through the app's own API.\n- GitHub: \\`cofactor github connect\\`, \\`cofactor sandbox validate\\`, merge the definition to the default branch (\\`connect\\` reads it from there; \\`--dir\\` if it isn't at the root), then \\`cofactor sandbox connect --application <app> --repo <owner/name>\\`.\n- Image: \\`cofactor sandbox validate --upload\\`, build for \\`linux/amd64\\`, then \\`cofactor sandbox push --application <app> <image> --definition cofactor.sandbox.yaml --tag nightly --wait\\`; it must say \\`Sync: syncable\\`. Then give the user the CI job for nightly pushes: the complete workflow file is \"NIGHTLY PUSH FROM GITHUB ACTIONS\" in \\`cofactor sandbox guide v2 upload\\` (its last step, the suite run, needs two more key scopes: \\`test-run:run\\` and \\`test-run:read\\`). CI signs in with an API key in \\`COFACTOR_API_TOKEN\\`; its secret is printed once, so never create it yourself. In the same handoff, give the user this to run in their own shell from the repository (an organization admin, with \\`jq\\` and \\`gh\\`; for other CI, store the secret in its secret store instead): \\`TOKEN=$(cofactor api-key create --name \"CI image push\" --scope sandbox:read --scope sandbox:publish --scope property:read --json | jq -er .secret) && printf %s \"$TOKEN\" | gh secret set COFACTOR_API_TOKEN\\`. If the key was created but not stored, revoke it (\\`cofactor api-key list\\`, then \\`cofactor api-key revoke <id>\\`) and run the command again.\nDone when \\`cofactor sandbox envs --application <app>\\` shows a current version.\n\n## 2a. Secrets (skip if the app needs none)\nAsk: **\"Run this in your own shell\"**, with the exact command and the provider's test key in an environment variable: \\`printf %s \"$KEY\" | cofactor sandbox secret set NAME --application <app>\\`. Never take a key in chat. Done when \\`cofactor sandbox secret list --application <app>\\` shows every name.\n\n## 2b. Preview and blockers\n- Find blockers yourself: scan the codebase for auth providers (Google, Auth0, Okta, Cognito, Clerk, SAML) and third-party services (email, payments, storage, Slack, Jira, AI). Compare each against \\`cofactor sandbox guide v2 emulation\\` and \\`cofactor sandbox guide v2 authentication\\`. Each one not emulated is a blocker; give options (emulate, stub in the app, use the provider's test mode, skip the journey).\n- \\`cofactor sandbox claim --application <app> --wait\\`: the app serves over https, the seed data is there, and each persona from \\`cofactor sandbox show <id>\\` signs in through the app's real login (check in a browser session, the \\`cofactor-browser-testing\\` skill). With several environments, also \\`cofactor sandbox verify-env --application <app>\\`.\nAsk: **\"Here is your app at <url> (sign in as <persona>). Which option for each blocker?\"** (no blockers: \"Does this look like your app?\"). Done when every persona signs in and each blocker has a decision; then \\`cofactor sandbox destroy <id>\\`.\n\n## 3. Existing tests or a new suite\nAsk: **\"Run your existing tests, or start a suite from scratch?\"** Find the sandbox environment's name in \\`cofactor environment list --application <app>\\` (type sandbox); it may differ from the definition's.\n\n**3a. Existing Playwright tests.** Copy how they run today: read their CI job and Playwright config for the base URL, env vars, global setup and sign-in. List what the sandbox can't give them (blockers from step 2b, fixed hosts, real third-party accounts, data from outside the app) and fix the config before scaling up. The tests must be in a GitHub repository. The runner sets \\`BASE_URL\\`, \\`APP_BASE_URL\\` and \\`PLAYWRIGHT_BASE_URL\\` to the copy's URL and passes each persona's login as \\`COFACTOR_PERSONAS\\` JSON: change their global setup to sign in from it (\\`cofactor sandbox guide v2 personas\\` and \\`authentication\\`). Requirements: the Cofactor GitHub App on that repository (\\`cofactor github connect\\`, already done if step 1 used GitHub); \\`@playwright/test\\` and \\`playwright\\` are exactly 1.62.1; one npm, pnpm or yarn lockfile; Node 22.16 on Linux amd64.\n\\`\\`\\`bash\ncofactor application repo link --application <app> --repo <owner/name>\ncofactor test-suite create --name \"<App> Playwright\" --kind external --provider playwright --repo <owner/name> --environment <sandbox environment>\ncofactor test-suite update <suite> --env-map <VAR>=<value> # only if the tests read variables: their CI's vars, never the base URLs; replaces the whole map\ncofactor test-suite run --suite <suite> --external-spec <one spec path> # one spec first, then the whole suite\n\\`\\`\\`\nA spec that needs a secret itself: ask the user to run, in their own shell with the value in an environment variable as in step 2a, \\`printf %s \"$VALUE\" | cofactor env set-var --application <app> --environment <sandbox environment> --sensitive --stdin NAME\\`, and map \\`NAME='$var.ENV.NAME'\\`, never the literal.\nDone when one spec passes on the sandbox, then the whole suite has run once.\n\n**3b. A new suite.** \\`cofactor skill install cofactor-write-test\\` and write 3 to 5 tests for the core journeys (sign-in, the main thing a user creates, the main thing they pay for). Before a test's first run, point it at the sandbox: \\`cofactor workflow patch <wf_...> --default-environment <sandbox environment>\\`; then \\`cofactor workflow run <wf_...>\\` runs it on a fresh copy. New map items default to in_dev; use \\`--stage <in_dev|alpha|beta|ga|deprecated>\\` on area/capability create|update and rule add|update only when instructed. Never set a child above its parent; promote parents first and deprecate children first. Record what each proves in the product map (\\`cofactor product-map guide\\`, \\`product-map area create <title>\\`, \\`product-map capability create <title> --area <CODE>\\`, \\`product-map link <CAP> <wf_...>\\`).\nDone when every test has passed once on the sandbox and is linked to a capability.\n\n## 4. Nightly schedule and alerts\nRecommend a nightly run with failure alerts. First run \\`cofactor teams status\\`: leave Teams out of the ask unless it shows Teams enabled. Ask: **\"Which Slack channel, Teams channel or email should failures go to? For Slack, approve the connection in the browser page I open; for Teams, run \\`cofactor teams install\\` in your own terminal and approve it.\"** Connecting is for organization admins:\n- Slack: run \\`cofactor slack connect\\` in the background: it opens Settings → Slack and waits up to 10 minutes for the user's approval. If it connected the wrong workspace, with the user's go-ahead run \\`cofactor slack disconnect --yes\\`, then connect again. A private channel must add the Cofactor app first (\\`/invite\\` in that channel).\n- Teams: the user's \\`cofactor teams install\\` opens Settings → Microsoft Teams in their browser (signing in first if needed), which sends them to the Microsoft consent page and waits for it; they then add the Cofactor app to the channel, and \\`cofactor teams channels\\` lists the name to pass to \\`--teams\\`.\n\\`\\`\\`bash\ncofactor test-suite create --name \"<App> Nightly\" # 3b only\ncofactor test-suite set-members <suite> --layer <wf_...,wf_...> # 3b only\ncofactor test-suite suites # 3a: the suite's id (3b: printed by create)\ncofactor schedule suite create --name \"<App> Nightly\" --suite-id <id> --at 02:00 --timezone <their IANA zone>\ncofactor alert create --on-schedule <scheduleId> --slack \"#<channel>\" --when failure # or --teams \"<channel>\", or --email <addr>\n\\`\\`\\`\nDone when \\`cofactor schedule suite get <scheduleId>\\` shows the next run and the alert.\nOptional recurring summary of results: \\`cofactor digest config set daily --at 08:00 --timezone <their IANA zone> --slack \"#<channel>\"\\` (admins; Slack channels only), then \\`cofactor digest email daily on\\` for their own inbox.\n\n## 5. First report\n- \\`cofactor test-suite run --suite <suite>\\` now (don't wait for tonight); it streams results and prints the run URL. Read it with \\`cofactor test-suite get <executionId>\\` (3b) or \\`cofactor external-run get <run-id>\\` (3a). For failures: \\`cofactor skill install cofactor-triage-tests\\` (and \\`cofactor-debug-run\\` for 3b).\n- Something to share: the run's web URL, plus a short summary (what ran, passed, failed and why) published with \\`cofactor utilities gist create summary.md --title \"<App> first Cofactor run\"\\`.\n- Tell them the total time since step 1 started, and how to poke around: \\`cofactor sandbox claim --application <app> --wait\\` prints the URL and each persona's login; \\`cofactor sandbox destroy <id>\\` when done.\nAsk: **\"Who on your team should see this?\"** Invite each with \\`cofactor org invite <email>\\` (organization admins; \\`--role admin\\` for another admin); they get an email to join. The \\`link:\\` it prints lets anyone join: never repeat it; if the email did not send, the user shares it with the invitee themselves.\n\n## How cost works\nUse this when choosing what tests to write.\n- The base plan is $99/month and includes 10,000 test executions. One execution is any flow run (in design or draft mode, or in a suite) or any single Playwright test run: one test paired with one environment. Fully cached, deterministic executions (Playwright tests included) are plentiful and count within those.\n- Agent time is metered separately as **agent hours**: live healing, failure diagnosis and agent-only testing (MCP tests, exploratory tests). Plans include a free allotment; never quote a number.\n- Prefer deterministic tests for anything that runs every night. Before setting up an MCP or exploratory test, tell the user it spends agent hours on every run and weigh that against what it covers that a deterministic test cannot.\n\nRules: neutral example names (Acme, example.com) in tests; never real credentials in steps or chat. If something fails on Cofactor's side, stop and give the user the exact command, the error and the time.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorProveWithTestsTemplate: SkillTemplate = {\n name: 'cofactor-prove-with-tests',\n description:\n 'Connect pull request acceptance criteria to passing Cofactor Workflow evidence and configure promotion. Use with every user-visible change.',\n version: '2.2.0',\n render: () => `---\nname: cofactor-prove-with-tests\nversion: 2.2.0\ndescription: Connect pull request acceptance criteria to passing Cofactor Workflow evidence and configure promotion. Use with every user-visible change.\nallowed-tools: Bash(cofactor workflow:*), Bash(cofactor sandbox:*), Bash(cofactor proofs:*), Bash(cofactor perf guide:*), Read\n---\n\n# Prove a Change with Tests\n\nRun \\`cofactor proofs guide\\` for the full procedure. Use with every user-visible change; pass \\`--org <org>\\` on every write. Performance: \\`cofactor perf guide\\`.\n\n1. **Find coverage first.** Search with \\`cofactor workflow list --search \"<words>\"\\`, inspect with \\`cofactor workflow get <wf_...> --format markdown\\`, and read assertions. Extend the existing journey; never add near-duplicates for a changed filter, column or field.\n2. **Choose the Workflow.** If an approved test already proves the criterion unchanged (the journey must still work, e.g. after a query change), run it as is and attach its run: it is cited as an existing test, proves it still works, and is never promoted. To change a test, fork approved coverage with \\`cofactor workflow fork fork <wf_...> --org <org>\\`; never edit the original. Create a draft only when no journey fits or separate data/role is needed (\\`cofactor workflow guide write-a-test\\`).\n3. **Configure promotion** on a fork/draft (not an existing test) before attaching evidence: \\`cofactor workflow set-promotion <workflowId> --promote-on merge|never|deploy:<stage> [--target-suite <suite>]... --org <org>\\`; \\`never\\` archives it at merge, for a proof about the change itself (one-time migration or backfill, flag rollout step, behaviour being removed). Do not choose a layer; curation and suite behavior are in the guide.\n4. **Prove the exact pushed commit.** Commit and push, leave a clean checkout, and use \\`git rev-parse HEAD\\` as \\`<sha>\\`. Claim, sync, and run the Workflow (fork, draft or existing test):\n \\`cofactor sandbox claim --application <app> --at <sha> --wait --org <org>\\`\n \\`cofactor sandbox sync <sandboxId> [--build] --org <org>\\`\n \\`cofactor workflow run <workflowId> --sandbox <sandboxId> --stream --org <org>\\`\n Iterate to passing; after every application or Workflow test change, commit/push application edits, sync, and rerun. Use the final passing run ID; keep the checkout clean. Exact tree/SHA requirements are in the guide.\n5. **Push and open a DRAFT PR.** Commit/push remaining changes; if application or Workflow tests changed, repeat step 4 first. Note PR number \\`<n>\\` for attach.\n6. **Number observable acceptance criteria.** Supply both \\`--text\\` and \\`--detail\\` for each new number; reuse them for additional evidence. Use the most specific node/assertion ID via optional \\`--node <id>\\` and \\`--asserted \"Asserted that …\"\\`. A performance run can prove a criterion: run it at the pushed head SHA, then attach it with \\`--perf-run <prun_...>\\`. One criterion can mix kinds and carry several items (a query change: a workflow run for behavior and a perf run for speed); every item must pass.\n7. **Attach after the draft PR exists.** Use exactly one subject flag set per command. For E2E evidence, omit optional \\`--node\\` only if no specific ID exists:\n \\`cofactor proofs attach --pr <n> --application <app> --criterion <n> --text \"<criterion>\" --detail \"<why this matters>\" --test <wf_...> --run <wrun_...> [--node <most-specific-id>] --asserted \"Asserted that …\" --org <org>\\`\n For performance evidence:\n \\`cofactor proofs attach --pr <n> --application <app> --criterion <n> --perf-run <prun_...> --asserted \"Asserted that …\" --org <org>\\`\n A test containing any \\`visual_checkpoint\\` node is a UI test, even when it also has other steps. Attaching it runs the same test at the PR base commit and the proof page shows each checkpoint's base, head and diff. Put checkpoints before steps that depend on the new behavior so the base run can reach them.\n Only for a criterion Cofactor cannot exercise at all (desktop client, hardware, third-party console; never a failing or flaky test), attach manual evidence: \\`cofactor proofs attach --pr <n> --application <app> --criterion <n> [--text \"<criterion>\" --detail \"<why>\"] --manual --notes <text|@file> [--artifact <https-url>]... --org <org>\\`. Say what you did and why Cofactor could not prove it; notes and links are shown to every reader, so redact secrets and customer data and never link signed URLs. It passes, is marked manual, and never promotes; re-attaching replaces it, so repeat every \\`--artifact\\`.\n8. **Render, check and update.** Replace the PR proof block with all of \\`cofactor proofs render --pr <n> --org <org>\\`; never hand-format criteria blocks. Check with \\`cofactor proofs status --repo <owner/repo> --pr <n> --org <org>\\`. Detach a whole criterion with \\`cofactor proofs detach --pr <n> --criterion <n> --org <org>\\`, or one item with \\`--test <wf_...>\\` / \\`--perf-run <prun_...>\\` / \\`--manual\\`; render again after every attach or detach.\n\nDiagnose with \\`cofactor proofs check --pr <n> --sha <head> --body-file <file> --org <org>\\` or \\`--body -\\` for stdin; see the guide for checks/stale evidence. Re-run refreshes stale E2E evidence; performance evidence needs a new run at the current head, an attach, and a detach of the old item; manual evidence is refreshed by attaching it again at the new head. Server and CI own promotion triggers; \\`cofactor trigger\\` is not your job. No observable acceptance criterion at all (dependency bump, docs-only change)? Hand-type this neutral v2 block, replacing the PR proof block and explaining why:\n\n\\`\\`\\`text\n<!-- cofactor:proof -->\nnone: <why this pull request has no criterion to prove>\n<!-- /cofactor:proof -->\n\\`\\`\\`\n\nAdd concise \\`## Proof notes\\` explaining uncertain choices, coverage/gaps, and reasons. Use neutral example names; never include customer names, domains, or credentials. A human approves by merging; the agent does not approve Workflows.\\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorTriageIssuesTemplate: SkillTemplate = {\n name: 'cofactor-triage-issues',\n description:\n 'Triage Cofactor issues by listing, inspecting, deduping, tagging, closing and handing them off. Use when the user asks about open issues, what broke, or which issues to fix first.',\n version: '2.0.1',\n render: () => `---\nname: cofactor-triage-issues\nversion: 2.0.1\ndescription: Triage Cofactor issues by listing, inspecting, deduping, tagging, closing and handing them off. Use when the user asks about open issues, what broke, or which issues to fix first.\nallowed-tools: Bash(cofactor issues:*), Bash(cofactor login:*), Read, Grep\n---\n\n# Triage Issues\n\nUse this when the user wants to review, dedupe, prioritise or close issues Cofactor found.\n\nRun \\`cofactor issues guide\\` first. It explains triage order, dedupe, tagging and handing an issue to an engineer.\n\nKey commands:\n\n\\`\\`\\`bash\ncofactor issues list # open issues, newest first\ncofactor issues get <issueId> # evidence, steps, linked runs, comments\ncofactor issues comment <issueId> --body <text|@file> # leave a note for the team\ncofactor issues tag <issueId> --add <names> # label for routing\ncofactor issues merge <dupId> --into <canonicalId> # fold a duplicate\ncofactor issues close <issueId> [--not-a-bug --reason <text>]\n\\`\\`\\`\n\nRule: read an issue with \\`issues get\\` before closing or merging it, and never paste credentials or tokens from its evidence into tickets or chat.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorTriageTestsTemplate: SkillTemplate = {\n name: 'cofactor-triage-tests',\n description:\n 'Triage Cofactor test results by finding failing runs and suites, telling real failures from flakes, and deciding the next step. Use when the user asks what failed, whether a suite is healthy, or how to read test results.',\n version: '2.0.1',\n render: () => `---\nname: cofactor-triage-tests\nversion: 2.0.1\ndescription: Triage Cofactor test results by finding failing runs and suites, telling real failures from flakes, and deciding the next step. Use when the user asks what failed, whether a suite is healthy, or how to read test results.\nallowed-tools: Bash(cofactor test-suite:*), Bash(cofactor workflow list:*), Bash(cofactor workflow runs:*), Bash(cofactor workflow guide:*), Bash(cofactor external-run:*), Bash(cofactor login:*), Read\n---\n\n# Triage Tests\n\nUse this when the user wants to know what failed, whether a suite is healthy, or what to do about a red run.\n\nRun \\`cofactor external-run guide\\` first (and \\`cofactor workflow guide\\` for how tests are structured).\n\nKey commands:\n\n\\`\\`\\`bash\ncofactor test-suite executions # recent suite runs\ncofactor test-suite get <executionId> --failures-only\ncofactor test-suite diagnostics <workflowId> <runId>\ncofactor workflow runs list <workflowId> # run history for one test\ncofactor external-run guide # CI-triggered runs and artifacts\n\\`\\`\\`\n\nRule: a failure is real only when it reproduces with the same evidence; hand a single unexplained failure to \\`cofactor-debug-run\\` instead of guessing.\n`,\n};\n","import type { SkillTemplate } from './types.js';\n\nexport const cofactorWriteTestTemplate: SkillTemplate = {\n name: 'cofactor-write-test',\n description:\n 'Author a Cofactor end-to-end test directly through the CLI by picking the journey, creating or patching the workflow, running it and returning its URL. Use when the user asks to write, add, extend or fix a test.',\n version: '2.0.5',\n render: () => `---\nname: cofactor-write-test\nversion: 2.0.5\ndescription: Author a Cofactor end-to-end test directly through the CLI by picking the journey, creating or patching the workflow, running it and returning its URL. Use when the user asks to write, add, extend or fix a test.\nallowed-tools: Bash(cofactor workflow:*), Bash(cofactor session guide:*), Bash(cofactor perf guide:*), Bash(cofactor login:*), Read\n---\n\n# Write a Test\n\nUse this when the user wants a new end-to-end test, or a change to an existing one.\n\nRun \\`cofactor workflow guide write-a-test\\` first. It covers journey altitude (one user goal per test), assertions that prove an outcome, and seed data.\n\nFor visual regression coverage, read \\`cofactor workflow guide visual-checkpoints\\` for checkpoint placement, severity, and Playwright attachments.\n\nPerformance: \\`cofactor perf guide\\`\n\nAuthor directly in the CLI, with no spec files:\n\n\\`\\`\\`bash\ncofactor workflow list --search \"<topic>\" # never create a duplicate\ncofactor workflow create ... # new test (see the guide for the format)\ncofactor workflow patch <workflowId> ... # edit settings\ncofactor workflow node ... # edit a single step\ncofactor workflow sync <workflowId> --from-file state.json # replace all steps\ncofactor workflow run <workflowId> # prove it passes\n\\`\\`\\`\n\nFinish by giving the user the workflow URL and the run result.\n\nRule: never put real passwords or tokens in steps; use the credential placeholders the guide describes.\n`,\n};\n","import type { SkillTemplate } from './types.js';\nimport { cofactorBrowserTestingTemplate } from './cofactor-browser-testing.js';\nimport { cofactorDebugRunTemplate } from './cofactor-debug-run.js';\nimport { cofactorOnboardingTemplate } from './cofactor-onboarding.js';\nimport { cofactorProveWithTestsTemplate } from './cofactor-prove-with-tests.js';\nimport { cofactorTriageIssuesTemplate } from './cofactor-triage-issues.js';\nimport { cofactorTriageTestsTemplate } from './cofactor-triage-tests.js';\nimport { cofactorWriteTestTemplate } from './cofactor-write-test.js';\n\nexport type { SkillTemplate };\n\nexport const SKILL_TEMPLATES: Record<string, SkillTemplate> = {\n 'cofactor-triage-issues': cofactorTriageIssuesTemplate,\n 'cofactor-triage-tests': cofactorTriageTestsTemplate,\n 'cofactor-write-test': cofactorWriteTestTemplate,\n 'cofactor-browser-testing': cofactorBrowserTestingTemplate,\n 'cofactor-debug-run': cofactorDebugRunTemplate,\n 'cofactor-prove-with-tests': cofactorProveWithTestsTemplate,\n 'cofactor-onboarding': cofactorOnboardingTemplate,\n};\n","import { SKILL_TEMPLATES } from \"./skill-templates/index.js\";\n\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split(\".\").map((n) => parseInt(n, 10) || 0);\n const pb = b.split(\".\").map((n) => parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (d !== 0) return d < 0 ? -1 : 1;\n }\n return 0;\n}\n\nexport function knownVersions(name: string): string[] {\n const t = SKILL_TEMPLATES[name];\n if (!t) return [];\n const all = new Set<string>([t.version, ...Object.keys(t.previousVersions ?? {})]);\n return [...all].sort(compareSemver);\n}\n\nfunction renderAtVersion(name: string, version: string): string | null {\n const t = SKILL_TEMPLATES[name];\n if (!t) return null;\n if (version === t.version) return t.render();\n const prev = t.previousVersions?.[version];\n return prev ? prev() : null;\n}\n\nfunction parseFlagArgs(argv: string[]): {\n positional: string[];\n flags: Record<string, string | true>;\n} {\n const positional: string[] = [];\n const flags: Record<string, string | true> = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n const next = argv[i + 1];\n if (next !== undefined && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\nexport function runVersions(argv: string[]) {\n const [name] = argv;\n if (!name || !SKILL_TEMPLATES[name]) {\n console.error(`Usage: canary skill versions <name>`);\n process.exit(1);\n }\n const versions = knownVersions(name);\n const current = SKILL_TEMPLATES[name].version;\n for (const v of versions) {\n console.log(v === current ? `${v} (current)` : v);\n }\n}\n\nfunction jsUnifiedDiff(a: string, b: string, labelA: string, labelB: string): string {\n const aLines = a.split(\"\\n\");\n const bLines = b.split(\"\\n\");\n const n = aLines.length;\n const m = bLines.length;\n const dp: number[][] = Array.from({ length: n + 1 }, () =>\n Array.from<number>({ length: m + 1 }).fill(0)\n );\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n dp[i][j] =\n aLines[i] === bLines[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n const out: string[] = [`--- ${labelA}`, `+++ ${labelB}`];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (aLines[i] === bLines[j]) {\n out.push(` ${aLines[i]}`);\n i++;\n j++;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n out.push(`-${aLines[i++]}`);\n } else {\n out.push(`+${bLines[j++]}`);\n }\n }\n while (i < n) out.push(`-${aLines[i++]}`);\n while (j < m) out.push(`+${bLines[j++]}`);\n return out.join(\"\\n\") + \"\\n\";\n}\n\nexport function runDiff(argv: string[]) {\n const { positional, flags } = parseFlagArgs(argv);\n const [name] = positional;\n\n if (!name) {\n console.error(\"Usage: canary skill diff <name> [--from <version>] [--to <version>]\");\n process.exit(1);\n }\n\n const template = SKILL_TEMPLATES[name];\n if (!template) {\n console.error(`Unknown skill \"${name}\".`);\n process.exit(1);\n }\n\n const versions = knownVersions(name);\n const to = typeof flags.to === \"string\" ? flags.to : template.version;\n const from =\n typeof flags.from === \"string\" ? flags.from : versions.filter((v) => v !== to).slice(-1)[0];\n\n if (!from) {\n console.error(\n `No prior version of \"${name}\" to diff against. Only known version: ${template.version}.`\n );\n process.exit(1);\n }\n\n const fromContent = renderAtVersion(name, from);\n const toContent = renderAtVersion(name, to);\n\n if (fromContent === null) {\n console.error(\n `Version \"${from}\" of skill \"${name}\" is not in the CLI. Known: ${versions.join(\", \")}.`\n );\n process.exit(1);\n }\n if (toContent === null) {\n console.error(\n `Version \"${to}\" of skill \"${name}\" is not in the CLI. Known: ${versions.join(\", \")}.`\n );\n process.exit(1);\n }\n\n if (from === to) {\n console.log(`(no diff — both sides are v${from})`);\n return;\n }\n\n process.stdout.write(jsUnifiedDiff(fromContent, toContent, `${name}@${from}`, `${name}@${to}`));\n}\n"],"mappings":"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","names":["existsSync","readFileSync","homedir","join","join","i","j","join","homedir","existsSync","readFileSync"]}
@@ -1,21 +1,21 @@
1
1
  import { createRequire as __cr } from "module"; import { fileURLToPath as __fup } from "url"; import { dirname as __dn } from "path"; const require = __cr(import.meta.url); const __filename = __fup(import.meta.url); const __dirname = __dn(__filename);
2
2
  import {
3
3
  openUrl
4
- } from "./chunk-ABT3BLRC.js";
4
+ } from "./chunk-5TKXHS3X.js";
5
5
  import {
6
6
  apiRequest,
7
7
  promptInput,
8
8
  requireOrgAdmin
9
- } from "./chunk-LL6TSQWV.js";
9
+ } from "./chunk-VKZOHJCE.js";
10
10
  import "./chunk-S3Q7MDCS.js";
11
- import "./chunk-76Z6E7XX.js";
11
+ import "./chunk-4UZN6TVT.js";
12
12
  import {
13
13
  decodeJwtPayload,
14
14
  hasFlag,
15
15
  resolveConfig,
16
16
  resolveOrgAppUrl
17
- } from "./chunk-3HI6QC4V.js";
18
- import "./chunk-UEJ2HTKU.js";
17
+ } from "./chunk-WRBU6TX7.js";
18
+ import "./chunk-MJVUMVLO.js";
19
19
  import "./chunk-TOWZAG3I.js";
20
20
 
21
21
  // src/slack.ts
@@ -159,4 +159,4 @@ export {
159
159
  slackConnectUrl,
160
160
  slackDisconnect
161
161
  };
162
- //# sourceMappingURL=slack-WE7THLLH.js.map
162
+ //# sourceMappingURL=slack-ZEK4GRND.js.map
@@ -12,15 +12,15 @@ import {
12
12
  workflowToSpec,
13
13
  writeNodeIds,
14
14
  writeWorkflowId
15
- } from "./chunk-ZL4O6C42.js";
15
+ } from "./chunk-HXBK3AGD.js";
16
16
  import "./chunk-DEK6B6LX.js";
17
- import "./chunk-76Z6E7XX.js";
17
+ import "./chunk-4UZN6TVT.js";
18
18
  import {
19
19
  fetchOrExit,
20
20
  getArgValue,
21
21
  hasFlag,
22
22
  resolveOrgAppUrl
23
- } from "./chunk-3HI6QC4V.js";
23
+ } from "./chunk-WRBU6TX7.js";
24
24
  import {
25
25
  isSpecFile,
26
26
  readableSpecDirs,
@@ -28,7 +28,7 @@ import {
28
28
  specExtension,
29
29
  splitSpecExtension,
30
30
  writeRawOutput
31
- } from "./chunk-UEJ2HTKU.js";
31
+ } from "./chunk-MJVUMVLO.js";
32
32
  import "./chunk-TOWZAG3I.js";
33
33
 
34
34
  // src/spec/index.ts
@@ -980,4 +980,4 @@ export {
980
980
  stampedSpecPath,
981
981
  uniqueName
982
982
  };
983
- //# sourceMappingURL=spec-SEOY7N3L.js.map
983
+ //# sourceMappingURL=spec-XPIRRSV6.js.map
@@ -149,13 +149,13 @@ import {
149
149
  verifyOnRun,
150
150
  verifySelectorAgainstRef,
151
151
  waitForTraceDomHydration
152
- } from "./chunk-5UUIBY6E.js";
153
- import "./chunk-IY3ZK46I.js";
152
+ } from "./chunk-TAVBFLCR.js";
153
+ import "./chunk-QOVJUSSL.js";
154
154
  import {
155
155
  buildLocatorString
156
156
  } from "./chunk-PBTGJYM5.js";
157
157
  import "./chunk-S3Q7MDCS.js";
158
- import "./chunk-76Z6E7XX.js";
158
+ import "./chunk-4UZN6TVT.js";
159
159
  import "./chunk-AK7WEGGB.js";
160
160
  import "./chunk-NQ7LMSSS.js";
161
161
  import "./chunk-5QHORHJT.js";
@@ -312,4 +312,4 @@ export {
312
312
  verifySelectorAgainstRef,
313
313
  waitForTraceDomHydration
314
314
  };
315
- //# sourceMappingURL=src-CCK3TKBX.js.map
315
+ //# sourceMappingURL=src-N7ZCYCXU.js.map
@@ -234,9 +234,9 @@ import {
234
234
  withRecoveryNotice,
235
235
  withRecoveryNoticeMCP,
236
236
  withToolTimeout
237
- } from "./chunk-IY3ZK46I.js";
237
+ } from "./chunk-QOVJUSSL.js";
238
238
  import "./chunk-S3Q7MDCS.js";
239
- import "./chunk-76Z6E7XX.js";
239
+ import "./chunk-4UZN6TVT.js";
240
240
  import "./chunk-AK7WEGGB.js";
241
241
  import "./chunk-NQ7LMSSS.js";
242
242
  import {
@@ -489,4 +489,4 @@ export {
489
489
  withRecoveryNoticeMCP,
490
490
  withToolTimeout
491
491
  };
492
- //# sourceMappingURL=src-AEWV5HYH.js.map
492
+ //# sourceMappingURL=src-XSBBMVGW.js.map
@@ -8,14 +8,14 @@ import {
8
8
  fetchList,
9
9
  promptChoice,
10
10
  selectProperty
11
- } from "./chunk-LL6TSQWV.js";
11
+ } from "./chunk-VKZOHJCE.js";
12
12
  import "./chunk-S3Q7MDCS.js";
13
- import "./chunk-76Z6E7XX.js";
13
+ import "./chunk-4UZN6TVT.js";
14
14
  import {
15
15
  getArgValue,
16
16
  resolveConfig
17
- } from "./chunk-3HI6QC4V.js";
18
- import "./chunk-UEJ2HTKU.js";
17
+ } from "./chunk-WRBU6TX7.js";
18
+ import "./chunk-MJVUMVLO.js";
19
19
  import "./chunk-TOWZAG3I.js";
20
20
 
21
21
  // src/local/start.ts
@@ -149,4 +149,4 @@ Use \`canary session\` commands to interact with the browser.`);
149
149
  export {
150
150
  runLocalStart
151
151
  };
152
- //# sourceMappingURL=start-EPGLHTND.js.map
152
+ //# sourceMappingURL=start-DKWLOQI6.js.map
@@ -1,17 +1,17 @@
1
1
  import { createRequire as __cr } from "module"; import { fileURLToPath as __fup } from "url"; import { dirname as __dn } from "path"; const require = __cr(import.meta.url); const __filename = __fup(import.meta.url); const __dirname = __dn(__filename);
2
2
  import {
3
3
  getPositionalArg
4
- } from "./chunk-LL6TSQWV.js";
4
+ } from "./chunk-VKZOHJCE.js";
5
5
  import "./chunk-S3Q7MDCS.js";
6
- import "./chunk-76Z6E7XX.js";
6
+ import "./chunk-4UZN6TVT.js";
7
7
  import {
8
8
  GLOBAL_VALUE_FLAGS,
9
9
  getArgValue,
10
10
  hasFlag
11
- } from "./chunk-3HI6QC4V.js";
11
+ } from "./chunk-WRBU6TX7.js";
12
12
  import {
13
13
  writeRawOutput
14
- } from "./chunk-UEJ2HTKU.js";
14
+ } from "./chunk-MJVUMVLO.js";
15
15
  import "./chunk-TOWZAG3I.js";
16
16
 
17
17
  // src/status.ts
@@ -434,4 +434,4 @@ function printHelp() {
434
434
  export {
435
435
  runStatus
436
436
  };
437
- //# sourceMappingURL=status-DTE2GXM2.js.map
437
+ //# sourceMappingURL=status-K7KH5DI3.js.map
@@ -7,12 +7,12 @@ import {
7
7
  runTag,
8
8
  splitCsv,
9
9
  updateEntityTags
10
- } from "./chunk-I5RHTCPY.js";
11
- import "./chunk-LL6TSQWV.js";
10
+ } from "./chunk-EL6KJ4PO.js";
11
+ import "./chunk-VKZOHJCE.js";
12
12
  import "./chunk-S3Q7MDCS.js";
13
- import "./chunk-76Z6E7XX.js";
14
- import "./chunk-3HI6QC4V.js";
15
- import "./chunk-UEJ2HTKU.js";
13
+ import "./chunk-4UZN6TVT.js";
14
+ import "./chunk-WRBU6TX7.js";
15
+ import "./chunk-MJVUMVLO.js";
16
16
  import "./chunk-TOWZAG3I.js";
17
17
  export {
18
18
  applyWorkflowTagFlags,
@@ -23,4 +23,4 @@ export {
23
23
  splitCsv,
24
24
  updateEntityTags
25
25
  };
26
- //# sourceMappingURL=tag-GIFEWGBL.js.map
26
+ //# sourceMappingURL=tag-2Y3OMQQC.js.map
@@ -4,25 +4,25 @@ import {
4
4
  formatUnknownTagsError,
5
5
  resolveTagNames,
6
6
  splitCsv
7
- } from "./chunk-I5RHTCPY.js";
7
+ } from "./chunk-EL6KJ4PO.js";
8
8
  import {
9
9
  UUID_RE,
10
10
  apiRequest,
11
11
  getArgValues,
12
12
  getPositionalArgs,
13
13
  getTargetOrg
14
- } from "./chunk-LL6TSQWV.js";
14
+ } from "./chunk-VKZOHJCE.js";
15
15
  import "./chunk-S3Q7MDCS.js";
16
- import "./chunk-76Z6E7XX.js";
16
+ import "./chunk-4UZN6TVT.js";
17
17
  import {
18
18
  GLOBAL_VALUE_FLAGS,
19
19
  getArgValue,
20
20
  hasFlag,
21
21
  resolveConfig
22
- } from "./chunk-3HI6QC4V.js";
22
+ } from "./chunk-WRBU6TX7.js";
23
23
  import {
24
24
  writeRawOutput
25
- } from "./chunk-UEJ2HTKU.js";
25
+ } from "./chunk-MJVUMVLO.js";
26
26
  import "./chunk-TOWZAG3I.js";
27
27
 
28
28
  // src/task.ts
@@ -942,4 +942,4 @@ async function runTask(argv) {
942
942
  export {
943
943
  runTask
944
944
  };
945
- //# sourceMappingURL=task-VLJCHSFB.js.map
945
+ //# sourceMappingURL=task-4PIOC4QV.js.map