@metabase/cli 0.1.16 → 0.1.17

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 (216) hide show
  1. package/README.md +21 -0
  2. package/dist/{add-collection-H4LcP-9B.mjs → add-collection-C-t9SQBk.mjs} +5 -5
  3. package/dist/add-collection-Dek6kiRI.mjs +11 -0
  4. package/dist/{archive-BCXoM1nX.mjs → archive-C7dnyzVY.mjs} +9 -7
  5. package/dist/{archive-D1mfiftv.mjs → archive-CaoUUTIb.mjs} +8 -7
  6. package/dist/{archive-CQQWkC5S.mjs → archive-D1FX-sbU.mjs} +7 -6
  7. package/dist/{archive-hN8PfvhX.mjs → archive-DS-KEB4a.mjs} +7 -6
  8. package/dist/{archive-CdUS-OG9.mjs → archive-LG8u7ec5.mjs} +7 -6
  9. package/dist/{archive-C6MDtV1F.mjs → archive-qSOcACQo.mjs} +8 -6
  10. package/dist/{archive-B3cjzOIK.mjs → archive-wNXwIiF0.mjs} +8 -7
  11. package/dist/auth-Kv2MRkRk.mjs +22 -0
  12. package/dist/{body-DB2upz6a.mjs → body-IcJ5kFtk.mjs} +3 -3
  13. package/dist/{branches-B6R60Vr1.mjs → branches-BlNCTmFB.mjs} +7 -6
  14. package/dist/{cancel-oPsWomYc.mjs → cancel-BnveTPNw.mjs} +6 -5
  15. package/dist/{cancel-task-CleJVDNI.mjs → cancel-task-CSVI8Zgl.mjs} +7 -6
  16. package/dist/{capabilities-BX1rnVuH.mjs → capabilities-N0jo5U7S.mjs} +1 -1
  17. package/dist/card-Bp58WEUF.mjs +26 -0
  18. package/dist/{card-wCPcuKSi.mjs → card-DEmcRlNO.mjs} +6 -5
  19. package/dist/{cards-Bw37jizL.mjs → cards-CMgGA8OZ.mjs} +8 -6
  20. package/dist/cli.mjs +54 -27
  21. package/dist/collection-D8TI20Ir.mjs +23 -0
  22. package/dist/{collection-namespace-CUDPh2rF.mjs → collection-namespace-CsaxEqOb.mjs} +2 -2
  23. package/dist/command-augment-DdZIfx1V.mjs +11 -0
  24. package/dist/{create-Bj6PuaAW.mjs → create-AeWNv0v-.mjs} +9 -8
  25. package/dist/{create-CZ0_s5ap.mjs → create-B1xfaZJB.mjs} +7 -6
  26. package/dist/{create-B87ZQjNM.mjs → create-B6LQutd0.mjs} +17 -12
  27. package/dist/{create-CF2Zn4pT.mjs → create-B79M8YpX.mjs} +10 -9
  28. package/dist/{create-Cy2TNnJB.mjs → create-Bg_uMu0p.mjs} +9 -8
  29. package/dist/{create-DSWjS09p.mjs → create-BpkWlgoR.mjs} +18 -12
  30. package/dist/{create-D-qE3Oq8.mjs → create-C7u3umLj.mjs} +9 -8
  31. package/dist/{create-B-mvVFIl.mjs → create-FZOrCw5k.mjs} +21 -12
  32. package/dist/{create-CfLaBO0V.mjs → create-I5Cv-MBa.mjs} +16 -11
  33. package/dist/{create-BEkuqChu.mjs → create-LHqwcVbS.mjs} +16 -11
  34. package/dist/{create-DwoqFYb9.mjs → create-SHKlj0z3.mjs} +9 -8
  35. package/dist/{create-branch-BaZ00MIc.mjs → create-branch-CGyT99Ny.mjs} +7 -6
  36. package/dist/{current-task-Dr5dOD4V.mjs → current-task-C-0hw2Ae.mjs} +7 -6
  37. package/dist/dashboard-C9pQCnX6.mjs +28 -0
  38. package/dist/{dashboard-B4bn3z6t.mjs → dashboard-DOplbKyQ.mjs} +7 -5
  39. package/dist/{database-BJxGUXhA.mjs → database-D9fftP-i.mjs} +1 -1
  40. package/dist/db-DWykmBOh.mjs +28 -0
  41. package/dist/{delete-DHrFA1SZ.mjs → delete--NYYN6wv.mjs} +8 -7
  42. package/dist/{delete-evwMw6Hk.mjs → delete-Do3nn9sl.mjs} +8 -7
  43. package/dist/{delete-runtime-CZMw_AGX.mjs → delete-runtime-B0ha5QR4.mjs} +3 -3
  44. package/dist/{delete-DJti0TOA.mjs → delete-tCVrYjKD.mjs} +8 -7
  45. package/dist/{delete-table-DvuuwVqu.mjs → delete-table-CWSGPw0i.mjs} +8 -7
  46. package/dist/{dependencies-DrV31Rj5.mjs → dependencies-CyFocD8I.mjs} +7 -6
  47. package/dist/{dirty-C-rkrnVM.mjs → dirty-BXM0YJ_a.mjs} +7 -6
  48. package/dist/document-DNDm8_Py.mjs +22 -0
  49. package/dist/{eid-BeXI-eII.mjs → eid-p-zn_1RJ.mjs} +13 -7
  50. package/dist/{error-CIObEXLY.mjs → error-5H_tcfL8.mjs} +2 -2
  51. package/dist/{export-CGa-SgEV.mjs → export-B_8wghyo.mjs} +9 -8
  52. package/dist/field-CFt1-KDR.mjs +21 -0
  53. package/dist/{fields-Recymu7n.mjs → fields-BsufL9kv.mjs} +8 -7
  54. package/dist/{get-rFcAVIch.mjs → get-4lufgahL.mjs} +7 -6
  55. package/dist/{get-BQxLtFE-.mjs → get-68P-L4ja.mjs} +7 -6
  56. package/dist/{get-Nc5GOs6-.mjs → get-B45uYMAs.mjs} +8 -6
  57. package/dist/{get-b4xbfFbA.mjs → get-B67pe00Z.mjs} +7 -6
  58. package/dist/{get-BAH_M5vj.mjs → get-BJoZkATD.mjs} +7 -6
  59. package/dist/{get-DaixPDU9.mjs → get-BTKeO4vE.mjs} +7 -6
  60. package/dist/{get-CYh2DBsq.mjs → get-C7mq17-2.mjs} +7 -6
  61. package/dist/{get-CHi8tU_1.mjs → get-CDLa6LiC.mjs} +9 -8
  62. package/dist/{get-CARdLkmp.mjs → get-CPw0ROO4.mjs} +7 -6
  63. package/dist/{get-CXMv-r1p.mjs → get-Cl5Ak73C.mjs} +9 -7
  64. package/dist/{get-BM-d3-zk.mjs → get-D3k2JUsa.mjs} +7 -6
  65. package/dist/{get-7fWSU6ow.mjs → get-DTqBuIf3.mjs} +6 -5
  66. package/dist/{get-Q2WZ79q_.mjs → get-DeLnNVQE.mjs} +8 -7
  67. package/dist/{get-C6g2C4dM.mjs → get-Df_3LCVC.mjs} +7 -6
  68. package/dist/{get-BD_P_Ejc.mjs → get-DurjkUKJ.mjs} +7 -6
  69. package/dist/{get-run-CfQR6ZNa.mjs → get-run-Dq4qfGfD.mjs} +7 -6
  70. package/dist/git-sync-ByvjqSiy.mjs +31 -0
  71. package/dist/group-BNE_RiH5.mjs +28 -0
  72. package/dist/{has-remote-changes-Bvyv4FLP.mjs → has-remote-changes-E-4N_O_t.mjs} +7 -6
  73. package/dist/{import-c3o3OAx0.mjs → import-Dg0j3HCP.mjs} +9 -8
  74. package/dist/{input-BXWgdKiS.mjs → input-7Sj85_K7.mjs} +1 -1
  75. package/dist/is-dirty-D7UMN0mt.mjs +10 -0
  76. package/dist/{is-dirty-BE53XwOC.mjs → is-dirty-DWw1yBeR.mjs} +4 -4
  77. package/dist/{items-1KkBMiO4.mjs → items-CQtt9X4M.mjs} +9 -8
  78. package/dist/{key-DwiMOWRQ.mjs → key-bltP32Pm.mjs} +1 -1
  79. package/dist/library-B5AvpACG.mjs +24 -0
  80. package/dist/{list-C4KnM3Rq.mjs → list-B1uVWy6A.mjs} +8 -6
  81. package/dist/{list-DPcPTqFU.mjs → list-BAOTQHst.mjs} +6 -5
  82. package/dist/{list-D52_BozQ.mjs → list-BF-W4jOZ.mjs} +9 -7
  83. package/dist/{list-7rwzxX6t.mjs → list-BFVuPodI.mjs} +6 -5
  84. package/dist/{list-DHb4vQUM.mjs → list-BHAWYZ1z.mjs} +6 -5
  85. package/dist/{list-BqgbrpQQ.mjs → list-BKUvhAs4.mjs} +6 -5
  86. package/dist/{list-CO5J3SZU.mjs → list-BgUWqZa2.mjs} +8 -7
  87. package/dist/{list-F0vkE22V.mjs → list-C4bALfCs.mjs} +7 -6
  88. package/dist/{list-Drr4JiWg.mjs → list-C9O2RY5u.mjs} +6 -5
  89. package/dist/{list-CSjFJDls.mjs → list-CfqpDTna.mjs} +6 -5
  90. package/dist/{list-FR8Q1SzV.mjs → list-CvhVYOVl.mjs} +7 -6
  91. package/dist/{list-BC2B02IR.mjs → list-D3TSAqwl.mjs} +6 -5
  92. package/dist/{list-BwdO1_gX.mjs → list-D5Gdz8hi.mjs} +6 -5
  93. package/dist/{list-DUEYX3bX.mjs → list-DG0FIhTK.mjs} +6 -5
  94. package/dist/{list-DIvOPW1g.mjs → list-KxQNqp4T.mjs} +8 -7
  95. package/dist/{login-C0Rf2hg0.mjs → login-Bt6j6yBM.mjs} +10 -9
  96. package/dist/{logout-C7_UON-s.mjs → logout-ANkL02p0.mjs} +6 -5
  97. package/dist/{manifest-B2F8iL7X.mjs → manifest-BVf8P4bl.mjs} +9 -2
  98. package/dist/measure-CgFwtL1r.mjs +25 -0
  99. package/dist/{metadata-Db3Kpo-z.mjs → metadata-ClehtgZj.mjs} +9 -8
  100. package/dist/{metadata-FltZq5Ek.mjs → metadata-DplshwI3.mjs} +8 -7
  101. package/dist/{command-augment-CAur0XOQ.mjs → notice-DyVl5aYB.mjs} +1 -11
  102. package/dist/parameter-CiJ4CwWE.mjs +118 -0
  103. package/dist/parameter-values-D4J8Ctu0.mjs +56 -0
  104. package/dist/{parse-enum-BatHQ-Gs.mjs → parse-enum-BL9i_brN.mjs} +1 -1
  105. package/dist/{parse-id-B5adfBlS.mjs → parse-id-D4LeTUsP.mjs} +1 -1
  106. package/dist/{parse-ref-CZr1bYIl.mjs → parse-ref-CB_KvF9h.mjs} +1 -1
  107. package/dist/{path-BojuJkE4.mjs → path-5nQgdvrs.mjs} +6 -5
  108. package/dist/{poll-AduuU55-.mjs → poll-BpAJpvb-.mjs} +2 -2
  109. package/dist/{poll-task-B00Qwd87.mjs → poll-task-TilgciQn.mjs} +2 -2
  110. package/dist/{preflight-QVPvG_Xg.mjs → preflight-OfHU3Toi.mjs} +4 -4
  111. package/dist/{process-DsGf7Mg5.mjs → process-j8UHMHc2.mjs} +1 -1
  112. package/dist/{prompt-Bc_bHSD0.mjs → prompt-C85xd9HR.mjs} +1 -1
  113. package/dist/{publish-h5RJh6im.mjs → publish-DKiqyDwo.mjs} +9 -8
  114. package/dist/{query-Dvi-Rksy.mjs → query-BWJ5h1g3.mjs} +19 -13
  115. package/dist/{query-BUkuB4bZ.mjs → query-CQ3xXa9P.mjs} +10 -8
  116. package/dist/{query-result-L5_NrwQR.mjs → query-result-D6mfoVfQ.mjs} +1 -1
  117. package/dist/{remove-collection-D8ZfB2RN.mjs → remove-collection-CO-aMzTO.mjs} +9 -8
  118. package/dist/{rescan-values-DOsDLrRG.mjs → rescan-values-DpL6LGAK.mjs} +9 -8
  119. package/dist/{resolve-BQ9vjlNJ.mjs → resolve-Dj2MTBkn.mjs} +1 -1
  120. package/dist/{run-CeG0KH5W.mjs → run-DUcdaZs3.mjs} +6 -5
  121. package/dist/{run-CjhD-Zbr.mjs → run-QYJ-mAaG.mjs} +9 -8
  122. package/dist/{runs-6k8C6kXF.mjs → runs-DgasTnGd.mjs} +8 -7
  123. package/dist/{runtime-CmAIahm5.mjs → runtime-BJtuxWM8.mjs} +5 -3
  124. package/dist/{schema-tables-C45QegaY.mjs → schema-tables-ooYjimrV.mjs} +8 -7
  125. package/dist/{schemas-EVwEFuTj.mjs → schemas-HjFPzsd-.mjs} +6 -5
  126. package/dist/{search-C_uw_D1U.mjs → search-vaT5EwhG.mjs} +11 -5
  127. package/dist/segment-BPC725mo.mjs +25 -0
  128. package/dist/{selectors-AktxTEMK.mjs → selectors-DlmZpo2L.mjs} +3 -3
  129. package/dist/{set-C3EAuyb8.mjs → set-CLHJauzG.mjs} +9 -8
  130. package/dist/{set-active-BW6LN6y0.mjs → set-active-oZOUe9V7.mjs} +6 -5
  131. package/dist/setting-DHYO-W5g.mjs +20 -0
  132. package/dist/{setup-CYrbNrlG.mjs → setup-D1de5Sbc.mjs} +8 -7
  133. package/dist/{skills-DJsuBguh.mjs → skills-B6gfH0iR.mjs} +1 -1
  134. package/dist/{skills-D6xQkmhu.mjs → skills-NhgVypJ7.mjs} +3 -3
  135. package/dist/snippet-DtLmHr2J.mjs +22 -0
  136. package/dist/{stash-C1V2FvJR.mjs → stash-DoRwelwY.mjs} +9 -8
  137. package/dist/{status-CxYw6zQM.mjs → status-BpMOlfsA.mjs} +8 -7
  138. package/dist/{status-DY92F9mn.mjs → status-CmRgHTrV.mjs} +6 -5
  139. package/dist/{summary-DOxgqJoA.mjs → summary-BEu7pmpq.mjs} +7 -6
  140. package/dist/{sync-schema-CQPfffjU.mjs → sync-schema-DTUXubMg.mjs} +11 -10
  141. package/dist/table-B1iBqmNu.mjs +22 -0
  142. package/dist/{table-CDMG0Zi5.mjs → table-DE3i82T_.mjs} +1 -1
  143. package/dist/transform-BuIooRQh.mjs +31 -0
  144. package/dist/transform-job-C3yz0krA.mjs +25 -0
  145. package/dist/transform-tag-CJD6mJUe.mjs +21 -0
  146. package/dist/{transforms-DzBJDydn.mjs → transforms-CWvMpLc9.mjs} +7 -6
  147. package/dist/{tree-B3f5F_dP.mjs → tree-D18vYSe4.mjs} +6 -5
  148. package/dist/{unpublish-B5RDeN-V.mjs → unpublish-CJbL4ZsC.mjs} +7 -6
  149. package/dist/{update-DSueNZRw.mjs → update-7DacwIvi.mjs} +10 -9
  150. package/dist/{update-D5gioyBa.mjs → update-BjjZIe2W.mjs} +10 -9
  151. package/dist/{update-C0pFSc1B.mjs → update-Bos8nnv0.mjs} +18 -13
  152. package/dist/{update-PZPNx0Xd.mjs → update-BvsvyBw9.mjs} +17 -12
  153. package/dist/{update-DudyZ-FP.mjs → update-CSxwZ2us.mjs} +11 -10
  154. package/dist/{update-CiWPEqQ-.mjs → update-Ck0Kxv8u.mjs} +10 -9
  155. package/dist/{update-D698CaeV.mjs → update-DV7IY7IQ.mjs} +10 -9
  156. package/dist/{update-DOfL_KPx.mjs → update-DhOfrW1j.mjs} +19 -13
  157. package/dist/{update-BIZ9XhjS.mjs → update-Doia9MP_.mjs} +17 -12
  158. package/dist/{update-I3TA2Tem.mjs → update-Dxa_6H2A.mjs} +22 -13
  159. package/dist/{update-dashcard-BXZ4vS15.mjs → update-dashcard-CZUWZhal.mjs} +11 -9
  160. package/dist/{update-CcvDVqNd.mjs → update-mr9todHq.mjs} +10 -9
  161. package/dist/{upgrade-4cWfLu90.mjs → upgrade-CBW8V9qZ.mjs} +7 -6
  162. package/dist/{uuid---pAboNQ.mjs → uuid-D6JVJ-R1.mjs} +10 -5
  163. package/dist/{validate-VawhJ5Sc.mjs → validate-BqNW4Sk1.mjs} +2 -2
  164. package/dist/{validate-query-CSV-TTnd.mjs → validate-query-CcZVKYPV.mjs} +3 -3
  165. package/dist/{values-I503dI7K.mjs → values-DBvuGnnA.mjs} +7 -6
  166. package/dist/{verify-BMhTWW9s.mjs → verify-LIShMNZ2.mjs} +2 -2
  167. package/dist/{wait-oMSs_IdS.mjs → wait-DUHze3_B.mjs} +8 -7
  168. package/dist/{wait-flags-HtCL2l1r.mjs → wait-flags-Ybpt98PK.mjs} +2 -2
  169. package/package.json +1 -1
  170. package/skill-data/core/SKILL.md +44 -56
  171. package/skill-data/data-workflow/SKILL.md +116 -0
  172. package/skill-data/{data-analysis/SKILL.md → data-workflow/references/answering-questions.md} +7 -13
  173. package/skill-data/{data-transformation/SKILL.md → data-workflow/references/building-clean-tables.md} +23 -32
  174. package/skill-data/{semantic-layer/SKILL.md → data-workflow/references/reusable-definitions.md} +26 -56
  175. package/skill-data/document/SKILL.md +10 -20
  176. package/skill-data/git-sync/SKILL.md +36 -36
  177. package/skill-data/mbql/SKILL.md +3 -15
  178. package/skill-data/mbql/references/operators.md +9 -0
  179. package/skill-data/transform/SKILL.md +26 -42
  180. package/skill-data/visualization/SKILL.md +6 -6
  181. package/skill-data/visualization/references/settings.md +12 -0
  182. package/skills/metabase-cli/SKILL.md +2 -2
  183. package/dist/add-collection-BqfYL4FU.mjs +0 -10
  184. package/dist/auth-BaCMFLTA.mjs +0 -19
  185. package/dist/card-DzH3aK0a.mjs +0 -20
  186. package/dist/collection-Wagz-ira.mjs +0 -20
  187. package/dist/dashboard-OUgS1Gi-.mjs +0 -21
  188. package/dist/db-Btfl5JMZ.mjs +0 -22
  189. package/dist/document-CU28GfFw.mjs +0 -19
  190. package/dist/field-BTbzlcyC.mjs +0 -18
  191. package/dist/git-sync-CBxS2urR.mjs +0 -28
  192. package/dist/is-dirty-Z-pqyVyB.mjs +0 -9
  193. package/dist/library-BlbH0xyK.mjs +0 -18
  194. package/dist/measure-BUedPu4K.mjs +0 -19
  195. package/dist/segment-CkZUZcWz.mjs +0 -19
  196. package/dist/setting-C50HEiGG.mjs +0 -17
  197. package/dist/snippet-BjaWAxCu.mjs +0 -19
  198. package/dist/table-B35ovbcd.mjs +0 -19
  199. package/dist/transform-DF79sJ0_.mjs +0 -25
  200. package/dist/transform-job-PmA_D8gz.mjs +0 -22
  201. package/dist/transform-tag-CE3cuO1K.mjs +0 -18
  202. package/skill-data/robot-data-engineer/SKILL.md +0 -142
  203. /package/dist/{body-flags-D7q87Btw.mjs → body-flags-DWTTxJpP.mjs} +0 -0
  204. /package/dist/{collection-Deiziuu2.mjs → collection-DrLpA1SO.mjs} +0 -0
  205. /package/dist/{document-qfwR0r63.mjs → document-1W7NRaO_.mjs} +0 -0
  206. /package/dist/{field-E0IBy4Uw.mjs → field-CMY_LWUe.mjs} +0 -0
  207. /package/dist/{measure-BCv5wDDN.mjs → measure-DoJvtCaA.mjs} +0 -0
  208. /package/dist/{paginate-BexjkjbY.mjs → paginate-FVZUxL4J.mjs} +0 -0
  209. /package/dist/{render-CkuFkWlQ.mjs → render-BTKnWL0d.mjs} +0 -0
  210. /package/dist/{revision-message-flag-CP5NFrWQ.mjs → revision-message-flag-CHrJgFFx.mjs} +0 -0
  211. /package/dist/{segment-BAUuELKs.mjs → segment-TXktTCfU.mjs} +0 -0
  212. /package/dist/{setting-DhMk0TNo.mjs → setting-m46MUtW5.mjs} +0 -0
  213. /package/dist/{snippet-D4SyVLKB.mjs → snippet-CtA2Pkoa.mjs} +0 -0
  214. /package/dist/{transform-MmqHKGU-.mjs → transform-DEF38FWe.mjs} +0 -0
  215. /package/dist/{transform-job-CtVziW85.mjs → transform-job-CtixL4An.mjs} +0 -0
  216. /package/dist/{transform-tag-wFiWmiyO.mjs → transform-tag-rsIrckCM.mjs} +0 -0
@@ -1,6 +1,6 @@
1
- import { ConfigError } from "./command-augment-CAur0XOQ.mjs";
2
- import { writeJson } from "./capabilities-BX1rnVuH.mjs";
3
- import { assertNotLegacyEnvelopeWrappingMbql5, isMbql5Query, validateQuery } from "./validate-VawhJ5Sc.mjs";
1
+ import { ConfigError } from "./notice-DyVl5aYB.mjs";
2
+ import { writeJson } from "./capabilities-N0jo5U7S.mjs";
3
+ import { assertNotLegacyEnvelopeWrappingMbql5, isMbql5Query, validateQuery } from "./validate-BqNW4Sk1.mjs";
4
4
 
5
5
  //#region src/commands/validate-query.ts
6
6
  const skipValidateFlag = { "skip-validate": {
@@ -1,9 +1,10 @@
1
- import "./command-augment-CAur0XOQ.mjs";
2
- import { connectionFlags, outputFlags, profileFlag } from "./error-CIObEXLY.mjs";
3
- import { defineMetabaseCommand } from "./runtime-CmAIahm5.mjs";
4
- import { formatScalar, renderSummary } from "./capabilities-BX1rnVuH.mjs";
5
- import { FieldValues, fieldValuesView } from "./field-E0IBy4Uw.mjs";
6
- import { parseId } from "./parse-id-B5adfBlS.mjs";
1
+ import "./notice-DyVl5aYB.mjs";
2
+ import { connectionFlags, outputFlags, profileFlag } from "./error-5H_tcfL8.mjs";
3
+ import "./command-augment-DdZIfx1V.mjs";
4
+ import { defineMetabaseCommand } from "./runtime-BJtuxWM8.mjs";
5
+ import { formatScalar, renderSummary } from "./capabilities-N0jo5U7S.mjs";
6
+ import { FieldValues, fieldValuesView } from "./field-CMY_LWUe.mjs";
7
+ import { parseId } from "./parse-id-D4LeTUsP.mjs";
7
8
 
8
9
  //#region src/commands/field/values.ts
9
10
  var values_default = defineMetabaseCommand({
@@ -1,5 +1,5 @@
1
- import { MetabaseError, NetworkError, TimeoutError, errorMessage } from "./command-augment-CAur0XOQ.mjs";
2
- import { HttpError, createClient, probeServer } from "./runtime-CmAIahm5.mjs";
1
+ import { MetabaseError, NetworkError, TimeoutError, errorMessage } from "./notice-DyVl5aYB.mjs";
2
+ import { HttpError, createClient, probeServer } from "./runtime-BJtuxWM8.mjs";
3
3
  import { z } from "zod";
4
4
 
5
5
  //#region src/domain/user.ts
@@ -1,10 +1,11 @@
1
- import "./command-augment-CAur0XOQ.mjs";
2
- import { connectionFlags, outputFlags, profileFlag } from "./error-CIObEXLY.mjs";
3
- import { defineMetabaseCommand } from "./runtime-CmAIahm5.mjs";
4
- import { renderSummary } from "./capabilities-BX1rnVuH.mjs";
5
- import { parseId } from "./parse-id-B5adfBlS.mjs";
6
- import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-AduuU55-.mjs";
7
- import { SyncTaskOrIdle, formatSyncTask, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-B00Qwd87.mjs";
1
+ import "./notice-DyVl5aYB.mjs";
2
+ import { connectionFlags, outputFlags, profileFlag } from "./error-5H_tcfL8.mjs";
3
+ import "./command-augment-DdZIfx1V.mjs";
4
+ import { defineMetabaseCommand } from "./runtime-BJtuxWM8.mjs";
5
+ import { renderSummary } from "./capabilities-N0jo5U7S.mjs";
6
+ import { parseId } from "./parse-id-D4LeTUsP.mjs";
7
+ import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-BpAJpvb-.mjs";
8
+ import { SyncTaskOrIdle, formatSyncTask, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-TilgciQn.mjs";
8
9
 
9
10
  //#region src/commands/git-sync/wait.ts
10
11
  const WaitResult = SyncTaskOrIdle;
@@ -1,5 +1,5 @@
1
- import { parseId } from "./parse-id-B5adfBlS.mjs";
2
- import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-AduuU55-.mjs";
1
+ import { parseId } from "./parse-id-D4LeTUsP.mjs";
2
+ import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-BpAJpvb-.mjs";
3
3
 
4
4
  //#region src/commands/wait-flags.ts
5
5
  const waitScheduleFlags = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metabase/cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Metabase CLI",
5
5
  "license": "AGPL-3.0",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: core
3
- description: Drive a Metabase instance from the terminal via the `mb` CLI — auth, databases, cards, dashboards, documents, collections, transforms, queries, search, git-sync. Use for any `mb verb` task.
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 `mb __manifest`, and the per-resource footguns (db, table, field, card, dashboard, collection, segment, measure, 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
 
@@ -15,44 +15,38 @@ auth | db | table | field | query | card | dashboard | snippet | segment | measu
15
15
  document | transform | transform-job | transform-tag | setting | search | git-sync | setup | eid | uuid | upgrade | skills
16
16
  ```
17
17
 
18
- The patterns below — auth, flag conventions, output flags, body input — apply across **every** group. Per-command flags, examples, and output schemas live in `mb __manifest` (see below). A few flows have their own specialized 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.
18
+ The conventions below — auth, flags, output, body input — hold across **every** group. Per-command flags, examples, and output schemas live in `mb __manifest`. 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.
19
19
 
20
20
  ## Auth & profiles
21
21
 
22
- **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's role is to _check_ what profiles exist, _ask_ which to use, and pass `--profile <name>` through every command.
23
-
24
- ### Discover what's already configured
22
+ **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.
25
23
 
26
24
  ```bash
27
- mb auth list --json # → {data: [{profile, url, authenticated, status, …}], returned, total}
25
+ mb auth list --json # → {data:[{profile,url,authenticated,status,…}], returned, total}
28
26
  mb auth status --json # → {profile, present, url} for the default profile
29
- mb auth status --profile <name> --json # → status of a specific profile
27
+ mb auth status --profile <name> --json # health probe for one profile
30
28
  ```
31
29
 
32
- `auth list` is the primary enumeration path — one call returns every configured profile with sanitized URL, an `authenticated` flag, and a probe `status` (`ok` / `auth-failed` / `network-error` / `server-error` / `not-probed`). Use it before asking which profile to pick. If it returns an empty `data: []`, ask the user to run `mb auth login` themselves (see the policy above) and tell you the profile name. `auth status` is a single-profile health probe when you already know the name.
30
+ `auth list` is the primary enumeration path — one call returns every profile with sanitized URL, an `authenticated` flag, and a probe `status` (`ok` / `auth-failed` / `network-error` / `server-error` / `not-probed`). Use it before asking which profile to pick.
33
31
 
34
- ### Pick the profile to use
32
+ - One profile and intent doesn't disambiguate → use it.
33
+ - Several → ask via `AskUserQuestion`, presenting the names from `auth list`.
34
+ - Empty `data: []` → ask the user to run `mb auth login` themselves and tell you the profile name.
35
35
 
36
- If exactly one profile is configured and intent doesn't disambiguate, use it. If multiple exist and the user hasn't named one, ask via `AskUserQuestion`, presenting the names from `auth list`. Once a name is established, pass `--profile <name>` to **every** subsequent command. Profile names are arbitrary local labels — `prod`, `staging` — let the user pick.
36
+ Once a name is established, pass `--profile <name>` to **every** subsequent command. Profile names are arbitrary local labels (`prod`, `staging`).
37
37
 
38
38
  ## Flag conventions
39
39
 
40
- ### `--profile` is per-subcommand, not global
40
+ **`--profile` is per-subcommand — it attaches after the full verb chain, not before it.**
41
41
 
42
42
  ```bash
43
43
  ✅ mb table list --profile prod --json
44
44
  ❌ mb --profile prod table list # → error: "Unknown command prod"
45
45
  ```
46
46
 
47
- `--profile` attaches **after** the full verb chain (`table list`, `card get`, `git-sync export`).
48
-
49
- ### `--wait` for async operations
50
-
51
- `transform run`, `git-sync import`, and similar async verbs return immediately by default. Pass `--wait` for any interactive flow where the next step depends on completion. Without it you'll race the operation and see "not ready" / transient connection refusals.
47
+ **`--wait` for async operations.** `transform run`, `git-sync import`, and similar verbs return immediately by default. Pass `--wait` whenever the next step depends on completion — without it you race the operation and see "not ready" / transient connection refusals.
52
48
 
53
- ### Some outputs are JSON envelopes, not bare strings
54
-
55
- A handful of "lookup" verbs return a JSON object even for a single field. `mb setting get <key>` returns `{"key": "...", "value": ...}`, not the bare value. Extract before reusing:
49
+ **Some "lookup" verbs return JSON envelopes, not bare values.** `mb setting get <key>` returns `{"key": "...", "value": ...}`. Extract before reusing:
56
50
 
57
51
  ```bash
58
52
  VALUE=$(mb setting get <key> --json | jq -r '.value')
@@ -63,9 +57,9 @@ VALUE=$(mb setting get <key> --json | jq -r '.value')
63
57
  Every list/get verb supports the same output flags:
64
58
 
65
59
  - `--json` — emit the full JSON envelope, safe for `jq`. Default is human-readable text.
66
- - `--full` — include every field (compact projection is the default for list/get).
67
- - `--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` (the projection runs per row) — `data.id` and `data[].id` both fail with `unknown field path: "data.id"`. On single-object verbs the path is root-relative: `--fields id,name,display` on `card get`, and `--fields data.rows` on `mb query` (whose `data` is an object, not an array).
68
- - `--max-bytes <n>` — cap **list** output size (drops trailing items, sets `truncated`). Default 65 536; `0` disables. Single-item commands (`get`, `metadata`) never truncate — they emit a stderr advisory when over the cap.
60
+ - `--full` — include every field (the compact projection is the default, and is the agent-facing contract).
61
+ - `--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).
62
+ - `--max-bytes <n>` — cap **list** output size (drops trailing items, sets `truncated`). Default 65536; `0` disables. Single-item commands (`get`, `metadata`) 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…"); raise `--max-bytes` or narrow with `--fields`.
69
63
 
70
64
  List envelope shape:
71
65
 
@@ -81,7 +75,7 @@ List envelope shape:
81
75
  }
82
76
  ```
83
77
 
84
- The compact item projection is the agent-facing contract — add `--full` for all Metabase fields. `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.
78
+ `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.
85
79
 
86
80
  ## Body input (create / update / run)
87
81
 
@@ -92,7 +86,7 @@ Verbs that take a payload accept it from one of four sources, **first non-empty
92
86
  3. stdin (auto-detected when piped, or explicit `--stdin` where supported)
93
87
  4. positional argument
94
88
 
95
- Exactly one required; passing two of `--body` + `--file` + `--stdin` is rejected with a `ConfigError`.
89
+ Exactly one required; passing two of `--body` / `--file` / `--stdin` is rejected with a `ConfigError`.
96
90
 
97
91
  ```bash
98
92
  cat > ./.scratch/body.json <<'EOF'
@@ -101,20 +95,14 @@ EOF
101
95
  mb <noun> create --file ./.scratch/body.json --profile <n> --json
102
96
  ```
103
97
 
104
- Single-quoted `'EOF'` prevents the shell from interpolating `$vars` inside the JSON.
98
+ Single-quoted `'EOF'` stops the shell interpolating `$vars` inside the JSON.
105
99
 
106
- Write these working files to **`./.scratch`** in the current directory (`mkdir -p ./.scratch` first), never `/tmp` — better permissions, they persist across the session, and the user can review them.
100
+ Write working files to **`./.scratch`** in the current directory (`mkdir -p ./.scratch` first), never `/tmp` — better permissions, they persist across the session, and the user can review them.
107
101
 
108
102
  ## Discover the full surface: `mb __manifest`
109
103
 
110
104
  The canonical, machine-readable inventory of every command — name, description, per-command `details`, examples, every flag with type and default, and the output JSON Schema:
111
105
 
112
- ```bash
113
- mb __manifest
114
- ```
115
-
116
- The leading `__` hides it from `--help`, but it's stable. Reach for it instead of `--help` per command — to enumerate verbs, validate flag names before constructing a command, or read an output schema before parsing. Pairs with `jq`:
117
-
118
106
  ```bash
119
107
  mb __manifest | jq -r '.commands[].command' # every command name
120
108
  mb __manifest | jq -r '.commands[] | select(.command | startswith("transform")) | .command' # verbs under "transform"
@@ -122,41 +110,41 @@ mb __manifest | jq '.commands[] | select(.command == "card query") | .args'
122
110
  mb __manifest | jq '.commands[] | select(.command == "card list") | .outputSchema' # output schema before parsing
123
111
  ```
124
112
 
113
+ The leading `__` hides it from `--help`, but it's stable. Reach for it instead of per-command `--help` to enumerate verbs, validate flag names, or read an output schema before parsing.
114
+
125
115
  ## Resource quirks worth memorizing
126
116
 
127
- Routine verb shapes (list / get / create / update), every flag, and output JSON Schemas live in `mb __manifest` — pull on demand. Below is only what the manifest does _not_ tell you: footguns and non-obvious behaviors.
117
+ Routine verb shapes (list / get / create / update), every flag, and output schemas live in `mb __manifest`. Below is only what the manifest does _not_ tell you: footguns and non-obvious behaviors.
128
118
 
129
119
  - **db traversal vs. rollup.** Default to granular: `database list` → `database schemas <db-id>` → `database schema-tables <db-id> <schema>` → `table get <table-id> --include fields`. The rollup endpoints (`database get --include tables.fields`, `database metadata <db-id>`) pull megabytes and blow the context window on any real warehouse — use them only on a small/dev db. `sync-schema` / `rescan-values` queue async work and return `{status:"ok"}` immediately; `sync-schema --wait` blocks until `initial_sync_status: complete`.
130
- - **table fields.** `table get` never returns fields on its own — pass `--include fields` (compact) or use `table fields <id>` (list envelope). `table metadata <id>` adds FKs + dimensions (heavier). `table update` patches table-level metadata only; physical columns aren't editable here.
131
- - **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. So the Library is 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 permission alone won't publish tables) 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; don't publish raw tables.
132
- - **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.
133
- - **card.** `dataset_query` is the **flat** `mbql/query` value, not a legacy `{type:"query",query:…}` envelope (→ `mbql` skill). `--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 the `viz` skill.
134
- - **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` against live server state and exit **2** with `{ok:false,errors:[…]}` on a bad ref — non-bypassable (no `--skip-validate`). `dashboard get <id>` (or `--full`) hydrates dashcards/tabs; `list` omits them. **Dashcard geometry: the grid is 24 columns wide.** Each dashcard's `{col, row, size_x, size_y}` is in grid units — `col` (0-indexed, left edge) and `size_x` are columns, `row`/`size_y` are rows; **full-width is `size_x: 24`** (`size_x: 12` is half a row — the usual cause of a card filling only half the width, since it's a common per-chart default). Keep `col + size_x ≤ 24`, start each card's `col` at 0 for a full-width stack, and don't overlap cards (the server stores whatever you send — it won't auto-fix collisions).
135
- - **snippet `--archived` is a swap, not a union** — list returns _either_ active _or_ archived rows, never both. (Same shape for `--filter archived` on dashboard/collection.)
136
- - **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` skill): segment = a filter, measure = exactly one aggregation.
137
- - **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.
138
- - **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 (it wraps bare-text responses into `{key, value}`).
120
+ - **table fields.** `table get` never returns fields on its own — pass `--include fields` (compact) or use `table fields <id>` (list envelope). `table metadata <id>` adds FKs + dimensions (heavier). `table update` patches table-level metadata only; physical columns aren't editable.
121
+ - **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.
122
+ - **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`.
123
+ - **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).
124
+ - **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.
125
+ - **snippet `--archived` is a swap, not a union** — list returns _either_ active _or_ archived rows, never both. (Same for `--filter archived` on dashboard/collection.)
126
+ - **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.
127
+ - **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`.
128
+ - **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}`).
139
129
  - **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.
140
- - **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 run's output table to register and returns `target_table_id`) or you get only `{run_id, final:null}`. (→ `transform` skill.)
130
+ - **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`.)
141
131
  - **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.
142
- - **eid** translates a string entity id → numeric id: `mb eid --model <model> <eid1,eid2> --json` (EIDs are a positional used with `--model`; or pass `--body '{"entity_ids":{"card":["…"]}}'`). Entity ids are NanoIDs that can start with `-`, which the positional form misreads as a flag (shell quotes don't help — the `-` survives into argv). For an id that may start with `-`, use `--body` — the id is a JSON string value, immune to flag parsing: `mb eid --body '{"entity_ids":{"card":["-…"]}}'`. Useful when an external system hands you an entity id and a verb needs the numeric one.
143
- - **query / uuid.** `mb query` is the ad-hoc MBQL surface (`--print-schema` → `--dry-run` → run); `mb uuid --count <n>` mints the `lib/uuid` values every MBQL 5 clause needs. Both workflows live in the `mbql` skill.
132
+ - **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).
133
+ - **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.
134
+ - **query / uuid.** `mb query` is the ad-hoc MBQL surface (`--print-schema` → `--dry-run` → run); `mb uuid --count <n>` mints the `lib/uuid` values every MBQL 5 clause needs. Both live in `mbql`.
144
135
 
145
136
  ## Specialized skills (load on demand)
146
137
 
147
- This core file is enough for any single-command task. Load the relevant skill **proactively** when intent matches — don't wing an MBQL body, a transform body, or the git-sync workflow from this overview alone. Load via `mb skills get <name>`.
148
-
149
- **Start here for anything bigger than one command.** If the user wants an outcome rather than a single verb — "make sense of my data", "build a data model", "go from raw data to a dashboard", "be my data analyst", "set up analytics for X", "answer questions about my data" — load `robot-data-engineer` first and let it route. The rest of this list is the toolbox it routes into.
138
+ This file is enough for any single-command task. For anything deeper, load the relevant skill **proactively** — don't wing an MBQL body, a transform body, or the git-sync workflow from this overview. Load via `mb skills get <name>`.
150
139
 
151
- - **`robot-data-engineer`** — the front-door router for the whole journey (raw data → clean tables → reusable definitions → dashboards or written answers) for a non-technical user. Detects where the user is, sets up auth and autonomy once, and routes to `data-transformation` / `semantic-layer` / `visualization` / `data-analysis`. Load this when the user describes a goal, not a step.
152
- - **`mbql`** — authoring or fixing any MBQL query body: `mb query`, a card `dataset_query`, a transform `source.query`, a measure/segment `definition`, "aggregate and group by", reading `--dry-run` errors. The query-body reference.
153
- - **`viz`** — choosing a card's `display` and authoring `visualization_settings`: "make it a bar chart", "set the pie dimension/metric", "format this column as currency", "the card renders as a table instead of a chart". The presentation counterpart to `mbql`.
154
- - **`transform`** — "create a transform", "run a transform", authoring transform body JSON, run inspection.
155
- - **`data-transformation`** — the higher-level workflow: turning a raw, normalized source database into a small set of clean, wide, analysis-ready tables for a non-technical user — "clean up", "flatten", "denormalize", "make sense of this database", "build analysis-ready tables". Wraps `transform` (the mechanics) with the investigate → propose → build flow.
156
- - **`semantic-layer`** — turning clean tables into reusable definitions: "make this filter reusable", "define active customers / net revenue / MRR officially", "create a segment / measure / metric", "so everyone uses the same definition". Builds on `mbql` (the definition bodies) and `transform` (widen a table first when a definition needs more than one).
157
- - **`git-sync`** — "import the latest changes", "export to git", "git sync", "dirty check", "stash before pulling".
140
+ - **`mbql`** — authoring/fixing any MBQL query body (`mb query`, card `dataset_query`, transform `source.query`, measure/segment `definition`); reading `--dry-run` errors. The query-body reference.
141
+ - **`visualization`** — choosing a card's `display` and authoring `visualization_settings`. The presentation counterpart to `mbql`.
142
+ - **`transform`** — transform body JSON, create + run-with-wait, run inspection, tags, jobs.
143
+ - **`document`** — Metabase documents (TipTap body, embedding cards).
144
+ - **`git-sync`** — round-tripping content to/from a git remote.
145
+ - **`data-workflow`** — the guided, end-to-end data workflow: investigate raw data, build clean analysis-ready tables, define reusable segments/measures/metrics, answer questions, build dashboards. **Start here when the user states a goal rather than a single verb** — "make sense of my data", "build a data model", "go from raw data to a dashboard", "be my data analyst", "set up analytics for X". It detects where the data is and routes to the right stage.
158
146
 
159
- If a task spans more than one, load each. Specialized skills assume the conventions above and won't repeat them. `mb skills list` enumerates everything on the installed version.
147
+ If a task spans more than one, load each. `mb skills list` enumerates everything on the installed version.
160
148
 
161
149
  ## Don't
162
150
 
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: data-workflow
3
+ description: Guided, end-to-end data work through the `mb` CLI — investigate a raw database, build clean analysis-ready tables, define reusable segments/measures/metrics, answer questions, and build dashboards. Detects where the data is, holds the shared conventions for collaborating with a human on data work, and carries the deep per-stage method in references. Use when the user states a data goal rather than a single command — "make sense of my data", "build a data model", "go from raw data to a dashboard", "be my data analyst", "set up analytics for X", "define active customers / MRR officially", "make this reusable", "who registered / what did people say".
4
+ allowed-tools: Read, Write, Edit, Bash, AskUserQuestion, EnterPlanMode, ExitPlanMode
5
+ ---
6
+
7
+ # Data workflow
8
+
9
+ The front door for turning a raw database into clean tables, reusable definitions, dashboards, and answers — all through the `mb` CLI. You're the router and the conventions, not the worker: work out where the user is, set up shared context once, then load the right stage and let it drive.
10
+
11
+ A data project moves through stages. A user can start at any of them — detect where their data already is, don't assume.
12
+
13
+ | Stage | What it does | Where the method lives |
14
+ | --------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
15
+ | **Build clean tables** | Raw, normalized source DB → a small set of wide, clean, analysis-ready tables (built as transforms) | `references/building-clean-tables.md` |
16
+ | **Define reusable metrics** | Clean tables → shared segments (saved filters), measures (saved calculations), metrics (official numbers) | `references/reusable-definitions.md` |
17
+ | **Answer questions** | Clean tables → a trustworthy plain-language written answer | `references/answering-questions.md` |
18
+ | **Build dashboards** | Clean tables / definitions → charts and dashboards people look at | the `visualization` skill (`mb skills get visualization`) |
19
+
20
+ The first three methods are references in this skill — read **only the one the current stage needs**: run `mb skills path data-workflow` and Read `references/<file>.md`. (`mb skills get data-workflow --full` appends all three at once — heavier; prefer the single Read.) "Build dashboards" is the standalone `visualization` skill because authoring a chart is a CLI capability in its own right.
21
+
22
+ CLI mechanics come from the reference skills, not from here: `mb skills get core` (auth, inspection, the `field`/`table`/`library`/`segment`/`measure` verbs), `mbql` (query and definition bodies), `transform` (creating/running transforms). This skill owns the _judgment_ — which tables, which definitions, what to keep — and the conventions below.
23
+
24
+ ## Setup — do this once, up front
25
+
26
+ 1. **Auth.** Pick the profile per `core`'s **Auth & profiles**: `mb auth list --json` — one → use it, several → ask which, none → ask the user to `mb auth login` — then carry `--profile <name>` into everything. That profile's `url` is the instance base URL the browser links in the references are built from. (Restated here because this skill may run before `core` is loaded; `core` is the full recipe.)
27
+
28
+ 2. **How hands-on they want to be — the autonomy slider.** Ask once, plainly:
29
+
30
+ > Quick thing — how hands-on do you want to be?
31
+ > • **Check with me on everything** — I'll run each step past you first.
32
+ > • **Balanced** (default) — I'll decide the obvious stuff and ask only when it matters.
33
+ > • **Just go** — I'll do what makes sense and show you the result.
34
+
35
+ Remember the answer for the whole session and apply it in every stage — don't re-ask when you move between stages.
36
+
37
+ ---
38
+
39
+ ## Shared Contract
40
+
41
+ The rules every stage follows. The reference files assume this contract rather than restating it.
42
+
43
+ **How you communicate.** You're doing data work for a human in the loop, and you usually can't tell how technical they are — the same request ("build me a dashboard about signups") comes from a domain expert and an engineer alike. Don't classify them. Instead:
44
+
45
+ - **Answer-first, detail on demand.** Lead every hand-off and decision with the plain-language point; keep the SQL / JSON / transform body _available if they ask_, never dumped on them and never hidden. One output then serves both readers — the domain expert stops at the sentence, the engineer asks for the query.
46
+ - **Mirror their words.** Match the vocabulary and terseness they use. With no signal yet (the first turn), start plain — clarity costs a fluent reader little, while jargon loses a non-technical one. The Jargon guidance below _is_ that plain default; relax it once they show fluency (they write SQL, use schema terms, ask for the raw query).
47
+ - **Rigor never flexes with register.** Terse or technical never means skip work: the method and checks below — decode, wire foreign keys, verify — run the same for everyone. Register changes what you _say_, never what you _do_.
48
+ - **Two things hold regardless of audience:** the PII and permission-denied guardrails below, and the verifiability touchpoints — say a non-obvious business rule back in plain terms and confirm it, and end with a recap plus something to open and eyeball. A technical user still can't see a wrong rule buried in a table; confirming it is correctness, not hand-holding.
49
+
50
+ **Jargon (the plain default).** Skip warehouse vocabulary a non-database reader won't know — grain, fact/dimension table, normalize, denormalize, surrogate key, materialize — and prefer plain phrasing: "one row per \_\_\_", "what it tells you", "links up with", "how full a column is". Don't overdo it: basic relational terms are fine — table, column, ERD, schema, key, foreign key, cardinality. **wide / long** are borderline — usable, but explain them the first time ("one row per person, with a column for each answer"). **Metabase's product terms are encouraged** — Question, Model, Segment, Measure, Metric, Transform — they're the user's tools, not jargon.
51
+
52
+ **PII.** Survey and registration data holds personal information — names, emails, phones, emergency contacts. Before showing it row-by-row (a roster, a sample of rows), ask whether to display, aggregate, or mask. Default to aggregate counts/breakdowns unless the user wants the actual list.
53
+
54
+ **Capability limits — know what you can't do.** The `mb` CLI authors and queries content, but it isn't the whole Metabase product. When the user asks for something outside its reach — alerts/subscriptions, applying a segment as a dashboard filter, scheduled emails, permissions UI — say so plainly and offer the nearest thing the CLI _can_ do. Don't attempt it, hit a server error, and surface raw SQL or a stack trace.
55
+
56
+ **Permission denied — stop, diagnose, offer a way back.** When a query fails with "permission denied", never quietly run a _different_ readable table and present its numbers as the answer. Instead, in order:
57
+
58
+ 1. **Stop.** Don't substitute another table.
59
+ 2. **Surface and diagnose in plain terms.** Name what was denied and the likely reason. The usual three: _right table, wrong login_ — it exists, but this CLI login isn't granted it (common on staging — a config thing, not a data problem); _right name, wrong copy_ — a readable table of a similar name lives in another schema/database; _name slightly off_ — what they called it isn't the real table name. E.g. "I can't read `analytics.account` — this login doesn't have access. That's usually a staging-permissions thing, not a problem with your data."
60
+ 3. **Offer to search — don't auto-crawl.** Ask first: "Want me to look for a table with a similar name this login _can_ read?" Only on yes, run `mb search` / `mb table list`, and surface any match as a **confirm question**, never a substituted answer.
61
+ 4. **Hand control back.** Don't propose or run a fix you can't reliably execute — no `GRANT`, no profile-switching. Recovery is the user's call.
62
+
63
+ **Scratch files.** Working files go in `./.scratch` (`mkdir -p` if absent), never `/tmp` — per `core`'s body-input section.
64
+
65
+ **Talking to the user.** Easy habits to slip on:
66
+
67
+ - **Don't reference things they never saw.** If you built a helper table or ran a probe earlier, reintroduce it in their terms or don't mention it.
68
+ - **Assume they read only the last ~30 lines.** Don't lean on context from far up; restate what they need to act on your question.
69
+ - **Plain permission requests.** Don't paste a wall of SQL/JSON and ask "run this?". Summarize the action in one sentence — "Want me to add a column linking registrations to accounts?" — and offer the details if they ask.
70
+
71
+ **Questions must carry their own context.** People hit go, step away, and skim the stretches where you think out loud. So whenever you ask for input, put the context the question depends on _right before it_, not as a back-reference. Lead with a short recap of only the few points the question turns on:
72
+
73
+ > Quick recap so this makes sense:
74
+ >
75
+ > - I found a mismatch in ...
76
+ > - It matters because ...
77
+ > - Here's what I was thinking, but I need to check ...
78
+ >
79
+ > The question.
80
+
81
+ **When genuinely unsure, ask — never assume.** "Just go" means _decide the obvious_, not _guess on the unclear_. A wrong-but-confident definition is worse than a one-line question. This holds in every autonomy mode.
82
+
83
+ **The final hard stop.** Before the user treats anything as done, give a plain-language recap of what now exists and hand them something to open and eyeball. Each stage stops within itself; **you** own the end-of-journey stop.
84
+
85
+ ---
86
+
87
+ ## Work out where they are, then route
88
+
89
+ Don't make the user name a _stage_ — but do find out _where their data lives_ before going looking.
90
+
91
+ **Ask before you crawl.** If you don't already know which database/schema/table the user means, ask — one plain question short-circuits a dozen tool calls. The asymmetry: if they name a **database**, ask which **schema**; if they name a **table**, ask which **database**. "If you don't know, no problem — I'll look" is the fallback, not the opener.
92
+
93
+ **When you do crawl,** use `core`'s cheap, narrowest-first ladder (never whole-warehouse rollups): `mb db list` → `db schemas <id>` → `db schema-tables <id> <schema>` → `table list [--db-id]` → `table fields <id>` (or `table metadata <id>` for FK targets and dimensions — heavier). Have a _name_ rather than a tree to walk? `mb search <query> [--models] [--db-id]`. Need to know what's in a column? `mb field summary <id>` (counts) and `field values <id>` (sample values). If a database looks freshly connected or an expected table is missing, offer `mb db sync-schema <id> --wait` before concluding it doesn't exist.
94
+
95
+ **Read the shape to pick a stage.** Raw, normalized, SaaS-synced tables (many tables, coded columns, `*_field`/`*_choice` lookups)? → **build clean tables** first. Already wide, clean, human-readable ones? Then it depends on the goal:
96
+
97
+ | What the user wants / what's there | Stage |
98
+ | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
99
+ | "Clean up / flatten / make sense of" raw, normalized data; no clean tables yet | Build clean tables → `references/building-clean-tables.md` |
100
+ | Clean tables exist; "make this reusable", "define active customers / revenue / MRR officially" | Define reusable metrics → `references/reusable-definitions.md` |
101
+ | Clean tables exist; "answer this question", "who registered", "analyze / report on X" (wants a written answer) | Answer questions → `references/answering-questions.md` |
102
+ | Clean tables (and maybe definitions) exist; "chart this", "build a dashboard", "show me X over time" | Build dashboards → `mb skills get visualization` |
103
+ | "Do the whole thing" / "set up analytics for X" from raw data | Start at build-clean-tables, then continue down the stages |
104
+
105
+ **Answer and dashboard are alternative endpoints, not a sequence.** Once tables are clean (and maybe defined), answering in prose and building a dashboard are two different things you can do with the data — route to whichever the goal calls for; neither has to precede the other.
106
+
107
+ **If state and goal disagree** — they ask for a dashboard but there are only raw tables — say so plainly and offer the earlier stage first: _"There aren't clean tables to chart yet — want me to build those first, then we'll chart them?"_ Don't silently build on raw data.
108
+
109
+ **The whole journey.** For the full arc (raw → dashboard), run the stages in order; let each stage's stopping point double as a check-in. No heavy gate between stages, but in **Check with me on everything** mode confirm the user's happy before the next. A user can drop in at any stage — someone with clean tables who just wants metrics goes straight to the reusable-definitions method; don't drag them back through cleaning. Always finish with your end-of-journey recap.
110
+
111
+ ## Don't
112
+
113
+ - **Don't do the deep work from this file.** It routes and sets conventions; the per-stage reference (or the `visualization` skill) carries the method. Read the one the current stage needs.
114
+ - **Don't re-ask the autonomy question** once it's set; apply it across stages.
115
+ - **Don't skip the starting-state check** and assume raw data — a user with clean tables shouldn't be sent through cleaning.
116
+ - **Don't drop the final recap** — you own the end-of-journey hard stop.
@@ -1,16 +1,10 @@
1
- ---
2
- name: data-analysis
3
- description: Answer real questions from clean, analysis-ready tables and hand back a plain-language report - an answer-finding task, not chart-building. Read the tables, turn the user's question into queries, run them on the live instance, sanity-check the numbers, write up findings the user can trust. Works over already-clean (wide, human-readable) data - survey/registration answers, event signups, customer lists, anything where the data holds the answer. Use when someone wants to "answer questions about my data", "report on who registered / signed up / responded", "what did people say", "analyze X", "explore this data", or "build me a report". For a non-technical user who knows their domain. Needs charts/dashboards? Use `visualization`. Tables still raw? Use `data-transformation` first.
4
- allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
5
- ---
6
-
7
- # Data Analysis
1
+ # Answer questions
8
2
 
9
- > **Shared contract (read first).** This skill is part of the `robot-data-engineer` family and follows its shared rules: audience is a non-technical user, so no database jargon (skip "normalize"/"grain"; ERD/foreign key are fine; explain "wide"/"long" the first time you use them). Ask before showing PII row-by-row (names, emails, phones) — default to aggregates. When asked for something the CLI can't do (alerts, dashboard filters), name the limit instead of erroring into raw SQL. Honor the autonomy mode the user picked. Full text and the autonomy slider live in the router — run `mb skills get robot-data-engineer` and read its **Shared Contract** if you haven't.
3
+ > Part of the **`data-workflow`** skill — the "answer questions" stage. It assumes that skill's **Shared Contract** (how to communicate, PII, autonomy, permission-denied) and final-recap rule. CLI mechanics: `mbql` / `mb query` for running queries.
10
4
 
11
5
  The user has a question and clean data that already holds the answer. Your job: find the answer, check it's right, and hand it back in plain language. You're an analyst, not a dashboard builder — the deliverable is a **trustworthy written answer**, optionally backed by a saved question they can re-open.
12
6
 
13
- This skill assumes the tables are already clean (wide, human-readable). If they're raw and normalized — lots of `*_field`/`*_choice` lookups, coded columns, JSON blobs — stop and route to `data-transformation` first; don't analyze on top of a mess.
7
+ This stage assumes the tables are already clean (wide, human-readable). If they're raw and normalized — lots of `*_field`/`*_choice` lookups, coded columns, JSON blobs — stop and route to the **build-clean-tables** stage first (`references/building-clean-tables.md`); don't analyze on top of a mess.
14
8
 
15
9
  ---
16
10
 
@@ -20,7 +14,7 @@ For each question the user asks:
20
14
 
21
15
  1. **Find where the answer lives.** List tables (`mb table list`, `mb db schema-tables <db> <schema>`). Read the columns (`mb table fields <id>`). Clean datasets often ship the same facts two ways — a **wide** table (one row per thing, easy to read) and a **long** table (one row per attribute, easy to aggregate over many-valued answers). Pick the one that fits the question: per-person facts → wide; "which option was most popular" across a multi-select → long.
22
16
 
23
- 2. **Turn the question into a query.** Write it, run it (`mb query`). Start small — a `count(*)` and a couple of sample rows to confirm you're pointed at the right table and the columns mean what you think. Then write the real query.
17
+ 2. **Turn the question into a query.** Write it, run it (`mb query`). Start small — a `count(*)` and a couple of sample rows to confirm you're pointed at the right table and the columns mean what you think. Then write the real query. Query mechanics → `mbql` / `mb query`.
24
18
 
25
19
  3. **Sanity-check before you believe it.** A number with no cross-check is a guess. Confirm row counts against a total you trust, watch for nulls/blanks inflating or deflating a percentage, and re-read the column you grouped on — a `type/Category` column with "confirmed"/"cancelled" means your "how many registered" answer depends on which statuses you counted. State the denominator.
26
20
 
@@ -42,7 +36,7 @@ When genuinely unsure which interpretation they mean, ask — never silently pic
42
36
 
43
37
  ## Survey / registration data — the common shape
44
38
 
45
- A lot of "analyze who registered / what did people say" work lands on event or survey data, which has a recognizable shape worth calling out:
39
+ A lot of "analyze who registered / what did people say" work lands on event or survey data, which has a recognizable shape:
46
40
 
47
41
  - A **per-registrant wide table** — name, company, role, status, plus one column per single-answer question. Use it for "who registered", rosters, breakdowns by role/version/company, and any per-person filter.
48
42
  - A **long answers table** — one row per (registrant, question, answer). Use it for **multi-select** questions (one person picks several options, so they can't flatten into one wide column) and for "which option was chosen most". Group by the question text, then by the answer value.
@@ -58,8 +52,8 @@ Three report families cover most asks:
58
52
 
59
53
  ## Don't
60
54
 
61
- - **Don't analyze raw, un-cleaned tables.** If the data is normalized/coded/JSON, route to `data-transformation` first and analyze the clean output.
55
+ - **Don't analyze raw, un-cleaned tables.** If the data is normalized/coded/JSON, route to the **build-clean-tables** stage first and analyze the clean output.
62
56
  - **Don't report a number you didn't sanity-check.** No denominator, no null-check → no answer.
63
57
  - **Don't silently pick a scope.** "Registered" vs "confirmed", all-time vs window — state which you used, or ask.
64
- - **Don't build charts/dashboards here.** A written answer (and maybe one saved question) is the deliverable; if they want it visual, that's `visualization`.
58
+ - **Don't build charts/dashboards here.** A written answer (and maybe one saved question) is the deliverable; if they want it visual, that's the `visualization` skill.
65
59
  - **Don't only count free-text.** Quote the real responses — the words carry the insight a count throws away.