@metabase/cli 0.1.6 → 0.1.8-alpha.cleanup-workspaces.75fe1d5

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 (198) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +16 -238
  3. package/dist/add-collection-BGifL-7Y.mjs +10 -0
  4. package/dist/{add-collection-BU8r3r2M.mjs → add-collection-C5ijC4e-.mjs} +8 -6
  5. package/dist/{archive-BNinrUak.mjs → archive-2GZVq0n2.mjs} +7 -8
  6. package/dist/{archive-lWgqiFAt.mjs → archive-C5pXDf6a.mjs} +5 -6
  7. package/dist/{archive-C1enZgKV.mjs → archive-CTEybKPq.mjs} +6 -7
  8. package/dist/{archive-DMPS8Kih.mjs → archive-DEtOH_jf.mjs} +5 -6
  9. package/dist/{archive-CDA0KxL8.mjs → archive-DTrn90If.mjs} +5 -6
  10. package/dist/{archive-CRhiBpPJ.mjs → archive-nqKJOyOt.mjs} +5 -6
  11. package/dist/auth-Divr9vkY.mjs +19 -0
  12. package/dist/{body-DjdFxjpg.mjs → body-BMyDvOjf.mjs} +2 -2
  13. package/dist/{branches-B1WRfG7-.mjs → branches-B7Zf-nxr.mjs} +5 -6
  14. package/dist/{cancel-Dl_Ho056.mjs → cancel-WwjcCE2R.mjs} +6 -7
  15. package/dist/{cancel-task-CdigdCaO.mjs → cancel-task-E4cCeJTc.mjs} +6 -7
  16. package/dist/{render-CfznwleY.mjs → capabilities-Dj3NgPHg.mjs} +66 -10
  17. package/dist/card-BHAcovSB.mjs +20 -0
  18. package/dist/{card-DlCAaAPq.mjs → card-BtPiKjbB.mjs} +1 -1
  19. package/dist/{cards-BGiJS675.mjs → cards-BW0Spirk.mjs} +4 -5
  20. package/dist/cli.mjs +23 -24
  21. package/dist/collection-DZx-vWb2.mjs +20 -0
  22. package/dist/{create-BNiva__H.mjs → create-BV_VpyyI.mjs} +11 -12
  23. package/dist/{create-BTcpaop_.mjs → create-B_Ysb6Ex.mjs} +7 -8
  24. package/dist/{create-BYlIju0b.mjs → create-BgeD2GMZ.mjs} +10 -11
  25. package/dist/{create-DGth_uOp.mjs → create-Bxkik5Fs.mjs} +9 -10
  26. package/dist/{create-CzzrbL0u.mjs → create-CZfHpi_I.mjs} +8 -9
  27. package/dist/{create-Be_0Vier.mjs → create-CbwFOL9h.mjs} +8 -9
  28. package/dist/{create-dhxPxfF3.mjs → create-CbyY4xTG.mjs} +12 -13
  29. package/dist/{create-CwGtmwqm.mjs → create-HCCdsuZR.mjs} +9 -10
  30. package/dist/{create-branch-DKZkoQ64.mjs → create-branch-BNRq3tO2.mjs} +6 -7
  31. package/dist/{current-task-CCRzm0_7.mjs → current-task-ZvTjL4hP.mjs} +7 -8
  32. package/dist/dashboard-DCWGcx3e.mjs +21 -0
  33. package/dist/{database-lH-B3G1I.mjs → database-_Td7rG4o.mjs} +1 -1
  34. package/dist/db-bD6fwLwc.mjs +22 -0
  35. package/dist/{delete-ZjnV35OJ.mjs → delete-D5-ITH10.mjs} +8 -7
  36. package/dist/{delete-Dimc-2y8.mjs → delete-DvmHTMwf.mjs} +8 -7
  37. package/dist/{delete-runtime-B6RQo_pw.mjs → delete-runtime-Bo7v-0au.mjs} +6 -6
  38. package/dist/{delete-table-agZJpivt.mjs → delete-table-DjmO5Qe4.mjs} +8 -7
  39. package/dist/{dirty-D4d0yHqj.mjs → dirty-BJgU1SGQ.mjs} +5 -6
  40. package/dist/{eid-BXzaQh0o.mjs → eid-pqSVgO2g.mjs} +12 -8
  41. package/dist/{error-C9S6PN3-.mjs → error-Br6irjpM.mjs} +3 -2
  42. package/dist/{export-DTygoXBP.mjs → export-gVXTOxC2.mjs} +10 -10
  43. package/dist/field-BFWc8q2W.mjs +18 -0
  44. package/dist/{field-yomXlkvl.mjs → field-MGxpNQUH.mjs} +12 -3
  45. package/dist/{fields-CoQi99gv.mjs → fields-DK2TYRK2.mjs} +6 -7
  46. package/dist/{get-DQTZG_NP.mjs → get-BjArD6Er.mjs} +4 -5
  47. package/dist/{get-C3HdQ91a.mjs → get-C1RSXOhf.mjs} +5 -6
  48. package/dist/{get-DSWFjy7O.mjs → get-C3RI_hKG.mjs} +4 -5
  49. package/dist/{get-C_w1kvN3.mjs → get-C7UEEICF.mjs} +6 -7
  50. package/dist/{get-Bzys7vgp.mjs → get-D-3tOuWQ.mjs} +4 -5
  51. package/dist/{get-Hc93A0Yz.mjs → get-DDF7_apz.mjs} +5 -6
  52. package/dist/{get-D3SbEQSE.mjs → get-DYgLtHb8.mjs} +4 -5
  53. package/dist/{get-CP3Z3NiH.mjs → get-DnK3WGDH.mjs} +6 -7
  54. package/dist/{get-C2p383Qc.mjs → get-DnyZMx-0.mjs} +5 -6
  55. package/dist/{get-DFxZXaKz.mjs → get-DtG5ytvs.mjs} +5 -7
  56. package/dist/{get-CzuzeKSe.mjs → get-Dy4NedW5.mjs} +7 -8
  57. package/dist/{get-Ddr0XLh7.mjs → get-_JI4GiPa.mjs} +5 -6
  58. package/dist/{get-run-B7sKdaDU.mjs → get-run-CZwIo5QR.mjs} +5 -6
  59. package/dist/{get-lb7q3JYs.mjs → get-xo5_PD1n.mjs} +3 -4
  60. package/dist/git-sync-Ch00miSa.mjs +28 -0
  61. package/dist/{has-remote-changes-BY10-nnE.mjs → has-remote-changes-tuuoPdHV.mjs} +7 -7
  62. package/dist/{import-CiMz4Wz-.mjs → import-BOzyRPTk.mjs} +11 -10
  63. package/dist/{is-dirty-BZOaryxT.mjs → is-dirty-BXN1F9yR.mjs} +5 -5
  64. package/dist/is-dirty-Bc1UHnBU.mjs +9 -0
  65. package/dist/{items-BWfvkY-J.mjs → items-CC4sSWv7.mjs} +4 -5
  66. package/dist/{list-SOG0whQ-.mjs → list-BUpOvQsd.mjs} +3 -4
  67. package/dist/{list-Clz5igWg.mjs → list-BlMpI88r.mjs} +4 -6
  68. package/dist/{list-2j7GsXsl.mjs → list-BqTdYtOW.mjs} +3 -4
  69. package/dist/{list-C3hfovHv.mjs → list-BvTuDJZp.mjs} +4 -5
  70. package/dist/{list-DZ8fNUoQ.mjs → list-C48ZZLM5.mjs} +6 -7
  71. package/dist/{list-BI4zr8LW.mjs → list-CJe45jFT.mjs} +6 -7
  72. package/dist/{list-D4sFiqX8.mjs → list-CMoG5_mh.mjs} +5 -6
  73. package/dist/{list-d58BprgJ.mjs → list-CkI3hESA.mjs} +4 -5
  74. package/dist/{list-sD5N3fGk.mjs → list-CybLzPZw.mjs} +6 -7
  75. package/dist/{list-CL7eCOQE.mjs → list-DLhU81LP.mjs} +3 -4
  76. package/dist/{list-Brgh-Z2v.mjs → list-Ddyb5T-7.mjs} +4 -5
  77. package/dist/{list-DXH7TlkU.mjs → list-tveV3LKh.mjs} +4 -5
  78. package/dist/{list--OYdUTtu.mjs → list-u7cmunGG.mjs} +4 -5
  79. package/dist/{login-Bm2AnCez.mjs → login-Bfsf6jLq.mjs} +17 -14
  80. package/dist/{logout-BlyRJODO.mjs → logout-BCsE_1Yg.mjs} +9 -9
  81. package/dist/{manifest-BBR46KFM.mjs → manifest-B_OfG-Ss.mjs} +1 -2
  82. package/dist/measure-D_eiCKq9.mjs +19 -0
  83. package/dist/{metadata-B8ZSF9LA.mjs → metadata-Cbqx1-yW.mjs} +7 -8
  84. package/dist/{metadata-DqiI2q9q.mjs → metadata-CzbGy4b-.mjs} +6 -7
  85. package/dist/{parse-id-lk_K-CEF.mjs → parse-id-DBwNYb4Y.mjs} +1 -1
  86. package/dist/{path-AEtZ3mBq.mjs → path-DJ-DfUGC.mjs} +4 -6
  87. package/dist/{poll-DHKDpCiq.mjs → poll-DWkVceIk.mjs} +1 -1
  88. package/dist/{poll-task-Cooi0lQV.mjs → poll-task-DOvUDrgL.mjs} +19 -3
  89. package/dist/{preflight-aXV5LyDs.mjs → preflight-D-l6sLCX.mjs} +3 -3
  90. package/dist/{query-AaKzYnTY.mjs → query--05TZxmk.mjs} +9 -8
  91. package/dist/{query-BlsVNZpD.mjs → query-BbbDpt3u.mjs} +12 -12
  92. package/dist/query-result-PoQE05Pe.mjs +19 -0
  93. package/dist/{remove-collection-CoCmrrQs.mjs → remove-collection-Dco3yXa-.mjs} +10 -9
  94. package/dist/{render-OQn3iRsI.mjs → render-BQHJhSP1.mjs} +1 -1
  95. package/dist/{rescan-values-C0FDsjT7.mjs → rescan-values-B1vE6I62.mjs} +9 -10
  96. package/dist/{run-B4Wn43zm.mjs → run-CWb_yZbK.mjs} +14 -14
  97. package/dist/{runs-Bbaszr18.mjs → runs-BLwEO5sW.mjs} +5 -6
  98. package/dist/{runtime-Dmv5VtUK.mjs → runtime-DKLBPRhd.mjs} +16 -87
  99. package/dist/{schema-tables-CaWinbuK.mjs → schema-tables-D1qE25GS.mjs} +6 -7
  100. package/dist/{schemas-DUgGpAyB.mjs → schemas-CFuYnQDg.mjs} +4 -5
  101. package/dist/{search-BLrBXLUk.mjs → search-CF4A051Z.mjs} +4 -5
  102. package/dist/segment-BP_vDpYM.mjs +19 -0
  103. package/dist/{set-DfGsta5O.mjs → set-BJ8Rs-vI.mjs} +7 -7
  104. package/dist/setting-EYI0HqTq.mjs +17 -0
  105. package/dist/{setup-C9ikBRw_.mjs → setup-DI6EGOdH.mjs} +7 -8
  106. package/dist/{skills-CiN1OQ8W.mjs → skills-BDPVoBWU.mjs} +33 -2
  107. package/dist/{skills-CUHIcQS6.mjs → skills-CRECMGAo.mjs} +3 -3
  108. package/dist/snippet-BwK58D1F.mjs +19 -0
  109. package/dist/{stash-EIDcSvpF.mjs → stash-BpPS0uG8.mjs} +11 -10
  110. package/dist/{status-95ElRAu9.mjs → status-BqFA7Tqr.mjs} +10 -8
  111. package/dist/{status-B0_MiZEf.mjs → status-CU5LYX0i.mjs} +4 -5
  112. package/dist/{summary-C12LiEuJ.mjs → summary-CraRyIM_.mjs} +5 -6
  113. package/dist/{sync-schema-Ba8M3DiX.mjs → sync-schema-DkfwPESH.mjs} +9 -10
  114. package/dist/table-CJMN6ql8.mjs +19 -0
  115. package/dist/{table-C7a5V6Zn.mjs → table-CkWja2UH.mjs} +1 -1
  116. package/dist/transform-BqV5ssDN.mjs +24 -0
  117. package/dist/transform-job-DvdOLV9b.mjs +19 -0
  118. package/dist/{tree-Des2ZG9d.mjs → tree-Bd1i-Y4U.mjs} +3 -4
  119. package/dist/{update-DzAN4SPj.mjs → update-BLZHmA0X.mjs} +10 -11
  120. package/dist/{update-CyIZdbIQ.mjs → update-BncGqeWt.mjs} +9 -10
  121. package/dist/{update-DSgceARZ.mjs → update-C4f-8fsU.mjs} +9 -10
  122. package/dist/{update-njHe3j-s.mjs → update-CgpgyDjd.mjs} +10 -11
  123. package/dist/{update-DBi5U8zb.mjs → update-CsYa--Eb.mjs} +12 -13
  124. package/dist/{update-mYVnoYNV.mjs → update-DA9aPhRr.mjs} +11 -12
  125. package/dist/{update-_QfgNa53.mjs → update-DtO-1_tj.mjs} +10 -11
  126. package/dist/{update-Bx54nWEI.mjs → update-IPsv9Pj0.mjs} +12 -13
  127. package/dist/{update-F6DmZncY.mjs → update-OZoOTnlY.mjs} +9 -10
  128. package/dist/{update-dashcard-wpSjv4M7.mjs → update-dashcard-D0VAwfNO.mjs} +8 -9
  129. package/dist/{upgrade-iAuvhX-W.mjs → upgrade-Bb_q7hJ7.mjs} +41 -28
  130. package/dist/{uuid-CMKnS8-z.mjs → uuid-DTdRruiz.mjs} +3 -4
  131. package/dist/{validate-dPEOnOf8.mjs → validate-CqVB_3_p.mjs} +1 -1
  132. package/dist/{validate-query-Cw6WE5Y8.mjs → validate-query-BUTNK00f.mjs} +2 -2
  133. package/dist/values-Bpt6obVW.mjs +44 -0
  134. package/dist/{verify-D5YtTqqp.mjs → verify-COt2q73-.mjs} +1 -1
  135. package/dist/{wait-Bv3Tsnv4.mjs → wait-DoKPlspq.mjs} +8 -9
  136. package/dist/{wait-flags-Dzq9BGQY.mjs → wait-flags-D1jNm0JK.mjs} +2 -2
  137. package/package.json +1 -1
  138. package/skill-data/core/SKILL.md +15 -28
  139. package/skill-data/git-sync/SKILL.md +8 -63
  140. package/skill-data/mbql/SKILL.md +2 -0
  141. package/skill-data/transform/SKILL.md +16 -6
  142. package/skill-data/visualization/SKILL.md +158 -0
  143. package/skill-data/visualization/references/settings.md +414 -0
  144. package/skills/metabase-cli/SKILL.md +1 -1
  145. package/dist/add-collection-C0w6ACQF.mjs +0 -11
  146. package/dist/auth-CzXb_zB2.mjs +0 -19
  147. package/dist/capabilities-7e9MgquN.mjs +0 -29
  148. package/dist/card-DP4rfoOi.mjs +0 -21
  149. package/dist/collection-tY18ezvn.mjs +0 -21
  150. package/dist/create-CHF313Qg.mjs +0 -52
  151. package/dist/credentials-dzeq7ckm.mjs +0 -88
  152. package/dist/dashboard-ChM_Tu0l.mjs +0 -22
  153. package/dist/database-CIXwHKjK.mjs +0 -17
  154. package/dist/db-DrQn_i3W.mjs +0 -22
  155. package/dist/delete-CM3jnAeQ.mjs +0 -100
  156. package/dist/deprovision-CwxcIT3k.mjs +0 -65
  157. package/dist/docker-Oq80q3tu.mjs +0 -515
  158. package/dist/field-Z6Pcxf4n.mjs +0 -19
  159. package/dist/git-sync-CiGAad76.mjs +0 -28
  160. package/dist/is-dirty-Ume4oV0j.mjs +0 -10
  161. package/dist/license-Dxarh-gG.mjs +0 -17
  162. package/dist/list-zSO0DMw-.mjs +0 -36
  163. package/dist/logs-CywPikkL.mjs +0 -60
  164. package/dist/measure-C44EK_xt.mjs +0 -20
  165. package/dist/parse-schemas-BqUdWUwq.mjs +0 -12
  166. package/dist/process-C7V8LJ-j.mjs +0 -105
  167. package/dist/provision-UWcNDoDe.mjs +0 -82
  168. package/dist/ps-CJU0EbrC.mjs +0 -80
  169. package/dist/ps-DEroLgbI.mjs +0 -11
  170. package/dist/remove-BFWun0e8.mjs +0 -63
  171. package/dist/segment-B3Uwwcsm.mjs +0 -20
  172. package/dist/set-B8cUbRLD.mjs +0 -68
  173. package/dist/setting-D2p2MA7f.mjs +0 -18
  174. package/dist/snippet-B7D0uWlz.mjs +0 -20
  175. package/dist/start-3PX3ahjT.mjs +0 -413
  176. package/dist/status-CEplmC44.mjs +0 -34
  177. package/dist/stop-CQ0XGrN8.mjs +0 -83
  178. package/dist/table-e6h8SLVX.mjs +0 -20
  179. package/dist/transform-BMYh1lsC.mjs +0 -25
  180. package/dist/transform-job-Cm7z5TfH.mjs +0 -20
  181. package/dist/update-DHZubok3.mjs +0 -77
  182. package/dist/url-DWaT6WIZ.mjs +0 -56
  183. package/dist/values-BfSTAbzc.mjs +0 -37
  184. package/dist/wait-8yV9_WIo.mjs +0 -19
  185. package/dist/workspace-BBXJczJK.mjs +0 -72
  186. package/dist/workspace-CKLZrR7l.mjs +0 -26
  187. package/dist/workspace-credentials-BXpABsNZ.mjs +0 -100
  188. package/dist/yaml-YTQiYJ9s.mjs +0 -43
  189. package/skill-data/viz/SKILL.md +0 -137
  190. package/skill-data/viz/references/settings.md +0 -312
  191. package/skill-data/workspace/SKILL.md +0 -390
  192. /package/dist/{body-flags-D7q87Btw.mjs → body-flags-D78h_-Ua.mjs} +0 -0
  193. /package/dist/{input-cMSEqISy.mjs → input-xewHccej.mjs} +0 -0
  194. /package/dist/{parse-enum-CrEWOhuY.mjs → parse-enum-Dr7ACrTR.mjs} +0 -0
  195. /package/dist/{prompt-CFKoys7k.mjs → prompt-u4WhE4T5.mjs} +0 -0
  196. /package/dist/{snippet-COggaWxx.mjs → snippet-xh42tYly.mjs} +0 -0
  197. /package/dist/{transform-GTW3G-01.mjs → transform-DyJb0bV0.mjs} +0 -0
  198. /package/dist/{transform-job-DeTDPMxt.mjs → transform-job-DpDGoqQt.mjs} +0 -0
@@ -1,56 +0,0 @@
1
- import "./command-augment-BH9qgQ5u.mjs";
2
- import { outputFlags } from "./error-C9S6PN3-.mjs";
3
- import { defineMetabaseCommand, localUrl } from "./runtime-Dmv5VtUK.mjs";
4
- import "./capabilities-7e9MgquN.mjs";
5
- import { renderScalar } from "./render-CfznwleY.mjs";
6
- import { parseId } from "./parse-id-lk_K-CEF.mjs";
7
- import "./poll-DHKDpCiq.mjs";
8
- import "./process-C7V8LJ-j.mjs";
9
- import { checkDockerReady, requireWorkspaceContainerLocation } from "./docker-Oq80q3tu.mjs";
10
- import { z } from "zod";
11
-
12
- //#region src/commands/workspace/url.ts
13
- const UrlResult = z.object({
14
- workspace_id: z.number().int().positive(),
15
- url: z.string()
16
- });
17
- const urlResultView = {
18
- compactPick: UrlResult,
19
- tableColumns: [{
20
- key: "workspace_id",
21
- label: "ID"
22
- }, {
23
- key: "url",
24
- label: "URL"
25
- }]
26
- };
27
- var url_default = defineMetabaseCommand({
28
- meta: {
29
- name: "url",
30
- description: "Print the local URL the workspace's container is bound to"
31
- },
32
- capabilities: null,
33
- args: {
34
- ...outputFlags,
35
- id: {
36
- type: "positional",
37
- description: "Workspace id",
38
- required: true
39
- }
40
- },
41
- outputSchema: UrlResult,
42
- examples: ["mb workspace url 1", "mb workspace url 1 --json"],
43
- async run({ args, ctx }) {
44
- const workspaceId = parseId(args.id);
45
- await checkDockerReady();
46
- const { hostPort } = await requireWorkspaceContainerLocation(workspaceId);
47
- const result = {
48
- workspace_id: workspaceId,
49
- url: localUrl(hostPort)
50
- };
51
- renderScalar(result, urlResultView, result.url, ctx);
52
- }
53
- });
54
-
55
- //#endregion
56
- export { url_default as default };
@@ -1,37 +0,0 @@
1
- import "./command-augment-BH9qgQ5u.mjs";
2
- import { connectionFlags, outputFlags, profileFlag } from "./error-C9S6PN3-.mjs";
3
- import { defineMetabaseCommand } from "./runtime-Dmv5VtUK.mjs";
4
- import "./capabilities-7e9MgquN.mjs";
5
- import { renderItem } from "./render-CfznwleY.mjs";
6
- import { FieldValues, fieldValuesView } from "./field-yomXlkvl.mjs";
7
- import { parseId } from "./parse-id-lk_K-CEF.mjs";
8
-
9
- //#region src/commands/field/values.ts
10
- var values_default = defineMetabaseCommand({
11
- meta: {
12
- name: "values",
13
- description: "Fetch the cached distinct values for a field (FieldValues list)"
14
- },
15
- capabilities: { minVersion: 58 },
16
- args: {
17
- ...outputFlags,
18
- ...profileFlag,
19
- ...connectionFlags,
20
- id: {
21
- type: "positional",
22
- description: "Field id",
23
- required: true
24
- }
25
- },
26
- outputSchema: FieldValues,
27
- examples: ["mb field values 100", "mb field values 100 --json"],
28
- async run({ args, ctx, getClient }) {
29
- const id = parseId(args.id);
30
- const client = await getClient();
31
- const values = await client.requestParsed(FieldValues, `/api/field/${id}/values`);
32
- renderItem(values, fieldValuesView, ctx);
33
- }
34
- });
35
-
36
- //#endregion
37
- export { values_default as default };
@@ -1,19 +0,0 @@
1
- import { pollUntil } from "./poll-DHKDpCiq.mjs";
2
- import { Workspace } from "./workspace-BBXJczJK.mjs";
3
-
4
- //#region src/commands/workspace/database/wait.ts
5
- async function waitForDatabaseProvisioned(client, workspaceId, databaseId, schedule) {
6
- return pollUntil(() => client.requestParsed(Workspace, `/api/ee/workspace-manager/${workspaceId}`), (workspace) => {
7
- const entry = workspace.databases?.find((row) => row.database_id === databaseId);
8
- return entry !== void 0 && entry.status === "provisioned";
9
- }, schedule);
10
- }
11
- async function waitForDatabaseGone(client, workspaceId, databaseId, schedule) {
12
- await pollUntil(() => client.requestParsed(Workspace, `/api/ee/workspace-manager/${workspaceId}`), (workspace) => {
13
- const entry = workspace.databases?.find((row) => row.database_id === databaseId);
14
- return entry === void 0;
15
- }, schedule);
16
- }
17
-
18
- //#endregion
19
- export { waitForDatabaseGone, waitForDatabaseProvisioned };
@@ -1,72 +0,0 @@
1
- import { z } from "zod";
2
-
3
- //#region src/domain/workspace.ts
4
- const WorkspaceDatabaseStatus = z.enum([
5
- "unprovisioned",
6
- "provisioning",
7
- "provisioned",
8
- "deprovisioning"
9
- ]);
10
- const WorkspaceDatabase = z.object({
11
- database_id: z.number().int(),
12
- output_namespace: z.string(),
13
- input_schemas: z.array(z.string().min(1)),
14
- status: WorkspaceDatabaseStatus
15
- }).loose();
16
- const WorkspaceCreator = z.object({
17
- id: z.number().int(),
18
- first_name: z.string().nullable(),
19
- last_name: z.string().nullable(),
20
- email: z.string(),
21
- common_name: z.string().nullable().optional()
22
- }).loose();
23
- const Workspace = z.object({
24
- id: z.number().int(),
25
- name: z.string(),
26
- creator: WorkspaceCreator.nullable(),
27
- created_at: z.string(),
28
- updated_at: z.string(),
29
- databases: z.array(WorkspaceDatabase).optional()
30
- }).loose();
31
- const WorkspaceCompact = Workspace.pick({
32
- id: true,
33
- name: true,
34
- databases: true
35
- }).strip();
36
- const WorkspaceDatabaseList = z.array(WorkspaceDatabase);
37
- const workspaceView = {
38
- compactPick: WorkspaceCompact,
39
- tableColumns: [
40
- {
41
- key: "id",
42
- label: "ID"
43
- },
44
- {
45
- key: "name",
46
- label: "Name"
47
- },
48
- {
49
- key: "databases",
50
- label: "Databases",
51
- format: (value) => formatDatabases(value)
52
- }
53
- ]
54
- };
55
- const WorkspaceCreateInput = z.object({ name: z.string().min(1) }).loose();
56
- const WorkspaceProvisionInput = z.object({
57
- database_id: z.number().int().positive(),
58
- input_schemas: z.array(z.string().min(1)).min(1)
59
- }).loose();
60
- const WorkspaceUpdateDatabaseInput = z.object({ input_schemas: z.array(z.string().min(1)).min(1) }).loose();
61
- function formatDatabases(value) {
62
- if (value === void 0) return "";
63
- const parsed = WorkspaceDatabaseList.safeParse(value);
64
- if (!parsed.success || parsed.data.length === 0) return "(none)";
65
- return parsed.data.map((entry) => {
66
- const schemas = entry.input_schemas.length === 0 ? "" : ` [${entry.input_schemas.join(", ")}]`;
67
- return `${entry.database_id} (${entry.status})${schemas}`;
68
- }).join("; ");
69
- }
70
-
71
- //#endregion
72
- export { Workspace, WorkspaceCompact, WorkspaceCreateInput, WorkspaceProvisionInput, WorkspaceUpdateDatabaseInput, workspaceView };
@@ -1,26 +0,0 @@
1
- import { defineCommand } from "citty";
2
-
3
- //#region src/commands/workspace/index.ts
4
- var workspace_default = defineCommand({
5
- meta: {
6
- name: "workspace",
7
- alias: "workspaces",
8
- description: "Manage Metabase workspaces (workspace-manager)"
9
- },
10
- subCommands: {
11
- list: () => import("./list-zSO0DMw-.mjs").then((mod) => mod.default),
12
- create: () => import("./create-CHF313Qg.mjs").then((mod) => mod.default),
13
- database: () => import("./database-CIXwHKjK.mjs").then((mod) => mod.default),
14
- start: () => import("./start-3PX3ahjT.mjs").then((mod) => mod.default),
15
- stop: () => import("./stop-CQ0XGrN8.mjs").then((mod) => mod.default),
16
- delete: () => import("./delete-CM3jnAeQ.mjs").then((mod) => mod.default),
17
- logs: () => import("./logs-CywPikkL.mjs").then((mod) => mod.default),
18
- url: () => import("./url-DWaT6WIZ.mjs").then((mod) => mod.default),
19
- credentials: () => import("./credentials-dzeq7ckm.mjs").then((mod) => mod.default),
20
- ps: () => import("./ps-DEroLgbI.mjs").then((mod) => mod.default),
21
- license: () => import("./license-Dxarh-gG.mjs").then((mod) => mod.default)
22
- }
23
- });
24
-
25
- //#endregion
26
- export { workspace_default as default };
@@ -1,100 +0,0 @@
1
- import { ConfigError } from "./command-augment-BH9qgQ5u.mjs";
2
- import { parseYaml, stringifyYaml } from "./yaml-YTQiYJ9s.mjs";
3
- import { z } from "zod";
4
- import { randomBytes } from "node:crypto";
5
-
6
- //#region src/core/workspace-credentials.ts
7
- const API_KEY_NAME = "Workspace API Key";
8
- const API_KEY_GROUP = "admin";
9
- const PASSWORD_BYTE_LENGTH = 18;
10
- const API_KEY_BYTE_LENGTH = 32;
11
- const WorkspaceCredentials = z.object({
12
- workspace_id: z.number().int().positive(),
13
- user: z.object({
14
- first_name: z.string().min(1),
15
- last_name: z.string().min(1),
16
- password: z.string().min(1),
17
- email: z.string().min(1)
18
- }),
19
- api_key: z.object({
20
- name: z.string().min(1),
21
- group: z.enum(["admin", "all-users"]),
22
- creator: z.string().min(1),
23
- key: z.string().regex(/^mb_[A-Za-z0-9+/=]+$/)
24
- })
25
- });
26
- function generateWorkspaceCredentials(workspaceId) {
27
- const email = `workspace-${workspaceId}@workspace.local`;
28
- return {
29
- workspace_id: workspaceId,
30
- user: {
31
- first_name: "Workspace",
32
- last_name: "Admin",
33
- password: randomBase64Url(PASSWORD_BYTE_LENGTH),
34
- email
35
- },
36
- api_key: {
37
- name: API_KEY_NAME,
38
- group: API_KEY_GROUP,
39
- creator: email,
40
- key: `mb_${randomBytes(API_KEY_BYTE_LENGTH).toString("base64")}`
41
- }
42
- };
43
- }
44
- const credentialsJsonEncoder = new TextEncoder();
45
- function buildCredentialsJson(credentials) {
46
- return credentialsJsonEncoder.encode(`${JSON.stringify(credentials, null, 2)}\n`);
47
- }
48
- const ConfigEnvelopeShape = z.object({
49
- version: z.number().int(),
50
- config: z.looseObject({})
51
- }).loose();
52
- function injectCredentialsIntoConfig(yamlInput, credentials) {
53
- const envelope = parseYaml(yamlInput, ConfigEnvelopeShape, { source: "config.yml" });
54
- if ("users" in envelope.config || "api-keys" in envelope.config) throw new ConfigError("config.yml already declares users or api-keys — refusing to overwrite parent-supplied credentials");
55
- const merged = {
56
- ...envelope,
57
- config: {
58
- ...envelope.config,
59
- users: [credentials.user],
60
- "api-keys": [credentials.api_key]
61
- }
62
- };
63
- return stringifyYaml(merged);
64
- }
65
- const REPO_SYNC_MODES = ["read-write", "read-only"];
66
- const RepoSyncMode = z.enum(REPO_SYNC_MODES);
67
- const ConfigEnvelopeWithSettingsShape = z.object({
68
- version: z.number().int(),
69
- config: z.object({ settings: z.looseObject({}).optional() }).loose()
70
- }).loose();
71
- const REMOTE_SYNC_KEYS = [
72
- "remote-sync-url",
73
- "remote-sync-branch",
74
- "remote-sync-type"
75
- ];
76
- function injectRepoSettingsIntoConfig(yamlInput, repo) {
77
- const envelope = parseYaml(yamlInput, ConfigEnvelopeWithSettingsShape, { source: "config.yml" });
78
- const existingSettings = envelope.config.settings ?? {};
79
- const conflicts = REMOTE_SYNC_KEYS.filter((key) => key in existingSettings);
80
- if (conflicts.length > 0) throw new ConfigError(`config.yml already declares remote-sync settings (${conflicts.join(", ")}) — refusing to overwrite parent-supplied values`);
81
- const merged = {
82
- ...envelope,
83
- config: {
84
- ...envelope.config,
85
- settings: {
86
- ...existingSettings,
87
- "remote-sync-url": repo.url,
88
- "remote-sync-branch": repo.branch,
89
- "remote-sync-type": repo.mode
90
- }
91
- }
92
- };
93
- return stringifyYaml(merged);
94
- }
95
- function randomBase64Url(byteLength) {
96
- return randomBytes(byteLength).toString("base64url");
97
- }
98
-
99
- //#endregion
100
- export { REPO_SYNC_MODES, RepoSyncMode, WorkspaceCredentials, buildCredentialsJson, generateWorkspaceCredentials, injectCredentialsIntoConfig, injectRepoSettingsIntoConfig };
@@ -1,43 +0,0 @@
1
- import { ConfigError, ValidationError, errorMessage } from "./command-augment-BH9qgQ5u.mjs";
2
- import { YAMLParseError, parse, stringify } from "yaml";
3
-
4
- //#region src/runtime/yaml.ts
5
- function parseYaml(input, schema, opts = {}) {
6
- const result = parseYamlResult(input, schema, opts);
7
- if (!result.ok) throw result.error;
8
- return result.value;
9
- }
10
- function parseYamlResult(input, schema, opts = {}) {
11
- const sourcePrefix = opts.source ? `${opts.source}: ` : "";
12
- let raw;
13
- try {
14
- raw = parse(input);
15
- } catch (error) {
16
- if (error instanceof YAMLParseError) return {
17
- ok: false,
18
- error: new ConfigError(`${sourcePrefix}invalid YAML: ${error.message}`)
19
- };
20
- return {
21
- ok: false,
22
- error: new ConfigError(`${sourcePrefix}invalid YAML: ${errorMessage(error)}`)
23
- };
24
- }
25
- const parsed = schema.safeParse(raw);
26
- if (!parsed.success) return {
27
- ok: false,
28
- error: new ValidationError(`${sourcePrefix}value did not match expected schema`, {
29
- source: opts.source ?? "<input>",
30
- zodIssues: parsed.error.issues
31
- })
32
- };
33
- return {
34
- ok: true,
35
- value: parsed.data
36
- };
37
- }
38
- function stringifyYaml(value) {
39
- return stringify(value, { lineWidth: 0 });
40
- }
41
-
42
- //#endregion
43
- export { parseYaml, parseYamlResult, stringifyYaml };
@@ -1,137 +0,0 @@
1
- ---
2
- name: viz
3
- description: Author Metabase `visualization_settings` and pick the right `display` for cards via the `mb` CLI. Covers the display → settings-namespace map (graph.*, pie.*, funnel.*, scalar.*, table.*, …), the column-name-vs-numeric-field-id rule, the `column_settings` JSON-string-key footgun, worked API-form examples per chart family, and the pull-from-UI escape hatch for complex charts. Load whenever shaping how a card renders by hand — "create a bar chart", "make this a line chart", "format this column as currency", "set the pie dimension and metric", "the card renders as a table instead of a chart", "add conditional formatting", or any `visualization_settings` work.
4
- allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
5
- ---
6
-
7
- # Visualization settings
8
-
9
- A card has two presentation fields alongside its `dataset_query`:
10
-
11
- - **`display`** — the chart type (`bar`, `line`, `pie`, `scalar`, `table`, …). One closed set of values; pick from the enum below.
12
- - **`visualization_settings`** — a free-form map whose keys are **namespaced by `display`** (`graph.*` for bar/line, `pie.*` for pie, …). The server stores almost anything and **silently ignores keys that don't apply** to the chosen `display`.
13
-
14
- The MBQL pre-flight does **not** validate `visualization_settings` — there is no `--skip-validate` to fail past, because nothing checks it. A `display` typo or a misnamed key is accepted by the API and the card just renders as a default table or drops the setting. So **the feedback loop is read-back, not pre-flight**: after `card create`/`update`, confirm with `mb card get <id> --full --json` (or open the card) that it rendered as intended.
15
-
16
- The general flag conventions and body-input precedence live in the `core` skill (`mb skills get core`); the `dataset_query` body itself is the `mbql` skill's job (`mb skills get mbql`). This skill is only about how the result is displayed.
17
-
18
- ## `display` decides everything
19
-
20
- `display` selects which setting namespace is read. Pick `display` first, then only the matching namespace's keys matter.
21
-
22
- | `display` | Settings namespace(s) | Key columns are named by |
23
- | ------------------------------------------- | --------------------------------------------------------- | ------------------------ |
24
- | `bar` `line` `area` `combo` `row` `scatter` | `graph.*`, `series_settings`, `column_settings` | output column **name** |
25
- | `waterfall` | `graph.*` + `waterfall.*` | output column name |
26
- | `boxplot` | `graph.*` + `boxplot.*` | output column name |
27
- | `pie` | `pie.*`, `column_settings` | output column name |
28
- | `scalar` `number` | `scalar.*` | output column name |
29
- | `smartscalar` | `scalar.comparisons` | output column name |
30
- | `funnel` | `funnel.*` | output column name |
31
- | `gauge` | `gauge.*` | — |
32
- | `map` | `map.*` | output column name |
33
- | `pivot` | `pivot_table.*`, `table.*` | output column name |
34
- | `sankey` | `sankey.*` | output column name |
35
- | `table` | `table.*`, `column_settings` | output column name |
36
- | `object` `list` | `column_settings` | output column name |
37
- | `progress` | `progress.goal`, `progress.color` (sparse — pull from UI) | — |
38
- | `heading` `text` `link` `iframe` `action` | dashcard-only `virtual_card` (see references) | — |
39
-
40
- Closed `display` enum (card-level): `table`, `bar`, `line`, `area`, `row`, `pie`, `scalar`, `smartscalar`, `number`, `combo`, `pivot`, `funnel`, `map`, `scatter`, `waterfall`, `progress`, `gauge`, `object`, `list`, `sankey`, `boxplot`. (`heading`/`text`/`link`/`iframe`/`action` are dashcard virtuals, not standalone cards.) An unknown value is accepted by the API but renders nothing useful — typos like `bargraph`/`linechart` are the most common cause of a "why is my chart blank" report.
41
-
42
- ## The rule that trips everyone: settings name **output columns**, by name
43
-
44
- `graph.dimensions`, `graph.metrics`, `pie.dimension`, `pie.metric`, `scalar.field`, `funnel.metric`, `map.latitude_column`, … all take **output column-name strings** — the names the query _produces_, not field ids. A `count` aggregation outputs the column `count`; a breakout on a field outputs that field's name; a named aggregation outputs its `name`. These strings are **identical in the API form and the portable (git-sync) form** — no numeric-vs-name footgun here.
45
-
46
- So the names you put in `visualization_settings` come from the query's output, not from `mb field`/`mb table`. If you set `name` on an aggregation (see the `mbql` skill, "Naming aggregation output columns"), use that same string here.
47
-
48
- ## Minimum-viable settings per chart family (API form)
49
-
50
- Each example is the `visualization_settings` block to pair with the given `display` on a `card create`/`update` body. The `dataset_query` is elided — build it per the `mbql` skill. The output columns referenced (`CATEGORY`, `count`) are whatever the query's breakout/aggregation produce.
51
-
52
- **Bar / line / area** — one dimension on the x-axis, one or more metrics:
53
-
54
- ```json
55
- "display": "bar",
56
- "visualization_settings": {
57
- "graph.dimensions": ["CATEGORY"],
58
- "graph.metrics": ["count"]
59
- }
60
- ```
61
-
62
- (Switch `display` to `line` or `area` with the same `graph.*` keys. Multiple metrics: `"graph.metrics": ["count", "sum"]`. Stacked: add `"stackable.stack_type": "stacked"`.)
63
-
64
- **Pie** — one dimension, one metric:
65
-
66
- ```json
67
- "display": "pie",
68
- "visualization_settings": { "pie.dimension": "CATEGORY", "pie.metric": "count" }
69
- ```
70
-
71
- **Scalar** (single big number) — the field to surface:
72
-
73
- ```json
74
- "display": "scalar",
75
- "visualization_settings": { "scalar.field": "count" }
76
- ```
77
-
78
- **Table** — column order/visibility plus per-column formatting:
79
-
80
- ```json
81
- "display": "table",
82
- "visualization_settings": {
83
- "table.columns": [
84
- { "name": "CATEGORY", "enabled": true },
85
- { "name": "count", "enabled": true }
86
- ],
87
- "column_settings": {
88
- "[\"name\",\"count\"]": { "column_title": "Orders" }
89
- }
90
- }
91
- ```
92
-
93
- An **empty** `"visualization_settings": {}` is valid for any `display` — Metabase falls back to sensible defaults (it auto-picks dimensions/metrics for a simple aggregate). Set keys only to override the defaults.
94
-
95
- ## `column_settings`: the JSON-string-key footgun
96
-
97
- `column_settings` is a map **whose keys are themselves JSON-encoded arrays** — so inside a JSON body the inner quotes must be escaped. The key is a _string_, never an object.
98
-
99
- - **Prefer the name form:** `["name", "<output column name>"]` → in a JSON body, `"[\"name\",\"count\"]"`. This is the canonical key Metabase writes (`getColumnKey`), and it's **identical in API and portable form**. Use it unless you have a reason not to.
100
- - **Ref form (legacy order!):** `["ref", ["field", <id>, <opts>]]`. The inner field ref here uses the **legacy MBQL-4 order** `["field", id, options]` (id **second**) — _not_ the MBQL-5 order `["field", {options}, id]` you use in `dataset_query`. In the API form `<id>` is the **numeric** field id; the portable form uses a name path. Because the order differs from MBQL 5, this form is easy to get wrong — reach for the name form instead.
101
-
102
- ```json
103
- "column_settings": {
104
- "[\"name\",\"TOTAL\"]": { "number_style": "currency", "currency": "USD", "decimals": 2 },
105
- "[\"name\",\"CREATED_AT\"]": { "date_style": "MMMM D, YYYY" }
106
- }
107
- ```
108
-
109
- The exhaustive per-column key list (number/date/link formatting, `view_as`, click behavior) is in the references file.
110
-
111
- ## Escape hatch: pull a real card instead of authoring from scratch
112
-
113
- For anything beyond a single dimension + metric — combo charts, conditional formatting, pivot splits, click behavior, series colors — the cheapest **correct** path is to build it once in the Metabase UI and copy the result:
114
-
115
- ```bash
116
- mb card get <id> --full --json | jq '.visualization_settings'
117
- ```
118
-
119
- Paste that block into your `card create`/`update` body. The server produced it, so it's guaranteed valid for that `display`. This beats guessing keys from memory, and it's token-cheap (no schema dump).
120
-
121
- ## Full key catalog
122
-
123
- The body above covers the high-frequency 90%. The complete per-display key tables — every `graph.*`/`pie.*`/`table.*`/… key, series settings, conditional formatting rules, pivot splits, the full `column_settings` formatting vocabulary, virtual-card (heading/text/link/iframe) settings, and click behavior — live in this skill's references file. Load it on demand, not by default:
124
-
125
- ```bash
126
- mb skills get viz --full # appends references/settings.md to this body
127
- mb skills path viz # → the skill dir; then Read references/settings.md
128
- ```
129
-
130
- ## Don't
131
-
132
- - Don't invent `display` values (`bargraph`, `linechart`, `histogram`) — use the closed enum; the API accepts the typo and renders nothing.
133
- - Don't put numeric field ids in `graph.dimensions`/`pie.metric`/`scalar.field` etc. — they take **output column-name strings**.
134
- - Don't write a `column_settings` key as an object — it's a JSON **string** (`"[\"name\",\"COL\"]"`), inner quotes escaped.
135
- - Don't use the MBQL-5 field-ref order inside a `column_settings` `["ref", …]` key — that key uses the **legacy** `["field", id, opts]` order. Prefer the `["name", …]` form and sidestep it.
136
- - Don't expect a pre-flight to catch viz mistakes — there is none. Verify by reading the card back.
137
- - Don't hand-author complex charts when you can pull a working `visualization_settings` from a UI-built card.