@metabase/cli 0.2.1 → 0.2.2-alpha.extract-api-client.27e2241

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 (324) hide show
  1. package/README.md +4 -1715
  2. package/dist/add-collection-B3Ty8SzB.mjs +36 -0
  3. package/dist/alert-DT-ee7yf.mjs +23 -0
  4. package/dist/alerts-Bf2RH_p_.mjs +43 -0
  5. package/dist/{append-BgDaYJW9.mjs → append-DFzQRPMd.mjs} +7 -12
  6. package/dist/{archive-DFCu5hVG.mjs → archive-4tmm946K.mjs} +8 -17
  7. package/dist/{archive-Bv59HYsU.mjs → archive-B6eXiyER.mjs} +7 -13
  8. package/dist/{archive-BM9HjJHQ.mjs → archive-BxNPHxOY.mjs} +7 -13
  9. package/dist/archive-ByvA49Kz.mjs +34 -0
  10. package/dist/{archive-Oh1iZu2y.mjs → archive-C7w49Grr.mjs} +7 -16
  11. package/dist/{archive-EoYl-lS-.mjs → archive-Cd29QC0c.mjs} +7 -13
  12. package/dist/{archive-BZpXnQSu.mjs → archive-ChORH5JH.mjs} +7 -13
  13. package/dist/archive-CwAdlv63.mjs +33 -0
  14. package/dist/{archive-BncW2dGw.mjs → archive-Dr9Xnx_Z.mjs} +7 -15
  15. package/dist/{archive-BCPA0HhV.mjs → archive-gid9Y09v.mjs} +8 -17
  16. package/dist/{archive-Czzktgho.mjs → archive-lQqs13Uz.mjs} +7 -13
  17. package/dist/auth-Dltxua89.mjs +19 -0
  18. package/dist/{body-DKcQw7G5.mjs → body-Cur4NJt9.mjs} +5 -8
  19. package/dist/{body-flags-CgHgJBRC.mjs → body-flags-AqKpN01Y.mjs} +1 -2
  20. package/dist/{branches-CCmtr3W8.mjs → branches-DchlyU0i.mjs} +7 -13
  21. package/dist/{cancel-72y10-Rg.mjs → cancel-BMQa5R1Z.mjs} +5 -12
  22. package/dist/{cancel-task-CGwdz91O.mjs → cancel-task-C5CU1pxU.mjs} +6 -10
  23. package/dist/card-CHI2bmds.mjs +24 -0
  24. package/dist/{card-B8G5jQQT.mjs → card-DZxRmver.mjs} +21 -48
  25. package/dist/card-zyUkr2nS.mjs +44 -0
  26. package/dist/cards-SccWvRQD.mjs +34 -0
  27. package/dist/cli.mjs +675 -81
  28. package/dist/client-BqhzKdLM.mjs +2194 -0
  29. package/dist/collection-CGoVLvcD.mjs +58 -0
  30. package/dist/collection-CY0AB99E.mjs +20 -0
  31. package/dist/{collection-CFoLPrY5.mjs → collection-CfulNRBG.mjs} +20 -63
  32. package/dist/{collection-namespace-C7mr_a8H.mjs → collection-namespace-GwydWBF3.mjs} +3 -5
  33. package/dist/{create-pTnveKkm.mjs → create-BNQ_DytP.mjs} +8 -15
  34. package/dist/{create-QYctYGSa.mjs → create-BOLwWt8Q.mjs} +9 -17
  35. package/dist/{create-C_WqoOf5.mjs → create-Beh-2uoN.mjs} +8 -15
  36. package/dist/{create-C3DThF9E.mjs → create-C79vErX0.mjs} +9 -20
  37. package/dist/{create-nXlnVzXl.mjs → create-CAQV2g6V.mjs} +9 -16
  38. package/dist/{create-E7XhC0gJ.mjs → create-CAWytBE5.mjs} +9 -17
  39. package/dist/{create-CPEOSxIH.mjs → create-CCh_LyW9.mjs} +8 -15
  40. package/dist/{create-7pbf5Wu0.mjs → create-CD008jdE.mjs} +13 -28
  41. package/dist/create-CHQx7jq4.mjs +45 -0
  42. package/dist/create-DF4QtgDL.mjs +44 -0
  43. package/dist/{create-CaWFrPRU.mjs → create-DJmXXQoq.mjs} +10 -18
  44. package/dist/{create-Brh8WCa3.mjs → create-DV-Ln5Mo.mjs} +8 -15
  45. package/dist/create-branch-CYo6jZth.mjs +35 -0
  46. package/dist/{create-U_XDwsIX.mjs → create-i14Wv3Tj.mjs} +8 -15
  47. package/dist/{create-BDY38_Kr.mjs → create-tQbnuz-I.mjs} +8 -15
  48. package/dist/{create-DFyZCXQD.mjs → create-zeveFdnd.mjs} +6 -10
  49. package/dist/cron-LKRffEC-.mjs +5 -0
  50. package/dist/{csv-CR2qhmC6.mjs → csv-B2Jgb1GM.mjs} +7 -19
  51. package/dist/{current-task-MUHaiHIg.mjs → current-task-MpBFGttd.mjs} +7 -12
  52. package/dist/{dashboard-B-MTpfeS.mjs → dashboard-BCpSq_G-.mjs} +9 -60
  53. package/dist/dashboard-BHJBoaG7.mjs +33 -0
  54. package/dist/dashboard-CsIFFpzK.mjs +58 -0
  55. package/dist/database-B19qlLKZ.mjs +38 -0
  56. package/dist/database-C8G6ZKG0.mjs +26 -0
  57. package/dist/db-DsfojyeH.mjs +24 -0
  58. package/dist/{delete-B58Cng0p.mjs → delete-B8e01xAG.mjs} +6 -11
  59. package/dist/{delete-CW3dYmuT.mjs → delete-BApOjQvl.mjs} +6 -11
  60. package/dist/{delete-doa3R-c5.mjs → delete-Ck0q4Dzp.mjs} +6 -11
  61. package/dist/{delete-BKMOtpjs.mjs → delete-DFmX7jTp.mjs} +6 -11
  62. package/dist/{delete-BMa26SzX.mjs → delete-Ob06PPie.mjs} +6 -11
  63. package/dist/{delete-runtime-_YOukDRC.mjs → delete-runtime-D74s6vhu.mjs} +6 -13
  64. package/dist/{delete-table-D_tjBZPd.mjs → delete-table-DuyhGrvA.mjs} +6 -11
  65. package/dist/{dependencies-BR_4um7h.mjs → dependencies-Bj3QrGIm.mjs} +10 -13
  66. package/dist/dirty-DNYoM6Bp.mjs +31 -0
  67. package/dist/document-BbskZPTT.mjs +19 -0
  68. package/dist/{document-CL4ML5FN.mjs → document-Cd2mmqCp.mjs} +5 -33
  69. package/dist/document-D6OybtP2.mjs +29 -0
  70. package/dist/{eid-DSOk7Khb.mjs → eid-WTZmDdsr.mjs} +12 -54
  71. package/dist/eid-translation-zEHtr5Oc.mjs +35 -0
  72. package/dist/{embedding-CKdw8q7p.mjs → embedding-i-KqpefC.mjs} +2 -4
  73. package/dist/events-Bn7jh5lP.mjs +39 -0
  74. package/dist/export-BjfoZRDJ.mjs +66 -0
  75. package/dist/field-BPsNa-TO.mjs +80 -0
  76. package/dist/{field-DsXTeqBy.mjs → field-Cr2DPUG9.mjs} +2 -81
  77. package/dist/field-Zau6Hc6X.mjs +18 -0
  78. package/dist/fields-CBBa-Prp.mjs +34 -0
  79. package/dist/{get-CHAH_F37.mjs → get-00lyLv6R.mjs} +7 -11
  80. package/dist/{get-T85qZgnv.mjs → get-B7sMgsFs.mjs} +7 -11
  81. package/dist/get-B_xdF1kq.mjs +31 -0
  82. package/dist/{get-DT2MOZ8L.mjs → get-ByBOq30r.mjs} +7 -11
  83. package/dist/get-Bz99dAxK.mjs +35 -0
  84. package/dist/get-C2-Q3iQ5.mjs +31 -0
  85. package/dist/get-CDJFVvhj.mjs +35 -0
  86. package/dist/get-CDMGbgrh.mjs +31 -0
  87. package/dist/get-CnbUCzDM.mjs +31 -0
  88. package/dist/{get-DtvzjfjG.mjs → get-CvI--9S_.mjs} +16 -12
  89. package/dist/{get-CH_JmPc-.mjs → get-DRvsATp-.mjs} +7 -11
  90. package/dist/{get-CgZ5qjQx.mjs → get-DY03Azx9.mjs} +6 -10
  91. package/dist/get-DYO1kywc.mjs +32 -0
  92. package/dist/{get-BSdOE5J4.mjs → get-D_h-G9bn.mjs} +7 -11
  93. package/dist/get-DdsoHaKH.mjs +31 -0
  94. package/dist/{get-DRK5-UdU.mjs → get-DkWO0EI0.mjs} +7 -11
  95. package/dist/{get-43Smv3RI.mjs → get-Dmj9Ygz1.mjs} +7 -17
  96. package/dist/get-DmpB6J9g.mjs +31 -0
  97. package/dist/{get-nZW0W7Ui.mjs → get-Dn9ZiSZr.mjs} +8 -16
  98. package/dist/{get-run-Cwia6e0d.mjs → get-run-Cnux9ln0.mjs} +7 -11
  99. package/dist/git-sync-BDnxPrqU.mjs +104 -0
  100. package/dist/git-sync-DxD_ng48.mjs +136 -0
  101. package/dist/git-sync-MQQYRYLg.mjs +28 -0
  102. package/dist/{group-CILtQqCL.mjs → group-DBM87IgC.mjs} +2 -4
  103. package/dist/has-remote-changes-C684Redh.mjs +35 -0
  104. package/dist/import-Rmmttboo.mjs +56 -0
  105. package/dist/{input-DzbvxKYU.mjs → input-DH9i67x_.mjs} +6 -11
  106. package/dist/{is-dirty-CHbUJ-bh.mjs → is-dirty-DYeJYhBz.mjs} +4 -8
  107. package/dist/{items-DN63mjpF.mjs → items-CQlPXBXE.mjs} +13 -29
  108. package/dist/key-BEhqIzIQ.mjs +10 -0
  109. package/dist/{library-DF2qx50w.mjs → library-Bsm5KsFF.mjs} +6 -9
  110. package/dist/library-ClLgrAXy.mjs +19 -0
  111. package/dist/library-DfYAT2Ep.mjs +21 -0
  112. package/dist/{list-n2PY3OIx.mjs → list-B4hJuMhA.mjs} +11 -27
  113. package/dist/list-B8nAGwP4.mjs +48 -0
  114. package/dist/list-BOET6zhP.mjs +36 -0
  115. package/dist/list-BP3MPq-M.mjs +36 -0
  116. package/dist/list-BpFp9Wre.mjs +28 -0
  117. package/dist/list-BtkWNtvY.mjs +34 -0
  118. package/dist/list-BtmsNOEn.mjs +28 -0
  119. package/dist/list-BzVTHOoH.mjs +28 -0
  120. package/dist/list-C5Zs8nrb.mjs +28 -0
  121. package/dist/list-CKK-s3Ty.mjs +28 -0
  122. package/dist/list-CMpoc2TN.mjs +70 -0
  123. package/dist/list-CNUiF8Z7.mjs +28 -0
  124. package/dist/list-CQDprvW0.mjs +39 -0
  125. package/dist/{list-C7TqbWG1.mjs → list-CQwOgIlj.mjs} +10 -24
  126. package/dist/list-DE9FM957.mjs +28 -0
  127. package/dist/{list-De82cXvn.mjs → list-DF2rvoO1.mjs} +22 -14
  128. package/dist/list-DMKDsBRd.mjs +38 -0
  129. package/dist/{list-B3HoSfYj.mjs → list-UhpKG6_m.mjs} +15 -15
  130. package/dist/{login-jy9rbYev.mjs → login-CGHeSjlP.mjs} +47 -52
  131. package/dist/{logout-CRbk1SuY.mjs → logout-DAxOlbv4.mjs} +7 -12
  132. package/dist/measure-4P0bOlZ3.mjs +29 -0
  133. package/dist/measure-BsYv0p26.mjs +22 -0
  134. package/dist/{measure-S9WszHre.mjs → measure-CtfjqJFP.mjs} +3 -30
  135. package/dist/network-error-CEb9ymDW.mjs +423 -0
  136. package/dist/notification-DaA4bBHW.mjs +138 -0
  137. package/dist/notification-Fcq1fIPw.mjs +67 -0
  138. package/dist/{parameter-BZ6y-Gfs.mjs → parameter-DUKR8NXo.mjs} +2 -11
  139. package/dist/{parameter-values-CcgcG3S5.mjs → parameter-values-CJTdqd8c.mjs} +17 -11
  140. package/dist/{parse-enum-C_2lGr3g.mjs → parse-enum-D0Jfm_Bz.mjs} +2 -4
  141. package/dist/{parse-id-CD54Chc5.mjs → parse-id-C_jmKFaa.mjs} +2 -4
  142. package/dist/{parse-ref-BLgKEEF-.mjs → parse-ref-ibKVB0J4.mjs} +3 -5
  143. package/dist/{path-CPMr1RJO.mjs → path-B5gHvrYL.mjs} +8 -9
  144. package/dist/{poll-DVF9EnEb.mjs → poll-75SvT7Zv.mjs} +11 -15
  145. package/dist/predicates-Bkm2IoeX.mjs +170 -0
  146. package/dist/preflight-YpPQo-sa.mjs +29 -0
  147. package/dist/{process-HDPKLS_z.mjs → process-DBOOrmET.mjs} +4 -6
  148. package/dist/publish-DijrxaCW.mjs +75 -0
  149. package/dist/pulse-BmsDenXm.mjs +133 -0
  150. package/dist/pulse-DhG6I9mI.mjs +57 -0
  151. package/dist/{query-Cxh9hmrP.mjs → query-BbqECzmF.mjs} +20 -44
  152. package/dist/{query-B3HDIsJ-.mjs → query-Dc__-KJH.mjs} +13 -24
  153. package/dist/{query-result-Drvjv7DD.mjs → query-result-DBDwk8TS.mjs} +4 -8
  154. package/dist/remove-collection-BOnxYvhj.mjs +36 -0
  155. package/dist/{render-CkuFkWlQ.mjs → render-CI93iP0I.mjs} +9 -11
  156. package/dist/{replace-BwvKDNur.mjs → replace-Cq4CxVa-.mjs} +7 -12
  157. package/dist/rescan-values-Dr_j416g.mjs +31 -0
  158. package/dist/revision-message-flag-8TCHYJV6.mjs +8 -0
  159. package/dist/run-C3DkS6NP.mjs +82 -0
  160. package/dist/{run-yrpSF6VL.mjs → run-DdGJ544X.mjs} +8 -18
  161. package/dist/runs-CUNWiidL.mjs +38 -0
  162. package/dist/runtime-DiKyBxOw.mjs +1007 -0
  163. package/dist/{schema-tables-ChBYz4mO.mjs → schema-tables-CV386fnC.mjs} +10 -14
  164. package/dist/{schemas-C2crnVML.mjs → schemas-DM-UqZBQ.mjs} +8 -12
  165. package/dist/search-DFBwUc6d.mjs +44 -0
  166. package/dist/{search-DnGEh6sZ.mjs → search-DmGScXs8.mjs} +14 -73
  167. package/dist/segment-BzUGM2Fr.mjs +22 -0
  168. package/dist/segment-C_gl5ag6.mjs +29 -0
  169. package/dist/{segment-BPb1H6DW.mjs → segment-OsrbUDzw.mjs} +3 -30
  170. package/dist/{selectors-Ll_TRxl5.mjs → selectors-DGDn0Hto.mjs} +4 -6
  171. package/dist/send-CVxxEpDB.mjs +49 -0
  172. package/dist/{set-tHsHXRGV.mjs → set-DFolTjbd.mjs} +10 -20
  173. package/dist/{set-active-qqDoBh_Z.mjs → set-active-BD8L1lPX.mjs} +7 -18
  174. package/dist/setting-CwRYgHYN.mjs +35 -0
  175. package/dist/setting-DTiLCW8g.mjs +22 -0
  176. package/dist/setting-DyhaeICs.mjs +17 -0
  177. package/dist/setup-BbDQN8fe.mjs +44 -0
  178. package/dist/setup-CO7QV-ao.mjs +21 -0
  179. package/dist/signal-CMd0EFUa.mjs +16 -0
  180. package/dist/{skills-rnvVgau4.mjs → skills--vK6J-e4.mjs} +4 -6
  181. package/dist/{skills-BKuiGkc1.mjs → skills-DTCrMcix.mjs} +13 -19
  182. package/dist/{snippet-DWiXNy4T.mjs → snippet-CyKAgIZl.mjs} +3 -32
  183. package/dist/snippet-DRwKb2x7.mjs +19 -0
  184. package/dist/snippet-oJLaYW9V.mjs +29 -0
  185. package/dist/stash-D0S4JmAz.mjs +61 -0
  186. package/dist/status-BhswxJL1.mjs +85 -0
  187. package/dist/{status-B5ar0uXc.mjs → status-hL1am-HV.mjs} +6 -8
  188. package/dist/subscription-_d5fB45F.mjs +22 -0
  189. package/dist/subscriptions-s4TF6Ax3.mjs +42 -0
  190. package/dist/summary-BytbDz6e.mjs +7 -0
  191. package/dist/summary-CsPvcUwW.mjs +31 -0
  192. package/dist/sync-schema-DaZ_MV-u.mjs +35 -0
  193. package/dist/sync-task-BACcrs0i.mjs +37 -0
  194. package/dist/{table-C3RIKiYM.mjs → table-CeeTJgQb.mjs} +4 -38
  195. package/dist/table-CsIJNPFf.mjs +37 -0
  196. package/dist/table-DYoC1kPn.mjs +18 -0
  197. package/dist/{timeline-BCTRThc-.mjs → timeline-CCSU2qOS.mjs} +2 -66
  198. package/dist/timeline-event-CNQdCTDg.mjs +19 -0
  199. package/dist/timeline-uDCmwGFT.mjs +66 -0
  200. package/dist/timeline-xlDbEKWg.mjs +21 -0
  201. package/dist/transform-Bs0EWijQ.mjs +28 -0
  202. package/dist/{transform-BVHYzWpK.mjs → transform-D3QX0jxA.mjs} +28 -74
  203. package/dist/transform-DoTyyXAu.mjs +74 -0
  204. package/dist/transform-job-50GZHhKH.mjs +37 -0
  205. package/dist/transform-job-BcLChRup.mjs +22 -0
  206. package/dist/{transform-job-CjsAXMej.mjs → transform-job-DRrK28IH.mjs} +14 -41
  207. package/dist/{transform-tag--IBQ-8Ij.mjs → transform-tag-CcElGp3C.mjs} +2 -21
  208. package/dist/transform-tag-Dmb4u3-Q.mjs +21 -0
  209. package/dist/transform-tag-_tgwlsdB.mjs +18 -0
  210. package/dist/{transforms-CLkv3e81.mjs → transforms-oU4zizbO.mjs} +10 -13
  211. package/dist/{tree-CB2IURsX.mjs → tree-CH-f3bjP.mjs} +6 -10
  212. package/dist/{unpublish-BkZldbkP.mjs → unpublish-BUl9RU5C.mjs} +7 -18
  213. package/dist/{update-B1dkPypu.mjs → update-BCS5FxKr.mjs} +11 -19
  214. package/dist/{update-8bTrglfc.mjs → update-BZPllQoR.mjs} +9 -16
  215. package/dist/{update-BacyVaLu.mjs → update-BiFDBcEH.mjs} +9 -16
  216. package/dist/update-BzMDeZiU.mjs +50 -0
  217. package/dist/{update-B4atxTx0.mjs → update-C4YJQFDS.mjs} +9 -16
  218. package/dist/{update-CGWTX1Z0.mjs → update-CHNSUHK4.mjs} +9 -16
  219. package/dist/{update-D7Ia9Qrt.mjs → update-CO4m4wH3.mjs} +10 -21
  220. package/dist/{update-CO9uCJxV.mjs → update-CVPAwJaH.mjs} +10 -18
  221. package/dist/{update-BHC3pwzR.mjs → update-CmDTljK-.mjs} +9 -16
  222. package/dist/{update-iY9WZqy0.mjs → update-CvOO8TED.mjs} +9 -17
  223. package/dist/{update-Cyxjg496.mjs → update-D-NE60AV.mjs} +9 -16
  224. package/dist/{update-D80GWpWl.mjs → update-Nfi44RrE.mjs} +10 -18
  225. package/dist/update-bD_Jh5-s.mjs +51 -0
  226. package/dist/{update-DajyWtBN.mjs → update-cYkvbqK8.mjs} +9 -16
  227. package/dist/update-dashcard-C3TuYO_k.mjs +50 -0
  228. package/dist/{update-BghbOcv6.mjs → update-tX9mKBN_.mjs} +10 -21
  229. package/dist/{upgrade-CXoNQ4FH.mjs → upgrade-DXMV4AyP.mjs} +37 -44
  230. package/dist/upload-CH632qW6.mjs +46 -0
  231. package/dist/upload-DAtxBBms.mjs +13 -0
  232. package/dist/upload-Dey_8rLf.mjs +13 -0
  233. package/dist/{uuid-D6dao_q4.mjs → uuid-BJkDWj9p.mjs} +5 -7
  234. package/dist/validate-BWchyW0V.mjs +1469 -0
  235. package/dist/{validate-query-D1N30wJ7.mjs → validate-query-DaGYSmpQ.mjs} +4 -5
  236. package/dist/{values-DIBAgSyz.mjs → values-Dxf1JEoA.mjs} +8 -13
  237. package/dist/verify-K96rItG5.mjs +89 -0
  238. package/dist/{wait-CW1OawkI.mjs → wait-DoMDH226.mjs} +10 -18
  239. package/dist/{wait-flags-DvNU8ahZ.mjs → wait-flags-DWEF9tX4.mjs} +14 -11
  240. package/dist/window-BkvrP0gB.mjs +64 -0
  241. package/package.json +5 -35
  242. package/skill-data/core/SKILL.md +31 -26
  243. package/skill-data/dashboard/SKILL.md +6 -2
  244. package/skill-data/document/SKILL.md +2 -2
  245. package/skill-data/git-sync/SKILL.md +20 -5
  246. package/skill-data/notification/SKILL.md +157 -0
  247. package/skill-data/transform/SKILL.md +1 -1
  248. package/.claude-plugin/marketplace.json +0 -19
  249. package/dist/add-collection-C8ZTPlIE.mjs +0 -9
  250. package/dist/add-collection-CUBn11d4.mjs +0 -60
  251. package/dist/auth-hgAnMUfi.mjs +0 -22
  252. package/dist/capabilities-DOTcPraV.mjs +0 -684
  253. package/dist/card-Ct-q_C4S.mjs +0 -26
  254. package/dist/cards-CYSyvN7Z.mjs +0 -38
  255. package/dist/cli.d.mts +0 -1
  256. package/dist/collection-K82kJWdj.mjs +0 -23
  257. package/dist/command-augment-D9pI9Vbh.mjs +0 -11
  258. package/dist/create-branch-DPE6itiS.mjs +0 -57
  259. package/dist/dashboard-B1iRSUBI.mjs +0 -35
  260. package/dist/database-CIbVSfua.mjs +0 -61
  261. package/dist/db-eWy7A-H3.mjs +0 -27
  262. package/dist/dirty-BKCg6oVN.mjs +0 -35
  263. package/dist/document-CVxhTnUD.mjs +0 -22
  264. package/dist/events-Dxm7me47.mjs +0 -44
  265. package/dist/export-Gb_wfZpt.mjs +0 -103
  266. package/dist/field-BTCw6voJ.mjs +0 -21
  267. package/dist/fields-hZeq6IF2.mjs +0 -37
  268. package/dist/get--rGDVyje.mjs +0 -35
  269. package/dist/get-7Np_G2je.mjs +0 -35
  270. package/dist/get-CP3lrIYi.mjs +0 -49
  271. package/dist/get-CuPCE_AG.mjs +0 -35
  272. package/dist/get-DB6Y9igl.mjs +0 -41
  273. package/dist/get-DWzMR8sn.mjs +0 -35
  274. package/dist/get-DZatHVdn.mjs +0 -38
  275. package/dist/git-sync-Cjrx2meo.mjs +0 -31
  276. package/dist/has-remote-changes-CIIib71u.mjs +0 -67
  277. package/dist/import-D9ID9Mz4.mjs +0 -94
  278. package/dist/is-dirty-DY5Zhsbk.mjs +0 -8
  279. package/dist/key-BnGRTX8U.mjs +0 -17
  280. package/dist/list-B1sdMz6m.mjs +0 -31
  281. package/dist/list-BSxMFDMR.mjs +0 -31
  282. package/dist/list-BeqcZVSn.mjs +0 -39
  283. package/dist/list-C0344yqi.mjs +0 -52
  284. package/dist/list-C5Ir-96z.mjs +0 -49
  285. package/dist/list-C6YpaUpC.mjs +0 -39
  286. package/dist/list-CQN2BpaW.mjs +0 -31
  287. package/dist/list-CY-jpBNE.mjs +0 -31
  288. package/dist/list-CkTsOOA7.mjs +0 -39
  289. package/dist/list-CvS68tLn.mjs +0 -31
  290. package/dist/list-KDHLmoUx.mjs +0 -31
  291. package/dist/list-MqqHcBvD.mjs +0 -31
  292. package/dist/measure-CPqisgyf.mjs +0 -25
  293. package/dist/paginate-CMqbqhMC.mjs +0 -49
  294. package/dist/poll-task-CpHGQOd5.mjs +0 -194
  295. package/dist/preflight-xhwEOHAt.mjs +0 -90
  296. package/dist/prompt-BgkWNgIR.mjs +0 -52
  297. package/dist/publish-xVPABwE8.mjs +0 -65
  298. package/dist/remove-collection-_a4uIlLB.mjs +0 -42
  299. package/dist/requests-qyh002pL.mjs +0 -96
  300. package/dist/rescan-values-Bd0Joerq.mjs +0 -40
  301. package/dist/resolve-Ct084wx3.mjs +0 -84
  302. package/dist/revision-message-flag-CHzX0cqV.mjs +0 -11
  303. package/dist/run-BfpKUjqL.mjs +0 -135
  304. package/dist/runs-D_08Ma08.mjs +0 -53
  305. package/dist/runtime-Ab96yYlM.mjs +0 -1695
  306. package/dist/segment-DyVTZSIM.mjs +0 -25
  307. package/dist/setting-B9xSyMf6.mjs +0 -20
  308. package/dist/setting-Cko6bE_w.mjs +0 -55
  309. package/dist/setup-CXGcyTuv.mjs +0 -71
  310. package/dist/snippet-C4h-GMUf.mjs +0 -22
  311. package/dist/stash-DxmpBS7x.mjs +0 -108
  312. package/dist/status-D5CR1SrS.mjs +0 -69
  313. package/dist/summary-BEEJl2O1.mjs +0 -40
  314. package/dist/sync-schema-B5HDpmrp.mjs +0 -54
  315. package/dist/table-DHmaW3Ec.mjs +0 -21
  316. package/dist/timeline-B0R6-dm8.mjs +0 -24
  317. package/dist/timeline-event-BVDTt-pM.mjs +0 -22
  318. package/dist/transform-Cq2_muWO.mjs +0 -31
  319. package/dist/transform-job-BpebgMnq.mjs +0 -25
  320. package/dist/transform-tag-B1xnFa9w.mjs +0 -21
  321. package/dist/update-dashcard-DLq7ihNO.mjs +0 -73
  322. package/dist/upload-D3eiApa0.mjs +0 -16
  323. package/dist/validate-Cqa14t7o.mjs +0 -1496
  324. package/dist/verify-DvhZWmS2.mjs +0 -79
@@ -1,6 +1,6 @@
1
- import { ConfigError, writeJson } from "./capabilities-DOTcPraV.mjs";
2
- import { assertNotLegacyEnvelopeWrappingMbql5, isMbql5Query, validateQuery } from "./validate-Cqa14t7o.mjs";
3
-
1
+ import { i as ConfigError } from "./predicates-Bkm2IoeX.mjs";
2
+ import { l as writeJson } from "./cli.mjs";
3
+ import { i as validateQuery, r as isMbql5Query, t as assertNotLegacyEnvelopeWrappingMbql5 } from "./validate-BWchyW0V.mjs";
4
4
  //#region src/commands/validate-query.ts
5
5
  const skipValidateFlag = { "skip-validate": {
6
6
  type: "boolean",
@@ -31,6 +31,5 @@ function preflightMbql5Query(query, labels, options) {
31
31
  writeJson(outcome);
32
32
  throw new ConfigError(`${labels.contextLabel}: ${outcome.errors.length} error(s) — pass valid MBQL 5 or use the legacy format`);
33
33
  }
34
-
35
34
  //#endregion
36
- export { CARD_DATASET_QUERY_LABELS, MEASURE_DEFINITION_LABELS, SEGMENT_DEFINITION_LABELS, TRANSFORM_SOURCE_QUERY_LABELS, preflightMbql5Query, skipValidateFlag };
35
+ export { preflightMbql5Query as a, TRANSFORM_SOURCE_QUERY_LABELS as i, MEASURE_DEFINITION_LABELS as n, skipValidateFlag as o, SEGMENT_DEFINITION_LABELS as r, CARD_DATASET_QUERY_LABELS as t };
@@ -1,9 +1,8 @@
1
- import { connectionFlags, formatScalar, outputFlags, profileFlag, renderSummary } from "./capabilities-DOTcPraV.mjs";
2
- import "./command-augment-D9pI9Vbh.mjs";
3
- import { defineMetabaseCommand } from "./runtime-Ab96yYlM.mjs";
4
- import { FieldValues, fieldValuesView } from "./field-DsXTeqBy.mjs";
5
- import { parseId } from "./parse-id-CD54Chc5.mjs";
6
-
1
+ import { F as outputFlags, I as profileFlag, M as connectionFlags, c as renderSummary, f as formatScalar } from "./cli.mjs";
2
+ import { t as defineMetabaseCommand } from "./runtime-DiKyBxOw.mjs";
3
+ import { t as parseId } from "./parse-id-C_jmKFaa.mjs";
4
+ import { s as FieldValues } from "./field-Cr2DPUG9.mjs";
5
+ import { n as fieldValuesView } from "./field-BPsNa-TO.mjs";
7
6
  //#region src/commands/field/values.ts
8
7
  var values_default = defineMetabaseCommand({
9
8
  meta: {
@@ -25,19 +24,15 @@ var values_default = defineMetabaseCommand({
25
24
  examples: ["mb field values 100", "mb field values 100 --json"],
26
25
  async run({ args, ctx, getClient }) {
27
26
  const id = parseId(args.id);
28
- const client = await getClient();
29
- const values = await client.requestParsed(FieldValues, `/api/field/${id}/values`);
27
+ const values = await (await getClient()).field.values(id);
30
28
  const fieldId = values.field_id ?? id;
31
29
  const count = values.values.length;
32
30
  renderSummary(values, fieldValuesView, () => {
33
31
  if (count === 0) return `Field ${fieldId} has no cached values.`;
34
32
  const more = values.has_more_values === true ? " (more available; rescan for the full set)" : "";
35
- const header = `Field ${fieldId} has ${count} cached value${count === 1 ? "" : "s"}${more}:`;
36
- const lines = values.values.map((row) => ` ${formatScalar(row[0])}`);
37
- return [header, ...lines].join("\n");
33
+ return [`Field ${fieldId} has ${count} cached value${count === 1 ? "" : "s"}${more}:`, ...values.values.map((row) => ` ${formatScalar(row[0])}`)].join("\n");
38
34
  }, ctx);
39
35
  }
40
36
  });
41
-
42
37
  //#endregion
43
- export { values_default as default };
38
+ export { values_default as default };
@@ -0,0 +1,89 @@
1
+ import { n as createClient } from "./client-BqhzKdLM.mjs";
2
+ import { f as errorMessage, l as TimeoutError, o as MetabaseError, s as NetworkError } from "./predicates-Bkm2IoeX.mjs";
3
+ import { F as tryParseTag, I as SessionProperties, u as USER_AGENT } from "./runtime-DiKyBxOw.mjs";
4
+ import { r as HttpError } from "./network-error-CEb9ymDW.mjs";
5
+ //#region ../client/src/version/probe.ts
6
+ const PROBE_PATH = "/api/session/properties";
7
+ const PROBE_TIMEOUT_MS = 1e4;
8
+ async function probeServer(client, opts = {}) {
9
+ const properties = await client.requestParsed(SessionProperties, PROBE_PATH, {
10
+ timeoutMs: PROBE_TIMEOUT_MS,
11
+ retries: opts.retries ?? 0
12
+ });
13
+ return {
14
+ version: tryParseTag(properties.version.tag),
15
+ tokenFeatures: properties["token-features"] ?? null
16
+ };
17
+ }
18
+ //#endregion
19
+ //#region src/core/auth/verify.ts
20
+ const VERIFY_TIMEOUT_MS = 15e3;
21
+ async function verifyAndProbe(url, credential, options = {}) {
22
+ const { refresh, signal } = options;
23
+ const mb = createClient({
24
+ url,
25
+ credential
26
+ }, {
27
+ userAgent: USER_AGENT,
28
+ ...refresh !== void 0 && { refreshCredential: refresh },
29
+ ...signal !== void 0 && { signal }
30
+ });
31
+ const userPromise = mb.user.current({
32
+ timeoutMs: VERIFY_TIMEOUT_MS,
33
+ retries: 0
34
+ });
35
+ const serverPromise = probeServer(mb);
36
+ const [userResult, serverResult] = await Promise.allSettled([userPromise, serverPromise]);
37
+ if (userResult.status === "rejected") return failure(userResult.reason, "user");
38
+ if (serverResult.status === "rejected") return failure(serverResult.reason, "server");
39
+ return {
40
+ ok: true,
41
+ user: {
42
+ id: userResult.value.id,
43
+ name: userResult.value.common_name,
44
+ isAdmin: userResult.value.is_superuser
45
+ },
46
+ server: serverResult.value
47
+ };
48
+ }
49
+ function failure(error, which) {
50
+ if (error instanceof HttpError) return {
51
+ ok: false,
52
+ which,
53
+ kind: error.status === 401 || error.status === 403 ? "auth" : "server",
54
+ status: error.status,
55
+ endpoint: error.developerDetail.url,
56
+ message: error.userMessage
57
+ };
58
+ if (error instanceof NetworkError) return {
59
+ ok: false,
60
+ which,
61
+ kind: "network",
62
+ endpoint: error.developerDetail.url,
63
+ message: error.userMessage
64
+ };
65
+ if (error instanceof TimeoutError) {
66
+ const detail = error.developerDetail;
67
+ return {
68
+ ok: false,
69
+ which,
70
+ kind: "network",
71
+ ...detail.kind === "http" && { endpoint: detail.url },
72
+ message: error.userMessage
73
+ };
74
+ }
75
+ if (error instanceof MetabaseError) return {
76
+ ok: false,
77
+ which,
78
+ kind: "server",
79
+ message: error.userMessage
80
+ };
81
+ return {
82
+ ok: false,
83
+ which,
84
+ kind: "server",
85
+ message: errorMessage(error)
86
+ };
87
+ }
88
+ //#endregion
89
+ export { verifyAndProbe as t };
@@ -1,10 +1,9 @@
1
- import { connectionFlags, outputFlags, profileFlag, renderSummary } from "./capabilities-DOTcPraV.mjs";
2
- import "./command-augment-D9pI9Vbh.mjs";
3
- import { defineMetabaseCommand } from "./runtime-Ab96yYlM.mjs";
4
- import { parseId } from "./parse-id-CD54Chc5.mjs";
5
- import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-DVF9EnEb.mjs";
6
- import { SyncTaskOrIdle, formatSyncTask, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-CpHGQOd5.mjs";
7
-
1
+ import { F as outputFlags, I as profileFlag, M as connectionFlags, c as renderSummary } from "./cli.mjs";
2
+ import { t as defineMetabaseCommand } from "./runtime-DiKyBxOw.mjs";
3
+ import { n as DEFAULT_TIMEOUT_MS, t as DEFAULT_INTERVAL_MS } from "./poll-75SvT7Zv.mjs";
4
+ import { r as parseWaitSchedule } from "./wait-flags-DWEF9tX4.mjs";
5
+ import { c as syncTaskView } from "./git-sync-DxD_ng48.mjs";
6
+ import { a as throwIfFailedTask, i as taskPollOptions, n as formatSyncTask, r as syncTaskIdleView, t as SyncTaskOrIdle } from "./sync-task-BACcrs0i.mjs";
8
7
  //#region src/commands/git-sync/wait.ts
9
8
  const WaitResult = SyncTaskOrIdle;
10
9
  var wait_default = defineMetabaseCommand({
@@ -34,22 +33,15 @@ var wait_default = defineMetabaseCommand({
34
33
  outputSchema: WaitResult,
35
34
  examples: ["mb git-sync wait", "mb git-sync wait --timeout 300000 --json"],
36
35
  async run({ args, ctx, getClient }) {
37
- const timeoutMs = parseId(args.timeout, "timeout");
38
- const intervalMs = parseId(args.interval, "interval");
39
- const client = await getClient();
40
- const final = await pollSyncTask(client, {
41
- timeoutMs,
42
- intervalMs
43
- });
36
+ const schedule = parseWaitSchedule(args);
37
+ const final = await (await getClient()).gitSync.waitForTask(taskPollOptions(schedule));
44
38
  if (final === null) {
45
- const idle = { status: "idle" };
46
- renderSummary(idle, syncTaskIdleView, "No git-sync task is running.", ctx);
39
+ renderSummary({ status: "idle" }, syncTaskIdleView, "No git-sync task is running.", ctx);
47
40
  return;
48
41
  }
49
42
  renderSummary(final, syncTaskView, formatSyncTask(final), ctx);
50
43
  throwIfFailedTask(final, "task");
51
44
  }
52
45
  });
53
-
54
46
  //#endregion
55
- export { wait_default as default };
47
+ export { wait_default as default };
@@ -1,6 +1,6 @@
1
- import { parseId } from "./parse-id-CD54Chc5.mjs";
2
- import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-DVF9EnEb.mjs";
3
-
1
+ import { t as interruptSignal } from "./cli.mjs";
2
+ import { t as parseId } from "./parse-id-C_jmKFaa.mjs";
3
+ import { n as DEFAULT_TIMEOUT_MS, t as DEFAULT_INTERVAL_MS } from "./poll-75SvT7Zv.mjs";
4
4
  //#region src/commands/wait-flags.ts
5
5
  const waitScheduleFlags = {
6
6
  timeout: {
@@ -30,17 +30,20 @@ const gitSyncWaitFlags = {
30
30
  },
31
31
  ...waitScheduleFlags
32
32
  };
33
+ function parseWaitSchedule(args) {
34
+ const interval = args.interval ?? String(2e3);
35
+ const timeout = args.timeout ?? String(6e5);
36
+ return {
37
+ intervalMs: parseId(interval, "interval"),
38
+ timeoutMs: parseId(timeout, "timeout"),
39
+ signal: interruptSignal
40
+ };
41
+ }
33
42
  function parseWaitFlags(args) {
34
- const interval = args.interval ?? String(DEFAULT_INTERVAL_MS);
35
- const timeout = args.timeout ?? String(DEFAULT_TIMEOUT_MS);
36
43
  return {
37
44
  enabled: args.wait === true,
38
- schedule: {
39
- intervalMs: parseId(interval, "interval"),
40
- timeoutMs: parseId(timeout, "timeout")
41
- }
45
+ schedule: parseWaitSchedule(args)
42
46
  };
43
47
  }
44
-
45
48
  //#endregion
46
- export { gitSyncWaitFlags, parseWaitFlags, waitFlags };
49
+ export { waitFlags as i, parseWaitFlags as n, parseWaitSchedule as r, gitSyncWaitFlags as t };
@@ -0,0 +1,64 @@
1
+ import { m as projectForList } from "./cli.mjs";
2
+ //#region src/output/window.ts
3
+ const MAX_REQUEST_PAGE_SIZE = 200;
4
+ function windowList(items, range, serverTotal) {
5
+ const held = items.length;
6
+ const start = Math.min(range.offset, held);
7
+ const end = range.limit === void 0 ? held : Math.min(start + range.limit, held);
8
+ const total = serverTotal ?? held;
9
+ const beyondWindow = end < held;
10
+ const withheldByServer = held < total;
11
+ return buildEnvelope(items.slice(start, end), range, total, beyondWindow || withheldByServer);
12
+ }
13
+ function windowServerPage(data, total, range) {
14
+ return buildEnvelope(data, range, total, range.offset + data.length < total);
15
+ }
16
+ async function collectForOutput(source, view, opts) {
17
+ const { range } = opts;
18
+ const budget = opts.maxBytes <= 0 ? Number.POSITIVE_INFINITY : opts.maxBytes;
19
+ const fetchMax = range.limit === void 0 ? void 0 : range.limit + 1;
20
+ const request = {
21
+ offset: range.offset,
22
+ ...fetchMax !== void 0 && {
23
+ max: fetchMax,
24
+ pageSize: Math.min(fetchMax, MAX_REQUEST_PAGE_SIZE)
25
+ }
26
+ };
27
+ const items = [];
28
+ let total = null;
29
+ let bytes = 0;
30
+ let exhausted = true;
31
+ for await (const page of source(request)) {
32
+ total = page.total ?? total;
33
+ for (const item of page.items) {
34
+ items.push(item);
35
+ bytes += measure(item, view, opts);
36
+ }
37
+ const budgetSpent = bytes > budget;
38
+ const capReached = fetchMax !== void 0 && items.length >= fetchMax;
39
+ if (budgetSpent || capReached) {
40
+ exhausted = false;
41
+ break;
42
+ }
43
+ }
44
+ const limit = range.limit;
45
+ return buildEnvelope(limit !== void 0 && items.length > limit ? items.slice(0, limit) : items, range, total, !exhausted);
46
+ }
47
+ function buildEnvelope(data, range, total, moreAvailable) {
48
+ const returned = data.length;
49
+ const hasMore = returned > 0 && moreAvailable;
50
+ return {
51
+ data,
52
+ returned,
53
+ offset: range.offset,
54
+ ...range.limit !== void 0 && { limit: range.limit },
55
+ total,
56
+ has_more: hasMore,
57
+ next_offset: hasMore ? range.offset + returned : null
58
+ };
59
+ }
60
+ function measure(item, view, opts) {
61
+ return Buffer.byteLength(JSON.stringify(projectForList(item, view, opts)), "utf8");
62
+ }
63
+ //#endregion
64
+ export { windowList as n, windowServerPage as r, collectForOutput as t };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@metabase/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.2-alpha.extract-api-client.27e2241",
4
4
  "description": "Metabase CLI",
5
5
  "license": "AGPL-3.0",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/metabase/mb-cli.git"
8
+ "url": "git+https://github.com/metabase/mb-cli.git",
9
+ "directory": "packages/cli"
9
10
  },
10
11
  "bin": {
11
12
  "mb": "./dist/cli.mjs"
@@ -13,8 +14,7 @@
13
14
  "files": [
14
15
  "dist",
15
16
  "skills",
16
- "skill-data",
17
- ".claude-plugin"
17
+ "skill-data"
18
18
  ],
19
19
  "type": "module",
20
20
  "publishConfig": {
@@ -25,23 +25,7 @@
25
25
  "build": "tsdown",
26
26
  "dev": "tsdown --watch",
27
27
  "start": "node dist/cli.mjs",
28
- "test": "vitest run --project unit",
29
- "test:watch": "vitest --project unit",
30
- "test:e2e": "vitest run --project e2e",
31
- "test:e2e:watch": "vitest --project e2e",
32
- "e2e:up": "docker compose -f tests/e2e/docker-compose.yml up -d --wait",
33
- "e2e:down": "docker compose -f tests/e2e/docker-compose.yml down -v",
34
- "e2e:bootstrap": "bun tests/e2e/setup/bootstrap.ts",
35
- "e2e:matrix": "bun scripts/e2e-matrix.ts",
36
- "e2e:logs": "docker compose -f tests/e2e/docker-compose.yml logs -f metabase",
37
- "typecheck": "tsc --noEmit",
38
- "lint": "oxlint",
39
- "lint:fix": "oxlint --fix",
40
- "lint:skills": "uvx skillsaw lint skill-data/ --strict",
41
- "format": "oxfmt",
42
- "format:check": "oxfmt --check",
43
- "sync:representations": "bun run scripts/sync-representations.ts",
44
- "prepublishOnly": "tsdown && publint"
28
+ "prepublishOnly": "tsdown && publint && ! grep -rE \"(from|import|require)[[:space:]]*\\(?['\\\"]@metabase\" dist/"
45
29
  },
46
30
  "dependencies": {
47
31
  "@clack/prompts": "^0.8.2",
@@ -54,20 +38,6 @@
54
38
  "yaml": "^2.8.4",
55
39
  "zod": "^4.0.0"
56
40
  },
57
- "devDependencies": {
58
- "@types/js-yaml": "^4.0.9",
59
- "@types/node": "^22.10.0",
60
- "@types/semver": "^7.7.1",
61
- "execa": "^9.5.2",
62
- "fast-check": "^4.7.0",
63
- "js-yaml": "^4.1.0",
64
- "oxfmt": "^0.47.0",
65
- "oxlint": "^1.62.0",
66
- "publint": "^0.3.0",
67
- "tsdown": "^0.9.0",
68
- "typescript": "^5.7.2",
69
- "vitest": "^2.1.8"
70
- },
71
41
  "engines": {
72
42
  "node": ">=20.6"
73
43
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: core
3
- description: Foundations for driving Metabase from the terminal with the `mb` CLI — authentication and named profiles, the flag/output/`--json` conventions every command shares, JSON body input, command discovery via `--help` (add `--json` for machine-readable schemas), and the per-resource footguns (db, table, field, upload, card, dashboard, collection, segment, measure, timeline, library, setting, search, eid). Load first for any `mb` task; it routes to the specialized skills for deeper work.
3
+ description: Foundations for driving Metabase from the terminal with the `mb` CLI — authentication and named profiles, the flag/output/`--json` conventions every command shares, JSON body input, command discovery via `--help` (add `--json` for machine-readable schemas), and the per-resource footguns (db, table, field, upload, card, dashboard, collection, segment, measure, timeline, alert, subscription, library, setting, search, eid). Load first for any `mb` task; it routes to the specialized skills for deeper work.
4
4
  allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
5
5
  ---
6
6
 
@@ -12,8 +12,8 @@ Top-level command groups (run `mb <group> --help` to discover verbs):
12
12
 
13
13
  ```
14
14
  auth | db | table | field | upload | query | card | dashboard | snippet | segment | measure | collection | library
15
- document | timeline | timeline-event | transform | transform-job | transform-tag | setting | search | git-sync | setup
16
- eid | uuid | upgrade | skills
15
+ document | timeline | timeline-event | transform | transform-job | transform-tag | alert | subscription | setting
16
+ search | git-sync | setup | eid | uuid | upgrade | skills
17
17
  ```
18
18
 
19
19
  The conventions below — auth, flags, output, body input — hold across **every** group. Per-command flags and examples live in each command's `--help`; add `--json` for the machine-readable form with the output JSON Schema. A few flows have their own skills (see "Specialized skills"). When a card needs a query, prefer MBQL over native SQL (portable, pre-flight-validated — load `mbql`); fall back to native SQL when MBQL can't express it.
@@ -23,7 +23,7 @@ The conventions below — auth, flags, output, body input — hold across **ever
23
23
  **The agent does not log in for the user.** Authentication is the human's job — they pick the base URL, paste credentials, and store them as a named profile. The agent checks what profiles exist, asks which to use, and passes `--profile <name>` through every command.
24
24
 
25
25
  ```bash
26
- mb auth list --json # → {data:[{profile,url,authenticated,status,…}], returned, total}
26
+ mb auth list --json # → list envelope; data is [{profile,url,authenticated,status,…}]
27
27
  mb auth status --json # → {profile, present, url} for the default profile
28
28
  mb auth status --profile <name> --json # health probe for one profile
29
29
  ```
@@ -60,26 +60,29 @@ Every list/get verb supports the same output flags:
60
60
  - `--json` — emit the full JSON envelope, safe for `jq`. Default is human-readable text.
61
61
  - `--full` — include every field (the compact projection is the default, and is the agent-facing contract).
62
62
  - `--fields a,b.c.d` — project specific dot-paths. Mutually exclusive with `--full`. **Paths are relative to each `data[]` item on list verbs, and to the root on single-item verbs.** So it's `--fields id,name` on `… list` / `database schema-tables` (`data.id` and `data[].id` both fail with `unknown field path: "data.id"`), and `--fields id,name,display` on `card get`, `--fields data.rows` on `mb query` (whose `data` is an object).
63
- - `--max-bytes <n>` — cap **list** output size (drops trailing items, sets `truncated`). Default 24576 (sized to fit under agent-harness tool-output limits); `0` disables. Single-item commands (`get`) never truncate — when their output exceeds the cap they throw a `ConfigError` (exit 2: "output is N bytes, over the M-byte --max-bytes cap; …") whose tail names the remedy: on schema-shaped commands it is the exact narrower command to run instead — follow it rather than raising the cap.
63
+ - `--max-bytes <n>` — cap output size. Default 24576 (sized to fit under agent-harness tool-output limits); `0` disables. On a list it drops trailing items and sets `truncated` (see below). Single-item commands (`get`) never truncate — over the cap they throw a `ConfigError` (exit 2: "output is N bytes, over the M-byte --max-bytes cap; …") whose tail names the remedy: on schema-shaped commands it is the exact narrower command to run instead — follow it rather than raising the cap.
64
64
  - JSON output is a single line when stdout is piped (pretty-printed only at a TTY) — always parse it, never scrape by line position.
65
65
 
66
- List envelope shape (metadata first, so counts and the truncation marker survive if a consumer cuts the tail):
67
-
68
- ```json
69
- {
70
- "returned": 10,
71
- "total": 42,
72
- "limit": 50,
73
- "truncated": { "reason": "max_bytes", "bytes": 123456 },
74
- "data": [
75
- /* items */
76
- ]
77
- }
78
- ```
66
+ ## List windows and resumption
67
+
68
+ Every list verb takes `--limit <n>` (items this call returns) and `--offset <n>` (where the window starts, default `0`), and answers with one envelope, metadata first so the counts and the resumption point survive a cut tail: `{returned, offset, limit?, total, has_more, next_offset, truncated?, data}`. `truncated` is `{reason: "max_bytes", bytes: N}`.
69
+
70
+ - **`has_more` decides whether to keep going — never compare counts.** `total` is the server's count on endpoints that report one and `null` on those that don't, so arithmetic over it is not a termination condition.
71
+ - **To continue, pass `next_offset` back as `--offset`.** When `has_more` is true `next_offset` is past the offset you sent, so the loop advances; when false the walk is over and `next_offset` is `null`.
72
+ - **`truncated` means the byte cap cut the output, not that the data ran out.** `has_more`/`next_offset` are recomputed to the cut point, so a capped list resumes like any window. Its `bytes` is what the untruncated answer would have measured, so it sizes the work left rather than the reply you hold. Narrow rows with `--fields` rather than raising `--max-bytes` — a bigger cap spends context on fields you didn't ask for, and the cap counts only what you asked for, so `--fields` buys rows directly. A capped list always returns at least one row; when not even one fits it exits 2 with "the smallest response this list can produce is N bytes, over the M-byte --max-bytes cap; …".
73
+ - `limit` is echoed only when you passed `--limit` — except `mb search`, which defaults to `--limit 20` (an unbounded search is expensive server-side) and so always reports one. On nouns the server doesn't page, one large `--limit` with narrow `--fields` is a single request; many small `--offset` hops are one request each.
79
74
 
80
- `truncated` is present only when the cap dropped trailing items.
75
+ The whole walk, literally:
81
76
 
82
- `total` is best-effort and may be `null` (empty / permissions-filtered collections, or `--limit` early-stop); use `returned` for the count you got and `data.length` for the rendered slice.
77
+ ```bash
78
+ offset=0
79
+ while : ; do
80
+ out=$(mb table list --db-id 1 --limit 50 --offset "$offset" --fields id,name --profile <n> --json)
81
+ echo "$out" | jq -c '.data[]'
82
+ [ "$(echo "$out" | jq -r '.has_more')" = "true" ] || break
83
+ offset=$(echo "$out" | jq -r '.next_offset')
84
+ done
85
+ ```
83
86
 
84
87
  ## Body input (create / update / run)
85
88
 
@@ -87,10 +90,10 @@ Verbs that take a payload accept it from one of four sources, **first non-empty
87
90
 
88
91
  1. `--body '<inline JSON>'`
89
92
  2. `--file <path>` — JSON file
90
- 3. stdin (auto-detected when piped, or explicit `--stdin` where supported)
93
+ 3. stdin (auto-detected when piped; `--file -` names it explicitly)
91
94
  4. positional argument
92
95
 
93
- Exactly one required; passing two of `--body` / `--file` / `--stdin` is rejected with a `ConfigError`.
96
+ Exactly one required; passing more than one of `--body` / `--file` / a positional argument is rejected with a `ConfigError`.
94
97
 
95
98
  ```bash
96
99
  cat > ./.scratch/body.json <<'EOF'
@@ -122,23 +125,24 @@ mb transform --help --json | jq -r '.commands[].command' # verbs under "transfo
122
125
 
123
126
  Routine verb shapes (list / get / create / update), every flag, and output schemas live in each command's `--help` (add `--json` for output schemas). Below is only what help does _not_ tell you: footguns and non-obvious behaviors.
124
127
 
125
- - **db traversal: the hydration ladder.** Start with `database get <db-id> --include tables` — the compact table map (id, name, schema, description per table), one call that fits most databases. Pick the relevant tables, then `table fields <table-id>` per table (bounded: fields are per-table). `--include tables.fields` is the full rollup — small databases only; when either outgrows the cap the error message names the next command down the ladder. Hundreds of tables? Traverse by schema (`database schemas <db-id>` → `database schema-tables <db-id> <schema>`) or look tables up by name (`search <term> --models table --db-id <db-id> --limit 10`). `sync-schema` / `rescan-values` queue async work and return `{status:"ok"}` immediately; `sync-schema --wait` blocks until `initial_sync_status: complete`.
128
+ - **db traversal: the hydration ladder.** Start with `database get <db-id> --include tables` — the compact table map (id, name, schema, description per table), one call that fits most databases. Pick the relevant tables, then `table fields <table-id>` per table (bounded: fields are per-table). `--include tables.fields` is the full rollup — small databases only. Hundreds of tables? Traverse by schema (`database schemas <db-id>` → `database schema-tables <db-id> <schema>`) or look tables up by name (`search <term> --models table --db-id <db-id> --limit 10`). `sync-schema` / `rescan-values` queue async work and return `{status:"ok"}` immediately; `sync-schema --wait` blocks until `initial_sync_status: complete`.
126
129
  - **table fields.** `table get` never returns fields on its own — pass `--include fields` (compact; the underlying query_metadata response also carries FK targets and dimensions, visible under `--full`) or use `table fields <id>` (list envelope). `table update` patches table-level metadata only; physical columns aren't editable.
127
130
  - **field has no `list`.** Fields are per-table — get them via `table get <id> --include fields`. Never enumerate fields across a whole db (context blow-up). `field summary` is live cardinality `{field_id, count, distincts}`; `field values` is the cached distinct set (`has_more_values: true` ⇒ truncated cache). `field update` patches metadata only (`base_type` isn't editable) — this is where you set a column's `semantic_type` or foreign-key target.
128
131
  - **upload (CSV → tables).** `upload csv --file <path>` creates a new table + model (prints `{model_id, table_id}`); `upload append <table-id>` / `upload replace <table-id> --file <path>` add to / overwrite a table **previously created by upload** (columns must match). The destination db+schema is admin-configured, not per-call — check with `mb setting get uploads-settings --json` (`db_id: null` ⇒ uploads off/unconfigured; needs admin to read). `--collection <id|root>` only sets the model's collection. Max 50 MB. Errors: **"The uploads database is not configured."** = no db has uploads enabled; **"Uploads are not enabled."** = the append/replace target isn't an uploaded table.
129
132
  - **card.** `dataset_query` is the **flat** `mbql/query` value, not a legacy `{type:"query",query:…}` envelope (→ `mbql`). `--export-format csv|xlsx` streams the raw export (pipe to a file), bypassing the JSON envelope. `archive` is the only delete; unarchive with `update --body '{"archived":false}'`. `visualization_settings` keys are scoped by `display` and aren't pre-flighted — see `visualization`.
130
133
  - **dashboard.** Dashcards round-trip through `PUT /api/dashboard/:id` (no per-dashcard endpoint): `update-dashcard <dash-id> <dashcard-id>` patches one safely; `update --body '{"dashcards":[…]}'` replaces the whole set (omitted ids are deleted server-side; negative ids for new cards). `create` accepts the **same** `dashcards` array in its initial body — lay out the whole dashboard in one call: negative ids for new cards, and `card_id:null` plus a `visualization_settings.virtual_card` block (`{display:"text"|"heading"|"link"|…}`) for non-question cards. `create`/`update` pre-flight every positive `card_id` and exit **2** with `{ok:false,errors:[…]}` on a bad ref (non-bypassable). `dashboard get <id>` (or `--full`) hydrates dashcards/tabs; `list` omits them. **The grid is 24 columns wide:** each dashcard's `{col, row, size_x, size_y}` is in grid units — **full-width is `size_x: 24`** (`size_x: 12` is half a row, the usual cause of a card filling only half the width). Keep `col + size_x ≤ 24`, start a full-width stack's `col` at 0, and don't overlap (the server stores collisions as sent — no auto-fix). Layout patterns and per-chart default sizes → the `dashboard` skill; load it before composing any `dashcards` array.
131
- - **dashboard parameters (filters).** A dashboard's `parameters` array holds its filter widgets; they're part of the dashboard record, so read them with `dashboard get <id> --fields parameters --json` (no separate verb). **Editing replaces the _whole_ array** (like dashcards), so it's a read-modify-write loop: pull the current set with `dashboard get <id> --fields parameters --json`, add/change entries, and send the full array back via `dashboard update --body '{"parameters":[…]}'` (or supply it in `create`). Omitting a parameter deletes it. Each parameter is `{id, type, …}`. **`id` is a descriptive slug-like string you pick (e.g. `order_status`), unique within this dashboard — Metabase stores any non-blank string verbatim. Do NOT invent a random/opaque id by guessing; reuse the `slug`. If you genuinely need an opaque id, mint one with `mb uuid` — never fabricate one.** `type` is a **closed enum**; an unlisted value is a hard parse error that echoes the full allowed set back to you: string ops `string/=` `string/!=` `string/contains` `string/does-not-contain` `string/starts-with` `string/ends-with`; number ops `number/=` `number/!=` `number/between` `number/>=` `number/<=`; date `date/single` `date/range` `date/relative` `date/month-year` `date/quarter-year` `date/all-options`; plus `category`, `id`, `boolean/=`, `temporal-unit`, and bare `number`/`text`/`date`/`boolean`. A parameter only filters a card once it is **mapped**: each dashcard's `parameter_mappings` is `[{parameter_id, target}]` where `parameter_id` must match a parameter's `id` exactly, and `target` is `["dimension", ["field", <field-id>, null]]` for an MBQL card column, `["dimension", ["template-tag", "<tag>"]]` for a native field-filter tag, or `["variable", ["template-tag", "<tag>"]]` for a native raw-value tag. Populate a dropdown with `values_source_type`: `"static-list"` + `values_source_config.values`, or `"card"` + `{card_id, value_field, label_field}`; omit it to pull live distinct values from the mapped field. `dashboard parameter-values <id> <parameter-id> [--query <substr>]` fetches those selectable values (`{values, has_more_values}`); `--query` is a case-insensitive substring search.
134
+ - **dashboard parameters (filters).** A dashboard's `parameters` array holds its filter widgets; they're part of the dashboard record, so read them with `dashboard get <id> --fields parameters --json` (no separate verb). **Editing replaces the _whole_ array** (like dashcards), so it's a read-modify-write loop and omitting a parameter deletes it. A parameter only filters a card once it is **mapped** onto that dashcard's `parameter_mappings` — an unmapped parameter is an inert widget. `type` is a **closed enum**; an unlisted value is a hard parse error that echoes the full allowed set back to you. `dashboard parameter-values <id> <parameter-id> [--query <substr>]` fetches a widget's selectable values (`{values, has_more_values}`; `--query` is a case-insensitive substring search). Parameter types, ids, mapping targets, and value sources → the `dashboard` skill; load it before authoring a `parameters` array.
135
+ - **alert / subscription are two unrelated systems.** `alert` watches one **card** and fires on a send condition (`/api/notification`: a cron string, `channel/email`-prefixed handlers, typed recipients); `subscription` delivers one **dashboard** on a schedule (`/api/pulse`: structured `schedule_type` + hour/day/frame, bare `email` channels, `{id}|{email}` recipients). The bodies are not interchangeable. Both silently deliver nowhere if the server has no SMTP / Slack app — check `mb setting get 'email-configured?'` (quote it; the `?` is a shell glob) before creating either. Their list-valued fields (`handlers`/`subscriptions`, `channels`/`cards`) **replace wholesale** on update, so adding one recipient is a read-modify-write. `mb card alerts <id>` and `mb dashboard subscriptions <id>` list what's already attached to a card/dashboard; `archive` deactivates rather than deletes. Load the `notification` skill before authoring either body.
132
136
  - **snippet `--archived` is a swap, not a union** — list returns _either_ active _or_ archived rows, never both. (Same for `--filter archived` on dashboard/collection.)
133
137
  - **segment / measure.** `update` and `archive` require a non-blank `revision_message` (audit-logged); the CLI does not synthesize it on `update`. `archive` defaults to `"Archived via mb CLI"` — override with `--revision-message`. `definition` is a flat MBQL clause (→ `mbql`): segment = a filter, measure = exactly one aggregation.
134
138
  - **timeline / timeline-event.** Timelines are collection-scoped event annotations for time-series charts: a timeline's events render only on time-series questions saved in the **same collection** (`collection_id`; null = root) — sub-collections do **not** inherit, and events never draw on dashboard cards, only in the question (and collection) view. To annotate a question's chart, create the timeline in that question's collection, then add events; an event only draws when its `timestamp` falls inside the chart's displayed time range. Event `create` requires `timestamp` (ISO 8601), `timezone` (IANA name), `time_matters` (true = the time of day is significant, false = date-only), and `timeline_id` — the API never auto-creates a default timeline (that's UI-only). There is no `timeline-event list`; enumerate with `timeline events <id>` (`--archived` to include archived). Archiving a timeline cascades `archived` to its events; `delete` is a **hard** delete of the timeline and all its events — prefer `archive`.
135
- - **collection `<ref>`** accepts four forms only — positive int, `root`, `trash`, or a 21-char entity_id; anything else is a client-side `ConfigError`. `collection items` auto-paginates (cap with `--limit`, which then omits `total`). `collection tree` is **JSON-only** (`--format text` is rejected). A transform collection needs `collection create --namespace transforms`.
139
+ - **collection `<ref>`** accepts four forms only — positive int, `root`, `trash`, or a 21-char entity_id; anything else is a client-side `ConfigError`. `collection items` pages the server endpoint, pulling only as far as the output cap can show — read `has_more`/`next_offset` to continue. `collection tree` is **JSON-only** (`--format text` is rejected). A transform collection needs `collection create --namespace transforms`.
136
140
  - **setting set** parses the value as **strict JSON**: a string is `'"value"'` (inner quotes), booleans `true`/`false`, numbers bare. Wrong quoting silently errors — confirm with `setting get <key>` after. `setting get --json` works on every value type (wrapping bare-text responses into `{key, value}`).
137
141
  - **search vs. list.** For plain enumeration of cards/dashboards/collections use the dedicated `… list` verbs; reach for `search --models <kind>` only for ranking against a query string or a cross-resource lookup.
138
142
  - **transform.** Iterate with `transform update <id>`, never `delete` + `create` (keeps the row, `entity_id`, materialized table, and YAML filename — avoids `_2` suffixes and noisy git history). `transform run` needs `--wait` (or `--sync`, which also waits for the output table to register and returns `target_table_id`) or you get only `{run_id, final:null}`. (→ `transform`.)
139
143
  - **setup is one-shot.** `mb setup` walks `/api/setup` for a **fresh** instance only — errors against an already-configured one. Mostly for bootstrapping local / e2e instances.
140
144
  - **eid** translates a string entity id → numeric id: `mb eid --model <model> <eid1,eid2> --json`. Entity ids are NanoIDs that can start with `-`, which the positional form misreads as a flag (shell quotes don't help) — for those, use `--body '{"entity_ids":{"card":["-…"]}}'` (the id is a JSON string value, immune to flag parsing).
141
- - **library.** EE-only (`library` premium feature, v59+). The Library is a curated subtree (`library-data` "Data" + `library-metrics` "Metrics" under a `library` root): tables published to **Data** appear first in data pickers and rank up in search; metrics saved to **Metrics** are prioritized in nav, search, and the query builder — it's how you tell people (and agents) "start from these, they're trusted." `library get` shows the Library and its Data/Metrics collection ids; `library create` provisions it (idempotent). `library publish --table-ids/--db-ids/--schemas` publishes tables into Data — it **resolves the Data collection itself and creates the Library if absent** (no collection id to find); each `--schemas` entry is `<db-id>:<schema>` (e.g. `1:public`), not a bare name. `publish` cascades to upstream FK dependencies, `unpublish` to downstream dependents; both need **admin or data-analyst** (Curate alone won't publish) and exit **403** without write **and** query permission on every affected table. Publish status shows on the table: `table get`/`table list` carry `is_published` (`collection_id` under `--full`). Good candidates are finished, analysis-ready tables — clean/combine via transforms first, then publish the polished result.
145
+ - **library.** EE-only (`library` premium feature, v59+). The Library is a curated subtree (`library-data` "Data" + `library-metrics` "Metrics" under a `library` root): tables published to **Data** appear first in data pickers and rank up in search; metrics saved to **Metrics** are prioritized in nav, search, and the query builder — it's how you tell people (and agents) "start from these, they're trusted." `library get` shows the Library and its Data/Metrics collection ids; `library create` provisions it (idempotent). `library publish --table-ids/--db-ids/--schemas` publishes tables into Data — it **resolves the Data collection itself and creates the Library if absent** (no collection id to find); each `--schemas` entry is `<db-id>:<schema>` (e.g. `1:public`), not a bare name. `publish` cascades to upstream FK dependencies, `unpublish` to downstream dependents; both need **admin or data-analyst** (Curate alone won't publish) and exit **403** without write **and** query permission on every affected table. Publish status shows on the table: `table get`/`table list` carry `is_published` (`collection_id` under `--full`). Good candidates are finished, analysis-ready tables — clean/combine via transforms first, then publish the polished result. Publishing does not put the Data collection in the git-sync scope: on a remote-sync instance, `mb git-sync add-collection <data-collection-id>` is what makes exports carry the published tables' metadata (see the `git-sync` skill).
142
146
  - **query / uuid.** `mb query` is the ad-hoc MBQL surface (`--print-schema` → `--dry-run` → run); `mb uuid --count <n>` mints the `lib/uuid` values MBQL clauses need. Both live in `mbql`.
143
147
 
144
148
  ## Specialized skills (load on demand)
@@ -150,6 +154,7 @@ This file is enough for any single-command task. For anything deeper, load the r
150
154
  - **`visualization`** — choosing a card's `display` and authoring `visualization_settings`. The presentation counterpart to `mbql`.
151
155
  - **`dashboard`** — building interactive dashboards: wiring filters (parameters + mappings), linked/cascading filters, cross-filtering, click behavior, series, and tabs. Load beyond a plain card-layout task.
152
156
  - **`metadata`** — setting field/table metadata: semantic types, foreign-key targets, dropdown/scan behavior, and column visibility, and the downstream features each unlocks. Load when editing what a column _means_, not its data.
157
+ - **`notification`** — scheduled delivery: question alerts (`mb alert`) and dashboard subscriptions (`mb subscription`). Choosing between them, the two schedule/recipient contracts, channel prerequisites, testing a send.
153
158
  - **`transform`** — transform body JSON, create + run-with-wait, run inspection, tags, jobs.
154
159
  - **`document`** — Metabase documents (TipTap body, embedding cards).
155
160
  - **`git-sync`** — round-tripping content to/from a git remote.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dashboard
3
- description: Build Metabase dashboards via the `mb` CLI — lay out dashcards on the 24-column grid (`{col,row,size_x,size_y}` math, per-chart default sizes) and turn cards into a filterable, cross-linked app. Covers wiring filters to cards (parameters + parameter_mappings), the field-filter vs. raw-variable target grammar, linked/cascading filters and their foreign-key requirement, cross-filtering, click-through, multi-series overlays, and tabs. The parameter type enum and whole-array replace semantics live in `core`. Triggers — "build a dashboard from these cards", "my dashboard is squished into half the width", "wire a filter to these cards", "make a filter cascade", "click a bar to filter the other charts", "add a dashboard tab", "add a second series", "why isn't my filter showing".
3
+ description: Build Metabase dashboards via the `mb` CLI — lay out dashcards on the 24-column grid (`{col,row,size_x,size_y}` math, per-chart default sizes) and turn cards into a filterable, cross-linked app. Covers wiring filters to cards (parameters + parameter_mappings), the field-filter vs. raw-variable target grammar, linked/cascading filters and their foreign-key requirement, cross-filtering, click-through, multi-series overlays, and tabs. The whole-array replace semantics live in `core`. Triggers — "build a dashboard from these cards", "my dashboard is squished into half the width", "wire a filter to these cards", "make a filter cascade", "click a bar to filter the other charts", "add a dashboard tab", "add a second series", "why isn't my filter showing".
4
4
  allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
5
5
  ---
6
6
 
@@ -8,7 +8,7 @@ allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
8
8
 
9
9
  A dashboard starts as cards on a grid; it becomes an **app** when filters drive the cards, charts cross-filter each other, and clicks navigate. This skill owns both: the grid layout and the interactive layer.
10
10
 
11
- **`core` owns the transport mechanics** — the whole-array replace semantics (editing `dashcards` or `parameters` replaces the entire set; omitted entries are deleted; new cards use negative ids), `update-dashcard` for a single safe patch vs. `update --body` for a full replace, the closed `parameter.type` enum, and the `parameter-values` verb. Read it first (`mb skills get core`). **`visualization`** owns each card's chart and the full `click_behavior` key catalog.
11
+ **`core` owns the transport mechanics** — the whole-array replace semantics (editing `dashcards` or `parameters` replaces the entire set; omitted entries are deleted; new cards use negative ids), `update-dashcard` for a single safe patch vs. `update --body` for a full replace, and the `parameter-values` verb. Read it first (`mb skills get core`). **`visualization`** owns each card's chart and the full `click_behavior` key catalog.
12
12
 
13
13
  Inspect before you wire: `mb dashboard get <id> --json` hydrates `parameters`, `dashcards`, and `tabs`; `mb dashboard cards <id>` lists just the dashcards.
14
14
 
@@ -47,6 +47,10 @@ A dashboard filter is one entry in the dashboard's `parameters` array **plus** a
47
47
  "target": ["dimension", ["field", 1779, null]] }
48
48
  ```
49
49
 
50
+ **`id` is a slug-like string you pick** (e.g. `order_status`), unique within the dashboard — Metabase stores any non-blank string verbatim, so reuse the `slug` rather than guessing an opaque value. If you genuinely need an opaque id, mint one with `mb uuid`; never fabricate one.
51
+
52
+ **`type` is a closed enum** — an unlisted value is a hard parse error that echoes the allowed set back: string ops `string/=` `string/!=` `string/contains` `string/does-not-contain` `string/starts-with` `string/ends-with`; number ops `number/=` `number/!=` `number/between` `number/>=` `number/<=`; date `date/single` `date/range` `date/relative` `date/month-year` `date/quarter-year` `date/all-options`; location `location/city` `location/state` `location/zip_code` `location/country`; plus `category`, `id`, `boolean/=`, `temporal-unit`, and bare `number`/`text`/`date`/`boolean`.
53
+
50
54
  The `target` grammar depends on what the card is:
51
55
 
52
56
  | Card's query | `target` |
@@ -20,13 +20,13 @@ mb document update <id> --file patch.json --profile <name> --json # PATCH sema
20
20
  mb document archive <id> --profile <name> --json # soft-delete (PUT archived:true)
21
21
  ```
22
22
 
23
- - `list` returns the standard envelope (`{data, returned, total}`). The compact item is `{id, name, collection_id, archived, creator_id, can_write}` and omits the (potentially huge) `document` body — pull the body with `get --full`.
23
+ - `list` returns the standard list envelope (see `core`). The compact item is `{id, name, collection_id, archived, creator_id, can_write}` and omits the (potentially huge) `document` body — pull the body with `get --full`.
24
24
  - `archive` is the only delete, mirroring `card` / `dashboard`. **Unarchive** with `mb document update <id> --body '{"archived":false}'`.
25
25
  - `update` is PATCH — send only the keys you want to change: `name`, `document`, `collection_id`, `collection_position`, `archived`, and `cards` (inline card creation works on update too, not just create — see below). Replacing `document` replaces the **whole** body; there is no partial-node patch.
26
26
 
27
27
  ## Node ids (`_id`)
28
28
 
29
- The editor anchors only these node types with an `_id` (a UUID): `paragraph`, `heading`, `codeBlock`, `orderedList`, `bulletList`, `blockquote`, `cardEmbed`, `supportingText`. **`create`/`update` require a non-empty `_id` on every node of those types** — the CLI validates before sending and rejects a body missing any (`every … node needs a non-empty string _id (mint with mb uuid)`). Other node types (`doc`, `text`, `listItem`, `resizeNode`, `flexContainer`, …) take no `_id` and are left alone. Without them the editor backfills ids when the document opens, which makes a freshly-saved document show a spurious "unsaved changes" prompt.
29
+ The editor anchors only these node types with an `_id` (a UUID): `paragraph`, `heading`, `codeBlock`, `orderedList`, `bulletList`, `blockquote`, `cardEmbed`, `supportingText`. **`create`/`update` require a non-empty `_id` on every node of those types** — the CLI validates before sending and rejects a body missing any (`every … node needs a non-empty string _id`). Other node types (`doc`, `text`, `listItem`, `resizeNode`, `flexContainer`, …) take no `_id` and are left alone. Without them the editor backfills ids when the document opens, which makes a freshly-saved document show a spurious "unsaved changes" prompt.
30
30
 
31
31
  Mint the ids with `mb uuid --count <n> --json` (→ `["…", …]`), one per id-bearing node, and set each as that node's `attrs._id`.
32
32