@wirecat/zoom-cli 0.60.0 → 0.61.0

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 (191) hide show
  1. package/README.md +7 -6
  2. package/dist/answers.d.ts +16 -0
  3. package/dist/answers.d.ts.map +1 -1
  4. package/dist/bin/main.js +1 -0
  5. package/dist/bin/main.js.map +1 -1
  6. package/dist/bin/zm.js +2 -2
  7. package/dist/bundle/{chunk-PUOBYJFI.js → all-profiles-HZLIU6RZ.js} +11 -7
  8. package/dist/bundle/answer-policy-GRODO2DY.js +96 -0
  9. package/dist/bundle/{anthropic-TT2XV74T.js → anthropic-O2YYPCVK.js} +4 -4
  10. package/dist/bundle/{app-server-POMYD6QV.js → app-server-YYCANTUE.js} +50 -50
  11. package/dist/bundle/{bun-JVDJVDHL.js → bun-UEFRULAT.js} +2 -2
  12. package/dist/bundle/{bun-sqlite-BBOPAQVG.js → bun-sqlite-VVYKOY7S.js} +3 -3
  13. package/dist/bundle/{chunk-KVPYI52N.js → chunk-2M2U43IF.js} +2 -2
  14. package/dist/bundle/{chunk-7GVNQOV6.js → chunk-35X6G276.js} +1 -1
  15. package/dist/bundle/{chunk-RH5YXXAB.js → chunk-3TGR4RDD.js} +32 -34
  16. package/dist/bundle/{chunk-YZZ6NBXC.js → chunk-4XI4PDEH.js} +31 -21
  17. package/dist/bundle/{chunk-W5EUHV3J.js → chunk-4XPIOW5L.js} +1 -1
  18. package/dist/bundle/{chunk-PU4FKK5T.js → chunk-5NRBNGR3.js} +2 -2
  19. package/dist/bundle/{chunk-LYZNVNJA.js → chunk-67WW33JB.js} +49 -24
  20. package/dist/bundle/{chunk-3P4LUGXI.js → chunk-6LHTWR3X.js} +2 -2
  21. package/dist/bundle/{chunk-SG3WSP7Y.js → chunk-6RV7KXDF.js} +7 -7
  22. package/dist/bundle/{chunk-VYUSEJE4.js → chunk-6SLGIPLT.js} +2 -2
  23. package/dist/bundle/{chunk-EOZWDEJL.js → chunk-77GJITSU.js} +2 -2
  24. package/dist/bundle/{chunk-72A7CIPL.js → chunk-7ATLKYBN.js} +17 -17
  25. package/dist/bundle/{chunk-YSZQ5SZK.js → chunk-7DMMNCY2.js} +3 -3
  26. package/dist/bundle/chunk-ABCHE4YP.js +217 -0
  27. package/dist/bundle/{chunk-G3MXAGF2.js → chunk-AOSIU5T6.js} +51 -38
  28. package/dist/bundle/{chunk-TAQKNWCD.js → chunk-B3PTSX5D.js} +2 -2
  29. package/dist/bundle/{chunk-J3N2LL37.js → chunk-B45MFBBF.js} +6 -6
  30. package/dist/bundle/{chunk-GNRYFESK.js → chunk-BNUNZTOU.js} +25 -25
  31. package/dist/bundle/{chunk-SK3K2VHF.js → chunk-BPQNTYLN.js} +388 -299
  32. package/dist/bundle/{chunk-LKV3NRCJ.js → chunk-CMG54Q4X.js} +120 -32
  33. package/dist/bundle/{chunk-DP5DX45H.js → chunk-COU66X3X.js} +7 -5
  34. package/dist/bundle/{chunk-NKFRV2LB.js → chunk-CUSGSXSR.js} +2 -2
  35. package/dist/bundle/{chunk-MFS52LTZ.js → chunk-DLAFGSTN.js} +1 -1
  36. package/dist/bundle/{chunk-DKIIKMSE.js → chunk-E4QPLXZT.js} +47 -47
  37. package/dist/bundle/{chunk-MGYFSXI5.js → chunk-E4T7IJJO.js} +26 -26
  38. package/dist/bundle/{chunk-AJA5ZAV6.js → chunk-F32GKBMF.js} +22 -5
  39. package/dist/bundle/{chunk-DN7VHENQ.js → chunk-FAOVUALC.js} +13 -13
  40. package/dist/bundle/{chunk-EF2RCQ3L.js → chunk-FBJC7OCI.js} +1 -1
  41. package/dist/bundle/{chunk-HIAO4MPA.js → chunk-FQ54A7GI.js} +1 -1
  42. package/dist/bundle/{chunk-EXFAA4N3.js → chunk-FXY45HU7.js} +6 -6
  43. package/dist/bundle/{chunk-2EVRKK75.js → chunk-GNHPYQMM.js} +2 -2
  44. package/dist/bundle/{chunk-M5WLBRL7.js → chunk-H5EAHMQN.js} +11 -11
  45. package/dist/bundle/chunk-HF233RN4.js +335 -0
  46. package/dist/bundle/{chunk-24DLFGES.js → chunk-HTGBUE2U.js} +2 -2
  47. package/dist/bundle/{chunk-RSLXLUTS.js → chunk-IKZFR645.js} +10 -10
  48. package/dist/bundle/chunk-JKWYXBGK.js +380 -0
  49. package/dist/bundle/{chunk-DAQXO6SM.js → chunk-KGZHRJ7H.js} +4 -4
  50. package/dist/bundle/{chunk-ZK7Y5K63.js → chunk-KPZIQKOF.js} +1 -1
  51. package/dist/bundle/{chunk-7T3BUWJK.js → chunk-KXYURHVE.js} +118 -95
  52. package/dist/bundle/{chunk-4HZRZDMC.js → chunk-KZGHGU2M.js} +4 -4
  53. package/dist/bundle/{chunk-2TV7UTHK.js → chunk-KZV5GU7G.js} +8 -8
  54. package/dist/bundle/{chunk-YIMI6O7R.js → chunk-L7VIPVHL.js} +263 -199
  55. package/dist/bundle/{chunk-XLJV3ZOH.js → chunk-LPJ3S6GE.js} +1 -1
  56. package/dist/bundle/{chunk-HBYE4EP2.js → chunk-LX6DO44O.js} +1 -1
  57. package/dist/bundle/{chunk-3UMXCNDI.js → chunk-LXOSBFWW.js} +7 -7
  58. package/dist/bundle/{chunk-KUBCUE6T.js → chunk-M3EVVGR6.js} +2 -2
  59. package/dist/bundle/{chunk-WVXAQVLG.js → chunk-MBMDF5EL.js} +6 -6
  60. package/dist/bundle/{chunk-KUBWRI5E.js → chunk-MTAVA2LS.js} +2 -2
  61. package/dist/bundle/{chunk-AQDWGJZT.js → chunk-MVRCLMQL.js} +39 -2
  62. package/dist/bundle/{chunk-UOFOMU3T.js → chunk-NVN4O5IC.js} +14 -10
  63. package/dist/bundle/{chunk-SKENSSY2.js → chunk-O3WVOAT7.js} +408 -420
  64. package/dist/bundle/{chunk-EROQ5SC7.js → chunk-OLZE27RS.js} +2 -2
  65. package/dist/bundle/{chunk-22UBF6U6.js → chunk-OMUX4LSS.js} +4 -4
  66. package/dist/bundle/{chunk-QJCVOVNR.js → chunk-OU46OTTE.js} +3 -3
  67. package/dist/bundle/{chunk-JBGYI5BY.js → chunk-OVVDOVLN.js} +2 -2
  68. package/dist/bundle/{chunk-I45V6AFG.js → chunk-P2NRA7E5.js} +2 -2
  69. package/dist/bundle/{chunk-7PQY4ISY.js → chunk-PCUPOGKR.js} +6 -4
  70. package/dist/bundle/{chunk-4MC4Z45G.js → chunk-QHT2LZRW.js} +6 -6
  71. package/dist/bundle/{decode-UBPIHVNG.js → chunk-RGOBGHWE.js} +21 -18
  72. package/dist/bundle/{chunk-UOL4ILXT.js → chunk-RSXLI5GP.js} +79 -59
  73. package/dist/bundle/{chunk-RNX73QCL.js → chunk-S726LZCH.js} +6 -6
  74. package/dist/bundle/{chunk-TB72GE55.js → chunk-SVBM6F4Z.js} +1 -1
  75. package/dist/bundle/{chunk-GXACHTB2.js → chunk-T7IQMYPW.js} +15 -3
  76. package/dist/bundle/{chunk-Q4NDCDFG.js → chunk-TD4Y5LXG.js} +25 -22
  77. package/dist/bundle/{chunk-V2QOLHPM.js → chunk-U4Y2QQ2D.js} +3 -3
  78. package/dist/bundle/{chunk-ODFIV4OS.js → chunk-UPWHCUVA.js} +617 -380
  79. package/dist/bundle/{chunk-E3AMUYNB.js → chunk-UYAKSUT5.js} +5 -5
  80. package/dist/bundle/{chunk-J5ZVGKSZ.js → chunk-VARX3SBT.js} +1 -1
  81. package/dist/bundle/{chunk-IFXPNXAH.js → chunk-WVYSOV3C.js} +16 -4
  82. package/dist/bundle/{chunk-LZBWU2IA.js → chunk-XOJGXWTK.js} +8 -8
  83. package/dist/bundle/{chunk-4FTPE5SB.js → chunk-XX2PDQ54.js} +31 -211
  84. package/dist/bundle/{chunk-D6L35XQS.js → chunk-XZ4OVTA5.js} +9 -9
  85. package/dist/bundle/{chunk-XAF2LHZG.js → chunk-YESOQEOB.js} +735 -826
  86. package/dist/bundle/{cli-WIMAOCXF.js → cli-O4LAGYXI.js} +60 -54
  87. package/dist/bundle/command-contract-67QKBY6M.js +38 -0
  88. package/dist/bundle/config-ABURZDD2.js +78 -0
  89. package/dist/bundle/decode-WRMZJJCR.js +20 -0
  90. package/dist/bundle/{dist-YYDTME5J.js → dist-SQK4GIJT.js} +14 -14
  91. package/dist/bundle/{echarts-4OQHS575.js → echarts-3DOOJSQR.js} +2 -2
  92. package/dist/bundle/{embed-7JHEPBFD.js → embed-OYRHTMFI.js} +4 -4
  93. package/dist/bundle/{embedder-HTRPWR6T.js → embedder-ZAYCL22W.js} +7 -7
  94. package/dist/bundle/{first-run-I52ADRJ2.js → first-run-QXSPIXOQ.js} +8 -8
  95. package/dist/bundle/first-screen-MD6HWIJW.js +36 -0
  96. package/dist/bundle/{folders-5ZBUQHAM.js → folders-EXQLKXVK.js} +2 -2
  97. package/dist/bundle/{instructions-3QZBKKPF.js → instructions-GFEOB7XJ.js} +1 -1
  98. package/dist/bundle/{main-64VVZ5QG.js → main-RADF3CRI.js} +17 -16
  99. package/dist/bundle/{mcp-OQBZXELQ.js → mcp-WSGVVZWI.js} +2 -2
  100. package/dist/bundle/{meetings-RD3NU6NN.js → meetings-6BIIT42H.js} +4 -4
  101. package/dist/bundle/{node-R2BLYUSB.js → node-A3B2YRQI.js} +2 -2
  102. package/dist/bundle/{node-sqlite-DGEEDBXV.js → node-sqlite-XRP5FUDY.js} +3 -3
  103. package/dist/bundle/{oauth-NRZMCFH3.js → oauth-YICY4AN4.js} +5 -5
  104. package/dist/bundle/{open-SUGCOCAU.js → open-4CNKSQRB.js} +2 -2
  105. package/dist/bundle/openai-YYRO3X7I.js +22 -0
  106. package/dist/bundle/{output-file-SXV2ANW7.js → output-file-7BXYV6OL.js} +3 -3
  107. package/dist/bundle/{process-IX5YWGDP.js → process-A45QXKID.js} +1 -1
  108. package/dist/bundle/{program-WGNTV7NS.js → program-DTP7BRTW.js} +422 -431
  109. package/dist/bundle/{prompt-NICXDWN3.js → prompt-5LMKO7SE.js} +3 -3
  110. package/dist/bundle/{recognize-6DAHO6X6.js → recognize-MB6WRGUD.js} +4 -2
  111. package/dist/bundle/{remote-JZ3TXP6I.js → remote-PD7WMTTS.js} +5 -5
  112. package/dist/bundle/{rerank-YSXWCAGZ.js → rerank-7E6GQ5Y6.js} +5 -5
  113. package/dist/bundle/{run-log-APHZZWC7.js → run-log-TCFK4LEC.js} +53 -53
  114. package/dist/bundle/{chunk-HWZXQLR5.js → serve-JBT2BWHK.js} +8 -6
  115. package/dist/bundle/server-CFIKEPLG.js +66 -0
  116. package/dist/bundle/{chunk-EH6G2LEU.js → server-H2UPGGBI.js} +43 -10
  117. package/dist/bundle/{services-D64U72OE.js → services-SJOTKL5V.js} +33 -26
  118. package/dist/bundle/{speech-QLCQAT4O.js → speech-4SL25GSC.js} +28 -5
  119. package/dist/bundle/{state-KAD3R27T.js → state-FVMTDZ6B.js} +4 -4
  120. package/dist/bundle/{store-7UNPRLZ3.js → store-DNPKBUVO.js} +13 -13
  121. package/dist/bundle/{store-2BHHS77S.js → store-TI77SCNL.js} +15 -15
  122. package/dist/bundle/store-connection-GIFWWMNO.js +76 -0
  123. package/dist/bundle/store-maintenance-command-WBKGF2CZ.js +55 -0
  124. package/dist/bundle/{streaming-AK6Q2ZGQ.js → streaming-UHAHGPH5.js} +4 -4
  125. package/dist/bundle/{tokens-CCM3D4ZT.js → tokens-Y2MX6JBL.js} +4 -4
  126. package/dist/bundle/zm.js +1 -1
  127. package/dist/commands.d.ts +1 -2
  128. package/dist/commands.d.ts.map +1 -1
  129. package/dist/commands.js +3 -16
  130. package/dist/commands.js.map +1 -1
  131. package/dist/contract-overrides.d.ts +0 -2
  132. package/dist/contract-overrides.d.ts.map +1 -1
  133. package/dist/contract-overrides.js +0 -158
  134. package/dist/contract-overrides.js.map +1 -1
  135. package/dist/login.d.ts +1 -0
  136. package/dist/login.d.ts.map +1 -1
  137. package/dist/login.js +1 -1
  138. package/dist/login.js.map +1 -1
  139. package/dist/program-bindings.d.ts +1 -1
  140. package/dist/program-bindings.d.ts.map +1 -1
  141. package/dist/program-bindings.js +16 -18
  142. package/dist/program-bindings.js.map +1 -1
  143. package/dist/program.d.ts +2 -4
  144. package/dist/program.d.ts.map +1 -1
  145. package/dist/program.js.map +1 -1
  146. package/dist/read-only.d.ts.map +1 -1
  147. package/dist/read-only.js +3 -0
  148. package/dist/read-only.js.map +1 -1
  149. package/dist/recording-schedule-setup.d.ts.map +1 -1
  150. package/dist/recording-schedule-setup.js +1 -0
  151. package/dist/recording-schedule-setup.js.map +1 -1
  152. package/dist/run.d.ts.map +1 -1
  153. package/dist/run.js +82 -32
  154. package/dist/run.js.map +1 -1
  155. package/dist/setup-commands.d.ts.map +1 -1
  156. package/dist/setup-commands.js +14 -47
  157. package/dist/setup-commands.js.map +1 -1
  158. package/dist/store-commands.d.ts.map +1 -1
  159. package/dist/store-commands.js +4 -1
  160. package/dist/store-commands.js.map +1 -1
  161. package/dist/tokens.d.ts +15 -0
  162. package/dist/tokens.d.ts.map +1 -1
  163. package/dist/tokens.js +40 -1
  164. package/dist/tokens.js.map +1 -1
  165. package/dist/version.d.ts +1 -1
  166. package/dist/version.js +1 -1
  167. package/package.json +3 -3
  168. package/dist/bundle/all-profiles-7OZPJY76.js +0 -25
  169. package/dist/bundle/answer-policy-PVWMA2QC.js +0 -96
  170. package/dist/bundle/chunk-57LT4A2E.js +0 -48
  171. package/dist/bundle/chunk-XMCVB4Q4.js +0 -390
  172. package/dist/bundle/chunk-YLBNPI7H.js +0 -2
  173. package/dist/bundle/command-contract-J7PDZQMC.js +0 -38
  174. package/dist/bundle/config-G62PBNZF.js +0 -79
  175. package/dist/bundle/first-screen-XNCFWOLC.js +0 -36
  176. package/dist/bundle/mcp-5SJXWEJW.js +0 -92
  177. package/dist/bundle/mcp-ZMIPDB4R.js +0 -189
  178. package/dist/bundle/serve-7VWL475U.js +0 -19
  179. package/dist/bundle/server-7LABFAA5.js +0 -53
  180. package/dist/bundle/server-VFXB5WRG.js +0 -66
  181. package/dist/bundle/store-connection-QTMLZ7LR.js +0 -76
  182. package/dist/bundle/store-maintenance-command-ND6PQCVZ.js +0 -54
  183. package/dist/mcp-command.d.ts +0 -33
  184. package/dist/mcp-command.d.ts.map +0 -1
  185. package/dist/mcp-command.js +0 -143
  186. package/dist/mcp-command.js.map +0 -1
  187. package/dist/mcp.d.ts +0 -30
  188. package/dist/mcp.d.ts.map +0 -1
  189. package/dist/mcp.js +0 -110
  190. package/dist/mcp.js.map +0 -1
  191. /package/dist/bundle/{chunk-O5EHUB2V.js → chunk-62EDJKGP.js} +0 -0
@@ -2,34 +2,33 @@ import { createRequire as __bundleRequire } from "node:module";
2
2
  const require = __bundleRequire(import.meta.url);
3
3
  import {
4
4
  ZM
5
- } from "./chunk-J5ZVGKSZ.js";
5
+ } from "./chunk-VARX3SBT.js";
6
6
  import {
7
7
  commandsCommand,
8
8
  formatSuggestions,
9
9
  meetingResultItem,
10
10
  runsCommand,
11
- sharedCommandTemplate,
12
11
  suggest
13
- } from "./chunk-SK3K2VHF.js";
12
+ } from "./chunk-BPQNTYLN.js";
14
13
  import {
15
14
  sharedStoreCommand
16
- } from "./chunk-DKIIKMSE.js";
15
+ } from "./chunk-E4QPLXZT.js";
17
16
  import {
18
17
  answerEntity
19
- } from "./chunk-4MC4Z45G.js";
18
+ } from "./chunk-QHT2LZRW.js";
20
19
  import {
21
- LOCAL_READ,
22
20
  NO_EFFECTS,
23
21
  REMOTE_READ,
24
22
  annotate,
25
23
  changesAuthorityNow,
26
- customizeSharedCommand,
24
+ checkConfigText,
27
25
  describeOptions,
28
26
  describeProgram,
29
27
  flatten,
30
28
  hasSharedContract,
31
29
  isLogin,
32
30
  isStoreChange,
31
+ issueMessage,
33
32
  itemOf,
34
33
  listOf,
35
34
  metaNow,
@@ -37,86 +36,211 @@ import {
37
36
  overrideSharedContract,
38
37
  profileFree,
39
38
  renderAnswer,
40
- snakeKeys
41
- } from "./chunk-G3MXAGF2.js";
39
+ snakeKeys,
40
+ usableProfileName
41
+ } from "./chunk-AOSIU5T6.js";
42
42
  import {
43
43
  readOnlyLockOf,
44
44
  readOnlyRefusal
45
- } from "./chunk-3P4LUGXI.js";
45
+ } from "./chunk-6LHTWR3X.js";
46
46
  import {
47
47
  setupPermissionCeiling
48
- } from "./chunk-4HZRZDMC.js";
48
+ } from "./chunk-KZGHGU2M.js";
49
49
  import {
50
50
  CEILING_KEY,
51
51
  DEFAULT_PERMISSIONS,
52
52
  LEVELS,
53
53
  keyForCommand,
54
54
  levelFor
55
- } from "./chunk-NKFRV2LB.js";
55
+ } from "./chunk-CUSGSXSR.js";
56
56
  import {
57
57
  MEETING_RESULT_ENTITIES
58
- } from "./chunk-UOL4ILXT.js";
58
+ } from "./chunk-RSXLI5GP.js";
59
59
  import {
60
60
  CliError,
61
61
  array,
62
62
  boolean,
63
+ check,
63
64
  createRenderer,
65
+ custom,
64
66
  exitCodeOfAnswer,
65
67
  integer,
66
68
  isoTimestamp,
67
69
  literal,
70
+ maxLength,
68
71
  minLength,
69
72
  minValue,
70
73
  nullable,
71
74
  number,
72
75
  optional,
76
+ parse,
73
77
  picklist,
74
78
  pipe,
75
79
  projectFields,
76
80
  record,
81
+ regex,
77
82
  safeParse,
83
+ saveConfigFile,
78
84
  strictObject,
79
85
  string,
80
86
  union
81
- } from "./chunk-YIMI6O7R.js";
87
+ } from "./chunk-L7VIPVHL.js";
82
88
  import {
83
89
  __name
84
90
  } from "./chunk-ZVVMGPBJ.js";
85
91
 
86
- // dist/read-only.js
87
- var pathOf = /* @__PURE__ */ __name((command) => {
88
- const words = [];
89
- for (let at = command; at?.parent; at = at.parent)
90
- words.unshift(at.name());
91
- return words.join(" ");
92
+ // dist/config.js
93
+ import { existsSync, readFileSync, statSync } from "node:fs";
94
+
95
+ // dist/config-issues.js
96
+ var isNode = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isNode");
97
+ var SETTING_NAMES = {
98
+ client_id: "zoom.client_id",
99
+ source: "source",
100
+ files_folder: "files.folder",
101
+ files_timezone: "files.timezone",
102
+ context_sources: "context.sources",
103
+ record: "record",
104
+ keep_runs_for_days: "keep_runs_for_days",
105
+ keep_successful_runs_for_days: "keep_successful_runs_for_days",
106
+ runs_size_limit_mb: "runs_size_limit_mb",
107
+ record_input: "record_input"
108
+ };
109
+ var SHELL_SAFE = /^[A-Za-z0-9_.:@-]*$/;
110
+ var fileIssue = /* @__PURE__ */ __name((file, what) => ({ kind: "invalid_value", file, what, at: [] }), "fileIssue");
111
+ var pathOf = /* @__PURE__ */ __name((raw, { profile, key }) => {
112
+ if (key === void 0)
113
+ return [];
114
+ if (profile !== void 0) {
115
+ const entry = isNode(raw.profiles) ? raw.profiles[profile] : void 0;
116
+ const permission = key.startsWith("permissions.") && !(isNode(entry) && Object.hasOwn(entry, key));
117
+ return permission ? ["profiles", profile, "permissions", key.slice("permissions.".length)] : ["profiles", profile, key];
118
+ }
119
+ if (Object.hasOwn(raw, key))
120
+ return [key];
121
+ if (key.startsWith("profiles."))
122
+ return ["profiles", key.slice("profiles.".length)];
123
+ return [key.split(".")[0]];
92
124
  }, "pathOf");
93
- var usesEmbeddings = /* @__PURE__ */ __name((command, path) => {
94
- const options = command.opts();
95
- if (path === "meetings embeddings")
96
- return true;
97
- return path === "search meetings" && options.model !== void 0;
98
- }, "usesEmbeddings");
99
- var refusalOf = /* @__PURE__ */ __name((command) => {
100
- const effects = metaOf(command).effects;
101
- const path = pathOf(command);
102
- if (isLogin(command))
103
- return "log in or out";
104
- if (effects?.remote === "write")
105
- return "change Zoom";
106
- if (usesEmbeddings(command, path))
107
- return "build meeting vectors or send text to an embedding service";
108
- if (changesAuthorityNow(command))
109
- return "change what a later run may do";
110
- if (!effects || isStoreChange(command))
111
- return "change the local store or local files";
112
- return void 0;
113
- }, "refusalOf");
114
- var refuseChangeWhenReadOnly = /* @__PURE__ */ __name((command, env) => {
115
- const lock2 = readOnlyLockOf(ZM, env);
116
- const refusal = lock2 && refusalOf(command);
117
- if (lock2 && refusal)
118
- throw readOnlyRefusal(lock2, refusal);
119
- }, "refuseChangeWhenReadOnly");
125
+ var inZmTerms = /* @__PURE__ */ __name((raw, issue) => {
126
+ const { fix: _, key: shared, ...rest } = issue;
127
+ const at = pathOf(raw, issue);
128
+ const [first] = at;
129
+ if (shared === void 0 || first === void 0)
130
+ return { ...rest, at };
131
+ const key = first === "profiles" ? shared : SETTING_NAMES[first] ?? first;
132
+ const named = key + shared.slice(first === "profiles" ? shared.length : first.length);
133
+ const fixable = [key, issue.profile ?? ""].every((word) => SHELL_SAFE.test(word));
134
+ return {
135
+ ...rest,
136
+ kind: issue.kind === "missing_setting" ? "invalid_value" : issue.kind,
137
+ key,
138
+ what: issue.what.replace(`setting ${shared}`, `setting ${named}`),
139
+ ...fixable ? { fix: `zm${issue.profile === void 0 ? "" : ` ${issue.profile}`} config unset ${key}` } : {},
140
+ at
141
+ };
142
+ }, "inZmTerms");
143
+ var configIssues = /* @__PURE__ */ __name((text2, file, schema, permissionKeys2) => {
144
+ const checked = checkConfigText(text2, { file, tool: "zm", schema });
145
+ const broken = checked.issues.find((issue) => issue.kind === "invalid_json");
146
+ if (broken)
147
+ return { issues: [{ ...broken, at: [] }], raw: null };
148
+ const raw = JSON.parse(text2);
149
+ if (!isNode(raw))
150
+ return { issues: [fileIssue(file, "the file has to be an object, in braces")], raw: null };
151
+ const found = /* @__PURE__ */ new Map();
152
+ const add = /* @__PURE__ */ __name((issue) => {
153
+ const id = issue.at.join("\0");
154
+ if (!found.has(id))
155
+ found.set(id, issue);
156
+ }, "add");
157
+ for (const issue of checked.issues)
158
+ add(inZmTerms(raw, issue));
159
+ if (permissionKeys2) {
160
+ const rest = JSON.stringify(withoutIssues(raw, [...found.values()]));
161
+ for (const issue of checkConfigText(rest, { file, tool: "zm", schema, knownPermissions: permissionKeys2 }).issues)
162
+ if (issue.kind === "unknown_permission")
163
+ add(inZmTerms(raw, issue));
164
+ }
165
+ return { issues: [...found.values()], raw };
166
+ }, "configIssues");
167
+ var withoutIssues = /* @__PURE__ */ __name((raw, issues) => {
168
+ const copy = structuredClone(raw);
169
+ for (const { at } of issues)
170
+ removeAt(copy, at);
171
+ return copy;
172
+ }, "withoutIssues");
173
+ var removeAt = /* @__PURE__ */ __name((raw, at) => {
174
+ const parent = at.slice(0, -1).reduce((node, key) => isNode(node) ? node[key] : void 0, raw);
175
+ if (isNode(parent))
176
+ delete parent[at.at(-1)];
177
+ }, "removeAt");
178
+ var publicIssue = /* @__PURE__ */ __name(({ at: _, ...issue }) => issue, "publicIssue");
179
+
180
+ // dist/profile.js
181
+ var profilePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
182
+ var profileAccountKey = /* @__PURE__ */ __name((profile) => `zm-profile:${profile}`, "profileAccountKey");
183
+ var given = /* @__PURE__ */ __name((value) => value?.trim() ? value.trim() : void 0, "given");
184
+ var usable = /* @__PURE__ */ __name((profile) => {
185
+ usableProfileName(profile);
186
+ if (!profilePattern.test(profile))
187
+ throw new CliError("validation_error", `"${profile}" cannot be a profile name \u2014 64 characters at most`);
188
+ return profile;
189
+ }, "usable");
190
+ var chooseProfile = /* @__PURE__ */ __name(({ word, env, profiles }) => {
191
+ const lock2 = given(env.ZM_PROFILE_LOCK);
192
+ const named = word !== void 0 ? word : given(env.ZM_PROFILE);
193
+ if (lock2 !== void 0)
194
+ usable(lock2);
195
+ if (named !== void 0 && lock2 !== void 0 && named !== lock2)
196
+ throw new CliError("permission_error", `this process is locked to profile ${lock2} (ZM_PROFILE_LOCK) \u2014 profile ${named} is refused`);
197
+ const profile = named ?? lock2;
198
+ if (profile === void 0) {
199
+ const here = profiles();
200
+ throw new CliError("validation_error", here.length === 0 ? "name a profile: there is none on this computer yet \u2014 create one with `zm personal session start` (any name in place of personal)" : `name a profile: \`zm <profile> \u2026\` \u2014 profiles here: ${here.join(", ")} (or set ZM_PROFILE)`, { profiles: [...here] });
201
+ }
202
+ return usable(profile);
203
+ }, "chooseProfile");
204
+
205
+ // dist/context-sources.js
206
+ var fields = {
207
+ id: pipe(string(), regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/)),
208
+ kind: picklist(["message", "mail", "document"]),
209
+ provider: pipe(string(), check((s) => !!s.trim() && Buffer.byteLength(s) <= 128)),
210
+ account: pipe(string(), check((s) => !!s.trim() && Buffer.byteLength(s) <= 1024))
211
+ };
212
+ var selected = pipe(array(strictObject(fields)), maxLength(8));
213
+ var contextSourcesSchema = pipe(array(strictObject({ ...fields, profile: pipe(string(), regex(profilePattern)) })), maxLength(64), check((entries) => {
214
+ const ids = /* @__PURE__ */ new Set(), identities = /* @__PURE__ */ new Set(), counts = /* @__PURE__ */ new Map();
215
+ for (const entry of entries) {
216
+ const id = JSON.stringify([entry.profile, entry.id]), key = JSON.stringify([entry.profile, entry.kind, entry.provider, entry.account]);
217
+ const count2 = (counts.get(entry.profile) ?? 0) + 1;
218
+ if (ids.has(id) || identities.has(key) || count2 > 8)
219
+ return false;
220
+ ids.add(id);
221
+ identities.add(key);
222
+ counts.set(entry.profile, count2);
223
+ }
224
+ return true;
225
+ }));
226
+ var replaceContextSources = /* @__PURE__ */ __name((value, profile, existing = []) => {
227
+ if (!profile)
228
+ throw new CliError("configuration_error", "name a profile: `zm <profile> config set context.sources \u2026`");
229
+ let input;
230
+ try {
231
+ input = JSON.parse(value);
232
+ } catch {
233
+ throw new CliError("validation_error", "context.sources must be a JSON array");
234
+ }
235
+ const parsed = safeParse(selected, input);
236
+ if (!parsed.success)
237
+ throw new CliError("validation_error", "context.sources needs at most eight unique source IDs with kind/provider/account; unknown fields are refused");
238
+ const combined = [...existing.filter((s) => s.profile !== profile), ...parsed.output.map((s) => ({ ...s, profile }))];
239
+ const all = safeParse(contextSourcesSchema, combined);
240
+ if (!all.success)
241
+ throw new CliError("validation_error", "context.sources contains duplicate IDs/identities or exceeds its profile limits");
242
+ return all.output;
243
+ }, "replaceContextSources");
120
244
 
121
245
  // dist/answer-entities.js
122
246
  var text = string();
@@ -348,8 +472,8 @@ var bodyOf = /* @__PURE__ */ __name((value) => {
348
472
  }, "bodyOf");
349
473
  var renderBody = /* @__PURE__ */ __name((command, body, options) => {
350
474
  const data = normalizeZoomAnswer(snakeKeys(body), metaOf(command).output?.entity);
351
- const fields = options.fields;
352
- const projected = fields ? projectFields(data, fields) : data;
475
+ const fields2 = options.fields;
476
+ const projected = fields2 ? projectFields(data, fields2) : data;
353
477
  const meta = metaNow({ ...projected.meta, run_id: options.meta.run_id, duration_ms: options.meta.duration_ms });
354
478
  const chunks = [];
355
479
  const streams = {
@@ -373,361 +497,42 @@ var renderBody = /* @__PURE__ */ __name((command, body, options) => {
373
497
  }, "renderBody");
374
498
  var wholeList = /* @__PURE__ */ __name((command, items) => listOf(command, { items, limit: Math.max(1, items.length), has_more: false }), "wholeList");
375
499
 
376
- // dist/contract-overrides.js
377
- var SHELL_OVERRIDES = {
378
- skill: [
379
- {
380
- command: ["skill"],
381
- field: "effects",
382
- before: null,
383
- after: {
384
- remote: "none",
385
- local: "none"
386
- },
387
- reason: "Zoom installs its own meeting instructions through its source renderer and treats the packaged primary skill as effect-free."
388
- },
389
- {
390
- command: ["skill", "show"],
391
- field: "examples",
392
- before: ["zm skill show"],
393
- after: ["zm skill show --json"],
394
- reason: "Zoom installs its own meeting instructions through its source renderer and treats the packaged primary skill as effect-free."
395
- },
396
- {
397
- command: ["skill", "install"],
398
- field: "examples",
399
- before: ["zm skill install --for agents"],
400
- after: ["zm skill install --for agents --json"],
401
- reason: "Zoom installs its own meeting instructions through its source renderer and treats the packaged primary skill as effect-free."
402
- }
403
- ],
404
- doctor: [
405
- {
406
- command: ["doctor"],
407
- field: "description",
408
- before: "the state this installation is in, without connecting unless --online",
409
- after: "check local runtime and public config without a login or database",
410
- reason: "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status."
411
- },
412
- {
413
- command: ["doctor"],
414
- field: "effects",
415
- before: {
416
- remote: "read",
417
- local: "read"
418
- },
419
- after: {
420
- remote: "none",
421
- local: "read"
422
- },
423
- reason: "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status."
424
- },
425
- {
426
- command: ["doctor"],
427
- field: "runnable",
428
- before: true,
429
- after: null,
430
- reason: "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status."
431
- },
432
- {
433
- command: ["doctor"],
434
- field: "options",
435
- before: [
436
- {
437
- flags: "--online",
438
- description: "also connect once and read the account; sends nothing",
439
- takes_value: false,
440
- mandatory: false
441
- }
442
- ],
443
- after: [],
444
- reason: "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status."
445
- },
446
- {
447
- command: ["doctor"],
448
- field: "children",
449
- before: ["reports"],
450
- after: [],
451
- reason: "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status."
452
- },
453
- {
454
- command: ["doctor"],
455
- field: "examples",
456
- before: null,
457
- after: ["zm doctor --json"],
458
- reason: "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status."
459
- }
460
- ],
461
- mcp: [
462
- {
463
- command: ["mcp"],
464
- field: "summary",
465
- before: "serve this profile's commands to an AI agent, and set that up",
466
- after: "serve zm's commands to an AI agent",
467
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
468
- },
469
- {
470
- command: ["mcp"],
471
- field: "description",
472
- before: "serve this profile to an agent over MCP and set it up \u2014 `claude mcp add zm -- zm <profile> mcp serve`",
473
- after: "serve zm's commands to an agent over MCP \u2014 `claude mcp add zm -- zm <profile> mcp serve`",
474
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
475
- },
476
- {
477
- command: ["mcp"],
478
- field: "children",
479
- before: ["serve", "revoke", "server", "config", "add", "check"],
480
- after: ["serve"],
481
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
482
- },
483
- {
484
- command: ["mcp", "serve"],
485
- field: "description",
486
- before: "serve this profile to an agent over MCP, on stdin and stdout \u2014 `claude mcp add zm -- zm <profile> mcp serve`; `zm mcp serve --profiles a,b` or `--profiles all` serves those profiles from one server and each tool asks which",
487
- after: "serve this profile to an agent over MCP, on stdin and stdout \u2014 `claude mcp add zm -- zm <profile> mcp serve`; `--profiles a,b` or `--profiles all` serves several from one server and each tool asks which",
488
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
489
- },
490
- {
491
- command: ["mcp", "serve"],
492
- field: "effects",
493
- before: {
494
- remote: "write",
495
- local: "write"
496
- },
497
- after: {
498
- remote: "read",
499
- local: "write"
500
- },
501
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
502
- },
503
- {
504
- command: ["mcp", "serve"],
505
- field: "examples",
506
- before: [
507
- "zm personal mcp serve",
508
- "zm mcp serve --profiles work,personal",
509
- "zm personal mcp serve --http --public-url https://laptop.example.ts.net"
510
- ],
511
- after: ["zm personal mcp serve"],
512
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
513
- },
514
- {
515
- command: ["mcp", "serve"],
516
- field: "options",
517
- before: [
518
- {
519
- flags: "--permission <key=level>",
520
- description: "make a permission stricter for this server only, like messages.send=deny; it never loosens the profile; repeat for more keys",
521
- takes_value: true,
522
- mandatory: false
523
- },
524
- {
525
- flags: "--profiles <names|all>",
526
- description: "serve several profiles from one server instead of one: names, comma-separated, or all for every profile",
527
- takes_value: true,
528
- mandatory: false
529
- },
530
- {
531
- flags: "--http",
532
- description: "serve over HTTP on 127.0.0.1 for ChatGPT and Claude in the browser, behind your tunnel; the profile's permissions decide",
533
- takes_value: false,
534
- mandatory: false
535
- },
536
- {
537
- flags: "--port <port>",
538
- description: "the local port for --http (default 8765)",
539
- takes_value: true,
540
- mandatory: false
541
- },
542
- {
543
- flags: "--public-url <url>",
544
- description: "the tunnel's https address the browser apps use, e.g. https://<name>.ts.net or https://<name>.ts.net/tg",
545
- takes_value: true,
546
- mandatory: false
547
- }
548
- ],
549
- after: [
550
- {
551
- flags: "--profiles <names|all>",
552
- description: "serve several profiles from one server instead of one: names, comma-separated, or all for every profile",
553
- takes_value: true,
554
- mandatory: false
555
- }
556
- ],
557
- reason: "Zoom serves meeting and archive commands over stdio under its selected profile; HTTP-specific options are unsupported."
558
- }
559
- ],
560
- search: [
561
- {
562
- command: ["search"],
563
- field: "summary",
564
- before: "search the local archive",
565
- after: null,
566
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
567
- },
568
- {
569
- command: ["search"],
570
- field: "description",
571
- before: "find things by text: one resource when you know it (messages, notes), or search all across messages and notes; for mail, the separate memo CLI: memo search mail",
572
- after: "opt-in shared store search; meetings by default",
573
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
574
- },
575
- {
576
- command: ["search"],
577
- field: "children",
578
- before: ["all", "messages", "notes", "conversations", "runs"],
579
- after: ["all"],
580
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
581
- },
582
- {
583
- command: ["search"],
584
- field: "effects",
585
- before: null,
586
- after: {
587
- remote: "none",
588
- local: "none"
589
- },
590
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
591
- },
592
- {
593
- command: ["search", "all"],
594
- field: "summary",
595
- before: "search stored messages, notes, calendar events and selected meeting transcripts",
596
- after: null,
597
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
598
- },
599
- {
600
- command: ["search", "all"],
601
- field: "description",
602
- before: "search messenger messages and notes in the local store, calendar events when the store holds a calendar, and a meeting account's transcripts when --source names one \u2014 best match first; not mail (the separate memo CLI searches it: memo search mail), tasks, people, memories or projects. Use it when you do not know where something was written; search messages or notes reads one kind with all its fields",
603
- after: "search meetings and, with --only, messages, mail and notes in the local store",
604
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
605
- },
606
- {
607
- command: ["search", "all"],
608
- field: "effects",
609
- before: {
610
- remote: "read",
611
- local: "read"
612
- },
613
- after: {
614
- remote: "none",
615
- local: "read"
616
- },
617
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
618
- },
619
- {
620
- command: ["search", "all"],
621
- field: "examples",
622
- before: ["zm personal search all draft"],
623
- after: ['zm personal search all "example plan" --json'],
624
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
625
- },
626
- {
627
- command: ["search", "all"],
628
- field: "arguments",
629
- before: [
630
- {
631
- name: "query",
632
- required: true,
633
- variadic: true,
634
- description: 'strict Lucene query: words, "phrases", AND/OR/NOT, field groups and date ranges'
635
- }
636
- ],
637
- after: [
638
- {
639
- name: "query",
640
- required: true,
641
- variadic: false,
642
- description: "words to find; a word also matches longer words it starts"
643
- }
644
- ],
645
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
646
- },
647
- {
648
- command: ["search", "all"],
649
- field: "options",
650
- before: [
651
- {
652
- flags: "--only <resources>",
653
- description: "only these resources, separated by commas: messages, notes, events; meetings when --source names a meeting account",
654
- takes_value: true,
655
- mandatory: false
656
- },
657
- {
658
- flags: "--source <accounts>",
659
- description: "only these accounts, separated by commas: provider:account as a hit shows it, a provider, a kind or group:<name>; each resource reads the ones of its kind, and meetings only when it names one",
660
- takes_value: true,
661
- mandatory: false
662
- },
663
- {
664
- flags: "--max-meetings <n>",
665
- description: "how many of the meeting account's meetings to look through, newest first, or all for every one (default 100)",
666
- takes_value: true,
667
- mandatory: false
668
- },
669
- {
670
- flags: "--limit <n>",
671
- description: "how many",
672
- takes_value: true,
673
- mandatory: false
674
- },
675
- {
676
- flags: "--page <n>",
677
- description: "which page, starting at 1",
678
- takes_value: true,
679
- mandatory: false
680
- },
681
- {
682
- flags: "--exact",
683
- description: "bare words and quotes match their exact form only, as exact:word does",
684
- takes_value: false,
685
- mandatory: false
686
- },
687
- {
688
- flags: "--timezone <zone>",
689
- description: "the IANA timezone for calendar date boundaries",
690
- takes_value: true,
691
- mandatory: false
692
- }
693
- ],
694
- after: [
695
- {
696
- flags: "--only <resources>",
697
- description: "comma-separated meetings,messages,mail,notes (default meetings)",
698
- takes_value: true,
699
- mandatory: false
700
- },
701
- {
702
- flags: "--limit <n>",
703
- description: "how many results, 1 through 1000 (default 100)",
704
- takes_value: true,
705
- mandatory: false,
706
- default: 100
707
- },
708
- {
709
- flags: "--page <n>",
710
- description: "which page, starting at 1",
711
- takes_value: true,
712
- mandatory: false
713
- },
714
- {
715
- flags: "--max-meetings <n>",
716
- description: "most meetings to look through, newest first, or all (default 100)",
717
- takes_value: true,
718
- mandatory: false
719
- },
720
- {
721
- flags: "--exact",
722
- description: "request exact matching; unsupported meeting queries are reported as skipped",
723
- takes_value: false,
724
- mandatory: false
725
- }
726
- ],
727
- reason: "Zoom searches explicit local meeting and archive sources, with opt-in unified store reads rather than a live messenger backend."
728
- }
729
- ]
730
- };
500
+ // dist/read-only.js
501
+ var pathOf2 = /* @__PURE__ */ __name((command) => {
502
+ const words = [];
503
+ for (let at = command; at?.parent; at = at.parent)
504
+ words.unshift(at.name());
505
+ return words.join(" ");
506
+ }, "pathOf");
507
+ var usesEmbeddings = /* @__PURE__ */ __name((command, path) => {
508
+ const options = command.opts();
509
+ if (path === "meetings embeddings")
510
+ return true;
511
+ return path === "search meetings" && options.model !== void 0;
512
+ }, "usesEmbeddings");
513
+ var refusalOf = /* @__PURE__ */ __name((command) => {
514
+ const effects = metaOf(command).effects;
515
+ const path = pathOf2(command);
516
+ if (path === "mcp serve")
517
+ return void 0;
518
+ if (isLogin(command))
519
+ return "log in or out";
520
+ if (effects?.remote === "write")
521
+ return "change Zoom";
522
+ if (usesEmbeddings(command, path))
523
+ return "build meeting vectors or send text to an embedding service";
524
+ if (changesAuthorityNow(command))
525
+ return "change what a later run may do";
526
+ if (!effects || isStoreChange(command))
527
+ return "change the local store or local files";
528
+ return void 0;
529
+ }, "refusalOf");
530
+ var refuseChangeWhenReadOnly = /* @__PURE__ */ __name((command, env) => {
531
+ const lock2 = readOnlyLockOf(ZM, env);
532
+ const refusal = lock2 && refusalOf(command);
533
+ if (lock2 && refusal)
534
+ throw readOnlyRefusal(lock2, refusal);
535
+ }, "refuseChangeWhenReadOnly");
731
536
 
732
537
  // dist/commands.js
733
538
  var addStandardCommandsDefinition = /* @__PURE__ */ __name((program, deps) => {
@@ -745,7 +550,6 @@ var addStandardCommandsDefinition = /* @__PURE__ */ __name((program, deps) => {
745
550
  deps.raw(`${formatSuggestions(suggestions)}
746
551
  `);
747
552
  }), { effects: NO_EFFECTS, examples: ["zm complete -- meetings s"] });
748
- annotate(program.command("doctor").description("check local runtime and public config without a login or database").action(() => deps.output(itemOf(deps.doctor()))), { effects: LOCAL_READ, examples: ["zm doctor --json"] });
749
553
  const session = annotate(program.command("session"), { effects: NO_EFFECTS }).description("the saved Zoom login, separate from local data profiles");
750
554
  annotate(session.command("status").description("show cached login state; remote verification is explicit").option("--check", "verify the session with Zoom").action(async (options) => deps.output(itemOf(await deps.sessionStatus(options.check === true)))), {
751
555
  effects: REMOTE_READ,
@@ -821,15 +625,7 @@ var exampleFor = /* @__PURE__ */ __name((path) => {
821
625
  };
822
626
  return `zm ${profile}${path}${argumentsByPath[path] ? ` ${argumentsByPath[path]}` : ""} --json`;
823
627
  }, "exampleFor");
824
- var addStandardCommands = /* @__PURE__ */ __name((...args) => {
825
- customizeSharedCommand(sharedCommandTemplate(ZM, "doctor"), "Zoom local diagnostics inspect runtime and public config only; online account checks belong to session status.", () => {
826
- addStandardCommandsDefinition(...args);
827
- const command = args[0].commands.find((command2) => command2.name() === "doctor");
828
- if (!command)
829
- throw new Error("doctor builder did not install its command");
830
- return command;
831
- }, SHELL_OVERRIDES.doctor);
832
- }, "addStandardCommands");
628
+ var addStandardCommands = addStandardCommandsDefinition;
833
629
 
834
630
  // dist/permissions.js
835
631
  var DEFAULT_PERMISSIONS2 = {
@@ -846,14 +642,14 @@ var discoveryLevels = /* @__PURE__ */ __name((own, env) => {
846
642
  };
847
643
  }, "discoveryLevels");
848
644
  var HOUSEKEEPING = /* @__PURE__ */ new Set([...PROFILE_FREE, "session", "mcp"]);
849
- var pathOf2 = /* @__PURE__ */ __name((command) => {
645
+ var pathOf3 = /* @__PURE__ */ __name((command) => {
850
646
  const words = [];
851
647
  for (let at = command; at?.parent; at = at.parent)
852
648
  words.unshift(at.name());
853
649
  return words;
854
650
  }, "pathOf");
855
651
  var permissionKeyForPath = /* @__PURE__ */ __name((path) => path.length === 0 || HOUSEKEEPING.has(path[0]) && keyForCommand(path) === null ? null : path.join("."), "permissionKeyForPath");
856
- var permissionKeyOf = /* @__PURE__ */ __name((command) => permissionKeyForPath(pathOf2(command)), "permissionKeyOf");
652
+ var permissionKeyOf = /* @__PURE__ */ __name((command) => permissionKeyForPath(pathOf3(command)), "permissionKeyOf");
857
653
  var permissionKeys = /* @__PURE__ */ __name((program) => {
858
654
  const keys = /* @__PURE__ */ new Set(["mcp.authority"]);
859
655
  const walk = /* @__PURE__ */ __name((command) => {
@@ -916,7 +712,7 @@ var checkPermission = /* @__PURE__ */ __name((command, context) => {
916
712
  }
917
713
  if (!context.confirm)
918
714
  throw new CliError("confirmation_required", `${at} asks first for profile ${profile}: add --yes to apply, or --dry-run to preview`, { key: at });
919
- return context.confirm(`zm: ${pathOf2(command).join(" ")} changes Zoom for profile ${profile}. Apply?`).then((yes) => {
715
+ return context.confirm(`zm: ${pathOf3(command).join(" ")} changes Zoom for profile ${profile}. Apply?`).then((yes) => {
920
716
  if (!yes)
921
717
  throw new CliError("cancelled", "not applied");
922
718
  command.setOptionValue("yes", true);
@@ -928,13 +724,200 @@ var guardCommand = /* @__PURE__ */ __name((command, env, context, confirm) => {
928
724
  return checkPermission(command, { ...context, ...confirm ? { confirm } : {}, ...ceiling ? { ceiling } : {} });
929
725
  }, "guardCommand");
930
726
 
727
+ // dist/config.js
728
+ var ProfileEntry = strictObject({
729
+ permissions: optional(record(pipe(string(), regex(/^[a-z][a-z.-]*$/)), picklist(LEVELS)))
730
+ });
731
+ var ConfigFile = strictObject({
732
+ client_id: optional(nullable(pipe(string(), check((id) => id.trim() !== "" && !/\s/.test(id), "has to be a Zoom client ID, without spaces")))),
733
+ source: optional(picklist(["api", "files"])),
734
+ files_folder: optional(nullable(string())),
735
+ files_timezone: optional(nullable(pipe(string(), check((zone) => {
736
+ try {
737
+ new Intl.DateTimeFormat("en", { timeZone: zone });
738
+ return true;
739
+ } catch {
740
+ return false;
741
+ }
742
+ }, "has to be an IANA time zone, such as Europe/Madrid")))),
743
+ profiles: optional(pipe(
744
+ // valibot's record takes a list too, reading its items as profiles named "0", "1"…
745
+ custom((value) => !Array.isArray(value), "has to be an object keyed by profile name, not a list"),
746
+ record(pipe(string(), regex(profilePattern, "has to be a profile name of 64 characters at most")), ProfileEntry)
747
+ )),
748
+ context_sources: optional(contextSourcesSchema),
749
+ record: optional(boolean()),
750
+ keep_runs_for_days: optional(pipe(number(), integer(), minValue(1))),
751
+ keep_successful_runs_for_days: optional(pipe(number(), integer(), minValue(1))),
752
+ runs_size_limit_mb: optional(pipe(number(), integer(), minValue(1))),
753
+ record_input: optional(union([boolean(), literal("failed")]))
754
+ });
755
+ var DOCTOR = "zm doctor";
756
+ var configOf = /* @__PURE__ */ __name((file) => ({
757
+ clientId: file.client_id ?? null,
758
+ source: file.source ?? "api",
759
+ filesFolder: file.files_folder ?? null,
760
+ filesTimezone: file.files_timezone ?? null,
761
+ profiles: Object.keys(file.profiles ?? {}).sort(),
762
+ permissions: Object.fromEntries(Object.entries(file.profiles ?? {}).flatMap(([name, entry]) => entry.permissions ? [[name, entry.permissions]] : [])),
763
+ ...file.context_sources === void 0 ? {} : { contextSources: file.context_sources },
764
+ ...file.record === void 0 ? {} : { record: file.record },
765
+ ...file.keep_runs_for_days === void 0 ? {} : { keepRunsForDays: file.keep_runs_for_days },
766
+ ...file.keep_successful_runs_for_days === void 0 ? {} : { keepSuccessfulRunsForDays: file.keep_successful_runs_for_days },
767
+ ...file.runs_size_limit_mb === void 0 ? {} : { runsSizeLimitMb: file.runs_size_limit_mb },
768
+ ...file.record_input === void 0 ? {} : { recordInput: file.record_input }
769
+ }), "configOf");
770
+ var inspectConfig = /* @__PURE__ */ __name((path, permissionKeys2) => {
771
+ let text2;
772
+ try {
773
+ text2 = readFileSync(path, "utf8");
774
+ } catch {
775
+ if (!existsSync(path))
776
+ return { found: false, issues: [], raw: {}, config: configOf({}) };
777
+ const what = statSync(path, { throwIfNoEntry: false })?.isDirectory() ? "the path is a folder, not a file" : "the file could not be read";
778
+ return { found: true, issues: [fileIssue(path, what)], raw: null, config: configOf({}) };
779
+ }
780
+ const { issues, raw } = configIssues(text2, path, ConfigFile, permissionKeys2);
781
+ return {
782
+ found: true,
783
+ issues,
784
+ raw,
785
+ config: configOf(raw ? parse(ConfigFile, withoutIssues(raw, issues)) : {})
786
+ };
787
+ }, "inspectConfig");
788
+ var readConfig = /* @__PURE__ */ __name((path, permissionKeys2) => {
789
+ const { issues, config } = inspectConfig(path, permissionKeys2);
790
+ if (issues.length > 0)
791
+ throw new CliError("configuration_error", issueMessage(issues.map(publicIssue), DOCTOR));
792
+ return config;
793
+ }, "readConfig");
794
+ var changeFile = /* @__PURE__ */ __name((path, permissionKeys2, change) => {
795
+ const inspection = inspectConfig(path, permissionKeys2);
796
+ if (!inspection.raw)
797
+ throw new CliError("configuration_error", issueMessage(inspection.issues.map(publicIssue), DOCTOR));
798
+ const raw = structuredClone(inspection.raw);
799
+ change(raw, inspection);
800
+ saveConfigFile(path, raw);
801
+ return inspectConfig(path, permissionKeys2).config;
802
+ }, "changeFile");
803
+ var profileEntry = /* @__PURE__ */ __name((raw, profile) => {
804
+ if (!isNode(raw.profiles))
805
+ raw.profiles = {};
806
+ const profiles = raw.profiles;
807
+ if (!isNode(profiles[profile]))
808
+ profiles[profile] = {};
809
+ return profiles[profile];
810
+ }, "profileEntry");
811
+ var FILE_KEYS = Object.fromEntries(Object.entries(SETTING_NAMES).map(([file, name]) => [name, file]));
812
+ var setConfig = /* @__PURE__ */ __name((path, key, value, profile, permissionKeys2) => changeFile(path, permissionKeys2, (raw, { config, issues }) => {
813
+ switch (key) {
814
+ case "permissions": {
815
+ const name = profile?.();
816
+ if (!name)
817
+ throw new CliError("validation_error", "name a profile: `zm <profile> config set permissions \u2026`");
818
+ profileEntry(raw, name).permissions = parsePermissions(value, permissionKeys2 ?? /* @__PURE__ */ new Set());
819
+ return;
820
+ }
821
+ case "context.sources": {
822
+ const broken = issues.find((issue) => issue.at[0] === "context_sources");
823
+ if (broken)
824
+ throw new CliError("configuration_error", issueMessage([publicIssue(broken)], DOCTOR));
825
+ raw.context_sources = replaceContextSources(value, profile?.() ?? null, config.contextSources);
826
+ return;
827
+ }
828
+ case "zoom.client_id":
829
+ if (!value.trim() || /\s/.test(value))
830
+ throw new CliError("validation_error", "client id must not contain whitespace");
831
+ raw.client_id = value;
832
+ return;
833
+ case "source":
834
+ if (value !== "api" && value !== "files")
835
+ throw new CliError("validation_error", "source must be api or files");
836
+ raw.source = value;
837
+ return;
838
+ case "files.folder":
839
+ if (!value.trim())
840
+ throw new CliError("validation_error", "folder must not be empty");
841
+ raw.files_folder = value;
842
+ return;
843
+ case "files.timezone":
844
+ try {
845
+ new Intl.DateTimeFormat("en", { timeZone: value });
846
+ } catch {
847
+ throw new CliError("validation_error", "expected an IANA time zone");
848
+ }
849
+ raw.files_timezone = value;
850
+ return;
851
+ case "record":
852
+ if (value !== "true" && value !== "false")
853
+ throw new CliError("validation_error", "record must be true or false");
854
+ raw.record = value === "true";
855
+ return;
856
+ case "keep_runs_for_days":
857
+ if (!/^[1-9]\d{0,4}$/.test(value))
858
+ throw new CliError("validation_error", "keep_runs_for_days must be a whole number of days, 1 or more");
859
+ raw.keep_runs_for_days = Number(value);
860
+ return;
861
+ case "record_input":
862
+ if (value !== "true" && value !== "false" && value !== "failed")
863
+ throw new CliError("validation_error", "record_input must be true, false or failed");
864
+ raw.record_input = value === "failed" ? value : value === "true";
865
+ return;
866
+ case "keep_successful_runs_for_days":
867
+ if (!/^[1-9]\d{0,4}$/.test(value))
868
+ throw new CliError("validation_error", "keep_successful_runs_for_days must be a whole number of days, 1 or more");
869
+ raw.keep_successful_runs_for_days = Number(value);
870
+ return;
871
+ case "runs_size_limit_mb":
872
+ if (!/^[1-9]\d{0,5}$/.test(value))
873
+ throw new CliError("validation_error", "runs_size_limit_mb must be a whole number of megabytes, 1 or more");
874
+ raw.runs_size_limit_mb = Number(value);
875
+ return;
876
+ default:
877
+ throw new CliError("validation_error", "unknown config key");
878
+ }
879
+ }), "setConfig");
880
+ var unsetConfig = /* @__PURE__ */ __name((path, key, profile, permissionKeys2) => changeFile(path, permissionKeys2, (raw, { issues }) => {
881
+ const reported = issues.find((issue) => issue.key === key && (issue.profile === void 0 || issue.profile === profile));
882
+ if (key === "context.sources" && !reported && profile !== void 0 && Array.isArray(raw.context_sources)) {
883
+ raw.context_sources = raw.context_sources.filter((source) => !isNode(source) || source.profile !== profile);
884
+ return;
885
+ }
886
+ const at = reported?.at ?? (FILE_KEYS[key] ? [FILE_KEYS[key]] : profileSettingAt(key, profile));
887
+ removeAt(raw, at);
888
+ const entry = isNode(raw.profiles) ? raw.profiles[at[1] ?? ""] : void 0;
889
+ if (at[2] === "permissions" && isNode(entry) && isNode(entry.permissions)) {
890
+ if (Object.keys(entry.permissions).length === 0)
891
+ delete entry.permissions;
892
+ }
893
+ }), "unsetConfig");
894
+ var profileSettingAt = /* @__PURE__ */ __name((key, profile) => {
895
+ if (key !== "permissions" && !key.startsWith("permissions."))
896
+ throw new CliError("validation_error", "unknown config key");
897
+ if (!profile)
898
+ throw new CliError("validation_error", `name a profile: \`zm <profile> config unset ${key}\``);
899
+ return key === "permissions" ? ["profiles", profile, "permissions"] : ["profiles", profile, "permissions", key.slice("permissions.".length)];
900
+ }, "profileSettingAt");
901
+ var addProfile = /* @__PURE__ */ __name((path, profile) => {
902
+ if (readConfig(path).profiles.includes(profile))
903
+ return;
904
+ changeFile(path, void 0, (raw) => {
905
+ profileEntry(raw, profile);
906
+ });
907
+ }, "addProfile");
908
+ var filesZone = /* @__PURE__ */ __name((config) => config.filesTimezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone, "filesZone");
909
+
931
910
  export {
911
+ publicIssue,
912
+ profilePattern,
913
+ profileAccountKey,
914
+ chooseProfile,
915
+ contextSourcesSchema,
932
916
  ZOOM_ANSWER_ENTITIES,
933
917
  declareZoomAnswers,
934
918
  bodyOf,
935
919
  renderBody,
936
920
  wholeList,
937
- SHELL_OVERRIDES,
938
921
  annotateMeetingCommands,
939
922
  markProfileFree,
940
923
  zoomRunsCommand,
@@ -943,6 +926,11 @@ export {
943
926
  discoveryLevels,
944
927
  permissionKeyForPath,
945
928
  permissionKeys,
946
- parsePermissions,
947
- guardCommand
929
+ guardCommand,
930
+ inspectConfig,
931
+ readConfig,
932
+ setConfig,
933
+ unsetConfig,
934
+ addProfile,
935
+ filesZone
948
936
  };