@metabase/cli 0.3.0 → 0.3.1-alpha.transform-tests.3fbcf8b
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.
- package/dist/{add-collection-B3Ty8SzB.mjs → add-collection-C-XJPp3F.mjs} +2 -2
- package/dist/{alert-DT-ee7yf.mjs → alert-Klz8Bhst.mjs} +6 -6
- package/dist/{alerts-Bf2RH_p_.mjs → alerts-Bp2vByJf.mjs} +3 -3
- package/dist/{append-DFzQRPMd.mjs → append-D16_s1HW.mjs} +4 -3
- package/dist/{archive-ChORH5JH.mjs → archive-BOJUGwyL.mjs} +2 -2
- package/dist/{archive-CwAdlv63.mjs → archive-Bj4MjbJY.mjs} +2 -2
- package/dist/{archive-ByvA49Kz.mjs → archive-C9iNjXcI.mjs} +2 -2
- package/dist/{archive-Cd29QC0c.mjs → archive-CA-HIfQq.mjs} +2 -2
- package/dist/{archive-4tmm946K.mjs → archive-D4nGMs8A.mjs} +2 -2
- package/dist/{archive-B6eXiyER.mjs → archive-Dd7ZTibw.mjs} +2 -2
- package/dist/{archive-lQqs13Uz.mjs → archive-Q_qUuYh8.mjs} +2 -2
- package/dist/{archive-BxNPHxOY.mjs → archive-RzzXt2V0.mjs} +2 -2
- package/dist/{archive-C7w49Grr.mjs → archive-lDnTIypd.mjs} +2 -2
- package/dist/{archive-gid9Y09v.mjs → archive-nDvHMzTv.mjs} +2 -2
- package/dist/{archive-Dr9Xnx_Z.mjs → archive-vzu8ghZZ.mjs} +4 -4
- package/dist/{auth-Dltxua89.mjs → auth-kyPQfiND.mjs} +4 -4
- package/dist/{body-Cur4NJt9.mjs → body-DxRSAMNC.mjs} +1 -1
- package/dist/{branches-DchlyU0i.mjs → branches-QixvzIpl.mjs} +1 -1
- package/dist/{cancel-BMQa5R1Z.mjs → cancel-CPStS4zJ.mjs} +2 -2
- package/dist/{cancel-task-C5CU1pxU.mjs → cancel-task--cuSISnl.mjs} +1 -1
- package/dist/{card-CHI2bmds.mjs → card-p2r_szeS.mjs} +7 -7
- package/dist/{cards-SccWvRQD.mjs → cards-CNbV8aGO.mjs} +4 -4
- package/dist/cli.mjs +32 -30
- package/dist/{client-BqhzKdLM.mjs → client-DynvZqa0.mjs} +98 -10
- package/dist/{collection-CY0AB99E.mjs → collection-CAM47Der.mjs} +6 -6
- package/dist/{collection-namespace-GwydWBF3.mjs → collection-namespace-CEoQ7G08.mjs} +1 -1
- package/dist/content-translation-BrHOrmj9.mjs +5 -0
- package/dist/content-translation-CxTabpLF.mjs +12 -0
- package/dist/{create-DV-Ln5Mo.mjs → create-BGV7ejai.mjs} +2 -2
- package/dist/{create-C79vErX0.mjs → create-BGy4L_yh.mjs} +2 -2
- package/dist/{create-DJmXXQoq.mjs → create-BMokmmLp2.mjs} +3 -3
- package/dist/{create-CAWytBE5.mjs → create-BTvSwLws.mjs} +2 -2
- package/dist/{create-Beh-2uoN.mjs → create-BikaTHCw.mjs} +2 -2
- package/dist/{create-zeveFdnd.mjs → create-BsvpUxJq.mjs} +1 -1
- package/dist/{create-DF4QtgDL.mjs → create-CEP4Jsrd.mjs} +2 -2
- package/dist/{create-i14Wv3Tj.mjs → create-CYhsYOOJ.mjs} +2 -2
- package/dist/{create-CD008jdE.mjs → create-CsABLrSI.mjs} +6 -6
- package/dist/{create-tQbnuz-I.mjs → create-CtDaASGO.mjs} +2 -2
- package/dist/{create-CHQx7jq4.mjs → create-DMLjSEkF.mjs} +2 -2
- package/dist/{create-CAQV2g6V.mjs → create-M8qXs24L.mjs} +2 -2
- package/dist/{create-BNQ_DytP.mjs → create-U15wd8_9.mjs} +2 -2
- package/dist/{create-BOLwWt8Q.mjs → create-UxWtLwXT.mjs} +2 -2
- package/dist/{create-CCh_LyW9.mjs → create-WIIp7MVV.mjs} +2 -2
- package/dist/{create-branch-CYo6jZth.mjs → create-branch-Bkq9rtf7.mjs} +1 -1
- package/dist/create-ku05K1Oj.mjs +34 -0
- package/dist/{csv-B2Jgb1GM.mjs → csv-GincCch9.mjs} +4 -3
- package/dist/{current-task-MpBFGttd.mjs → current-task-CbnNWQ7H.mjs} +1 -1
- package/dist/{dashboard-CsIFFpzK.mjs → dashboard-BlbNszi8.mjs} +1 -1
- package/dist/{dashboard-BCpSq_G-.mjs → dashboard-CKUR8ZpQ.mjs} +1 -0
- package/dist/{dashboard-BHJBoaG7.mjs → dashboard-ReNaou5J.mjs} +9 -9
- package/dist/{db-DsfojyeH.mjs → db-2hSYsqHk.mjs} +6 -6
- package/dist/{delete-BApOjQvl.mjs → delete-B2wmUpj_.mjs} +2 -2
- package/dist/{delete-DFmX7jTp.mjs → delete-BEPw7WRT.mjs} +2 -2
- package/dist/{delete-B8e01xAG.mjs → delete-Bv3_SIqh.mjs} +2 -2
- package/dist/{delete-Ob06PPie.mjs → delete-C1YmyeVy.mjs} +2 -2
- package/dist/delete-CZqleA9Q.mjs +44 -0
- package/dist/{delete-Ck0q4Dzp.mjs → delete-DNsY94Ok.mjs} +2 -2
- package/dist/{delete-table-DuyhGrvA.mjs → delete-table-DySwoEaq.mjs} +2 -2
- package/dist/{dependencies-Bj3QrGIm.mjs → dependencies-ygT6uMu4.mjs} +2 -2
- package/dist/{dirty-DNYoM6Bp.mjs → dirty-BkiHZ8gb.mjs} +1 -1
- package/dist/{document-BbskZPTT.mjs → document-DGbDloCb.mjs} +5 -5
- package/dist/download-Chr-YNTG.mjs +28 -0
- package/dist/{eid-WTZmDdsr.mjs → eid-BvY-YGpN.mjs} +2 -2
- package/dist/{events-Bn7jh5lP.mjs → events-B01P0G7C.mjs} +2 -2
- package/dist/{export-BjfoZRDJ.mjs → export-CG23iezf.mjs} +2 -2
- package/dist/{field-Zau6Hc6X.mjs → field-DikmNcAt.mjs} +4 -4
- package/dist/{fields-CBBa-Prp.mjs → fields-C9BF3jHL.mjs} +2 -2
- package/dist/{get-ByBOq30r.mjs → get-B3jvGI0b.mjs} +2 -2
- package/dist/{get-CvI--9S_.mjs → get-B4GltkXP.mjs} +1 -1
- package/dist/get-BHpVRSbm.mjs +32 -0
- package/dist/{get-DmpB6J9g.mjs → get-BYSFFlsd.mjs} +2 -2
- package/dist/{get-Dn9ZiSZr.mjs → get-Blbcl76m.mjs} +2 -2
- package/dist/{get-D_h-G9bn.mjs → get-BtauixMx.mjs} +2 -2
- package/dist/{get-CDJFVvhj.mjs → get-Buxkx-RX.mjs} +1 -1
- package/dist/{get-C2-Q3iQ5.mjs → get-C1V7vZse.mjs} +2 -2
- package/dist/{get-Dmj9Ygz1.mjs → get-C99cjjD0.mjs} +2 -2
- package/dist/{get-DRvsATp-.mjs → get-CMMXBVff.mjs} +2 -2
- package/dist/{get-CnbUCzDM.mjs → get-CkMLxzVy.mjs} +2 -2
- package/dist/{get-Bz99dAxK.mjs → get-DY-e5oP7.mjs} +4 -4
- package/dist/{get-DdsoHaKH.mjs → get-DZpRq_Fw.mjs} +2 -2
- package/dist/{get-DYO1kywc.mjs → get-DdSB-fpR.mjs} +2 -2
- package/dist/{get-CDMGbgrh.mjs → get-DvqYIBp5.mjs} +2 -2
- package/dist/{get-DkWO0EI0.mjs → get-FJofgEPB.mjs} +1 -1
- package/dist/{get-B_xdF1kq.mjs → get-N5EUCDL0.mjs} +2 -2
- package/dist/{get-00lyLv6R.mjs → get-PKhv8WUf.mjs} +2 -2
- package/dist/{get-B7sMgsFs.mjs → get-UW0DOjH5.mjs} +2 -2
- package/dist/{get-DY03Azx9.mjs → get-gFM8-HHP.mjs} +1 -1
- package/dist/{get-run-Cnux9ln0.mjs → get-run-F7ARJeAD.mjs} +2 -2
- package/dist/git-sync-IW4T2sKq.mjs +28 -0
- package/dist/{has-remote-changes-C684Redh.mjs → has-remote-changes-Bwyp8mc-.mjs} +1 -1
- package/dist/{import-Rmmttboo.mjs → import-CPY8aM8d.mjs} +2 -2
- package/dist/{is-dirty-DYeJYhBz.mjs → is-dirty-0F_UJY7Q.mjs} +1 -1
- package/dist/{items-CQlPXBXE.mjs → items-FUop0zGR.mjs} +1 -1
- package/dist/{library-Bsm5KsFF.mjs → library-DpOtb0E0.mjs} +4 -4
- package/dist/{list-CQwOgIlj.mjs → list--B2EUWJg.mjs} +1 -1
- package/dist/list-B-74c1BD.mjs +35 -0
- package/dist/{list-BpFp9Wre.mjs → list-BASNYNJr.mjs} +1 -1
- package/dist/{list-CKK-s3Ty.mjs → list-BQaXU1bp.mjs} +1 -1
- package/dist/{list-CQDprvW0.mjs → list-BQrk4Ua4.mjs} +3 -3
- package/dist/{list-BP3MPq-M.mjs → list-Beoh2AYD.mjs} +1 -1
- package/dist/{list-CNUiF8Z7.mjs → list-Bqm0F1Y-.mjs} +1 -1
- package/dist/{list-B4hJuMhA.mjs → list-C2qxVTu7.mjs} +1 -1
- package/dist/{list-DMKDsBRd.mjs → list-CGkgypYz.mjs} +1 -1
- package/dist/{list-UhpKG6_m.mjs → list-CvzWE6CS.mjs} +1 -1
- package/dist/{list-C5Zs8nrb.mjs → list-DMlFbccD.mjs} +1 -1
- package/dist/{list-B8nAGwP4.mjs → list-DdFViPYS.mjs} +1 -1
- package/dist/{list-BtkWNtvY.mjs → list-DfbsmsHv.mjs} +2 -2
- package/dist/{list-CMpoc2TN.mjs → list-GyP4b_tU.mjs} +1 -1
- package/dist/{list-DF2rvoO1.mjs → list-Uc1OxV36.mjs} +3 -3
- package/dist/{list-BzVTHOoH.mjs → list-ba7lI44w.mjs} +1 -1
- package/dist/{list-BtmsNOEn.mjs → list-lzIKVtE9.mjs} +1 -1
- package/dist/{list-BOET6zhP.mjs → list-rQ-6XSua.mjs} +1 -1
- package/dist/{list-DE9FM957.mjs → list-xC99-2X0.mjs} +1 -1
- package/dist/{login-CGHeSjlP.mjs → login-D5jt0q9K.mjs} +3 -3
- package/dist/{logout-DAxOlbv4.mjs → logout-DViy0VzV.mjs} +1 -1
- package/dist/{measure-BsYv0p26.mjs → measure-IPlonpqU.mjs} +5 -5
- package/dist/{network-error-CEb9ymDW.mjs → network-error-D6CiOEBw.mjs} +10 -2
- package/dist/{parameter-values-CJTdqd8c.mjs → parameter-values-CHyOCxmR.mjs} +2 -2
- package/dist/{parse-id-C_jmKFaa.mjs → parse-id-CPINxy7h.mjs} +1 -1
- package/dist/{path-B5gHvrYL.mjs → path-bMZzUOVo.mjs} +1 -1
- package/dist/{preflight-YpPQo-sa.mjs → preflight-CoF1Em99.mjs} +1 -1
- package/dist/{publish-DijrxaCW.mjs → publish-Cs-OUG6n.mjs} +2 -2
- package/dist/{query-Dc__-KJH.mjs → query-CEdmSEq8.mjs} +2 -2
- package/dist/{query-BbqECzmF.mjs → query-CpD46hL6.mjs} +4 -9
- package/dist/{remove-collection-BOnxYvhj.mjs → remove-collection-DynsqkwG.mjs} +2 -2
- package/dist/{replace-Cq4CxVa-.mjs → replace-C6YqqCG9.mjs} +4 -3
- package/dist/{rescan-values-Dr_j416g.mjs → rescan-values-C6PB02uT.mjs} +2 -2
- package/dist/run-C7PXBBEl.mjs +50 -0
- package/dist/{run-C3DkS6NP.mjs → run-Cb86sH_c.mjs} +3 -3
- package/dist/{run-DdGJ544X.mjs → run-CpmWoOGp.mjs} +2 -2
- package/dist/{runs-CUNWiidL.mjs → runs-CCRszsbB.mjs} +2 -2
- package/dist/{runtime-DiKyBxOw.mjs → runtime-BMJv4VOi.mjs} +2 -2
- package/dist/{schema-tables-CV386fnC.mjs → schema-tables-BQdFNy1B.mjs} +2 -2
- package/dist/{schemas-DM-UqZBQ.mjs → schemas-CNAPFh4n.mjs} +2 -2
- package/dist/{search-DmGScXs8.mjs → search-BKVV6YtB.mjs} +2 -2
- package/dist/{segment-BzUGM2Fr.mjs → segment-CDoZHSYX.mjs} +5 -5
- package/dist/{selectors-DGDn0Hto.mjs → selectors-BXbjj36S.mjs} +2 -2
- package/dist/{send-CVxxEpDB.mjs → send-D2eXL9lt.mjs} +2 -2
- package/dist/{set-active-BD8L1lPX.mjs → set-active-DT61WwV0.mjs} +1 -1
- package/dist/{set-DFolTjbd.mjs → set-sHBtSGLi.mjs} +2 -2
- package/dist/{setting-DyhaeICs.mjs → setting-dkfKvCxc.mjs} +3 -3
- package/dist/{setup-BbDQN8fe.mjs → setup-TOwWatgm.mjs} +2 -2
- package/dist/{skills--vK6J-e4.mjs → skills-BcOjZldN.mjs} +3 -3
- package/dist/{snippet-DRwKb2x7.mjs → snippet-DMdFqvNq.mjs} +5 -5
- package/dist/{stash-D0S4JmAz.mjs → stash-BgWw2lyu.mjs} +2 -2
- package/dist/{status-hL1am-HV.mjs → status-B14FO8n7.mjs} +2 -2
- package/dist/{status-BhswxJL1.mjs → status-J4pEIm-c.mjs} +1 -1
- package/dist/stream-McixcoUl.mjs +7 -0
- package/dist/{subscription-_d5fB45F.mjs → subscription-B1uuKxM7.mjs} +5 -5
- package/dist/{subscriptions-s4TF6Ax3.mjs → subscriptions-BHIATSN6.mjs} +3 -3
- package/dist/{summary-CsPvcUwW.mjs → summary-B1V5TXaZ.mjs} +2 -2
- package/dist/{sync-schema-DaZ_MV-u.mjs → sync-schema-D1vX-rpv.mjs} +3 -3
- package/dist/{table-DYoC1kPn.mjs → table-CDeO1WbH.mjs} +4 -4
- package/dist/{timeline-xlDbEKWg.mjs → timeline-MQFX3Fla.mjs} +7 -7
- package/dist/{timeline-event-CNQdCTDg.mjs → timeline-event-oGmne082.mjs} +5 -5
- package/dist/transform-CWIqW64R.mjs +28 -0
- package/dist/transform-job-DpF2MARE.mjs +22 -0
- package/dist/{transform-tag-_tgwlsdB.mjs → transform-tag-Bpj8l5Ci.mjs} +4 -4
- package/dist/transform-test-BJOPAwKl.mjs +25 -0
- package/dist/transform-test-BhkpwFqD.mjs +16 -0
- package/dist/transform-test-Dhcj7u-U.mjs +142 -0
- package/dist/{transforms-oU4zizbO.mjs → transforms-K7Y4ON_q.mjs} +2 -2
- package/dist/{tree-CH-f3bjP.mjs → tree-CtFtroe4.mjs} +1 -1
- package/dist/{unpublish-BUl9RU5C.mjs → unpublish-D7UaaIWA.mjs} +2 -2
- package/dist/{update-C4YJQFDS.mjs → update-3ksm443P.mjs} +3 -3
- package/dist/{update-BiFDBcEH.mjs → update-B7veBLhx.mjs} +3 -3
- package/dist/{update-CmDTljK-.mjs → update-BicO3Lio.mjs} +3 -3
- package/dist/{update-CHNSUHK4.mjs → update-BlBEKrNE.mjs} +3 -3
- package/dist/{update-tX9mKBN_.mjs → update-BpuZsX9z.mjs} +7 -7
- package/dist/{update-CVPAwJaH.mjs → update-BvbPpgOL.mjs} +3 -3
- package/dist/{update-BZPllQoR.mjs → update-CGJXd_E3.mjs} +3 -3
- package/dist/{update-BCS5FxKr.mjs → update-C_wTtrtX.mjs} +4 -4
- package/dist/{update-BzMDeZiU.mjs → update-D9Nfv864.mjs} +3 -3
- package/dist/{update-D-NE60AV.mjs → update-DUNJEk8m.mjs} +3 -3
- package/dist/{update-cYkvbqK8.mjs → update-HqUKBeM2.mjs} +3 -3
- package/dist/{update-CO4m4wH3.mjs → update-MWaDj2VX.mjs} +3 -3
- package/dist/{update-bD_Jh5-s.mjs → update-YkB3xWUh.mjs} +3 -3
- package/dist/{update-CvOO8TED.mjs → update-bix8NoKq.mjs} +3 -3
- package/dist/{update-Nfi44RrE.mjs → update-dRAPKE3c.mjs} +3 -3
- package/dist/{update-dashcard-C3TuYO_k.mjs → update-dashcard-BGqKMqQb.mjs} +5 -5
- package/dist/update-e4ufwrkF.mjs +41 -0
- package/dist/{upgrade-DXMV4AyP.mjs → upgrade-DkQ1wk4z.mjs} +2 -2
- package/dist/upload-BfGc-L4t.mjs +42 -0
- package/dist/upload-C3z5ZaXA.mjs +24 -0
- package/dist/{upload-CH632qW6.mjs → upload-CD555ui1.mjs} +1 -24
- package/dist/{upload-Dey_8rLf.mjs → upload-JN6EK96c.mjs} +3 -3
- package/dist/{uuid-BJkDWj9p.mjs → uuid-BLBLkWAF.mjs} +1 -1
- package/dist/{values-Dxf1JEoA.mjs → values-8CrXBkyg.mjs} +2 -2
- package/dist/{verify-K96rItG5.mjs → verify-nNVN-0CR.mjs} +3 -3
- package/dist/{wait-DoMDH226.mjs → wait-YrD7UYFF.mjs} +2 -2
- package/dist/{wait-flags-DWEF9tX4.mjs → wait-flags-CDtMS8FP.mjs} +1 -1
- package/package.json +1 -1
- package/skill-data/core/SKILL.md +6 -5
- package/skill-data/dashboard/SKILL.md +2 -2
- package/skill-data/transform/SKILL.md +55 -1
- package/dist/git-sync-MQQYRYLg.mjs +0 -28
- package/dist/transform-Bs0EWijQ.mjs +0 -28
- package/dist/transform-job-BcLChRup.mjs +0 -22
package/skill-data/core/SKILL.md
CHANGED
|
@@ -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, alert, subscription, 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, content translation, 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
|
|
|
@@ -11,8 +11,8 @@ The official Metabase CLI (`mb`) drives a Metabase instance over its REST API: a
|
|
|
11
11
|
Top-level command groups (run `mb <group> --help` to discover verbs):
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
auth | db | table | field | upload | query | card | dashboard | snippet | segment | measure | collection | library
|
|
15
|
-
document | timeline | timeline-event | transform | transform-job | transform-tag | alert | subscription | setting
|
|
14
|
+
auth | db | table | field | upload | content-translation | query | card | dashboard | snippet | segment | measure | collection | library
|
|
15
|
+
document | timeline | timeline-event | transform | transform-job | transform-tag | transform-test | alert | subscription | setting
|
|
16
16
|
search | git-sync | setup | eid | uuid | upgrade | skills
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -129,8 +129,9 @@ Routine verb shapes (list / get / create / update), every flag, and output schem
|
|
|
129
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.
|
|
130
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.
|
|
131
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.
|
|
132
|
+
- **content-translation.** EE-only (`content_translation` premium feature), admin-only, and separate from Remote Sync. `content-translation download > translations.csv` streams the complete active dictionary; `content-translation upload --file translations.csv` replaces every active translation with the file's contents. Always upload the canonical complete CSV, never a partial patch. An empty dictionary downloads as Metabase's four-row sample dictionary — don't re-upload it as real translations. Metabase limits dictionaries to 1.5 MiB.
|
|
132
133
|
- **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`.
|
|
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).
|
|
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). Every dashcard must include `card_id`, including existing rows; use `card_id:null` plus a `visualization_settings.virtual_card` block (`{display:"text"|"heading"|"link"|…}`) for non-question cards. `create` accepts the **same** `dashcards` array in its initial body, so lay out the whole dashboard in one call. `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.
|
|
134
135
|
- **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
136
|
- **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.
|
|
136
137
|
- **snippet `--archived` is a swap, not a union** — list returns _either_ active _or_ archived rows, never both. (Same for `--filter archived` on dashboard/collection.)
|
|
@@ -139,7 +140,7 @@ Routine verb shapes (list / get / create / update), every flag, and output schem
|
|
|
139
140
|
- **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`.
|
|
140
141
|
- **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}`).
|
|
141
142
|
- **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.
|
|
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`.)
|
|
143
|
+
- **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-test run <id>` checks a transform against fixtures in temp tables — no real table is read — and exits non-zero unless it passes (v64+). (→ `transform`.)
|
|
143
144
|
- **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.
|
|
144
145
|
- **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).
|
|
145
146
|
- **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).
|
|
@@ -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, 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; every dashcard carries `card_id`, with `null` for virtual cards; 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
|
|
|
@@ -123,7 +123,7 @@ Set the **driver** chart's whole-card click behavior to `crossfilter`, mapping t
|
|
|
123
123
|
- **Auto-connect / the missing map:** a filter that "does nothing" or "won't show" is almost always unmapped, or mapped only to cards on another tab.
|
|
124
124
|
- **Time-grouping parameters** (`temporal-unit`) bind only to a datetime column in the query's **last** stage — add one after a time-bucketed summary and it can't attach.
|
|
125
125
|
- **Required + default:** a `required: true` parameter with no `default` blocks its cards until a value is chosen; give it a `default` for expensive queries you don't want running unfiltered.
|
|
126
|
-
- **Whole-array replace:** never send a partial `parameters`/`dashcards` array to `update` — you'll delete what you omit. Use `update-dashcard` for a single-card change.
|
|
126
|
+
- **Whole-array replace:** never send a partial `parameters`/`dashcards` array to `update` — you'll delete what you omit. Include `card_id` on every dashcard (`null` for virtual cards). Use `update-dashcard` for a single-card change.
|
|
127
127
|
|
|
128
128
|
## Don't
|
|
129
129
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: transform
|
|
3
|
-
description: Author and run Metabase transforms via `mb` — body shape (native SQL or structured MBQL), create + run-with-wait, run inspection, dependencies, cancel, the `update`-vs-recreate iteration rule, the writable-keys-only PATCH contract, plus transform tags and tag-driven transform-job schedules. Load when the user touches transforms — "create a transform", "run a transform", "fix a failing transform", "list transform runs", "cancel a running transform", "manage transform tags", "run a transform job", or anything `mb transform …` / `mb transform-job …` / `mb transform-tag …`.
|
|
3
|
+
description: Author and run Metabase transforms via `mb` — body shape (native SQL or structured MBQL), create + run-with-wait, run inspection, dependencies, cancel, the `update`-vs-recreate iteration rule, the writable-keys-only PATCH contract, transform tests (fixtures and expectations run against temp tables), plus transform tags and tag-driven transform-job schedules. Load when the user touches transforms — "create a transform", "run a transform", "fix a failing transform", "test a transform", "list transform runs", "cancel a running transform", "manage transform tags", "run a transform job", or anything `mb transform …` / `mb transform-job …` / `mb transform-tag …` / `mb transform-test …`.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -172,6 +172,60 @@ mb transform run "$ID" --wait --profile <n> --json # → succeeded
|
|
|
172
172
|
|
|
173
173
|
If you really must `create + delete` instead, do the `delete` **before** the first `git-sync export` so the failed entity never lands in git history — an export of a soft-failed state is noise that needs a follow-up cleanup commit. See `git-sync`, "Read state before mutating", for the ordering rule.
|
|
174
174
|
|
|
175
|
+
## Transform tests (v64+)
|
|
176
|
+
|
|
177
|
+
A transform test replaces every table the transform reads with a fixture, runs it into a temp table, and checks that output. No real table is read or written.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
mb transform-test list --transform <id> --profile <n> --json # --transform is optional
|
|
181
|
+
mb transform-test get <id> --full --profile <n> --json # --full for inputs/expectations
|
|
182
|
+
mb transform-test create --file ./.scratch/test.json --profile <n> --json
|
|
183
|
+
mb transform-test update <id> --file ./.scratch/patch.json --profile <n> --json
|
|
184
|
+
mb transform-test delete <id> --yes --profile <n>
|
|
185
|
+
mb transform-test run <id> --profile <n> --json # exits non-zero unless it passes
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**`inputs`** — one per table the transform reads, each naming a `table` plus either `format: "sql"` with `sql`, or `format: "rows"` with `columns` (each a `name` and a `database_type` the warehouse takes as a `CAST` target) and `rows`.
|
|
189
|
+
|
|
190
|
+
**`expectations`** — `type: "empty"` with the `sql` that must return no rows, or `type: "equals"`, which needs the same `format` split as an input (`"rows"` with `columns`/`rows`, or `"sql"` with a query). An `equals` without a `format` is refused.
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"transform_id": 1,
|
|
195
|
+
"name": "adults only",
|
|
196
|
+
"inputs": [
|
|
197
|
+
{
|
|
198
|
+
"table": { "schema": "public", "name": "people" },
|
|
199
|
+
"format": "rows",
|
|
200
|
+
"columns": [
|
|
201
|
+
{ "name": "id", "database_type": "INTEGER" },
|
|
202
|
+
{ "name": "age", "database_type": "INTEGER" }
|
|
203
|
+
],
|
|
204
|
+
"rows": [
|
|
205
|
+
{ "id": 1, "age": 30 },
|
|
206
|
+
{ "id": 2, "age": 12 }
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
"expectations": [
|
|
211
|
+
{
|
|
212
|
+
"type": "equals",
|
|
213
|
+
"name": "exactly one row, id 1",
|
|
214
|
+
"format": "rows",
|
|
215
|
+
"columns": [{ "name": "id", "database_type": "INTEGER" }],
|
|
216
|
+
"rows": [{ "id": 1 }]
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"type": "empty",
|
|
220
|
+
"name": "no null ids",
|
|
221
|
+
"sql": "SELECT * FROM public.adults WHERE id IS NULL"
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Create and update bodies are closed — strip `id`, `entity_id`, `creator_id`, `created_at` and `updated_at` from a `get --full` body before sending it back.
|
|
228
|
+
|
|
175
229
|
## Drop the materialized table (keep the transform)
|
|
176
230
|
|
|
177
231
|
```bash
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DBM87IgC.mjs";
|
|
2
|
-
//#region src/commands/git-sync/index.ts
|
|
3
|
-
var git_sync_default = defineCommandGroup({
|
|
4
|
-
name: "git-sync",
|
|
5
|
-
description: "Sync Metabase content with a git remote",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "git-sync",
|
|
8
|
-
purpose: "import/export round-trip and dirty checks"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
status: () => import("./status-BhswxJL1.mjs").then((mod) => mod.default),
|
|
12
|
-
"is-dirty": () => import("./is-dirty-DYeJYhBz.mjs").then((mod) => mod.default),
|
|
13
|
-
"has-remote-changes": () => import("./has-remote-changes-C684Redh.mjs").then((mod) => mod.default),
|
|
14
|
-
dirty: () => import("./dirty-DNYoM6Bp.mjs").then((mod) => mod.default),
|
|
15
|
-
"current-task": () => import("./current-task-MpBFGttd.mjs").then((mod) => mod.default),
|
|
16
|
-
"cancel-task": () => import("./cancel-task-C5CU1pxU.mjs").then((mod) => mod.default),
|
|
17
|
-
wait: () => import("./wait-DoMDH226.mjs").then((mod) => mod.default),
|
|
18
|
-
import: () => import("./import-Rmmttboo.mjs").then((mod) => mod.default),
|
|
19
|
-
export: () => import("./export-BjfoZRDJ.mjs").then((mod) => mod.default),
|
|
20
|
-
stash: () => import("./stash-D0S4JmAz.mjs").then((mod) => mod.default),
|
|
21
|
-
branches: () => import("./branches-DchlyU0i.mjs").then((mod) => mod.default),
|
|
22
|
-
"create-branch": () => import("./create-branch-CYo6jZth.mjs").then((mod) => mod.default),
|
|
23
|
-
"add-collection": () => import("./add-collection-B3Ty8SzB.mjs").then((mod) => mod.default),
|
|
24
|
-
"remove-collection": () => import("./remove-collection-BOnxYvhj.mjs").then((mod) => mod.default)
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
//#endregion
|
|
28
|
-
export { git_sync_default as default };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DBM87IgC.mjs";
|
|
2
|
-
//#region src/commands/transform/index.ts
|
|
3
|
-
var transform_default = defineCommandGroup({
|
|
4
|
-
name: "transform",
|
|
5
|
-
description: "Manage Metabase transforms",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "transform",
|
|
8
|
-
purpose: "body shape, run-with-wait, iterate"
|
|
9
|
-
}, {
|
|
10
|
-
skill: "mbql",
|
|
11
|
-
purpose: "MBQL source.query bodies"
|
|
12
|
-
}],
|
|
13
|
-
subCommands: {
|
|
14
|
-
list: () => import("./list-C5Zs8nrb.mjs").then((mod) => mod.default),
|
|
15
|
-
get: () => import("./get-ByBOq30r.mjs").then((mod) => mod.default),
|
|
16
|
-
dependencies: () => import("./dependencies-Bj3QrGIm.mjs").then((mod) => mod.default),
|
|
17
|
-
create: () => import("./create-DJmXXQoq.mjs").then((mod) => mod.default),
|
|
18
|
-
update: () => import("./update-BCS5FxKr.mjs").then((mod) => mod.default),
|
|
19
|
-
delete: () => import("./delete-Ck0q4Dzp.mjs").then((mod) => mod.default),
|
|
20
|
-
"delete-table": () => import("./delete-table-DuyhGrvA.mjs").then((mod) => mod.default),
|
|
21
|
-
run: () => import("./run-C3DkS6NP.mjs").then((mod) => mod.default),
|
|
22
|
-
cancel: () => import("./cancel-BMQa5R1Z.mjs").then((mod) => mod.default),
|
|
23
|
-
"get-run": () => import("./get-run-Cnux9ln0.mjs").then((mod) => mod.default),
|
|
24
|
-
runs: () => import("./runs-CUNWiidL.mjs").then((mod) => mod.default)
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
//#endregion
|
|
28
|
-
export { transform_default as default };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DBM87IgC.mjs";
|
|
2
|
-
//#region src/commands/transform-job/index.ts
|
|
3
|
-
var transform_job_default = defineCommandGroup({
|
|
4
|
-
name: "transform-job",
|
|
5
|
-
description: "Manage Metabase transform jobs",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "transform",
|
|
8
|
-
purpose: "tag-driven job schedules"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
list: () => import("./list-BzVTHOoH.mjs").then((mod) => mod.default),
|
|
12
|
-
get: () => import("./get-DRvsATp-.mjs").then((mod) => mod.default),
|
|
13
|
-
create: () => import("./create-Beh-2uoN.mjs").then((mod) => mod.default),
|
|
14
|
-
update: () => import("./update-CmDTljK-.mjs").then((mod) => mod.default),
|
|
15
|
-
delete: () => import("./delete-DFmX7jTp.mjs").then((mod) => mod.default),
|
|
16
|
-
run: () => import("./run-DdGJ544X.mjs").then((mod) => mod.default),
|
|
17
|
-
transforms: () => import("./transforms-oU4zizbO.mjs").then((mod) => mod.default),
|
|
18
|
-
"set-active": () => import("./set-active-BD8L1lPX.mjs").then((mod) => mod.default)
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
//#endregion
|
|
22
|
-
export { transform_job_default as default };
|