@keystrokehq/cli 0.0.0-staging-20260714051854

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 (253) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +272 -0
  3. package/dist/alias-RTYYYW3D-CLFgrowj.mjs +98 -0
  4. package/dist/alias-RTYYYW3D-CLFgrowj.mjs.map +1 -0
  5. package/dist/awk2-LA3USKJP-BbsfXVlR.mjs +2737 -0
  6. package/dist/awk2-LA3USKJP-BbsfXVlR.mjs.map +1 -0
  7. package/dist/base64-C2AIWVNC-C0WIgu5V.mjs +123 -0
  8. package/dist/base64-C2AIWVNC-C0WIgu5V.mjs.map +1 -0
  9. package/dist/basename-UB3CIYNI-BgNN3bGm.mjs +53 -0
  10. package/dist/basename-UB3CIYNI-BgNN3bGm.mjs.map +1 -0
  11. package/dist/bash-YZ33HQZQ-N6YyKtUH.mjs +118 -0
  12. package/dist/bash-YZ33HQZQ-N6YyKtUH.mjs.map +1 -0
  13. package/dist/cat-TSFMZVYS-Dz3-oHsV.mjs +63 -0
  14. package/dist/cat-TSFMZVYS-Dz3-oHsV.mjs.map +1 -0
  15. package/dist/chmod-TFEPA42X-YF02QJUv.mjs +125 -0
  16. package/dist/chmod-TFEPA42X-YF02QJUv.mjs.map +1 -0
  17. package/dist/chunk-27JIFWUR-B6ZjjMMI.mjs +100 -0
  18. package/dist/chunk-27JIFWUR-B6ZjjMMI.mjs.map +1 -0
  19. package/dist/chunk-4I3HOE5Z-BixWWVkW.mjs +719 -0
  20. package/dist/chunk-4I3HOE5Z-BixWWVkW.mjs.map +1 -0
  21. package/dist/chunk-4RUAZWKT-D60fyWAB.mjs +22543 -0
  22. package/dist/chunk-4RUAZWKT-D60fyWAB.mjs.map +1 -0
  23. package/dist/chunk-4WKZNNJK-CiwxAWRf.mjs +69 -0
  24. package/dist/chunk-4WKZNNJK-CiwxAWRf.mjs.map +1 -0
  25. package/dist/chunk-5H5SCKJM-BvfXlL01.mjs +606 -0
  26. package/dist/chunk-5H5SCKJM-BvfXlL01.mjs.map +1 -0
  27. package/dist/chunk-AQ6FYS2X-CkVetjym.mjs +37 -0
  28. package/dist/chunk-AQ6FYS2X-CkVetjym.mjs.map +1 -0
  29. package/dist/chunk-BZUGFHVS-CPWRFwK8.mjs +34 -0
  30. package/dist/chunk-BZUGFHVS-CPWRFwK8.mjs.map +1 -0
  31. package/dist/chunk-CHFEPBH4-BUdgjFtD.mjs +594 -0
  32. package/dist/chunk-CHFEPBH4-BUdgjFtD.mjs.map +1 -0
  33. package/dist/chunk-DLL7UR66-BUYgzxnR.mjs +14 -0
  34. package/dist/chunk-DLL7UR66-BUYgzxnR.mjs.map +1 -0
  35. package/dist/chunk-DiodbrVj.mjs +27 -0
  36. package/dist/chunk-EBAPSGAO-Ctfslw2R.mjs +247 -0
  37. package/dist/chunk-EBAPSGAO-Ctfslw2R.mjs.map +1 -0
  38. package/dist/chunk-FOCWZZDE-BIntqBh2.mjs +19 -0
  39. package/dist/chunk-FOCWZZDE-BIntqBh2.mjs.map +1 -0
  40. package/dist/chunk-HBVMHTO5-CJyD-QZX.mjs +10 -0
  41. package/dist/chunk-HBVMHTO5-CJyD-QZX.mjs.map +1 -0
  42. package/dist/chunk-L2UW7DWF-B3tEHhPF.mjs +14 -0
  43. package/dist/chunk-L2UW7DWF-B3tEHhPF.mjs.map +1 -0
  44. package/dist/chunk-L64BMZUV-CyR7RKok.mjs +30 -0
  45. package/dist/chunk-L64BMZUV-CyR7RKok.mjs.map +1 -0
  46. package/dist/chunk-LEKBROJD-CJMrAyu9.mjs +3113 -0
  47. package/dist/chunk-LEKBROJD-CJMrAyu9.mjs.map +1 -0
  48. package/dist/chunk-NRSASXYY-CuWyREpD.mjs +41 -0
  49. package/dist/chunk-NRSASXYY-CuWyREpD.mjs.map +1 -0
  50. package/dist/chunk-QAYAQNCG-Bl0Kbd53.mjs +63 -0
  51. package/dist/chunk-QAYAQNCG-Bl0Kbd53.mjs.map +1 -0
  52. package/dist/chunk-QIQMJJZ4-BwKdslXs.mjs +93 -0
  53. package/dist/chunk-QIQMJJZ4-BwKdslXs.mjs.map +1 -0
  54. package/dist/chunk-SAI2SPQQ-CVRoDNs9.mjs +26 -0
  55. package/dist/chunk-SAI2SPQQ-CVRoDNs9.mjs.map +1 -0
  56. package/dist/chunk-SO6R3ZKN-tTw_RMDX.mjs +140 -0
  57. package/dist/chunk-SO6R3ZKN-tTw_RMDX.mjs.map +1 -0
  58. package/dist/chunk-STHBFACM-lyj-j2a-.mjs +8 -0
  59. package/dist/chunk-STHBFACM-lyj-j2a-.mjs.map +1 -0
  60. package/dist/chunk-SX2HC7SO-Cc4Hpis1.mjs +20 -0
  61. package/dist/chunk-SX2HC7SO-Cc4Hpis1.mjs.map +1 -0
  62. package/dist/chunk-TDD4NFYE-wsWW75MX.mjs +21 -0
  63. package/dist/chunk-TDD4NFYE-wsWW75MX.mjs.map +1 -0
  64. package/dist/chunk-TN7HHBQW-CSB_R-XD.mjs +1137 -0
  65. package/dist/chunk-TN7HHBQW-CSB_R-XD.mjs.map +1 -0
  66. package/dist/chunk-VPADYNBD-BKlA28GJ.mjs +122 -0
  67. package/dist/chunk-VPADYNBD-BKlA28GJ.mjs.map +1 -0
  68. package/dist/chunk-W5DWRFSU-lCyWk0ph.mjs +11 -0
  69. package/dist/chunk-W5DWRFSU-lCyWk0ph.mjs.map +1 -0
  70. package/dist/chunk-WNH3HOQA-BCZUOjCJ.mjs +34 -0
  71. package/dist/chunk-WNH3HOQA-BCZUOjCJ.mjs.map +1 -0
  72. package/dist/chunk-XRFHFXFP-BGxzVZgK.mjs +16 -0
  73. package/dist/chunk-XRFHFXFP-BGxzVZgK.mjs.map +1 -0
  74. package/dist/chunk-YCLFEX4T-COc1AThz.mjs +77 -0
  75. package/dist/chunk-YCLFEX4T-COc1AThz.mjs.map +1 -0
  76. package/dist/clear-HKGFEOF6-CekN2x-O.mjs +28 -0
  77. package/dist/clear-HKGFEOF6-CekN2x-O.mjs.map +1 -0
  78. package/dist/column-XT6UFXNQ-DHENV9D2.mjs +143 -0
  79. package/dist/column-XT6UFXNQ-DHENV9D2.mjs.map +1 -0
  80. package/dist/comm-VV2LDX2J-ppxDJFkY.mjs +87 -0
  81. package/dist/comm-VV2LDX2J-ppxDJFkY.mjs.map +1 -0
  82. package/dist/configs/oxlintrc.json +27 -0
  83. package/dist/configs/vitest.config.mjs +42 -0
  84. package/dist/configs/vitest.setup.integration.mjs +37 -0
  85. package/dist/cp-BISAAS7A-CMWayU4n.mjs +106 -0
  86. package/dist/cp-BISAAS7A-CMWayU4n.mjs.map +1 -0
  87. package/dist/cut-OKARJCCV-Bt8b58eI.mjs +119 -0
  88. package/dist/cut-OKARJCCV-Bt8b58eI.mjs.map +1 -0
  89. package/dist/date-UUUPW43J-B7T5OTZZ.mjs +188 -0
  90. package/dist/date-UUUPW43J-B7T5OTZZ.mjs.map +1 -0
  91. package/dist/diff-MWJFIG7X-DhnPc_5r.mjs +755 -0
  92. package/dist/diff-MWJFIG7X-DhnPc_5r.mjs.map +1 -0
  93. package/dist/dirname-MPHRFUTI-Dkb3S4OX.mjs +43 -0
  94. package/dist/dirname-MPHRFUTI-Dkb3S4OX.mjs.map +1 -0
  95. package/dist/dist-BFOvwXwm.mjs +31042 -0
  96. package/dist/dist-BFOvwXwm.mjs.map +1 -0
  97. package/dist/dist-BoZPZ9Sz.mjs +8498 -0
  98. package/dist/dist-BoZPZ9Sz.mjs.map +1 -0
  99. package/dist/dist-D9y3OVoD.mjs +3 -0
  100. package/dist/dist-De18Uq1U.mjs +11680 -0
  101. package/dist/dist-De18Uq1U.mjs.map +1 -0
  102. package/dist/dist-yDNd8kGO.mjs +801 -0
  103. package/dist/dist-yDNd8kGO.mjs.map +1 -0
  104. package/dist/du-572XNP42-ClP4jXB1.mjs +176 -0
  105. package/dist/du-572XNP42-ClP4jXB1.mjs.map +1 -0
  106. package/dist/echo-NDWZZHPO-CCp_-MxA.mjs +137 -0
  107. package/dist/echo-NDWZZHPO-CCp_-MxA.mjs.map +1 -0
  108. package/dist/env-36M5BO7M-CsP_aiWr.mjs +119 -0
  109. package/dist/env-36M5BO7M-CsP_aiWr.mjs.map +1 -0
  110. package/dist/expand-JSPG6VOP-B-YUvYpu.mjs +145 -0
  111. package/dist/expand-JSPG6VOP-B-YUvYpu.mjs.map +1 -0
  112. package/dist/expr-5JAACS4X-1TBq84gG.mjs +153 -0
  113. package/dist/expr-5JAACS4X-1TBq84gG.mjs.map +1 -0
  114. package/dist/file-IPZJC3FQ-DcZNOWyY.mjs +4201 -0
  115. package/dist/file-IPZJC3FQ-DcZNOWyY.mjs.map +1 -0
  116. package/dist/find-INTH3OLC-6p47KeeT.mjs +1332 -0
  117. package/dist/find-INTH3OLC-6p47KeeT.mjs.map +1 -0
  118. package/dist/fold-4TQNYMSW-C54bHzLd.mjs +138 -0
  119. package/dist/fold-4TQNYMSW-C54bHzLd.mjs.map +1 -0
  120. package/dist/grep-V3LQVMRQ-D99Bq7Kj.mjs +335 -0
  121. package/dist/grep-V3LQVMRQ-D99Bq7Kj.mjs.map +1 -0
  122. package/dist/gzip-O5ASJAFY-CZDRROqP.mjs +592 -0
  123. package/dist/gzip-O5ASJAFY-CZDRROqP.mjs.map +1 -0
  124. package/dist/head-442HYESI-D96RMdki.mjs +36 -0
  125. package/dist/head-442HYESI-D96RMdki.mjs.map +1 -0
  126. package/dist/help-HZ6M2CKN--DK8mY2L.mjs +123 -0
  127. package/dist/help-HZ6M2CKN--DK8mY2L.mjs.map +1 -0
  128. package/dist/history-WYYKSLSZ-ACNQVupn.mjs +48 -0
  129. package/dist/history-WYYKSLSZ-ACNQVupn.mjs.map +1 -0
  130. package/dist/hostname-C4HQXXUP-CXVVFkUK.mjs +24 -0
  131. package/dist/hostname-C4HQXXUP-CXVVFkUK.mjs.map +1 -0
  132. package/dist/html-to-markdown-JW4MSQZO-DQOxFIvF.mjs +15890 -0
  133. package/dist/html-to-markdown-JW4MSQZO-DQOxFIvF.mjs.map +1 -0
  134. package/dist/index.mjs +9675 -0
  135. package/dist/index.mjs.map +1 -0
  136. package/dist/join-TBRGI3LQ-B8I9tkJ5.mjs +198 -0
  137. package/dist/join-TBRGI3LQ-B8I9tkJ5.mjs.map +1 -0
  138. package/dist/jq-4XLYLOS5-wFZYfsfJ.mjs +257 -0
  139. package/dist/jq-4XLYLOS5-wFZYfsfJ.mjs.map +1 -0
  140. package/dist/js-exec-N5KEZBH7-CoRL1IOd.mjs +333 -0
  141. package/dist/js-exec-N5KEZBH7-CoRL1IOd.mjs.map +1 -0
  142. package/dist/lib-D4GpdNNK.mjs +45 -0
  143. package/dist/lib-D4GpdNNK.mjs.map +1 -0
  144. package/dist/ln-4LGSXXGD-Dg0R9i5G.mjs +101 -0
  145. package/dist/ln-4LGSXXGD-Dg0R9i5G.mjs.map +1 -0
  146. package/dist/ls-ZJGQER7M-DLDSfI4x.mjs +1891 -0
  147. package/dist/ls-ZJGQER7M-DLDSfI4x.mjs.map +1 -0
  148. package/dist/lzma-CTMDi254.mjs +1135 -0
  149. package/dist/lzma-CTMDi254.mjs.map +1 -0
  150. package/dist/maybe-auto-update-C-HUlgKp.mjs +139 -0
  151. package/dist/maybe-auto-update-C-HUlgKp.mjs.map +1 -0
  152. package/dist/md5sum-SPU24VSG-DQc8sqXO.mjs +16 -0
  153. package/dist/md5sum-SPU24VSG-DQc8sqXO.mjs.map +1 -0
  154. package/dist/mkdir-MEPGZOB6-BjUKzhdL.mjs +58 -0
  155. package/dist/mkdir-MEPGZOB6-BjUKzhdL.mjs.map +1 -0
  156. package/dist/mv-W5BIQ646-CdSIyY-U.mjs +93 -0
  157. package/dist/mv-W5BIQ646-CdSIyY-U.mjs.map +1 -0
  158. package/dist/nl-WSDW7I4O-DmtCnyKU.mjs +208 -0
  159. package/dist/nl-WSDW7I4O-DmtCnyKU.mjs.map +1 -0
  160. package/dist/od-WOKFDJTP-DZ2nxQNJ.mjs +73 -0
  161. package/dist/od-WOKFDJTP-DZ2nxQNJ.mjs.map +1 -0
  162. package/dist/paste-7JC6S4DX-CtmM5Qy8.mjs +113 -0
  163. package/dist/paste-7JC6S4DX-CtmM5Qy8.mjs.map +1 -0
  164. package/dist/printf-TWGXF445-B7cTysaa.mjs +880 -0
  165. package/dist/printf-TWGXF445-B7cTysaa.mjs.map +1 -0
  166. package/dist/pwd-WE6EN5AV-CO8o2WQS.mjs +34 -0
  167. package/dist/pwd-WE6EN5AV-CO8o2WQS.mjs.map +1 -0
  168. package/dist/python3-POMOR4OA-CKy80mpF.mjs +299 -0
  169. package/dist/python3-POMOR4OA-CKy80mpF.mjs.map +1 -0
  170. package/dist/readlink-OPJF4DL5-Rc1Mz_Xx.mjs +76 -0
  171. package/dist/readlink-OPJF4DL5-Rc1Mz_Xx.mjs.map +1 -0
  172. package/dist/rev-5EHFX4EJ-3dd9vwHW.mjs +66 -0
  173. package/dist/rev-5EHFX4EJ-3dd9vwHW.mjs.map +1 -0
  174. package/dist/rg-S4FXYXWB-BbXVo6JX.mjs +1539 -0
  175. package/dist/rg-S4FXYXWB-BbXVo6JX.mjs.map +1 -0
  176. package/dist/rm-SSGETQVQ-Ch53Rmrr.mjs +81 -0
  177. package/dist/rm-SSGETQVQ-Ch53Rmrr.mjs.map +1 -0
  178. package/dist/rmdir-OC4ZLPYA-D3QCHlIB.mjs +132 -0
  179. package/dist/rmdir-OC4ZLPYA-D3QCHlIB.mjs.map +1 -0
  180. package/dist/run-package-manager-update-D_jU5wZe.mjs +457 -0
  181. package/dist/run-package-manager-update-D_jU5wZe.mjs.map +1 -0
  182. package/dist/sed-S5UIK574-DE1KeTk3.mjs +1722 -0
  183. package/dist/sed-S5UIK574-DE1KeTk3.mjs.map +1 -0
  184. package/dist/seq-M5EC7Q57-BHfGjQvK.mjs +85 -0
  185. package/dist/seq-M5EC7Q57-BHfGjQvK.mjs.map +1 -0
  186. package/dist/sha1sum-2PTOAFR6-DNjSNcYK.mjs +16 -0
  187. package/dist/sha1sum-2PTOAFR6-DNjSNcYK.mjs.map +1 -0
  188. package/dist/sha256sum-NS7D3IXX-BMaCKkT5.mjs +16 -0
  189. package/dist/sha256sum-NS7D3IXX-BMaCKkT5.mjs.map +1 -0
  190. package/dist/skills-bundle/_AGENTS.mcp.md +161 -0
  191. package/dist/skills-bundle/_AGENTS.md +362 -0
  192. package/dist/sleep-X22JJINO-Do5hEQQW.mjs +67 -0
  193. package/dist/sleep-X22JJINO-Do5hEQQW.mjs.map +1 -0
  194. package/dist/sort-SW2YEO5B-B7j1zw8k.mjs +320 -0
  195. package/dist/sort-SW2YEO5B-B7j1zw8k.mjs.map +1 -0
  196. package/dist/split-4KKZZXXE-h8GD4HP4.mjs +248 -0
  197. package/dist/split-4KKZZXXE-h8GD4HP4.mjs.map +1 -0
  198. package/dist/sqlite3-CGOEFJAO-DvzzghDg.mjs +2879 -0
  199. package/dist/sqlite3-CGOEFJAO-DvzzghDg.mjs.map +1 -0
  200. package/dist/stat-CD34IZ4P-B5ZOJh4J.mjs +65 -0
  201. package/dist/stat-CD34IZ4P-B5ZOJh4J.mjs.map +1 -0
  202. package/dist/strings-6WDHLGMX-DdiEdoL-.mjs +179 -0
  203. package/dist/strings-6WDHLGMX-DdiEdoL-.mjs.map +1 -0
  204. package/dist/tac-2STMMJYW-DPyeWM9R.mjs +53 -0
  205. package/dist/tac-2STMMJYW-DPyeWM9R.mjs.map +1 -0
  206. package/dist/tail-R4PCA2C4-CUfroNeu.mjs +37 -0
  207. package/dist/tail-R4PCA2C4-CUfroNeu.mjs.map +1 -0
  208. package/dist/tar-STHHZTZ6-DRf60e-G.mjs +2838 -0
  209. package/dist/tar-STHHZTZ6-DRf60e-G.mjs.map +1 -0
  210. package/dist/tee-YUZ2FKCJ-po_dfyc_.mjs +46 -0
  211. package/dist/tee-YUZ2FKCJ-po_dfyc_.mjs.map +1 -0
  212. package/dist/templates/hello-world/README.md +14 -0
  213. package/dist/templates/hello-world/keystroke.config.ts +3 -0
  214. package/dist/templates/hello-world/package.json +23 -0
  215. package/dist/templates/hello-world/src/actions/greet.ts +21 -0
  216. package/dist/templates/hello-world/src/agents/hello.int.test.ts +13 -0
  217. package/dist/templates/hello-world/src/agents/hello.ts +9 -0
  218. package/dist/templates/hello-world/src/workflows/greeting.test.ts +11 -0
  219. package/dist/templates/hello-world/src/workflows/greeting.ts +14 -0
  220. package/dist/templates/hello-world/tsconfig.json +20 -0
  221. package/dist/time-D4LNBSWX-DVWhAldK.mjs +112 -0
  222. package/dist/time-D4LNBSWX-DVWhAldK.mjs.map +1 -0
  223. package/dist/timeout-YDCRSLPQ-B_yntmXU.mjs +113 -0
  224. package/dist/timeout-YDCRSLPQ-B_yntmXU.mjs.map +1 -0
  225. package/dist/touch-UA33VN3N-oW1SBT1r.mjs +104 -0
  226. package/dist/touch-UA33VN3N-oW1SBT1r.mjs.map +1 -0
  227. package/dist/tr-36LHWFRQ-CTq3z6wq.mjs +167 -0
  228. package/dist/tr-36LHWFRQ-CTq3z6wq.mjs.map +1 -0
  229. package/dist/tree-YLD52CNT-CIozNsLQ.mjs +186 -0
  230. package/dist/tree-YLD52CNT-CIozNsLQ.mjs.map +1 -0
  231. package/dist/true-FHQXJXBE-DsJOznSp.mjs +31 -0
  232. package/dist/true-FHQXJXBE-DsJOznSp.mjs.map +1 -0
  233. package/dist/unexpand-CADSA4VO-Cq9DTcUg.mjs +155 -0
  234. package/dist/unexpand-CADSA4VO-Cq9DTcUg.mjs.map +1 -0
  235. package/dist/uniq-XSIZR6PB-D5lt-IXF.mjs +92 -0
  236. package/dist/uniq-XSIZR6PB-D5lt-IXF.mjs.map +1 -0
  237. package/dist/watch-app-DTIeKrbl-CSpsNzVG.mjs +100 -0
  238. package/dist/watch-app-DTIeKrbl-CSpsNzVG.mjs.map +1 -0
  239. package/dist/wc-LF7NU4LA-BFPabrwD.mjs +111 -0
  240. package/dist/wc-LF7NU4LA-BFPabrwD.mjs.map +1 -0
  241. package/dist/which-XEM24D5D-2LvlkpUo.mjs +62 -0
  242. package/dist/which-XEM24D5D-2LvlkpUo.mjs.map +1 -0
  243. package/dist/whoami-XMTX52VE-24Kwqrk6.mjs +24 -0
  244. package/dist/whoami-XMTX52VE-24Kwqrk6.mjs.map +1 -0
  245. package/dist/xan-Y6WF3IRG-DjKO96Pj.mjs +2832 -0
  246. package/dist/xan-Y6WF3IRG-DjKO96Pj.mjs.map +1 -0
  247. package/dist/xan-view-HDVKHFC2-DhDNVE_V.mjs +12 -0
  248. package/dist/xan-view-HDVKHFC2-DhDNVE_V.mjs.map +1 -0
  249. package/dist/xargs-MGZPH7AX-D2bIgrdg.mjs +112 -0
  250. package/dist/xargs-MGZPH7AX-D2bIgrdg.mjs.map +1 -0
  251. package/dist/yq-4QJW3EQG-XhB3aACo.mjs +8610 -0
  252. package/dist/yq-4QJW3EQG-XhB3aACo.mjs.map +1 -0
  253. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2026 Sprint Labs, Inc. All rights reserved.
2
+
3
+ This private canonical monorepo contains materials under different terms:
4
+
5
+ - The downstream public projection described by `oss/` is made available under
6
+ the Elastic License 2.0 in `oss/LICENSE`.
7
+ - Code and materials in paths containing an exact `cloud` segment are
8
+ proprietary and governed by the nearest applicable proprietary license.
9
+
10
+ Access to this private repository does not itself grant a license to use, copy,
11
+ modify, distribute, make available, or create derivative works from its
12
+ contents. Sprint Labs employees, contractors, customers, and partners receive
13
+ rights only under their applicable written agreements.
package/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # keystroke CLI
2
+
3
+ The primary interface for working with keystroke — locally and against a remote deployment.
4
+
5
+ **Local** commands hit your local platform API (`PUBLIC_PLATFORM_URL` in the project `.env`, or the dev session URL while `keystroke dev` is running). **Cloud** commands hit the **keystroke platform** control plane (`platformUrl`), which manages and routes to deployed keystroke servers per project.
6
+
7
+ Distributed via npm as the `keystroke` binary. Staging pre-releases use the opt-in `@staging` dist-tag.
8
+
9
+ ## Philosophy
10
+
11
+ Keep the CLI small and boring.
12
+
13
+ - **Few dependencies** — only add a package when it clearly earns its place
14
+ - **Plain output** — no TUI, spinners, or heavy UX frameworks unless we truly need them
15
+ - **Agent-first** — commands should be predictable, scriptable, and easy for AI agents to invoke
16
+ - **Split concerns** — non-secret config in one place, secrets in the OS keychain
17
+
18
+ Right now the CLI exposes `init`, `build`, `dev`, `start`, `lint`, `typecheck`, `test`, `deploy`, `pull`, `update`, `health`, `auth`, `--help`, and `--version`.
19
+
20
+ ## Command grammar
21
+
22
+ Stripe-style: plural REST collection, then a verb, then the primary slug. New commands **must** follow this shape.
23
+
24
+ ```text
25
+ keystroke <collection> <verb> [<slug>] [<sub-id>] [--flags]
26
+ keystroke <collection> <sub-collection> <verb> [<slug>] [<sub-id>] [--flags]
27
+ keystroke <verb> # lifecycle only (init, build, dev, deploy, update, …)
28
+ ```
29
+
30
+ Rules:
31
+
32
+ - **Collections are plural** and match the HTTP API / SDK / `src/` dirs — `workflows`, `agents`, `triggers`, `projects`, `apps`, `channels`, `credentials`. Never singular.
33
+ - **The primary resource is positional**, not a flag. The collection already names the type, so `workflows run greeting` — never `workflows run --workflow greeting`.
34
+ - **Nested resources are sub-collections before the verb** — `workflows runs list <slug>`, `apps actions get <app> <tool>`. Not flat (`workflows-runs-list`) and not verb-first (`workflows list runs`).
35
+ - **A second positional is the child id** — `workflows runs cancel <workflow> <run-id>`, `agents sessions cancel <agent> <session-id>`.
36
+ - **Flags are for two things only:**
37
+ - **Payload / options** — `--input`, `--message`, `--include`, `--limit`.
38
+ - **Scope or a *different* resource type** — global `--project` / `--local`; cross-references like `triggers disable <trigger> --workflow <slug>` where the positional is the trigger and the flag narrows to one attachment. Do not add type-named flags (`--workflow`, `--agent`) to that type's own commands.
39
+ - **Verbs are consistent across collections** — `list`, `get`, `create`, `update`, `delete`, `run`/`execute`/`prompt`. Prefer `get` over `show`, `create` over `set`.
40
+
41
+ Example command tree:
42
+
43
+ ```text
44
+ keystroke workflows run <slug> --input '{...}'
45
+ keystroke workflows runs list|get|cancel <slug> [<run-id>]
46
+ keystroke agents prompt <slug> --message "…"
47
+ keystroke agents sessions list|get|cancel <slug> [<session-id>]
48
+ keystroke triggers invoke <slug> [--input '{…}'] [--workflow <s> | --agent <s>]
49
+ keystroke triggers disable|enable <slug> [--workflow <s> | --agent <s>]
50
+ keystroke triggers runs list|get <slug> [--workflow <s> | --agent <s>]
51
+ keystroke apps actions list|get <app> [<tool>]
52
+ keystroke apps execute <app> <tool> --input '{...}'
53
+ keystroke credentials create|get|rotate|delete <key>
54
+ ```
55
+
56
+ ### `auth`
57
+
58
+ Authenticate with Keystroke via Better Auth device flow. Config lives in `~/.keystroke`; bearer tokens live in the OS keychain.
59
+
60
+ ```bash
61
+ keystroke auth login
62
+ keystroke auth login --web-url http://localhost:3000
63
+ keystroke auth login --web-url https://keystroke.ai --platform-url https://api.keystroke.ai
64
+ keystroke auth status
65
+ keystroke auth logout
66
+ ```
67
+
68
+ | Setting | Default | Purpose |
69
+ | ------------- | -------------------------- | ---------------------------------------------------------------- |
70
+ | `webUrl` | `https://keystroke.ai` | Web dashboard; device login and session checks |
71
+ | `platformUrl` | `https://api.keystroke.ai` | Platform API (direct; used by CLI platform commands) |
72
+
73
+ `auth login` persists both `webUrl` and `platformUrl`. Omit `--web-url` to always reset to production defaults (`https://keystroke.ai` / `https://api.keystroke.ai`), even if a previous login pointed at localhost. Local dev: `--web-url http://localhost:3000` (platform URL resolves to `http://localhost:3002`).
74
+
75
+ Existing commands do not require auth yet. Use `resolveCliAuth()` when adding protected commands.
76
+
77
+ ### Platform commands
78
+
79
+ Org-scoped platform commands require `keystroke auth login` plus an organization target: pass `--organization <slug>` or set `organization` in `keystroke.config.ts` (via `keystroke projects link --project <slug>`). Project-scoped commands also accept `--project <slug>` or the `project` field in `keystroke.config.ts`.
80
+
81
+ ```bash
82
+ keystroke org update --name "Acme Inc"
83
+ keystroke org members list
84
+ keystroke org members invite --email ada@example.com --role admin
85
+ keystroke org members role <userId> --role builder
86
+ keystroke org members remove <userId>
87
+ keystroke org leave --yes
88
+ keystroke api-key list
89
+ keystroke api-key create --name "CI"
90
+ keystroke api-key revoke <apiKeyId> --yes
91
+ keystroke --project <slug> project members list
92
+ keystroke --project <slug> project members invite --email ada@example.com --role admin
93
+ keystroke --project <slug> project members role <userId> --role builder
94
+ keystroke --project <slug> project members remove <userId>
95
+ keystroke --project <slug> project members leave --yes
96
+ keystroke --project <slug> project settings get
97
+ keystroke --project <slug> project settings update --description "Notes" --default-role builder --invite-permission all
98
+ ```
99
+
100
+ `organization` is an alias for `org`. List/get-style commands print JSON; mutations set a non-zero exit code on failure.
101
+
102
+ ### `trigger`
103
+
104
+ List triggers, resolve webhook URLs, and manually invoke after deploy (requires `keystroke auth login`):
105
+
106
+ ```bash
107
+ keystroke triggers list
108
+ keystroke triggers get incoming-message
109
+ keystroke triggers url incoming-message
110
+ keystroke triggers invoke inbox-sync
111
+ keystroke triggers invoke signup --input '{"name":"Ada","email":"ada@example.com"}'
112
+ ```
113
+
114
+ `url` prints a single line suitable for piping into curl or pasting into external webhook config. `invoke` is platform-only (not `--local`): webhook invokes take `--input`; cron and poll take none (cron always uses its static payload). Narrow with `--workflow` / `--agent` when a trigger has multiple attachments.
115
+
116
+ ### `init`
117
+
118
+ Scaffold a new project from the bundled `hello-world` template — definitions only under `src/`, no `server.ts`.
119
+
120
+ ```bash
121
+ # Interactive (TTY)
122
+ keystroke init
123
+
124
+ # Headless (scripts, AI agents)
125
+ keystroke init my-app --yes
126
+ keystroke init --name my-app --dir ./my-app --yes --skip-install
127
+ ```
128
+
129
+ | Flag | Purpose |
130
+ | ---------------- | ------------------------------------- |
131
+ | `--name` | Package name (kebab-case) |
132
+ | `--template` | Template name (default `hello-world`) |
133
+ | `-y, --yes` | Skip prompts |
134
+ | `--skip-install` | Don't run package manager install |
135
+ | `--pm` | Force npm, pnpm, yarn, or bun |
136
+
137
+ Scaffolded projects include a committed `tsconfig.json` and `package.json` scripts for `lint`, `typecheck`, and `test` (invoking the globally installed `keystroke` binary). Lint config (oxlint) ships in the CLI bundle; projects declare `@types/node`, TypeScript, and vitest in devDependencies — not `@keystrokehq/cli`.
138
+
139
+ ### `lint`
140
+
141
+ Lint `src/` with bundled oxlint. Config lives in the CLI bundle (`dist/configs/oxlintrc.json`), not in the project.
142
+
143
+ ```bash
144
+ keystroke lint
145
+ keystroke lint --dir ./my-app
146
+ ```
147
+
148
+ ### `typecheck`
149
+
150
+ Type-check with bundled TypeScript using the project's `tsconfig.json`.
151
+
152
+ ```bash
153
+ keystroke typecheck
154
+ keystroke typecheck --dir ./my-app
155
+ ```
156
+
157
+ ### `test`
158
+
159
+ Run tests with bundled vitest. Config lives in the CLI bundle (`dist/configs/vitest.config.mjs`).
160
+
161
+ ```bash
162
+ keystroke test
163
+ keystroke test --project unit
164
+ keystroke test --project integration
165
+ ```
166
+
167
+ ### `build`
168
+
169
+ Build the project to `dist/` using the framework bootstrap (no user `server.ts` required).
170
+
171
+ ```bash
172
+ keystroke build
173
+ keystroke build --dir ./my-app
174
+ ```
175
+
176
+ ### `deploy`
177
+
178
+ Lint, typecheck, build, upload, and promote a project artifact on the platform. Requires `keystroke auth login` and a linked project (or `--project <slug>`).
179
+
180
+ ```bash
181
+ keystroke deploy
182
+ keystroke deploy --filter workflows/ping --filter agents/world
183
+ ```
184
+
185
+ `--filter` matches exact build entry keys (`agents/foo`, `workflows/bar`, …). Repeat the flag for multiple modules. Targeted deploy downloads the active artifact, overlays rebuilt module files, merges `route-manifest.json`, and uploads a full tarball — the first deploy for a project must be a full deploy without `--filter`. Config and bundled assets are carried forward from the active artifact; skill/asset drift is not validated in v1.
186
+
187
+ ### `dev`
188
+
189
+ Watch `src/`, rebuild `dist/` on change, and restart the API. **Not true hot reload** — each change reruns tsdown and boots a fresh server process so discovery picks up new agents/workflows/triggers.
190
+
191
+ ```bash
192
+ keystroke dev
193
+ keystroke dev --port 3002
194
+ ```
195
+
196
+ Same flags as `start`.
197
+
198
+ ### `start`
199
+
200
+ Build the API incrementally and start the server. Re-running without changes reuses rolldown cache.
201
+
202
+ Database defaults to SQLite at `./data/dev.db` unless `DATABASE_URL` points at Postgres.
203
+
204
+ ```bash
205
+ keystroke start
206
+ keystroke start --port 3002
207
+ ```
208
+
209
+ | Flag | Purpose |
210
+ | -------- | ----------------------- |
211
+ | `--dir` | Project root |
212
+ | `--port` | API port (default 3002) |
213
+
214
+ Use `keystroke build` for a clean API rebuild.
215
+
216
+ ### Portable local install
217
+
218
+ Bundle a self-contained CLI you can run outside the monorepo:
219
+
220
+ ```bash
221
+ pnpm cli:pack
222
+ # installs `keystroke` to ~/.local/bin (ensure it is on PATH)
223
+ keystroke --help
224
+ ```
225
+
226
+ Custom output directory: `node apps/cli/scripts/pack.mjs /path/to/install`.
227
+
228
+ ## Dependencies
229
+
230
+ | Package | Role |
231
+ | ------------------------------------------------------------------ | ---------------------------------------------------------------------- |
232
+ | [`commander`](https://github.com/tj/commander.js) | Argument parsing, `--help`, `--version`, subcommands |
233
+ | [`conf`](https://github.com/sindresorhus/conf) | Persistent non-secret config (profiles, defaults, project prefs). MIT. |
234
+ | [`@napi-rs/keyring`](https://github.com/Brooooooklyn/keyring-node) | API tokens and other secrets via the OS keychain. MIT. |
235
+
236
+ `conf` stores `webUrl`, `platformUrl`, and other non-secrets under `~/.keystroke`. `@napi-rs/keyring` stores bearer tokens — macOS Keychain, Windows Credential Manager, or Secret Service on Linux — so tokens never sit in a plaintext config file.
237
+
238
+ ## Development
239
+
240
+ ```bash
241
+ pnpm cli --help
242
+ pnpm --filter @keystrokehq/cli dev
243
+ pnpm --filter @keystrokehq/cli build
244
+ pnpm --filter @keystrokehq/cli test
245
+ ```
246
+
247
+ Build output goes to `dist/index.mjs` with a Node shebang for the `keystroke` bin.
248
+
249
+ ### `keystroke-dev` (contributor CLI)
250
+
251
+ `apps/cli/bin/keystroke-dev` is a thin bash wrapper that runs the CLI source tree directly through tsx — no `pnpm --filter ... build` between edits. It sets `KEYSTROKE_DEV=1` and `NODE_OPTIONS=--conditions=development`, so workspace packages resolve to their `src/*.ts` instead of `dist/*.mjs`.
252
+
253
+ This wrapper is **contributor-only**. It is not in `package.json`'s `bin` map and does not ship to npm — `keystroke-dev` and the published `keystroke` never collide.
254
+
255
+ After cloning + `pnpm install`:
256
+
257
+ ```bash
258
+ pnpm --filter @keystrokehq/cli link-dev
259
+ # symlinks apps/cli/bin/keystroke-dev → ~/.local/bin/keystroke-dev
260
+ # (override the install location with KEYSTROKE_DEV_BIN_DIR)
261
+
262
+ keystroke-dev --help
263
+ keystroke-dev start --dir ~/my-project
264
+ ```
265
+
266
+ Resolvers prefer source when it exists. Source paths only exist in the monorepo, so the published CLI still uses bundled assets — there's no fork in behavior, just a fallback chain.
267
+
268
+ To exercise the bundled flow end-to-end, use `pnpm cli:pack` (builds, packs, and installs `keystroke-dev` from `dist/`).
269
+
270
+ ## Distribution
271
+
272
+ Published to npm as a Node CLI. Native keyring binaries ship via `@napi-rs/keyring` optional platform packages — no compile step on install for supported platforms.
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ import { r as s, t as o$1 } from "./chunk-QAYAQNCG-Bl0Kbd53.mjs";
3
+ import "./chunk-BZUGFHVS-CPWRFwK8.mjs";
4
+ import { createRequire } from "node:module";
5
+ //#region ../../node_modules/.pnpm/just-bash@3.0.1/node_modules/just-bash/dist/bundle/chunks/chunk-FHC24QSK.js
6
+ createRequire(import.meta.url);
7
+ var d = {
8
+ name: "alias",
9
+ summary: "define or display aliases",
10
+ usage: "alias [name[=value] ...]",
11
+ options: [" --help display this help and exit"]
12
+ }, o = "BASH_ALIAS_", m = {
13
+ name: "alias",
14
+ async execute(e, a) {
15
+ if (o$1(e)) return s(d);
16
+ if (e.length === 0) {
17
+ let s = "";
18
+ for (let [i, t] of a.env) if (i.startsWith(o)) {
19
+ let n = i.slice(o.length);
20
+ s += `alias ${n}='${t}'
21
+ `;
22
+ }
23
+ return {
24
+ stdout: s,
25
+ stderr: "",
26
+ exitCode: 0
27
+ };
28
+ }
29
+ let l = e[0] === "--" ? e.slice(1) : e;
30
+ for (let s of l) {
31
+ let i = s.indexOf("=");
32
+ if (i === -1) {
33
+ let t = o + s;
34
+ return a.env.get(t) ? {
35
+ stdout: `alias ${s}='${a.env.get(t)}'
36
+ `,
37
+ stderr: "",
38
+ exitCode: 0
39
+ } : {
40
+ stdout: "",
41
+ stderr: `alias: ${s}: not found
42
+ `,
43
+ exitCode: 1
44
+ };
45
+ } else {
46
+ let t = s.slice(0, i), n = s.slice(i + 1);
47
+ (n.startsWith("'") && n.endsWith("'") || n.startsWith("\"") && n.endsWith("\"")) && (n = n.slice(1, -1)), a.env.set(o + t, n);
48
+ }
49
+ }
50
+ return {
51
+ stdout: "",
52
+ stderr: "",
53
+ exitCode: 0
54
+ };
55
+ }
56
+ }, c = {
57
+ name: "unalias",
58
+ async execute(e, a) {
59
+ if (o$1(e)) return s({
60
+ name: "unalias",
61
+ summary: "remove alias definitions",
62
+ usage: "unalias name [name ...]",
63
+ options: ["-a remove all aliases", " --help display this help and exit"]
64
+ });
65
+ if (e.length === 0) return {
66
+ stdout: "",
67
+ stderr: `unalias: usage: unalias [-a] name [name ...]
68
+ `,
69
+ exitCode: 1
70
+ };
71
+ if (e[0] === "-a") {
72
+ for (let t of a.env.keys()) t.startsWith(o) && a.env.delete(t);
73
+ return {
74
+ stdout: "",
75
+ stderr: "",
76
+ exitCode: 0
77
+ };
78
+ }
79
+ let l = e[0] === "--" ? e.slice(1) : e, s$1 = !1, i = "";
80
+ for (let t of l) {
81
+ let n = o + t;
82
+ a.env.get(n) ? a.env.delete(n) : (i += `unalias: ${t}: not found
83
+ `, s$1 = !0);
84
+ }
85
+ return {
86
+ stdout: "",
87
+ stderr: i,
88
+ exitCode: s$1 ? 1 : 0
89
+ };
90
+ }
91
+ };
92
+ //#endregion
93
+ //#region ../../node_modules/.pnpm/just-bash@3.0.1/node_modules/just-bash/dist/bundle/chunks/alias-RTYYYW3D.js
94
+ createRequire(import.meta.url);
95
+ //#endregion
96
+ export { m as aliasCommand, c as unaliasCommand };
97
+
98
+ //# sourceMappingURL=alias-RTYYYW3D-CLFgrowj.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias-RTYYYW3D-CLFgrowj.mjs","names":["u","r","s"],"sources":["../../../node_modules/.pnpm/just-bash@3.0.1/node_modules/just-bash/dist/bundle/chunks/chunk-FHC24QSK.js","../../../node_modules/.pnpm/just-bash@3.0.1/node_modules/just-bash/dist/bundle/chunks/alias-RTYYYW3D.js"],"sourcesContent":["import{createRequire} from\"node:module\";const require=createRequire(import.meta.url);\nimport{a as r,b as u}from\"./chunk-QAYAQNCG.js\";var d={name:\"alias\",summary:\"define or display aliases\",usage:\"alias [name[=value] ...]\",options:[\" --help display this help and exit\"]},o=\"BASH_ALIAS_\",m={name:\"alias\",async execute(e,a){if(u(e))return r(d);if(e.length===0){let s=\"\";for(let[i,t]of a.env)if(i.startsWith(o)){let n=i.slice(o.length);s+=`alias ${n}='${t}'\n`}return{stdout:s,stderr:\"\",exitCode:0}}let l=e[0]===\"--\"?e.slice(1):e;for(let s of l){let i=s.indexOf(\"=\");if(i===-1){let t=o+s;return a.env.get(t)?{stdout:`alias ${s}='${a.env.get(t)}'\n`,stderr:\"\",exitCode:0}:{stdout:\"\",stderr:`alias: ${s}: not found\n`,exitCode:1}}else{let t=s.slice(0,i),n=s.slice(i+1);(n.startsWith(\"'\")&&n.endsWith(\"'\")||n.startsWith('\"')&&n.endsWith('\"'))&&(n=n.slice(1,-1)),a.env.set(o+t,n)}}return{stdout:\"\",stderr:\"\",exitCode:0}}},c={name:\"unalias\",async execute(e,a){if(u(e))return r({name:\"unalias\",summary:\"remove alias definitions\",usage:\"unalias name [name ...]\",options:[\"-a remove all aliases\",\" --help display this help and exit\"]});if(e.length===0)return{stdout:\"\",stderr:`unalias: usage: unalias [-a] name [name ...]\n`,exitCode:1};if(e[0]===\"-a\"){for(let t of a.env.keys())t.startsWith(o)&&a.env.delete(t);return{stdout:\"\",stderr:\"\",exitCode:0}}let l=e[0]===\"--\"?e.slice(1):e,s=!1,i=\"\";for(let t of l){let n=o+t;a.env.get(n)?a.env.delete(n):(i+=`unalias: ${t}: not found\n`,s=!0)}return{stdout:\"\",stderr:i,exitCode:s?1:0}}},p={name:\"alias\",flags:[]},h={name:\"unalias\",flags:[{flag:\"-a\",type:\"boolean\"}]};export{m as a,c as b,p as c,h as d};\n","import{createRequire} from\"node:module\";const require=createRequire(import.meta.url);\nimport{a,b,c,d}from\"./chunk-FHC24QSK.js\";import\"./chunk-QAYAQNCG.js\";import\"./chunk-BZUGFHVS.js\";export{a as aliasCommand,c as flagsForFuzzing,b as unaliasCommand,d as unaliasFlagsForFuzzing};\n"],"x_google_ignoreList":[0,1],"mappings":";;;;;AAAsD,cAAc,OAAO,KAAK,GAAG;AACpC,IAAI,IAAE;CAAC,MAAK;CAAQ,SAAQ;CAA4B,OAAM;CAA2B,SAAQ,CAAC,uCAAuC;AAAC,GAAE,IAAE,eAAc,IAAE;CAAC,MAAK;CAAQ,MAAM,QAAQ,GAAE,GAAE;EAAC,IAAGA,IAAE,CAAC,GAAE,OAAOC,EAAE,CAAC;EAAE,IAAG,EAAE,WAAS,GAAE;GAAC,IAAI,IAAE;GAAG,KAAI,IAAG,CAAC,GAAE,MAAK,EAAE,KAAI,IAAG,EAAE,WAAW,CAAC,GAAE;IAAC,IAAI,IAAE,EAAE,MAAM,EAAE,MAAM;IAAE,KAAG,SAAS,EAAE,IAAI,EAAE;;GAChX;GAAC,OAAM;IAAC,QAAO;IAAE,QAAO;IAAG,UAAS;GAAC;EAAC;EAAC,IAAI,IAAE,EAAE,OAAK,OAAK,EAAE,MAAM,CAAC,IAAE;EAAE,KAAI,IAAI,KAAK,GAAE;GAAC,IAAI,IAAE,EAAE,QAAQ,GAAG;GAAE,IAAG,MAAI,IAAG;IAAC,IAAI,IAAE,IAAE;IAAE,OAAO,EAAE,IAAI,IAAI,CAAC,IAAE;KAAC,QAAO,SAAS,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE;;KACvL,QAAO;KAAG,UAAS;IAAC,IAAE;KAAC,QAAO;KAAG,QAAO,UAAU,EAAE;;KACpD,UAAS;IAAC;GAAC,OAAK;IAAC,IAAI,IAAE,EAAE,MAAM,GAAE,CAAC,GAAE,IAAE,EAAE,MAAM,IAAE,CAAC;IAAE,CAAC,EAAE,WAAW,GAAG,KAAG,EAAE,SAAS,GAAG,KAAG,EAAE,WAAW,IAAG,KAAG,EAAE,SAAS,IAAG,OAAK,IAAE,EAAE,MAAM,GAAE,EAAE,IAAG,EAAE,IAAI,IAAI,IAAE,GAAE,CAAC;GAAC;EAAC;EAAC,OAAM;GAAC,QAAO;GAAG,QAAO;GAAG,UAAS;EAAC;CAAC;AAAC,GAAE,IAAE;CAAC,MAAK;CAAU,MAAM,QAAQ,GAAE,GAAE;EAAC,IAAGD,IAAE,CAAC,GAAE,OAAOC,EAAE;GAAC,MAAK;GAAU,SAAQ;GAA2B,OAAM;GAA0B,SAAQ,CAAC,8BAA6B,uCAAuC;EAAC,CAAC;EAAE,IAAG,EAAE,WAAS,GAAE,OAAM;GAAC,QAAO;GAAG,QAAO;;GAC5c,UAAS;EAAC;EAAE,IAAG,EAAE,OAAK,MAAK;GAAC,KAAI,IAAI,KAAK,EAAE,IAAI,KAAK,GAAE,EAAE,WAAW,CAAC,KAAG,EAAE,IAAI,OAAO,CAAC;GAAE,OAAM;IAAC,QAAO;IAAG,QAAO;IAAG,UAAS;GAAC;EAAC;EAAC,IAAI,IAAE,EAAE,OAAK,OAAK,EAAE,MAAM,CAAC,IAAE,GAAEC,MAAE,CAAC,GAAE,IAAE;EAAG,KAAI,IAAI,KAAK,GAAE;GAAC,IAAI,IAAE,IAAE;GAAE,EAAE,IAAI,IAAI,CAAC,IAAE,EAAE,IAAI,OAAO,CAAC,KAAG,KAAG,YAAY,EAAE;GAChP,MAAE,CAAC;EAAE;EAAC,OAAM;GAAC,QAAO;GAAG,QAAO;GAAE,UAASA,MAAE,IAAE;EAAC;CAAC;AAAC;;;ACNI,cAAc,OAAO,KAAK,GAAG"}