@metabase/cli 0.1.8 → 0.1.10
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/.claude-plugin/marketplace.json +1 -1
- package/README.md +89 -236
- package/dist/add-collection-D9wXgmRj.mjs +10 -0
- package/dist/{add-collection-CwrbKmC1.mjs → add-collection-DUqTrC5T.mjs} +5 -5
- package/dist/{archive-DqUtqRut.mjs → archive-0krZxAXq.mjs} +5 -6
- package/dist/{archive-ZnnJc2iT.mjs → archive-44EWiXud.mjs} +6 -7
- package/dist/{archive-BpKZsGAm.mjs → archive-B59Y7ajB.mjs} +6 -7
- package/dist/{archive-BO3DOWI4.mjs → archive-BEIyIsin.mjs} +5 -6
- package/dist/{archive-BzvqQd34.mjs → archive-BZfpjMir.mjs} +5 -6
- package/dist/{archive-BAjGIzhn.mjs → archive-DtE2H4A6.mjs} +6 -7
- package/dist/archive-_GMNY8wH.mjs +39 -0
- package/dist/auth-cFC5m69m.mjs +19 -0
- package/dist/{body-DDYKoyMt.mjs → body-BdRyuvU4.mjs} +2 -2
- package/dist/{branches-DjiGsjAz.mjs → branches-Jpv-FNds.mjs} +5 -6
- package/dist/{cancel-BwtDQ2MR.mjs → cancel-ChC4lFd4.mjs} +4 -5
- package/dist/{cancel-task-uJp18RvR.mjs → cancel-task-DyhIkNaL.mjs} +5 -6
- package/dist/{render-0_GsapXa.mjs → capabilities-7L9GVMd_.mjs} +45 -4
- package/dist/card-ClvGX6dQ.mjs +20 -0
- package/dist/{card-ezYiriML.mjs → card-DnIeMmUn.mjs} +18 -2
- package/dist/{cards-z68PANDD.mjs → cards-O-nKkQKP.mjs} +5 -6
- package/dist/cli.mjs +24 -34
- package/dist/{collection-Bcy8cWYH.mjs → collection-BPTlcFw5.mjs} +8 -2
- package/dist/collection-DjvowSJC.mjs +20 -0
- package/dist/collection-namespace-7724zUMx.mjs +12 -0
- package/dist/{create-BzK59YlR.mjs → create-B4f4Pldw.mjs} +11 -12
- package/dist/{create-4EAGYVyp.mjs → create-BbF9zVFP.mjs} +12 -10
- package/dist/{create-Dd_Gyg_F.mjs → create-BnFHcnlL.mjs} +7 -8
- package/dist/{create-GVfCQU3B.mjs → create-BuKx7kw6.mjs} +7 -8
- package/dist/{create-CQ4Vg4Ge.mjs → create-BxRsXQrm.mjs} +9 -10
- package/dist/{create-7JOWFxqu.mjs → create-CvYKJOcE.mjs} +10 -11
- package/dist/create-D45uFXlo.mjs +44 -0
- package/dist/create-DS52EhPd.mjs +52 -0
- package/dist/{create-DHWfmO2L.mjs → create-DeZ2x2Db.mjs} +9 -10
- package/dist/{create-branch-CdWGiREu.mjs → create-branch-KOWUIE72.mjs} +5 -6
- package/dist/{current-task-nPs-iCLi.mjs → current-task-ClcWPPMc.mjs} +5 -6
- package/dist/dashboard-BFeURTOw.mjs +21 -0
- package/dist/{database-BXiue1in.mjs → database-Dsv4QBs0.mjs} +20 -10
- package/dist/db-CSH1kwQr.mjs +22 -0
- package/dist/{delete-CJqLgr6w.mjs → delete-CX2VUA5R.mjs} +6 -7
- package/dist/{delete-Do1agSiL.mjs → delete-D68oS73R.mjs} +6 -7
- package/dist/{delete-runtime-uuYbd4k2.mjs → delete-runtime-CjFc69tS.mjs} +2 -2
- package/dist/{delete-table-ZiJDpMFT.mjs → delete-table-DLvL9mDA.mjs} +6 -7
- package/dist/{dirty-BnTG7w7v.mjs → dirty-1OrXpc7E.mjs} +5 -6
- package/dist/document-CcfiiV3b.mjs +100 -0
- package/dist/document-KdT_Xj6r.mjs +19 -0
- package/dist/{eid-CwQ_smOD.mjs → eid-CzLhHZMW.mjs} +6 -7
- package/dist/{error-CTVL5CdB.mjs → error-BWXBhqLW.mjs} +1 -1
- package/dist/{export-DR2cC4rL.mjs → export-B5z8w-xo.mjs} +7 -8
- package/dist/field-CTFnZI8G.mjs +18 -0
- package/dist/{fields-Ck31lDz9.mjs → fields-sC7pzmPX.mjs} +6 -7
- package/dist/{get-pO0wiy1e.mjs → get-4GEDd9YN.mjs} +5 -6
- package/dist/get-BC60bhel.mjs +36 -0
- package/dist/{get-CyG_P55z.mjs → get-BYw3xS0X.mjs} +6 -7
- package/dist/{get-C71ypFQk.mjs → get-Bo1FGyFs.mjs} +5 -6
- package/dist/{get-BNKsNCcx.mjs → get-ByZ4HR2T.mjs} +5 -6
- package/dist/{get-DxqzDKKK.mjs → get-C6n86-dS.mjs} +5 -6
- package/dist/{get-DyArILlF.mjs → get-CHb6J908.mjs} +5 -6
- package/dist/{get-F338MOK-.mjs → get-DLwb_gUh.mjs} +5 -6
- package/dist/{get-CICzGFSW.mjs → get-DTHLETau.mjs} +6 -7
- package/dist/{get-BFJ3VBPa.mjs → get-Dl62Fy6Y.mjs} +5 -6
- package/dist/{get-BZiu-u-9.mjs → get-Fn9WkNhS.mjs} +7 -8
- package/dist/{get-GWRprk7k.mjs → get-ZesERdyk.mjs} +5 -7
- package/dist/{get-BPOd0Rm8.mjs → get-lcX52Skc.mjs} +5 -6
- package/dist/{get-DauAF3sm.mjs → get-reSMTfQi.mjs} +5 -6
- package/dist/{get-run-DhM_PyVy.mjs → get-run-CpCbHJad.mjs} +5 -6
- package/dist/git-sync-C2vib8rx.mjs +28 -0
- package/dist/{has-remote-changes-Ca0exJmb.mjs → has-remote-changes-CPz_-uxd.mjs} +5 -6
- package/dist/{import-DjclIzGP.mjs → import-DaWgprK6.mjs} +7 -8
- package/dist/is-dirty-Bb0Rtj7x.mjs +9 -0
- package/dist/{is-dirty-Cke0a1ie.mjs → is-dirty-DZlI7lQx.mjs} +4 -4
- package/dist/{items-BSpapmCU.mjs → items-hgbRYsYD.mjs} +7 -8
- package/dist/{list-BI1PfPjn.mjs → list-36H-dvJZ.mjs} +5 -6
- package/dist/list-B9J3ujwn.mjs +32 -0
- package/dist/{list-BRXGDSMo.mjs → list-BGerkRHH.mjs} +5 -6
- package/dist/{list-CEE9yKNp.mjs → list-BWv5y307.mjs} +4 -5
- package/dist/{list-V5IuMr_5.mjs → list-BgHESP7b.mjs} +4 -5
- package/dist/{list-DWWGcUTg.mjs → list-CCZnH2-Z.mjs} +5 -7
- package/dist/{list-Fjjtpghb.mjs → list-CGdOC9zX.mjs} +6 -7
- package/dist/{list-DmO4ADQq.mjs → list-CKeVS1IZ.mjs} +4 -5
- package/dist/{list-D1qhCQn0.mjs → list-Cd2nOCAx.mjs} +6 -7
- package/dist/{list-fIV-P6wP.mjs → list-D9EuxFHO.mjs} +4 -5
- package/dist/{list-Br77Mw6U.mjs → list-DBlsRSpZ.mjs} +5 -6
- package/dist/{list-bVlCwg8g.mjs → list-DO8T-nmF.mjs} +4 -5
- package/dist/{list-Brt4oKO7.mjs → list-DOVX3vCb.mjs} +6 -7
- package/dist/{list-DUyWON1F.mjs → list-kath_2cX.mjs} +4 -5
- package/dist/{login-BJGhZLgZ.mjs → login-BzrAGJfu.mjs} +9 -10
- package/dist/{logout-BAGLqtnV.mjs → logout-CKBiltoS.mjs} +4 -5
- package/dist/{manifest-BNh0Lw6p.mjs → manifest-BPHqF5LY.mjs} +1 -2
- package/dist/measure-Dw1QpRZa.mjs +19 -0
- package/dist/{metadata-B-GOcWqL.mjs → metadata-BcGcUEVJ.mjs} +6 -7
- package/dist/{metadata-DJAdsOoh.mjs → metadata-BjOrKtnv.mjs} +7 -8
- package/dist/{parse-id-D1LTTt9L.mjs → parse-id--iVTCKSo.mjs} +1 -1
- package/dist/{path-D5kX-msX.mjs → path-LgGU6Bd0.mjs} +4 -6
- package/dist/{poll-DxpnK1wW.mjs → poll-BucRFJT-.mjs} +1 -1
- package/dist/{poll-task-D8mG49IN.mjs → poll-task-DTzKB3T3.mjs} +2 -2
- package/dist/{preflight-Df_FqJ6o.mjs → preflight-CzqVX0PP.mjs} +3 -3
- package/dist/{query-zWFRDH3T.mjs → query-BVZkK6Qk.mjs} +7 -8
- package/dist/{query-OIuumiXN.mjs → query-DG_jygDF.mjs} +11 -12
- package/dist/{query-result-ABPLz6I4.mjs → query-result-B4kTRid7.mjs} +1 -1
- package/dist/{remove-collection-BxmiXWKz.mjs → remove-collection-HdeAfLyi.mjs} +7 -8
- package/dist/{rescan-values-M7g81KIl.mjs → rescan-values-hWubCruZ.mjs} +8 -11
- package/dist/run-C1-lDmQF.mjs +136 -0
- package/dist/{runs-CqfJIuh_.mjs → runs-Q6DYQyqj.mjs} +6 -7
- package/dist/{runtime-B40L_bj8.mjs → runtime-colqvhLf.mjs} +11 -78
- package/dist/{schema-tables-CjBRF0_0.mjs → schema-tables-BEastV_8.mjs} +6 -7
- package/dist/{schemas-GIIbek2O.mjs → schemas-CgawwI_k.mjs} +4 -5
- package/dist/{search-h78uOYec.mjs → search-BWo7xSPP.mjs} +4 -5
- package/dist/segment-DMuYvFjg.mjs +19 -0
- package/dist/{set-BRDxcLcQ.mjs → set-7Nm2ZTb_.mjs} +7 -8
- package/dist/{setting-mKzZJpQY.mjs → setting-DSGXJehQ.mjs} +3 -3
- package/dist/{setup-WTIT2WbM.mjs → setup-aJLGLrIT.mjs} +6 -7
- package/dist/{skills-BkregMyb.mjs → skills-CY_FmaPo.mjs} +33 -2
- package/dist/skills-Q2AFsYvc.mjs +18 -0
- package/dist/snippet-Df2TrP7-.mjs +19 -0
- package/dist/{stash-DxoAJzcK.mjs → stash-DPQ0c-Cd.mjs} +7 -8
- package/dist/{status-B1dc3bbQ.mjs → status-CvAATvV0.mjs} +4 -5
- package/dist/{status-D0Ukfodl.mjs → status-CvKPrV5X.mjs} +6 -7
- package/dist/{summary-3qOMUcEX.mjs → summary-CeOnoOq2.mjs} +5 -6
- package/dist/sync-schema-aOPBc3CY.mjs +55 -0
- package/dist/{table-qDD2kApF.mjs → table-CkWja2UH.mjs} +1 -1
- package/dist/table-pK4OkVtL.mjs +19 -0
- package/dist/{transform-BKahefz_.mjs → transform--dviwMA1.mjs} +1 -0
- package/dist/transform-D60veFH8.mjs +24 -0
- package/dist/transform-job-DXt5LsrY.mjs +19 -0
- package/dist/{tree-DsnIPFyE.mjs → tree-MOQOBeAP.mjs} +4 -5
- package/dist/update-57uxZWcR.mjs +52 -0
- package/dist/{update-CLsqoEJ8.mjs → update-B6mg3AZD.mjs} +8 -9
- package/dist/{update-CZEd_Eej.mjs → update-BD9xkglP.mjs} +9 -10
- package/dist/{update-BEtl9LpG.mjs → update-BRrnfG0q.mjs} +8 -9
- package/dist/{update-DPouQi4U.mjs → update-BWyCK8QV.mjs} +13 -11
- package/dist/{update-DWn-nLPo.mjs → update-Bj9s0ri8.mjs} +8 -9
- package/dist/{update-BsgHRoZ8.mjs → update-BkMWBzvk.mjs} +11 -12
- package/dist/{update-Baya6OkO.mjs → update-CitS-QRN.mjs} +12 -13
- package/dist/{update-BRLcnSwK.mjs → update-DfNKr_vS.mjs} +10 -11
- package/dist/{update-UaPqSfPN.mjs → update-Dri4Zg2H.mjs} +10 -11
- package/dist/{update-dashcard-DK9X91ha.mjs → update-dashcard-D_-ura3Y.mjs} +8 -9
- package/dist/{upgrade-UqdvTikR.mjs → upgrade-CFkZ4USY.mjs} +34 -7
- package/dist/{uuid-BWCaWG4O.mjs → uuid-DpinhSxA.mjs} +3 -4
- package/dist/{validate-dPEOnOf8.mjs → validate-B62TRDGV.mjs} +1 -1
- package/dist/{validate-query-CYvOP8Ld.mjs → validate-query-BpiN1CFu.mjs} +2 -2
- package/dist/{values-D_wycrcr.mjs → values-BSS4DRxk.mjs} +5 -6
- package/dist/{verify-D7hb6VMy.mjs → verify-B_A7v8TY.mjs} +1 -1
- package/dist/{wait-B5IpNFCG.mjs → wait-D3iSnjMM.mjs} +6 -7
- package/dist/{wait-flags-CNIeSq0_.mjs → wait-flags-_LnHOeBA.mjs} +2 -2
- package/package.json +1 -1
- package/skill-data/core/SKILL.md +19 -32
- package/skill-data/document/SKILL.md +162 -0
- package/skill-data/git-sync/SKILL.md +8 -63
- package/skill-data/mbql/SKILL.md +95 -28
- package/skill-data/mbql/references/operators.md +13 -13
- package/skill-data/transform/SKILL.md +18 -7
- package/skills/metabase-cli/SKILL.md +1 -1
- package/dist/add-collection-DxtuNxeP.mjs +0 -11
- package/dist/auth-B9B4pUaH.mjs +0 -19
- package/dist/capabilities-7e9MgquN.mjs +0 -29
- package/dist/card-D54unw6r.mjs +0 -20
- package/dist/collection-B5kIKRTL.mjs +0 -20
- package/dist/create-6XE7GYxk.mjs +0 -45
- package/dist/create-C8gA-XP2.mjs +0 -54
- package/dist/credentials-CFA9iGZG.mjs +0 -88
- package/dist/dashboard-lw6IFfOs.mjs +0 -21
- package/dist/database-BPT6BrmF.mjs +0 -17
- package/dist/db-CBCj8sBg.mjs +0 -22
- package/dist/delete-CiV6f69N.mjs +0 -104
- package/dist/deprovision-C-qEnh-P.mjs +0 -67
- package/dist/docker-B-QQWThD.mjs +0 -515
- package/dist/field-DJmQ2pul.mjs +0 -18
- package/dist/git-sync-rmjYOGFK.mjs +0 -28
- package/dist/is-dirty-DFGgGLDi.mjs +0 -10
- package/dist/license-j0tDQLKI.mjs +0 -17
- package/dist/list-evetBTcH.mjs +0 -36
- package/dist/logs-jx5b_YDk.mjs +0 -60
- package/dist/measure-BfgxqewH.mjs +0 -19
- package/dist/parse-schemas-DDK9nXuh.mjs +0 -12
- package/dist/process-CM7Uu5q_.mjs +0 -105
- package/dist/provision-BJd6zO1D.mjs +0 -83
- package/dist/ps-CpyHEvv7.mjs +0 -11
- package/dist/ps-dEqRGeB3.mjs +0 -80
- package/dist/remove-BNQ1c6hB.mjs +0 -64
- package/dist/run-DTsx8bLb.mjs +0 -96
- package/dist/segment-CoElN2b-.mjs +0 -19
- package/dist/set-Dclba9xF.mjs +0 -68
- package/dist/skills-tMYd5d9v.mjs +0 -18
- package/dist/snippet-B84H3tfp.mjs +0 -19
- package/dist/start-B7ByBicB.mjs +0 -414
- package/dist/status-DAzD1Cn_.mjs +0 -34
- package/dist/stop-Cvexagxh.mjs +0 -87
- package/dist/sync-schema-CrmVX1cy.mjs +0 -44
- package/dist/table-B0fRQv91.mjs +0 -19
- package/dist/transform-K_kp6Rdm.mjs +0 -24
- package/dist/transform-job-CuNN8zgv.mjs +0 -19
- package/dist/update-hiJdbbsb.mjs +0 -78
- package/dist/url-LMJZRDv4.mjs +0 -56
- package/dist/wait-DHjXk3jD.mjs +0 -19
- package/dist/workspace-Bt8n3ojY.mjs +0 -25
- package/dist/workspace-D8HtUN0y.mjs +0 -72
- package/dist/workspace-credentials-8CBMQJFz.mjs +0 -100
- package/dist/yaml-Gv6wRFMF.mjs +0 -43
- package/skill-data/workspace/SKILL.md +0 -390
- /package/dist/{body-flags-D7q87Btw.mjs → body-flags-D78h_-Ua.mjs} +0 -0
- /package/dist/{dashboard-B4bn3z6t.mjs → dashboard-FY5UzJ_Z.mjs} +0 -0
- /package/dist/{field-E0IBy4Uw.mjs → field-MGxpNQUH.mjs} +0 -0
- /package/dist/{input-cMSEqISy.mjs → input-xewHccej.mjs} +0 -0
- /package/dist/{key-vkNkH82H.mjs → key-y4TtxKwU.mjs} +0 -0
- /package/dist/{measure-Bt3InQsA.mjs → measure-COGAoZpo.mjs} +0 -0
- /package/dist/{paginate-BexjkjbY.mjs → paginate-Dfm9eO9A.mjs} +0 -0
- /package/dist/{parse-enum-CrEWOhuY.mjs → parse-enum-Dr7ACrTR.mjs} +0 -0
- /package/dist/{parse-ref-DKag6a6I.mjs → parse-ref-BiETXmvm.mjs} +0 -0
- /package/dist/{prompt-CFKoys7k.mjs → prompt-u4WhE4T5.mjs} +0 -0
- /package/dist/{render-khznBlla.mjs → render-BQHJhSP1.mjs} +0 -0
- /package/dist/{revision-message-flag-DY29-cgz.mjs → revision-message-flag-Bo-Kvv6F.mjs} +0 -0
- /package/dist/{segment-DhBmcr_E.mjs → segment-d-708KKO.mjs} +0 -0
- /package/dist/{setting-BzCng1Ub.mjs → setting-CSJvi1-6.mjs} +0 -0
- /package/dist/{snippet-bi_0XbNT.mjs → snippet-BZvo05ua.mjs} +0 -0
- /package/dist/{transform-job-DjhoJbiV.mjs → transform-job-n8W6tLqF.mjs} +0 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { connectionFlags, outputFlags, profileFlag } from "./error-
|
|
3
|
-
import { defineMetabaseCommand } from "./runtime-
|
|
4
|
-
import "./capabilities-
|
|
5
|
-
import
|
|
6
|
-
import "./
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import "./validate-
|
|
11
|
-
import {
|
|
12
|
-
import { Measure, MeasureUpdateInput, measureView } from "./measure-Bt3InQsA.mjs";
|
|
2
|
+
import { connectionFlags, outputFlags, profileFlag } from "./error-BWXBhqLW.mjs";
|
|
3
|
+
import { defineMetabaseCommand } from "./runtime-colqvhLf.mjs";
|
|
4
|
+
import { renderSummary } from "./capabilities-7L9GVMd_.mjs";
|
|
5
|
+
import "./input-xewHccej.mjs";
|
|
6
|
+
import { parseId } from "./parse-id--iVTCKSo.mjs";
|
|
7
|
+
import { readBody } from "./body-BdRyuvU4.mjs";
|
|
8
|
+
import { bodyInputFlags } from "./body-flags-D78h_-Ua.mjs";
|
|
9
|
+
import "./validate-B62TRDGV.mjs";
|
|
10
|
+
import { MEASURE_DEFINITION_LABELS, preflightMbql5Query, skipValidateFlag } from "./validate-query-BpiN1CFu.mjs";
|
|
11
|
+
import { Measure, MeasureUpdateInput, measureView } from "./measure-COGAoZpo.mjs";
|
|
13
12
|
|
|
14
13
|
//#region src/commands/measure/update.ts
|
|
15
14
|
var update_default = defineMetabaseCommand({
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { ConfigError } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { connectionFlags, outputFlags, profileFlag } from "./error-
|
|
3
|
-
import { defineMetabaseCommand } from "./runtime-
|
|
4
|
-
import "./capabilities-
|
|
5
|
-
import
|
|
6
|
-
import "./
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { DashboardDetail, Dashcard, DashcardPatchInput, dashcardView } from "./dashboard-B4bn3z6t.mjs";
|
|
2
|
+
import { connectionFlags, outputFlags, profileFlag } from "./error-BWXBhqLW.mjs";
|
|
3
|
+
import { defineMetabaseCommand } from "./runtime-colqvhLf.mjs";
|
|
4
|
+
import { renderSummary } from "./capabilities-7L9GVMd_.mjs";
|
|
5
|
+
import "./input-xewHccej.mjs";
|
|
6
|
+
import { parseId } from "./parse-id--iVTCKSo.mjs";
|
|
7
|
+
import { readBody } from "./body-BdRyuvU4.mjs";
|
|
8
|
+
import { bodyInputFlags } from "./body-flags-D78h_-Ua.mjs";
|
|
9
|
+
import { DashboardDetail, Dashcard, DashcardPatchInput, dashcardView } from "./dashboard-FY5UzJ_Z.mjs";
|
|
11
10
|
|
|
12
11
|
//#region src/commands/dashboard/update-dashcard.ts
|
|
13
12
|
var update_dashcard_default = defineMetabaseCommand({
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { AbortError, NetworkError, TimeoutError, UnknownError, errorMessage } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { outputFlags, package_default } from "./error-
|
|
3
|
-
import { HttpError, USER_AGENT, combineAborts, defineMetabaseCommand, parseJson, throwIfAborted } from "./runtime-
|
|
4
|
-
import "./capabilities-
|
|
5
|
-
import {
|
|
6
|
-
import { promptConfirm } from "./prompt-CFKoys7k.mjs";
|
|
7
|
-
import { streamProcess } from "./process-CM7Uu5q_.mjs";
|
|
1
|
+
import { AbortError, NetworkError, TimeoutError, UnknownError, errorMessage, isNotFoundError } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
+
import { outputFlags, package_default } from "./error-BWXBhqLW.mjs";
|
|
3
|
+
import { HttpError, USER_AGENT, combineAborts, defineMetabaseCommand, parseJson, throwIfAborted } from "./runtime-colqvhLf.mjs";
|
|
4
|
+
import { renderItem, writeText } from "./capabilities-7L9GVMd_.mjs";
|
|
5
|
+
import { promptConfirm } from "./prompt-u4WhE4T5.mjs";
|
|
8
6
|
import { z } from "zod";
|
|
9
7
|
import { realpathSync } from "node:fs";
|
|
10
8
|
import { compare, valid } from "semver";
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
11
10
|
|
|
12
11
|
//#region src/core/http/npm-registry.ts
|
|
13
12
|
const DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -250,6 +249,34 @@ function compareSemver(a, b) {
|
|
|
250
249
|
return compare(a, b);
|
|
251
250
|
}
|
|
252
251
|
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/runtime/process.ts
|
|
254
|
+
var ProcessNotFoundError = class extends Error {
|
|
255
|
+
command;
|
|
256
|
+
constructor(command) {
|
|
257
|
+
super(`command not found: ${command}`);
|
|
258
|
+
this.name = "ProcessNotFoundError";
|
|
259
|
+
this.command = command;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const stdoutDecoder = new TextDecoder("utf-8");
|
|
263
|
+
function streamProcess(command, args, options = {}) {
|
|
264
|
+
return new Promise((resolve, reject) => {
|
|
265
|
+
const child = spawn(command, args, {
|
|
266
|
+
stdio: "inherit",
|
|
267
|
+
...options.shell === true ? { shell: true } : {}
|
|
268
|
+
});
|
|
269
|
+
child.on("error", (error) => {
|
|
270
|
+
if (isNotFoundError(error)) {
|
|
271
|
+
reject(new ProcessNotFoundError(command));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
reject(error);
|
|
275
|
+
});
|
|
276
|
+
child.on("close", (code) => resolve(code));
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
253
280
|
//#endregion
|
|
254
281
|
//#region src/commands/upgrade.ts
|
|
255
282
|
const UpgradeCommandSchema = z.object({
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { ConfigError } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { outputFlags } from "./error-
|
|
3
|
-
import { defineMetabaseCommand, parseInteger } from "./runtime-
|
|
4
|
-
import "./capabilities-
|
|
5
|
-
import { writeJson, writeText } from "./render-0_GsapXa.mjs";
|
|
2
|
+
import { outputFlags } from "./error-BWXBhqLW.mjs";
|
|
3
|
+
import { defineMetabaseCommand, parseInteger } from "./runtime-colqvhLf.mjs";
|
|
4
|
+
import { writeJson, writeText } from "./capabilities-7L9GVMd_.mjs";
|
|
6
5
|
import { z } from "zod";
|
|
7
6
|
import { randomUUID } from "node:crypto";
|
|
8
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigError, escapeJsonPointerSegment } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { isPlainObject } from "./capabilities-
|
|
2
|
+
import { isPlainObject } from "./capabilities-7L9GVMd_.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
5
5
|
import addFormats from "ajv-formats";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConfigError } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { writeJson } from "./
|
|
3
|
-
import { assertNotLegacyEnvelopeWrappingMbql5, isMbql5Query, validateQuery } from "./validate-
|
|
2
|
+
import { writeJson } from "./capabilities-7L9GVMd_.mjs";
|
|
3
|
+
import { assertNotLegacyEnvelopeWrappingMbql5, isMbql5Query, validateQuery } from "./validate-B62TRDGV.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/commands/validate-query.ts
|
|
6
6
|
const skipValidateFlag = { "skip-validate": {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { connectionFlags, outputFlags, profileFlag } from "./error-
|
|
3
|
-
import { defineMetabaseCommand } from "./runtime-
|
|
4
|
-
import "./capabilities-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { parseId } from "./parse-id-D1LTTt9L.mjs";
|
|
2
|
+
import { connectionFlags, outputFlags, profileFlag } from "./error-BWXBhqLW.mjs";
|
|
3
|
+
import { defineMetabaseCommand } from "./runtime-colqvhLf.mjs";
|
|
4
|
+
import { formatScalar, renderSummary } from "./capabilities-7L9GVMd_.mjs";
|
|
5
|
+
import { FieldValues, fieldValuesView } from "./field-MGxpNQUH.mjs";
|
|
6
|
+
import { parseId } from "./parse-id--iVTCKSo.mjs";
|
|
8
7
|
|
|
9
8
|
//#region src/commands/field/values.ts
|
|
10
9
|
var values_default = defineMetabaseCommand({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MetabaseError, NetworkError, TimeoutError, errorMessage } from "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { HttpError, createClient, probeServer } from "./runtime-
|
|
2
|
+
import { HttpError, createClient, probeServer } from "./runtime-colqvhLf.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
//#region src/domain/user.ts
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import "./command-augment-BH9qgQ5u.mjs";
|
|
2
|
-
import { connectionFlags, outputFlags, profileFlag } from "./error-
|
|
3
|
-
import { defineMetabaseCommand } from "./runtime-
|
|
4
|
-
import "./capabilities-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { SyncTaskOrIdle, formatSyncTask, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-
|
|
8
|
-
import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-DxpnK1wW.mjs";
|
|
2
|
+
import { connectionFlags, outputFlags, profileFlag } from "./error-BWXBhqLW.mjs";
|
|
3
|
+
import { defineMetabaseCommand } from "./runtime-colqvhLf.mjs";
|
|
4
|
+
import { renderSummary } from "./capabilities-7L9GVMd_.mjs";
|
|
5
|
+
import { parseId } from "./parse-id--iVTCKSo.mjs";
|
|
6
|
+
import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-BucRFJT-.mjs";
|
|
7
|
+
import { SyncTaskOrIdle, formatSyncTask, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-DTzKB3T3.mjs";
|
|
9
8
|
|
|
10
9
|
//#region src/commands/git-sync/wait.ts
|
|
11
10
|
const WaitResult = SyncTaskOrIdle;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { parseId } from "./parse-id
|
|
2
|
-
import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-
|
|
1
|
+
import { parseId } from "./parse-id--iVTCKSo.mjs";
|
|
2
|
+
import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-BucRFJT-.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/commands/wait-flags.ts
|
|
5
5
|
const waitScheduleFlags = {
|
package/package.json
CHANGED
package/skill-data/core/SKILL.md
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: core
|
|
3
|
-
description: Drive a Metabase instance from the terminal via the `mb` CLI — auth, databases, cards, dashboards, collections, transforms, queries, search, git-sync
|
|
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.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# metabase-cli (core)
|
|
8
8
|
|
|
9
|
-
The official Metabase CLI (`mb`) drives a Metabase instance over its REST API. It covers auth, list/get/create/update/delete on every resource, query and transform execution, content search, git-sync (representations ↔ instance),
|
|
9
|
+
The official Metabase CLI (`mb`) drives a Metabase instance over its REST API. It covers auth, list/get/create/update/delete on every resource, query and transform execution, content search, git-sync (representations ↔ instance), and entity-id translation.
|
|
10
10
|
|
|
11
11
|
Top-level command groups (run `mb <group> --help` to discover verbs):
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
auth | db | table | field | query | card | dashboard | snippet | segment | measure | collection
|
|
15
|
-
transform | transform-job | setting | search | git-sync |
|
|
15
|
+
document | transform | transform-job | 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; load them on demand (see "Specialized skills"). Authoring any query body (cards, transforms, measures, segments, ad-hoc `mb query`) is one — load `mbql` whenever you build MBQL by hand.
|
|
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; load them on demand (see "Specialized skills"). Authoring any query body (cards, transforms, measures, segments, ad-hoc `mb query`) is one — load `mbql` whenever you build MBQL by hand. When a **question** (card) needs a query, prefer MBQL over native SQL — it's portable across warehouse engines and the CLI pre-flight-validates it. Try it first, but don't force it: fall back to native SQL when MBQL can't express the query, or when an MBQL body keeps failing server-side and you can't resolve it.
|
|
19
19
|
|
|
20
20
|
## Auth & profiles
|
|
21
21
|
|
|
22
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
23
|
|
|
24
|
-
**The one exception** is a freshly bootstrapped workspace child: its API key is minted by the parent the human already authorized, so the agent reads it via `mb workspace credentials <ws-id>` and saves it with `auth login` — piping the key on **stdin** (`printf '%s' "$KEY" | mb auth login …`), never on an `--api-key` flag (the CLI rejects the flag form). See the `workspace` skill, step 4.
|
|
25
|
-
|
|
26
24
|
### Discover what's already configured
|
|
27
25
|
|
|
28
26
|
```bash
|
|
@@ -35,17 +33,7 @@ mb auth status --profile <name> --json # → status of a specific profile
|
|
|
35
33
|
|
|
36
34
|
### Pick the profile to use
|
|
37
35
|
|
|
38
|
-
If exactly one profile is configured and the user's intent doesn't disambiguate, use it. If multiple profiles 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
|
|
39
|
-
|
|
40
|
-
### Other secrets (license, warehouse passwords)
|
|
41
|
-
|
|
42
|
-
Same rule: the human runs the storing command. To check whether a license is present:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
mb workspace license status --json # → {present: bool}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
If `present: false`, ask the user to run `echo "<your-token>" | mb workspace license set` from their terminal — don't paste the token in chat.
|
|
36
|
+
If exactly one profile is configured and the user's intent doesn't disambiguate, use it. If multiple profiles 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.
|
|
49
37
|
|
|
50
38
|
## Flag conventions
|
|
51
39
|
|
|
@@ -56,21 +44,21 @@ If `present: false`, ask the user to run `echo "<your-token>" | mb workspace lic
|
|
|
56
44
|
❌ mb --profile prod table list # → error: "Unknown command prod"
|
|
57
45
|
```
|
|
58
46
|
|
|
59
|
-
`--profile` attaches **after** the full verb chain (`table list`, `card get`, `
|
|
47
|
+
`--profile` attaches **after** the full verb chain (`table list`, `card get`, `git-sync export`).
|
|
60
48
|
|
|
61
49
|
### `--wait` for async operations
|
|
62
50
|
|
|
63
|
-
`
|
|
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.
|
|
64
52
|
|
|
65
53
|
### Some outputs are JSON envelopes, not bare strings
|
|
66
54
|
|
|
67
|
-
A handful of "lookup" verbs return a JSON object even when you only want a single field. `mb
|
|
55
|
+
A handful of "lookup" verbs return a JSON object even when you only want a single field. `mb setting get <key>` returns `{"key": "...", "value": ...}`, not the bare value. Don't drop them raw into another flag — extract:
|
|
68
56
|
|
|
69
57
|
```bash
|
|
70
|
-
|
|
58
|
+
VALUE=$(mb setting get <key> --json | jq -r '.value')
|
|
71
59
|
```
|
|
72
60
|
|
|
73
|
-
If you find yourself
|
|
61
|
+
If you find yourself piping a `--json` envelope straight into another flag and the receiving command rejects it, this is what happened.
|
|
74
62
|
|
|
75
63
|
## Output
|
|
76
64
|
|
|
@@ -78,7 +66,7 @@ Every list/get verb supports the same output flags:
|
|
|
78
66
|
|
|
79
67
|
- `--json` — emit the full JSON envelope, safe for `jq`. Default is human-readable text.
|
|
80
68
|
- `--full` — include every field (compact projection is the default for list/get).
|
|
81
|
-
- `--fields a,b.c.d` — project specific dot-paths. Mutually exclusive with `--full`.
|
|
69
|
+
- `--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).
|
|
82
70
|
- `--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.
|
|
83
71
|
|
|
84
72
|
List envelope shape:
|
|
@@ -140,28 +128,27 @@ Use it to (a) enumerate verbs, (b) validate flag names before constructing a com
|
|
|
140
128
|
|
|
141
129
|
Routine verb shapes (list / get / create / update), every flag, and output JSON Schemas live in `mb __manifest` — pull them on demand. Below is only what the manifest does _not_ tell you: the footguns and non-obvious behaviors.
|
|
142
130
|
|
|
143
|
-
- **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
|
|
131
|
+
- **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`.
|
|
144
132
|
- **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.
|
|
145
133
|
- **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.
|
|
146
134
|
- **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.
|
|
147
|
-
- **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; use negative ids for new 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.
|
|
135
|
+
- **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; use negative ids for new cards). `create` accepts the **same** `dashcards` array in its initial body, so you can 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 that only fills 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).
|
|
148
136
|
- **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.)
|
|
149
137
|
- **segment / measure** `update` and `archive` require a non-blank `revision_message` (audit-logged); the CLI does not synthesize it on `update`. `archive` defaults to `"Archived via mb CLI"` — override with `--revision-message`. `definition` is a flat MBQL clause (→ `mbql` skill): segment = a filter, measure = exactly one aggregation.
|
|
150
138
|
- **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.
|
|
151
139
|
- **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}`).
|
|
152
140
|
- **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.
|
|
153
|
-
- **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 you get only `{run_id, final:null}`. (→ `transform` skill.)
|
|
141
|
+
- **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.)
|
|
154
142
|
- **setup is one-shot.** `mb setup` walks `/api/setup` for a **fresh** instance only — it errors against an already-configured one. Mostly for bootstrapping local / e2e instances.
|
|
155
|
-
- **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":["…"]}}'`). Useful when an external system hands you an entity id and a verb needs the numeric one.
|
|
143
|
+
- **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.
|
|
156
144
|
- **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.
|
|
157
145
|
|
|
158
146
|
## Specialized skills (load on demand)
|
|
159
147
|
|
|
160
|
-
This core file is enough for any single-command task. Load the relevant skill **proactively** when intent matches — don't wing an MBQL body,
|
|
148
|
+
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 each via `mb skills get <name>`.
|
|
161
149
|
|
|
162
150
|
- **`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.
|
|
163
151
|
- **`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`.
|
|
164
|
-
- **`workspace`** — "spin up a workspace", "provision", "start a local Metabase against my prod", anything `mb workspace …`. **Mandatory** before `workspace start` — ask the user about Remote Sync up front (the bind mount is create-time only).
|
|
165
152
|
- **`transform`** — "create a transform", "run a transform", authoring transform body JSON, run inspection.
|
|
166
153
|
- **`git-sync`** — "import the latest changes", "export to git", "git sync", "dirty check", "stash before pulling".
|
|
167
154
|
|
|
@@ -169,9 +156,9 @@ If a task spans more than one, load each. Specialized skills assume the conventi
|
|
|
169
156
|
|
|
170
157
|
## Don't
|
|
171
158
|
|
|
172
|
-
- **Don't run `mb auth login` for the user** — authentication is theirs (see §Auth).
|
|
173
|
-
- Don't paste credentials
|
|
159
|
+
- **Don't run `mb auth login` for the user** — authentication is theirs (see §Auth).
|
|
160
|
+
- Don't paste credentials or warehouse passwords in chat. Have the user run the storing command.
|
|
174
161
|
- Don't put `--profile` before the verb chain — the CLI parses it as a subcommand and errors out.
|
|
175
|
-
- Don't omit `--wait` on `
|
|
162
|
+
- Don't omit `--wait` on `transform run` / `git-sync import` for interactive flows; the next step will race the operation.
|
|
176
163
|
- Don't drop a JSON-envelope verb's output raw into another flag. Extract with `--json | jq -r '.<field>'`.
|
|
177
164
|
- Don't add a third-party HTTP library or shell into `curl` against `/api/...` when a `mb <verb>` exists — that bypasses retries, schema validation, and credential redaction.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: document
|
|
3
|
+
description: Author and edit Metabase documents via `mb` — the TipTap (ProseMirror) JSON body shape, the node-type inventory (paragraphs, headings, lists, plus the Metabase-custom `cardEmbed` / `smartLink` / `flexContainer` / `resizeNode`), the per-node-type `_id` requirement, embedding existing or brand-new cards, and the list/get/create/update/archive verbs. Load when the user touches documents — "create a document", "add a card to a document", "edit a document", "list documents", or anything `mb document …`.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Documents
|
|
8
|
+
|
|
9
|
+
A **document** is a Metabase rich-text page (a "report" / notebook) that mixes prose with embedded saved questions and links to other Metabase entities. The body is a **TipTap** JSON tree (TipTap is the editor; the wire format is ProseMirror JSON, and the server stores it under `content_type: "application/json+vnd.prose-mirror"`).
|
|
10
|
+
|
|
11
|
+
This skill covers authoring the body and driving the verbs. General flag conventions, body-input precedence, and output flags live in the `core` skill (`mb skills get core`).
|
|
12
|
+
|
|
13
|
+
## Command surface
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mb document list --profile <name> --json # non-archived docs visible to you
|
|
17
|
+
mb document get <id> --profile <name> --full --json # one doc incl. its TipTap body
|
|
18
|
+
mb document create --file doc.json --profile <name> --json
|
|
19
|
+
mb document update <id> --file patch.json --profile <name> --json # PATCH semantics
|
|
20
|
+
mb document archive <id> --profile <name> --json # soft-delete (PUT archived:true)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `list` returns the standard envelope (`{data, returned, total}`). The compact item is `{id, name, collection_id, archived, creator_id, can_write}` — it does **not** include the (potentially huge) `document` body. Pull the body with `get --full`.
|
|
24
|
+
- `archive` is the only delete, mirroring `card` / `dashboard`. **Unarchive** with `mb document update <id> --body '{"archived":false}'`.
|
|
25
|
+
- `update` is PATCH — send only the keys you want to change (`name`, `document`, `collection_id`, `collection_position`, `archived`). Replacing `document` replaces the **whole** body; there is no partial-node patch.
|
|
26
|
+
|
|
27
|
+
## Node ids (`_id`)
|
|
28
|
+
|
|
29
|
+
The editor anchors only these node types with an `_id` (a UUID): `paragraph`, `heading`, `codeBlock`, `orderedList`, `bulletList`, `blockquote`, `cardEmbed`, `supportingText`. **`create`/`update` require a non-empty `_id` on every node of those types** and reject a body missing any; other node types (`doc`, `text`, `listItem`, `resizeNode`, `flexContainer`, …) don't take an `_id` and are left alone. Mint the ids with the bundled `uuid` command — one per id-bearing node:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
mb uuid --count 5 --json # → ["…", …] one UUID per id-bearing node
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Set each as that node's `attrs._id`. Without them the editor backfills ids when the document opens, which makes a freshly-saved document show a spurious "unsaved changes" prompt.
|
|
36
|
+
|
|
37
|
+
## Body shape (create / update)
|
|
38
|
+
|
|
39
|
+
The create body is `{name, document, collection_id?, collection_position?}`. `name` and `document` are required on create; everything is optional on update.
|
|
40
|
+
|
|
41
|
+
`document` is the TipTap tree — a root `doc` node whose `content` is an array of block nodes (replace each `<uuid-N>` with an `mb uuid` value):
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"name": "Weekly report",
|
|
46
|
+
"collection_id": 12,
|
|
47
|
+
"document": {
|
|
48
|
+
"type": "doc",
|
|
49
|
+
"content": [
|
|
50
|
+
{
|
|
51
|
+
"type": "heading",
|
|
52
|
+
"attrs": { "level": 1, "_id": "<uuid-1>" },
|
|
53
|
+
"content": [{ "type": "text", "text": "Weekly report" }]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "paragraph",
|
|
57
|
+
"attrs": { "_id": "<uuid-2>" },
|
|
58
|
+
"content": [{ "type": "text", "text": "Orders trended up this week." }]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`collection_id: null` (or omitted) files the document in "Our analytics" (the root). `collection_id` accepts any normal analytics collection id (unlike transforms, documents are not namespace-restricted).
|
|
66
|
+
|
|
67
|
+
## Node inventory
|
|
68
|
+
|
|
69
|
+
Every node is `{ "type": string, "attrs"?: object, "content"?: [nodes], "text"?: string, "marks"?: [marks] }`. The id-bearing types listed above carry `attrs._id`; the rest don't.
|
|
70
|
+
|
|
71
|
+
**Standard text nodes** (TipTap StarterKit):
|
|
72
|
+
|
|
73
|
+
- `doc` — the root; `content` holds block nodes.
|
|
74
|
+
- `paragraph` — `content` is inline nodes (usually `text`). An empty paragraph (`{ "type": "paragraph", "attrs": { "_id": "<uuid>" } }`) is a blank line.
|
|
75
|
+
- `text` — a leaf with `text` and optional `marks` (no `_id`).
|
|
76
|
+
- `heading` — `attrs.level` 1–6.
|
|
77
|
+
- `bulletList` / `orderedList` — `content` is `listItem` nodes (no `_id`); each `listItem` wraps `paragraph`(s).
|
|
78
|
+
- `blockquote`, `codeBlock`, `horizontalRule`, `hardBreak`, `image`.
|
|
79
|
+
|
|
80
|
+
**Marks** on `text` (the `marks` array): `bold`, `italic`, `strike`, `code`, plus `link` (`attrs.href`). Example: `{ "type": "text", "text": "important", "marks": [{ "type": "bold" }] }`.
|
|
81
|
+
|
|
82
|
+
**Metabase-custom nodes** (the reason a document is more than a wiki page):
|
|
83
|
+
|
|
84
|
+
- **`cardEmbed`** — an embedded saved question. Block, atomic, id-bearing. `attrs: { "id": <card-id>, "name": <string|null>, "_id": "<uuid>" }`. `name` overrides the displayed title (`null` = use the card's own name). Card embeds are commonly wrapped in a `resizeNode` to give them a fixed height.
|
|
85
|
+
- **`resizeNode`** — wraps a single `cardEmbed` or `flexContainer` to make it resizable (no `_id`). `attrs: { "height": <px>, "minHeight": <px> }`, `content` is exactly one `cardEmbed`/`flexContainer`.
|
|
86
|
+
- **`flexContainer`** — a horizontal row of 1–3 `cardEmbed` / `supportingText` cells side by side (no `_id`). `attrs.columnWidths` is an array of width percentages.
|
|
87
|
+
- **`supportingText`** — a text column that sits next to a card inside a `flexContainer` (id-bearing); `content` is the usual block nodes (`paragraph`, `heading`, lists, …).
|
|
88
|
+
- **`smartLink`** — an inline reference to a Metabase entity (renders as a live chip). Inline, atomic, no `_id`. `attrs: { "entityId": <id>, "model": <model>, "label": <string|null>, "href": <relative-path> }`. `model` ∈ `card`, `dataset`, `metric`, `dashboard`, `collection`, `table`, `database`, `document`, `transform`, `segment`, `measure`, `user`, `action`, `indexed-entity`.
|
|
89
|
+
- **`metabot`** — an inline Metabot prompt block.
|
|
90
|
+
|
|
91
|
+
## Embedding an existing card
|
|
92
|
+
|
|
93
|
+
A document embedding an existing card (id 114) under a heading (only the id-bearing nodes carry `_id`):
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"type": "doc",
|
|
98
|
+
"content": [
|
|
99
|
+
{
|
|
100
|
+
"type": "heading",
|
|
101
|
+
"attrs": { "level": 2, "_id": "<uuid-1>" },
|
|
102
|
+
"content": [{ "type": "text", "text": "Orders" }]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"type": "resizeNode",
|
|
106
|
+
"attrs": { "height": 400, "minHeight": 200 },
|
|
107
|
+
"content": [{ "type": "cardEmbed", "attrs": { "id": 114, "name": null, "_id": "<uuid-2>" } }]
|
|
108
|
+
},
|
|
109
|
+
{ "type": "paragraph", "attrs": { "_id": "<uuid-3>" } }
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
To embed an existing card, find its id with `mb card list --profile <name> --json` (or `mb search --models card "<text>"`), then reference it in a `cardEmbed`.
|
|
115
|
+
|
|
116
|
+
## Creating brand-new cards inline with the document
|
|
117
|
+
|
|
118
|
+
You can create cards atomically with the document instead of pre-creating them. Reference each new card by a **negative** id in its `cardEmbed.attrs.id`, then supply the card definitions in a top-level `cards` map keyed by the same negative ids. The server creates the real cards and rewrites the negative ids to the real positive ids in the stored body.
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"name": "Auto report",
|
|
123
|
+
"document": {
|
|
124
|
+
"type": "doc",
|
|
125
|
+
"content": [
|
|
126
|
+
{ "type": "cardEmbed", "attrs": { "id": -1, "name": null, "_id": "<uuid-1>" } },
|
|
127
|
+
{ "type": "paragraph", "attrs": { "_id": "<uuid-2>" } }
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"cards": {
|
|
131
|
+
"-1": {
|
|
132
|
+
"name": "Order count",
|
|
133
|
+
"display": "scalar",
|
|
134
|
+
"dataset_query": { "...": "an MBQL or native query — see the mbql skill" },
|
|
135
|
+
"visualization_settings": {}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Each entry in `cards` needs at least `{name, dataset_query, display, visualization_settings}` (these are card definitions, not TipTap nodes, so they take no `_id`). Author the `dataset_query` with the `mbql` skill (`mb skills get mbql`) and the `visualization_settings` with the `viz` skill. For most edits, prefer embedding cards that already exist (a plain positive `id` in `cardEmbed`) — inline creation is for "build the report and its questions in one shot".
|
|
142
|
+
|
|
143
|
+
## Iterating on a document
|
|
144
|
+
|
|
145
|
+
`update` replaces the whole `document` body, so the safe loop is **read → edit → write**. A fetched body already carries `_id`s on its id-bearing nodes, so preserve them — only mint new ones for id-bearing nodes you add:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
mb document get <id> --full --profile <name> --json | jq '.document' > /tmp/body.json
|
|
149
|
+
# edit /tmp/body.json (add nodes — give each new id-bearing node a fresh `mb uuid` _id) …
|
|
150
|
+
jq -n --slurpfile d /tmp/body.json '{document: $d[0]}' > /tmp/patch.json
|
|
151
|
+
mb document update <id> --file /tmp/patch.json --profile <name> --json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Don't hand-merge a partial node tree into a live document — pull the current `document`, mutate the array, and PUT the whole thing back. To rename without touching the body, patch only `name`: `mb document update <id> --body '{"name":"New title"}'`.
|
|
155
|
+
|
|
156
|
+
## Don't
|
|
157
|
+
|
|
158
|
+
- Don't omit `_id` on an id-bearing node (`paragraph`, `heading`, `codeBlock`, `orderedList`, `bulletList`, `blockquote`, `cardEmbed`, `supportingText`) — `create`/`update` reject the body ("did not match expected schema"). Mint ids with `mb uuid`.
|
|
159
|
+
- Don't paste a whole `document get` response into `update` — `update` only accepts `name`, `document`, `collection_id`, `collection_position`, `archived`. Send the body under the `document` key, not the full record.
|
|
160
|
+
- Don't put the full `document` body in `list` expectations — `list` is compact and omits it by design; use `get --full`.
|
|
161
|
+
- Don't invent node types. Stick to the inventory above; unknown block types render as empty/broken in the editor even though the response schema is lenient.
|
|
162
|
+
- Don't author a card's `dataset_query` or `visualization_settings` from this skill alone — load `mbql` and `viz`.
|