@wirecat/zoom-cli 0.56.0 → 0.58.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 (147) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/zm.js +35 -5
  3. package/dist/bundle/all-profiles-RS5IWIGR.js +25 -0
  4. package/dist/bundle/answer-policy-R7VZMCGE.js +96 -0
  5. package/dist/bundle/anthropic-5QHQR4WF.js +70 -0
  6. package/dist/bundle/app-server-7LANSZGE.js +232 -0
  7. package/dist/bundle/bun-O6RL6LRQ.js +169 -0
  8. package/dist/bundle/bun-sqlite-PEJM6CS4.js +69 -0
  9. package/dist/bundle/chunk-24DLFGES.js +97 -0
  10. package/dist/bundle/chunk-27P22POE.js +1109 -0
  11. package/dist/bundle/chunk-3SCTDFNO.js +3398 -0
  12. package/dist/bundle/chunk-3SERIWJD.js +36139 -0
  13. package/dist/bundle/chunk-4AURKUDZ.js +60 -0
  14. package/dist/bundle/chunk-4NGLRHWO.js +24 -0
  15. package/dist/bundle/chunk-5D4AEUVA.js +24783 -0
  16. package/dist/bundle/chunk-5DVW77VC.js +789 -0
  17. package/dist/bundle/chunk-6CYLVFXM.js +9 -0
  18. package/dist/bundle/chunk-6FL25KC5.js +264 -0
  19. package/dist/bundle/chunk-7D2CD3E3.js +193 -0
  20. package/dist/bundle/chunk-7GVNQOV6.js +17 -0
  21. package/dist/bundle/chunk-7H3ZRDLW.js +630 -0
  22. package/dist/bundle/chunk-7Z4ANTAK.js +1095 -0
  23. package/dist/bundle/chunk-A6323R5P.js +22 -0
  24. package/dist/bundle/chunk-ADLS6FVG.js +24600 -0
  25. package/dist/bundle/chunk-AIXLOMH4.js +63 -0
  26. package/dist/bundle/chunk-AQDWGJZT.js +188 -0
  27. package/dist/bundle/chunk-B32SF7J3.js +18 -0
  28. package/dist/bundle/chunk-BAQLQIMI.js +1938 -0
  29. package/dist/bundle/chunk-BGILD4CI.js +1109 -0
  30. package/dist/bundle/chunk-BXZ6WSVF.js +100 -0
  31. package/dist/bundle/chunk-CTGI4ES2.js +138 -0
  32. package/dist/bundle/chunk-CVIKKIGE.js +76 -0
  33. package/dist/bundle/chunk-DDYR6DYL.js +78 -0
  34. package/dist/bundle/chunk-DFDN6AUB.js +21 -0
  35. package/dist/bundle/chunk-DP5DX45H.js +151 -0
  36. package/dist/bundle/chunk-DXKVEOSS.js +53 -0
  37. package/dist/bundle/chunk-DXZTLB24.js +120 -0
  38. package/dist/bundle/chunk-G27MRA24.js +82 -0
  39. package/dist/bundle/chunk-HTQTIKWP.js +928 -0
  40. package/dist/bundle/chunk-IYAGQXED.js +433 -0
  41. package/dist/bundle/chunk-K76WFW4I.js +124 -0
  42. package/dist/bundle/chunk-KVHRHBLY.js +884 -0
  43. package/dist/bundle/chunk-L2UIJDWB.js +31 -0
  44. package/dist/bundle/chunk-L3VS3H34.js +482 -0
  45. package/dist/bundle/chunk-MBT7GP7K.js +1970 -0
  46. package/dist/bundle/chunk-MFS52LTZ.js +570 -0
  47. package/dist/bundle/chunk-MMT46EN4.js +29 -0
  48. package/dist/bundle/chunk-MNUTWGSA.js +6094 -0
  49. package/dist/bundle/chunk-N7GAQ27N.js +82 -0
  50. package/dist/bundle/chunk-NDXAZB5Z.js +409 -0
  51. package/dist/bundle/chunk-NOKFJJPA.js +1028 -0
  52. package/dist/bundle/chunk-NW7IMGRR.js +6848 -0
  53. package/dist/bundle/chunk-O5EHUB2V.js +2 -0
  54. package/dist/bundle/chunk-OBZWUNO4.js +160 -0
  55. package/dist/bundle/chunk-PACC5N6T.js +240 -0
  56. package/dist/bundle/chunk-PF25S7L4.js +422 -0
  57. package/dist/bundle/chunk-PKTFZAXG.js +48 -0
  58. package/dist/bundle/chunk-PNBEREOU.js +35626 -0
  59. package/dist/bundle/chunk-POOGFSRA.js +385 -0
  60. package/dist/bundle/chunk-PP3JGQQE.js +3517 -0
  61. package/dist/bundle/chunk-Q2Z3VCM4.js +2 -0
  62. package/dist/bundle/chunk-QCFHL4ES.js +45 -0
  63. package/dist/bundle/chunk-QFGBMS67.js +492 -0
  64. package/dist/bundle/chunk-RUP467ZX.js +948 -0
  65. package/dist/bundle/chunk-RXDIG23Z.js +166 -0
  66. package/dist/bundle/chunk-SIA7HJE2.js +8192 -0
  67. package/dist/bundle/chunk-SL3SXQZ5.js +100 -0
  68. package/dist/bundle/chunk-SV5L36WK.js +19 -0
  69. package/dist/bundle/chunk-T6AAM7UT.js +846 -0
  70. package/dist/bundle/chunk-U6QW67SU.js +18673 -0
  71. package/dist/bundle/chunk-UKR7KH3H.js +288 -0
  72. package/dist/bundle/chunk-UOFOMU3T.js +836 -0
  73. package/dist/bundle/chunk-URO44C5T.js +3570 -0
  74. package/dist/bundle/chunk-UXM7I35J.js +281 -0
  75. package/dist/bundle/chunk-UYJUTZTT.js +73 -0
  76. package/dist/bundle/chunk-VOAVOK4I.js +1146 -0
  77. package/dist/bundle/chunk-VSUY7PDW.js +192 -0
  78. package/dist/bundle/chunk-VYUSEJE4.js +98 -0
  79. package/dist/bundle/chunk-XFCSPOLZ.js +25 -0
  80. package/dist/bundle/chunk-XT7XVPEM.js +538 -0
  81. package/dist/bundle/chunk-Y5E2WNWB.js +35 -0
  82. package/dist/bundle/chunk-YIFIY7ZE.js +58 -0
  83. package/dist/bundle/chunk-YIMI6O7R.js +5292 -0
  84. package/dist/bundle/chunk-YJRMMZI5.js +275 -0
  85. package/dist/bundle/chunk-YSHSCBPM.js +2315 -0
  86. package/dist/bundle/chunk-ZC5UXEIH.js +215 -0
  87. package/dist/bundle/chunk-ZHXIXDH5.js +161 -0
  88. package/dist/bundle/chunk-ZTOAAYFV.js +122 -0
  89. package/dist/bundle/chunk-ZVVMGPBJ.js +50 -0
  90. package/dist/bundle/cli-IQTASP44.js +831 -0
  91. package/dist/bundle/command-contract-WHZPF7NA.js +38 -0
  92. package/dist/bundle/config-IP5SGHKN.js +79 -0
  93. package/dist/bundle/dist-WT73DF46.js +136 -0
  94. package/dist/bundle/dist-XUFQCJXW.js +7577 -0
  95. package/dist/bundle/echarts-LD3AI55P.js +42501 -0
  96. package/dist/bundle/embed-XEMH4LNX.js +35 -0
  97. package/dist/bundle/embedder-ZCYKSKAE.js +108 -0
  98. package/dist/bundle/first-run-LGYDLIUM.js +23 -0
  99. package/dist/bundle/first-screen-LYQKPNF4.js +36 -0
  100. package/dist/bundle/folders-5ZBUQHAM.js +13 -0
  101. package/dist/bundle/instructions-RZMSW3OC.js +11 -0
  102. package/dist/bundle/main-NKY3JGXY.js +130 -0
  103. package/dist/bundle/mcp-7OXUHLTO.js +189 -0
  104. package/dist/bundle/mcp-OQBZXELQ.js +165 -0
  105. package/dist/bundle/mcp-VISEXTVC.js +92 -0
  106. package/dist/bundle/meetings-XPBHVZAU.js +215 -0
  107. package/dist/bundle/node-P4E63KXA.js +2340 -0
  108. package/dist/bundle/node-TLZSIHIJ.js +21 -0
  109. package/dist/bundle/node-ZRLYQL7J.js +176 -0
  110. package/dist/bundle/node-sqlite-BBEDYBWO.js +45 -0
  111. package/dist/bundle/oauth-UHVRGKZU.js +17 -0
  112. package/dist/bundle/open-J4FCAUAJ.js +19 -0
  113. package/dist/bundle/output-file-SXV2ANW7.js +63 -0
  114. package/dist/bundle/process-LL77573L.js +91 -0
  115. package/dist/bundle/program-EPMIJCGA.js +5845 -0
  116. package/dist/bundle/prompt-LUUMQTMY.js +12 -0
  117. package/dist/bundle/recognize-EMHQX4XF.js +190 -0
  118. package/dist/bundle/remote-ZXS6D7VB.js +26 -0
  119. package/dist/bundle/rerank-WP7RKZNB.js +49 -0
  120. package/dist/bundle/run-log-GS2L66G6.js +111 -0
  121. package/dist/bundle/serve-L6KLLXK2.js +19 -0
  122. package/dist/bundle/server-NOFYENP5.js +53 -0
  123. package/dist/bundle/server-P5TXAPBY.js +66 -0
  124. package/dist/bundle/services-SPOEWVK3.js +330 -0
  125. package/dist/bundle/speech-6OBAKMND.js +44 -0
  126. package/dist/bundle/state-HN5EJKXQ.js +33 -0
  127. package/dist/bundle/store-LEU3M6IN.js +124 -0
  128. package/dist/bundle/store-ZP2URKET.js +141 -0
  129. package/dist/bundle/store-connection-I53XZ2TS.js +76 -0
  130. package/dist/bundle/store-maintenance-command-PSCHEHHY.js +54 -0
  131. package/dist/bundle/streaming-AK6Q2ZGQ.js +15 -0
  132. package/dist/bundle/tokens-CCM3D4ZT.js +17 -0
  133. package/dist/bundle/zm.js +8 -0
  134. package/dist/contract-overrides.d.ts.map +1 -1
  135. package/dist/contract-overrides.js +29 -17
  136. package/dist/contract-overrides.js.map +1 -1
  137. package/dist/mcp-command.d.ts +3 -2
  138. package/dist/mcp-command.d.ts.map +1 -1
  139. package/dist/mcp-command.js +62 -10
  140. package/dist/mcp-command.js.map +1 -1
  141. package/dist/program-bindings.d.ts.map +1 -1
  142. package/dist/program-bindings.js +1 -0
  143. package/dist/program-bindings.js.map +1 -1
  144. package/dist/version.d.ts +1 -1
  145. package/dist/version.js +1 -1
  146. package/package.json +7 -5
  147. package/skills/zoom-cli/SKILL.md +2 -0
@@ -0,0 +1,948 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ ZM
5
+ } from "./chunk-SV5L36WK.js";
6
+ import {
7
+ commandsCommand,
8
+ formatSuggestions,
9
+ meetingResultItem,
10
+ runsCommand,
11
+ sharedCommandTemplate,
12
+ suggest
13
+ } from "./chunk-U6QW67SU.js";
14
+ import {
15
+ sharedStoreCommand
16
+ } from "./chunk-SIA7HJE2.js";
17
+ import {
18
+ answerEntity
19
+ } from "./chunk-RXDIG23Z.js";
20
+ import {
21
+ LOCAL_READ,
22
+ NO_EFFECTS,
23
+ REMOTE_READ,
24
+ annotate,
25
+ changesAuthorityNow,
26
+ customizeSharedCommand,
27
+ describeOptions,
28
+ describeProgram,
29
+ flatten,
30
+ hasSharedContract,
31
+ isLogin,
32
+ isStoreChange,
33
+ itemOf,
34
+ listOf,
35
+ metaNow,
36
+ metaOf,
37
+ overrideSharedContract,
38
+ profileFree,
39
+ renderAnswer,
40
+ snakeKeys
41
+ } from "./chunk-MNUTWGSA.js";
42
+ import {
43
+ readOnlyLockOf,
44
+ readOnlyRefusal
45
+ } from "./chunk-XFCSPOLZ.js";
46
+ import {
47
+ setupPermissionCeiling
48
+ } from "./chunk-4AURKUDZ.js";
49
+ import {
50
+ CEILING_KEY,
51
+ DEFAULT_PERMISSIONS,
52
+ LEVELS,
53
+ keyForCommand,
54
+ levelFor
55
+ } from "./chunk-PF25S7L4.js";
56
+ import {
57
+ MEETING_RESULT_ENTITIES
58
+ } from "./chunk-PP3JGQQE.js";
59
+ import {
60
+ CliError,
61
+ array,
62
+ boolean,
63
+ createRenderer,
64
+ exitCodeOfAnswer,
65
+ integer,
66
+ isoTimestamp,
67
+ literal,
68
+ minLength,
69
+ minValue,
70
+ nullable,
71
+ number,
72
+ optional,
73
+ picklist,
74
+ pipe,
75
+ projectFields,
76
+ record,
77
+ safeParse,
78
+ strictObject,
79
+ string,
80
+ union
81
+ } from "./chunk-YIMI6O7R.js";
82
+ import {
83
+ __name
84
+ } from "./chunk-ZVVMGPBJ.js";
85
+
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
+ }, "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");
120
+
121
+ // dist/answer-entities.js
122
+ var text = string();
123
+ var identifier = pipe(text, minLength(1));
124
+ var nullableText = nullable(text);
125
+ var count = pipe(number(), integer(), minValue(0));
126
+ var flag = boolean();
127
+ var optionalCount = optional(count);
128
+ var scope = strictObject({ provider: text, account: text });
129
+ var asset = strictObject({
130
+ id: nullableText,
131
+ type: text,
132
+ format: nullableText,
133
+ size: nullable(count),
134
+ status: text,
135
+ available: flag,
136
+ started_at: nullableText,
137
+ ended_at: nullableText
138
+ });
139
+ var occurrence = strictObject({ id: text, uuid: text, title: nullableText, started_at: nullableText });
140
+ var recording = strictObject({ ...occurrence.entries, assets: array(asset) });
141
+ var archivedFile = strictObject({
142
+ id: text,
143
+ path: text,
144
+ size: count,
145
+ sha256: text,
146
+ remote_size: nullable(count),
147
+ type: text,
148
+ format: nullableText,
149
+ started_at: nullableText,
150
+ ended_at: nullableText
151
+ });
152
+ var archive = strictObject({
153
+ uuid: text,
154
+ manifest_path: text,
155
+ downloaded: array(archivedFile),
156
+ skipped: array(archivedFile),
157
+ unavailable: array(asset)
158
+ });
159
+ var manifest = strictObject({ version: literal(1), meeting: occurrence, files: array(archivedFile) });
160
+ var lock = strictObject({
161
+ name: text,
162
+ status: picklist(["active", "stale", "foreign", "unrecognized"]),
163
+ pid: nullable(count),
164
+ host: nullableText
165
+ });
166
+ var archiveReceipt = strictObject({
167
+ window: strictObject({ from: text, to: text }),
168
+ meeting: strictObject({ id: text, uuid: text, title: nullableText }),
169
+ archive,
170
+ availability: optional(literal("unknown")),
171
+ checkpoint_revision: optional(nullable(count))
172
+ });
173
+ var remote = strictObject({
174
+ id: text,
175
+ uuid: nullableText,
176
+ title: nullableText,
177
+ type: nullable(number()),
178
+ started_at: nullableText,
179
+ duration_minutes: nullable(number()),
180
+ timezone: nullableText,
181
+ agenda: nullableText,
182
+ join_url: nullableText
183
+ });
184
+ var remoteChange = strictObject({
185
+ action: picklist(["create", "update", "cancel"]),
186
+ applied: flag,
187
+ request: strictObject({
188
+ method: picklist(["POST", "PATCH", "DELETE"]),
189
+ path: text,
190
+ body: optional(record(text, union([text, number()])))
191
+ }),
192
+ meeting: optional(remote)
193
+ });
194
+ var schedule = strictObject({
195
+ version: literal(1),
196
+ id: text,
197
+ name: text,
198
+ scope,
199
+ destination: text,
200
+ from: text,
201
+ daily_at: text,
202
+ time_zone: text,
203
+ lookback_days: count,
204
+ max_bytes: count,
205
+ created_at: pipe(text, isoTimestamp())
206
+ });
207
+ var job = strictObject({
208
+ version: literal(1),
209
+ schedule,
210
+ capture: strictObject({ profile: text, client_id: text, config_dir: text, runtime: text, cli_path: text }),
211
+ state: picklist(["pending", "enabled", "disabled"])
212
+ });
213
+ var scheduleReceipt = strictObject({
214
+ applied: flag,
215
+ backend: text,
216
+ job,
217
+ units: optional(strictObject({ service_name: text, timer_name: text, service: text, timer: text })),
218
+ timer_state: picklist(["not_checked", "verified_enabled", "verified_disabled"])
219
+ });
220
+ var cue = strictObject({ start_ms: count, end_ms: count, speaker: nullableText, text });
221
+ var archiveImport = strictObject({
222
+ uuid: text,
223
+ asset_ids: array(text),
224
+ status: picklist(["acknowledged", "unavailable"]),
225
+ meeting_id: optional(identifier),
226
+ created: optional(flag),
227
+ inserted_transcripts: optionalCount,
228
+ replayed_transcripts: optionalCount,
229
+ superseded_transcripts: optionalCount,
230
+ reason: optional(literal("missing_or_deleted"))
231
+ });
232
+ var searchHit = strictObject({
233
+ source: text,
234
+ id: nullableText,
235
+ title: nullableText,
236
+ time: nullableText,
237
+ text: nullableText,
238
+ url: nullableText,
239
+ people: array(text),
240
+ container_id: nullableText,
241
+ details: record(text, nullable(union([text, number(), flag])))
242
+ });
243
+ var ZOOM_ANSWER_ENTITIES = {
244
+ "recordings list": { name: "zoom_recording", schema: recording },
245
+ "recordings show": { name: "zoom_recording", schema: recording },
246
+ "recordings download": { name: "zoom_archive", schema: union([archive, archiveReceipt]) },
247
+ "recordings archive show": { name: "zoom_archive_manifest", schema: manifest },
248
+ "recordings archive check": {
249
+ name: "zoom_archive_check",
250
+ schema: strictObject({ manifest_path: text, id: text, path: text, valid: flag })
251
+ },
252
+ "recordings archive locks": { name: "zoom_archive_lock", schema: lock },
253
+ "recordings archive recover": {
254
+ name: "zoom_archive_recovery",
255
+ schema: strictObject({ locks: array(lock), removed: array(text) })
256
+ },
257
+ "recordings archive transcript": {
258
+ name: "zoom_archive_transcript",
259
+ schema: strictObject({ meeting: occurrence, asset: archivedFile, cues: array(cue) })
260
+ },
261
+ "recordings archive import": { name: "zoom_archive_import", schema: archiveImport },
262
+ "recordings schedule list": { name: "zoom_archive_job", schema: job },
263
+ "recordings schedule show": { name: "zoom_archive_job", schema: job },
264
+ "recordings schedule create": { name: "zoom_archive_schedule_change", schema: scheduleReceipt },
265
+ "recordings schedule disable": { name: "zoom_archive_schedule_change", schema: scheduleReceipt },
266
+ "recordings schedule run": { name: "zoom_archive_receipt", schema: archiveReceipt },
267
+ "remote-meetings list": { name: "zoom_remote_meeting", schema: remote },
268
+ "remote-meetings show": { name: "zoom_remote_meeting", schema: remote },
269
+ "remote-meetings invitation": {
270
+ name: "zoom_remote_invitation",
271
+ schema: strictObject({ id: text, invitation: text })
272
+ },
273
+ "remote-meetings create": { name: "zoom_remote_change", schema: remoteChange },
274
+ "remote-meetings update": { name: "zoom_remote_change", schema: remoteChange },
275
+ "remote-meetings cancel": { name: "zoom_remote_change", schema: remoteChange },
276
+ "zoom search": { name: "zoom_search_hit", schema: searchHit },
277
+ "meetings embeddings": { name: "meeting_embedding", schema: MEETING_RESULT_ENTITIES.meeting_embedding, shared: true },
278
+ "meetings sync": { name: "meeting_ingestion", schema: MEETING_RESULT_ENTITIES.meeting_ingestion, shared: true },
279
+ "meetings import": { name: "meeting_ingestion", schema: MEETING_RESULT_ENTITIES.meeting_ingestion, shared: true },
280
+ watch: { name: "meeting_ingestion", schema: MEETING_RESULT_ENTITIES.meeting_ingestion, shared: true },
281
+ "meetings export": { name: "meeting_export", schema: MEETING_RESULT_ENTITIES.meeting_export, shared: true },
282
+ "meetings update": { name: "meeting_association", schema: MEETING_RESULT_ENTITIES.meeting_association, shared: true },
283
+ "meetings link": { name: "meeting_association", schema: MEETING_RESULT_ENTITIES.meeting_association, shared: true },
284
+ "meetings transcribe": {
285
+ name: "meeting_transcription",
286
+ schema: MEETING_RESULT_ENTITIES.meeting_transcription,
287
+ shared: true
288
+ }
289
+ };
290
+ var declareZoomAnswers = /* @__PURE__ */ __name((program) => {
291
+ const walk = /* @__PURE__ */ __name((command, path) => {
292
+ const entity = ZOOM_ANSWER_ENTITIES[path.join(" ")];
293
+ if (entity?.shared)
294
+ annotate(command, { output: { entity: entity.name } });
295
+ else if (entity)
296
+ answerEntity(command, entity.name, entity.schema);
297
+ for (const child of command.commands)
298
+ walk(child, [...path, child.name()]);
299
+ }, "walk");
300
+ walk(program, []);
301
+ }, "declareZoomAnswers");
302
+ var publicValue = /* @__PURE__ */ __name((value, key = "") => {
303
+ if (typeof value === "number" && key === "meeting_id")
304
+ return String(value);
305
+ if (typeof value === "number" && key === "created_at")
306
+ return new Date(value).toISOString();
307
+ if (Array.isArray(value))
308
+ return value.map((item) => publicValue(item));
309
+ if (value && typeof value === "object")
310
+ return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, publicValue(item, name)]));
311
+ return value;
312
+ }, "publicValue");
313
+ var schemas = new Map(Object.values(ZOOM_ANSWER_ENTITIES).map(({ name, schema }) => [name, schema]));
314
+ var normalizeZoomAnswer = /* @__PURE__ */ __name((body, entity) => {
315
+ const schema = entity ? schemas.get(entity) : void 0;
316
+ if (!schema)
317
+ return body;
318
+ const checked = /* @__PURE__ */ __name((value) => {
319
+ if (entity && Object.hasOwn(MEETING_RESULT_ENTITIES, entity))
320
+ return meetingResultItem(entity, value);
321
+ const parsed = safeParse(schema, publicValue(value));
322
+ if (!parsed.success) {
323
+ const applied = value && typeof value === "object" && "applied" in value && value.applied === true;
324
+ throw new CliError(applied ? "outcome_unknown" : "invalid_response", `the command returned an invalid ${entity} answer`);
325
+ }
326
+ return parsed.output;
327
+ }, "checked");
328
+ return "item" in body ? { ...body, item: checked(body.item) } : { ...body, items: body.items.map(checked) };
329
+ }, "normalizeZoomAnswer");
330
+
331
+ // dist/answer-output.js
332
+ var UTC_TIME = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?Z/;
333
+ var record2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "record");
334
+ var only = /* @__PURE__ */ __name((value, keys) => Object.keys(value).every((key) => keys.includes(key)), "only");
335
+ var bodyOf = /* @__PURE__ */ __name((value) => {
336
+ const data = snakeKeys(value);
337
+ if (record2(data) && only(data, ["item", "items", "page", "next", "missing", "meta"])) {
338
+ if ("item" in data || Array.isArray(data.items) && record2(data.page))
339
+ return data;
340
+ }
341
+ if (record2(data) && Array.isArray(data.items) && only(data, ["items", "page", "limit", "has_more"]))
342
+ return listOf("list", {
343
+ items: data.items,
344
+ limit: Math.max(1, data.items.length),
345
+ has_more: data.has_more === true
346
+ });
347
+ return itemOf(data);
348
+ }, "bodyOf");
349
+ var renderBody = /* @__PURE__ */ __name((command, body, options) => {
350
+ const data = normalizeZoomAnswer(snakeKeys(body), metaOf(command).output?.entity);
351
+ const fields = options.fields;
352
+ const projected = fields ? projectFields(data, fields) : data;
353
+ const meta = metaNow({ ...projected.meta, run_id: options.meta.run_id, duration_ms: options.meta.duration_ms });
354
+ const chunks = [];
355
+ const streams = {
356
+ data: /* @__PURE__ */ __name((text3) => chunks.push(`${text3}
357
+ `), "data"),
358
+ diagnostic: /* @__PURE__ */ __name((text3) => options.diagnostic(`${text3}
359
+ `), "diagnostic")
360
+ };
361
+ const renderer = createRenderer({ format: options.format, color: false, quiet: options.quiet, streams });
362
+ for (const warning of options.warnings ?? [])
363
+ renderer.warn(warning);
364
+ const exitCode = process.exitCode;
365
+ try {
366
+ renderAnswer(command, { renderer, format: options.format, streams }, { ...projected, meta });
367
+ } finally {
368
+ process.exitCode = exitCode;
369
+ }
370
+ const text2 = chunks.join("");
371
+ const label = options.format === "pretty" && UTC_TIME.test(text2) ? "times in UTC\n" : "";
372
+ return { text: text2 + label, exitCode: exitCodeOfAnswer(meta, metaOf(command).partial === true) };
373
+ }, "renderBody");
374
+ var wholeList = /* @__PURE__ */ __name((command, items) => listOf(command, { items, limit: Math.max(1, items.length), has_more: false }), "wholeList");
375
+
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
+ };
731
+
732
+ // dist/commands.js
733
+ var addStandardCommandsDefinition = /* @__PURE__ */ __name((program, deps) => {
734
+ program.addCommand(commandsCommand(ZM).copyInheritedSettings(program));
735
+ program.addCommand(sharedStoreCommand().copyInheritedSettings(program));
736
+ annotate(program.command("complete").description("answer shell completion requests").argument("[words...]", "shell words ending in the partial word").action((words) => {
737
+ const suggestions = suggest({
738
+ commands: describeProgram(program),
739
+ globalOptions: describeOptions(program),
740
+ words
741
+ });
742
+ if (program.opts().json || program.opts().jsonl)
743
+ deps.output(wholeList("complete", suggestions));
744
+ else
745
+ deps.raw(`${formatSuggestions(suggestions)}
746
+ `);
747
+ }), { 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
+ const session = annotate(program.command("session"), { effects: NO_EFFECTS }).description("the saved Zoom login, separate from local data profiles");
750
+ 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
+ effects: REMOTE_READ,
752
+ examples: ["zm personal session status --json", "zm personal session status --check --dry-run --json"]
753
+ });
754
+ }, "addStandardCommandsDefinition");
755
+ var annotateMeetingCommands = /* @__PURE__ */ __name((program) => {
756
+ for (const item of flatten(describeProgram(program))) {
757
+ let command = program;
758
+ for (const part of item.path) {
759
+ const found = command.commands.find((child) => child.name() === part);
760
+ if (found)
761
+ command = found;
762
+ }
763
+ if (command.commands.length)
764
+ continue;
765
+ const path = item.path.join(" ");
766
+ if (!metaOf(command).effects)
767
+ throw new CliError("configuration_error", `command effects are missing: ${path}`);
768
+ const examples = item.examples?.map((example) => PROFILE_FREE.has(item.path[0] ?? "") ? example : example.replace(`zm ${path}`, `zm personal ${path}`)) ?? [exampleFor(path)];
769
+ if (JSON.stringify(examples) === JSON.stringify(item.examples))
770
+ continue;
771
+ const change = /* @__PURE__ */ __name((one) => {
772
+ annotate(one, { examples });
773
+ }, "change");
774
+ if (hasSharedContract(command))
775
+ overrideSharedContract(command, "Zoom account examples explicitly name the personal profile required for meeting reads.", change);
776
+ else
777
+ change(command);
778
+ }
779
+ }, "annotateMeetingCommands");
780
+ var PROFILE_FREE = /* @__PURE__ */ new Set([
781
+ "commands",
782
+ "complete",
783
+ "config",
784
+ "doctor",
785
+ "guide",
786
+ "help",
787
+ "skill",
788
+ "upgrade",
789
+ "models",
790
+ "runs"
791
+ ]);
792
+ var markProfileFree = /* @__PURE__ */ __name((program) => {
793
+ for (const command of program.commands)
794
+ if (PROFILE_FREE.has(command.name()))
795
+ profileFree(command);
796
+ }, "markProfileFree");
797
+ var zoomRunsCommand = /* @__PURE__ */ __name(() => {
798
+ const runs = runsCommand(ZM);
799
+ overrideSharedContract(runs, "Zoom declares effects on every command group, the shared run log's included.", (group) => {
800
+ annotate(group, { effects: NO_EFFECTS });
801
+ });
802
+ return runs;
803
+ }, "zoomRunsCommand");
804
+ var exampleFor = /* @__PURE__ */ __name((path) => {
805
+ const profile = PROFILE_FREE.has(path.split(" ")[0] ?? "") ? "" : "personal ";
806
+ if (path === "mcp serve")
807
+ return "zm personal mcp serve";
808
+ if (path === "session start")
809
+ return "zm personal session start";
810
+ const argumentsByPath = {
811
+ "commands info": "meetings list",
812
+ "config set": "files.timezone Europe/Madrid",
813
+ "meetings sync": "--dry-run",
814
+ "meetings show": "1",
815
+ "meetings transcript": "1",
816
+ "meetings summary": "1",
817
+ "meetings export": "1 --format markdown",
818
+ "meetings people": '"Alice Example"',
819
+ "meetings projects evidence": 'RES "identity_id:12"',
820
+ "meetings import": "./downloaded-transcripts"
821
+ };
822
+ return `zm ${profile}${path}${argumentsByPath[path] ? ` ${argumentsByPath[path]}` : ""} --json`;
823
+ }, "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");
833
+
834
+ // dist/permissions.js
835
+ var DEFAULT_PERMISSIONS2 = {
836
+ ...DEFAULT_PERMISSIONS,
837
+ "remote-meetings": "ask"
838
+ };
839
+ var discoveryLevels = /* @__PURE__ */ __name((own, env) => {
840
+ const ceiling = setupPermissionCeiling(env);
841
+ return {
842
+ ...DEFAULT_PERMISSIONS2,
843
+ ...own,
844
+ ...ceiling ? { [CEILING_KEY]: ceiling } : {},
845
+ ...readOnlyLockOf(ZM, env) ? { [CEILING_KEY]: "readonly" } : {}
846
+ };
847
+ }, "discoveryLevels");
848
+ var HOUSEKEEPING = /* @__PURE__ */ new Set([...PROFILE_FREE, "session", "mcp"]);
849
+ var pathOf2 = /* @__PURE__ */ __name((command) => {
850
+ const words = [];
851
+ for (let at = command; at?.parent; at = at.parent)
852
+ words.unshift(at.name());
853
+ return words;
854
+ }, "pathOf");
855
+ 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");
857
+ var permissionKeys = /* @__PURE__ */ __name((program) => {
858
+ const keys = /* @__PURE__ */ new Set(["mcp.authority"]);
859
+ const walk = /* @__PURE__ */ __name((command) => {
860
+ const key = permissionKeyOf(command);
861
+ if (key) {
862
+ const parts = key.split(".");
863
+ for (let size = 1; size <= parts.length; size++)
864
+ keys.add(parts.slice(0, size).join("."));
865
+ }
866
+ for (const child of command.commands)
867
+ walk(child);
868
+ }, "walk");
869
+ walk(program);
870
+ return keys;
871
+ }, "permissionKeys");
872
+ var parsePermissions = /* @__PURE__ */ __name((value, known) => {
873
+ let parsed;
874
+ try {
875
+ parsed = JSON.parse(value);
876
+ } catch {
877
+ throw new CliError("validation_error", 'permissions must be a JSON object: {"remote-meetings": "allow"}');
878
+ }
879
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
880
+ throw new CliError("validation_error", 'permissions must be a JSON object: {"remote-meetings": "allow"}');
881
+ for (const [key, level] of Object.entries(parsed)) {
882
+ if (!known.has(key))
883
+ throw new CliError("validation_error", `no command is called ${key}; a key is a command path, dotted`, {
884
+ keys: [...known].sort()
885
+ });
886
+ if (!LEVELS.includes(level))
887
+ throw new CliError("validation_error", `${key}: a level is one of ${LEVELS.join(", ")}`);
888
+ }
889
+ return parsed;
890
+ }, "parsePermissions");
891
+ var refuse = /* @__PURE__ */ __name((key, level, profile, what) => new CliError("permission_error", `${what}: ${key} is ${level} for profile ${profile} \u2014 \`zm ${profile} config set permissions \u2026\` changes it`, { key, level }), "refuse");
892
+ var checkPermission = /* @__PURE__ */ __name((command, context) => {
893
+ const key = permissionKeyOf(command);
894
+ if (!key)
895
+ return;
896
+ const named = context.profile();
897
+ const profile = named ?? "<profile>";
898
+ const own = named === void 0 ? {} : context.config().permissions[named] ?? {};
899
+ const levels = context.ceiling ? { ...own, [CEILING_KEY]: context.ceiling } : own;
900
+ const { level, key: by } = levelFor(levels, key, DEFAULT_PERMISSIONS2);
901
+ const at = by ?? key;
902
+ if (level === "deny")
903
+ throw refuse(at, level, profile, "refused");
904
+ const changes = refusalOf(command);
905
+ if (level === "readonly" && changes && by === CEILING_KEY)
906
+ throw new CliError("permission_error", `refused to ${changes}: the WireCat setup answer keeps every tool read-only \u2014 \`tg setup\`, \`max setup\` or \`wa setup\` at a terminal changes it`, { key, level });
907
+ if (level === "readonly" && changes)
908
+ throw refuse(at, level, profile, `refused to ${changes}`);
909
+ const options = command.opts();
910
+ const confirms = metaOf(command).effects?.remote === "write" && command.options.some(({ long }) => long === "--yes");
911
+ if (!confirms || options.dryRun || options.yes)
912
+ return;
913
+ if (level === "allow") {
914
+ command.setOptionValue("yes", true);
915
+ return;
916
+ }
917
+ if (!context.confirm)
918
+ 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) => {
920
+ if (!yes)
921
+ throw new CliError("cancelled", "not applied");
922
+ command.setOptionValue("yes", true);
923
+ });
924
+ }, "checkPermission");
925
+ var guardCommand = /* @__PURE__ */ __name((command, env, context, confirm) => {
926
+ refuseChangeWhenReadOnly(command, env);
927
+ const ceiling = setupPermissionCeiling(env);
928
+ return checkPermission(command, { ...context, ...confirm ? { confirm } : {}, ...ceiling ? { ceiling } : {} });
929
+ }, "guardCommand");
930
+
931
+ export {
932
+ ZOOM_ANSWER_ENTITIES,
933
+ declareZoomAnswers,
934
+ bodyOf,
935
+ renderBody,
936
+ wholeList,
937
+ SHELL_OVERRIDES,
938
+ annotateMeetingCommands,
939
+ markProfileFree,
940
+ zoomRunsCommand,
941
+ addStandardCommands,
942
+ DEFAULT_PERMISSIONS2 as DEFAULT_PERMISSIONS,
943
+ discoveryLevels,
944
+ permissionKeyForPath,
945
+ permissionKeys,
946
+ parsePermissions,
947
+ guardCommand
948
+ };