@wirecat/zoom-cli 0.13.0 → 0.15.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 (213) hide show
  1. package/README.md +4 -4
  2. package/dist/answer-output.d.ts +21 -2
  3. package/dist/answer-output.d.ts.map +1 -1
  4. package/dist/answer-output.js +44 -37
  5. package/dist/answer-output.js.map +1 -1
  6. package/dist/answers.d.ts +2 -2
  7. package/dist/answers.d.ts.map +1 -1
  8. package/dist/answers.js +12 -43
  9. package/dist/answers.js.map +1 -1
  10. package/dist/api.d.ts.map +1 -1
  11. package/dist/api.js +20 -19
  12. package/dist/api.js.map +1 -1
  13. package/dist/archive-commands.d.ts +5 -4
  14. package/dist/archive-commands.d.ts.map +1 -1
  15. package/dist/archive-commands.js +31 -30
  16. package/dist/archive-commands.js.map +1 -1
  17. package/dist/archive-import.d.ts +2 -2
  18. package/dist/archive-import.d.ts.map +1 -1
  19. package/dist/archive-import.js +20 -30
  20. package/dist/archive-import.js.map +1 -1
  21. package/dist/archive-transcripts.d.ts.map +1 -1
  22. package/dist/archive-transcripts.js +22 -21
  23. package/dist/archive-transcripts.js.map +1 -1
  24. package/dist/bin/zm.js +2 -5
  25. package/dist/bin/zm.js.map +1 -1
  26. package/dist/command-effects.js +1 -1
  27. package/dist/command-effects.js.map +1 -1
  28. package/dist/commands.d.ts +2 -1
  29. package/dist/commands.d.ts.map +1 -1
  30. package/dist/commands.js +8 -8
  31. package/dist/commands.js.map +1 -1
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +54 -37
  34. package/dist/config.js.map +1 -1
  35. package/dist/errors.d.ts +0 -4
  36. package/dist/errors.d.ts.map +1 -1
  37. package/dist/errors.js +2 -7
  38. package/dist/errors.js.map +1 -1
  39. package/dist/execution.d.ts.map +1 -1
  40. package/dist/execution.js +3 -4
  41. package/dist/execution.js.map +1 -1
  42. package/dist/files.d.ts.map +1 -1
  43. package/dist/files.js +9 -9
  44. package/dist/files.js.map +1 -1
  45. package/dist/folders.d.ts +2 -7
  46. package/dist/folders.d.ts.map +1 -1
  47. package/dist/folders.js +2 -35
  48. package/dist/folders.js.map +1 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +2 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/ingestion-search-commands.d.ts +3 -2
  54. package/dist/ingestion-search-commands.d.ts.map +1 -1
  55. package/dist/ingestion-search-commands.js +5 -5
  56. package/dist/ingestion-search-commands.js.map +1 -1
  57. package/dist/json-fields.d.ts +7 -0
  58. package/dist/json-fields.d.ts.map +1 -0
  59. package/dist/json-fields.js +23 -0
  60. package/dist/json-fields.js.map +1 -0
  61. package/dist/keys.d.ts +1 -1
  62. package/dist/keys.d.ts.map +1 -1
  63. package/dist/keys.js +7 -5
  64. package/dist/keys.js.map +1 -1
  65. package/dist/local-transcription-commands.d.ts +3 -2
  66. package/dist/local-transcription-commands.d.ts.map +1 -1
  67. package/dist/local-transcription-commands.js +6 -6
  68. package/dist/local-transcription-commands.js.map +1 -1
  69. package/dist/local-transcription.d.ts.map +1 -1
  70. package/dist/local-transcription.js +13 -12
  71. package/dist/local-transcription.js.map +1 -1
  72. package/dist/login.d.ts.map +1 -1
  73. package/dist/login.js +8 -7
  74. package/dist/login.js.map +1 -1
  75. package/dist/mcp-server.d.ts +2 -0
  76. package/dist/mcp-server.d.ts.map +1 -1
  77. package/dist/mcp-server.js +33 -42
  78. package/dist/mcp-server.js.map +1 -1
  79. package/dist/meeting-context-commands.d.ts +2 -1
  80. package/dist/meeting-context-commands.d.ts.map +1 -1
  81. package/dist/meeting-context-commands.js +10 -15
  82. package/dist/meeting-context-commands.js.map +1 -1
  83. package/dist/meeting-context.d.ts +6 -6
  84. package/dist/meeting-context.d.ts.map +1 -1
  85. package/dist/meeting-context.js +8 -21
  86. package/dist/meeting-context.js.map +1 -1
  87. package/dist/meeting-integration-commands.d.ts +3 -2
  88. package/dist/meeting-integration-commands.d.ts.map +1 -1
  89. package/dist/meeting-integration-commands.js +6 -6
  90. package/dist/meeting-integration-commands.js.map +1 -1
  91. package/dist/meeting-integration.d.ts.map +1 -1
  92. package/dist/meeting-integration.js +2 -2
  93. package/dist/meeting-integration.js.map +1 -1
  94. package/dist/meeting-mcp-command.d.ts +19 -0
  95. package/dist/meeting-mcp-command.d.ts.map +1 -0
  96. package/dist/meeting-mcp-command.js +41 -0
  97. package/dist/meeting-mcp-command.js.map +1 -0
  98. package/dist/meeting-preparation-mcp.d.ts +131 -0
  99. package/dist/meeting-preparation-mcp.d.ts.map +1 -0
  100. package/dist/meeting-preparation-mcp.js +20 -0
  101. package/dist/meeting-preparation-mcp.js.map +1 -0
  102. package/dist/meeting-preparation.d.ts +22 -0
  103. package/dist/meeting-preparation.d.ts.map +1 -0
  104. package/dist/meeting-preparation.js +29 -0
  105. package/dist/meeting-preparation.js.map +1 -0
  106. package/dist/meeting-project-evidence-commands.d.ts +1 -4
  107. package/dist/meeting-project-evidence-commands.d.ts.map +1 -1
  108. package/dist/meeting-project-evidence-commands.js +2 -6
  109. package/dist/meeting-project-evidence-commands.js.map +1 -1
  110. package/dist/meeting-project-evidence-mcp.d.ts.map +1 -1
  111. package/dist/meeting-project-evidence-mcp.js +2 -4
  112. package/dist/meeting-project-evidence-mcp.js.map +1 -1
  113. package/dist/meeting-read-command-bindings.d.ts +10 -0
  114. package/dist/meeting-read-command-bindings.d.ts.map +1 -0
  115. package/dist/meeting-read-command-bindings.js +13 -0
  116. package/dist/meeting-read-command-bindings.js.map +1 -0
  117. package/dist/meeting-search-commands.d.ts +3 -2
  118. package/dist/meeting-search-commands.d.ts.map +1 -1
  119. package/dist/meeting-search-commands.js +46 -38
  120. package/dist/meeting-search-commands.js.map +1 -1
  121. package/dist/meeting-semantic-commands.d.ts +3 -2
  122. package/dist/meeting-semantic-commands.d.ts.map +1 -1
  123. package/dist/meeting-semantic-commands.js +12 -12
  124. package/dist/meeting-semantic-commands.js.map +1 -1
  125. package/dist/meeting-semantic.d.ts.map +1 -1
  126. package/dist/meeting-semantic.js +3 -2
  127. package/dist/meeting-semantic.js.map +1 -1
  128. package/dist/occurrence-schedule.d.ts +3 -0
  129. package/dist/occurrence-schedule.d.ts.map +1 -0
  130. package/dist/occurrence-schedule.js +106 -0
  131. package/dist/occurrence-schedule.js.map +1 -0
  132. package/dist/output-file.js +3 -3
  133. package/dist/output-file.js.map +1 -1
  134. package/dist/program.d.ts +14 -28
  135. package/dist/program.d.ts.map +1 -1
  136. package/dist/program.js +152 -317
  137. package/dist/program.js.map +1 -1
  138. package/dist/recording-archive.d.ts +1 -1
  139. package/dist/recording-archive.d.ts.map +1 -1
  140. package/dist/recording-archive.js +99 -46
  141. package/dist/recording-archive.js.map +1 -1
  142. package/dist/recording-partial-store.d.ts.map +1 -1
  143. package/dist/recording-partial-store.js +11 -10
  144. package/dist/recording-partial-store.js.map +1 -1
  145. package/dist/recording-promotion-store.d.ts.map +1 -1
  146. package/dist/recording-promotion-store.js +4 -4
  147. package/dist/recording-promotion-store.js.map +1 -1
  148. package/dist/recording-schedule-commands.d.ts +3 -2
  149. package/dist/recording-schedule-commands.d.ts.map +1 -1
  150. package/dist/recording-schedule-commands.js +12 -12
  151. package/dist/recording-schedule-commands.js.map +1 -1
  152. package/dist/recording-schedule-store.d.ts.map +1 -1
  153. package/dist/recording-schedule-store.js +15 -14
  154. package/dist/recording-schedule-store.js.map +1 -1
  155. package/dist/recording-schedule-systemd.d.ts.map +1 -1
  156. package/dist/recording-schedule-systemd.js +16 -15
  157. package/dist/recording-schedule-systemd.js.map +1 -1
  158. package/dist/recording-schedule.d.ts +1 -1
  159. package/dist/recording-schedule.d.ts.map +1 -1
  160. package/dist/recording-schedule.js +15 -14
  161. package/dist/recording-schedule.js.map +1 -1
  162. package/dist/recording-sync-store.d.ts.map +1 -1
  163. package/dist/recording-sync-store.js +9 -9
  164. package/dist/recording-sync-store.js.map +1 -1
  165. package/dist/recording-sync.d.ts +1 -1
  166. package/dist/recording-sync.d.ts.map +1 -1
  167. package/dist/recording-sync.js +10 -19
  168. package/dist/recording-sync.js.map +1 -1
  169. package/dist/recordings.d.ts.map +1 -1
  170. package/dist/recordings.js +19 -18
  171. package/dist/recordings.js.map +1 -1
  172. package/dist/remote-http.d.ts +1 -0
  173. package/dist/remote-http.d.ts.map +1 -1
  174. package/dist/remote-http.js +26 -14
  175. package/dist/remote-http.js.map +1 -1
  176. package/dist/remote-meeting-id.d.ts +2 -0
  177. package/dist/remote-meeting-id.d.ts.map +1 -0
  178. package/dist/remote-meeting-id.js +7 -0
  179. package/dist/remote-meeting-id.js.map +1 -0
  180. package/dist/remote-meetings.d.ts.map +1 -1
  181. package/dist/remote-meetings.js +10 -13
  182. package/dist/remote-meetings.js.map +1 -1
  183. package/dist/store-connection.d.ts +1 -7
  184. package/dist/store-connection.d.ts.map +1 -1
  185. package/dist/store-connection.js +95 -176
  186. package/dist/store-connection.js.map +1 -1
  187. package/dist/streaming.js +3 -3
  188. package/dist/streaming.js.map +1 -1
  189. package/dist/tokens.d.ts.map +1 -1
  190. package/dist/tokens.js +10 -9
  191. package/dist/tokens.js.map +1 -1
  192. package/dist/unified-search.d.ts +1 -10
  193. package/dist/unified-search.d.ts.map +1 -1
  194. package/dist/unified-search.js +7 -6
  195. package/dist/unified-search.js.map +1 -1
  196. package/dist/upcoming-meetings.d.ts +10 -0
  197. package/dist/upcoming-meetings.d.ts.map +1 -0
  198. package/dist/upcoming-meetings.js +24 -0
  199. package/dist/upcoming-meetings.js.map +1 -0
  200. package/dist/watch-commands.d.ts +2 -1
  201. package/dist/watch-commands.d.ts.map +1 -1
  202. package/dist/watch-commands.js +8 -8
  203. package/dist/watch-commands.js.map +1 -1
  204. package/package.json +3 -3
  205. package/skills/zoom-cli/SKILL.md +127 -169
  206. package/dist/ordinary-file.d.ts +0 -3
  207. package/dist/ordinary-file.d.ts.map +0 -1
  208. package/dist/ordinary-file.js +0 -16
  209. package/dist/ordinary-file.js.map +0 -1
  210. package/dist/wav-audio.d.ts +0 -2
  211. package/dist/wav-audio.d.ts.map +0 -1
  212. package/dist/wav-audio.js +0 -2
  213. package/dist/wav-audio.js.map +0 -1
package/dist/program.js CHANGED
@@ -1,33 +1,33 @@
1
1
  import { homedir } from "node:os";
2
2
  import { dirname, join } from "node:path";
3
- import { createDeadline, createRenderer, errorObjectOf, errorRecordOf, exitCodeOfAnswer, exitCodeOfError, fieldsOf, isCliError, projectFields, realSleep, renderError, } from "@wirecat/cli-base";
3
+ import { CliError, createDeadline, createOutputBuffer, createRenderer, errorObjectOf, errorRecordOf, exitCodeOfError, isCliError, projectFields, realSleep, renderError, } from "@wirecat/cli-base";
4
4
  import { metaOf } from "@wirecat/cli-base/commands";
5
- import { jsonlRecords, listOf } from "@wirecat/cli-core/cli";
6
- import { importFiles, listed, MeetingError, pull, } from "@wirecat/cli-core/meetings";
5
+ import { checkJson, itemOf, snakeKeys } from "@wirecat/cli-core/cli";
6
+ import { importFiles, pull, } from "@wirecat/cli-core/meetings";
7
7
  import { addMeetingCommands, addMeetingPassageCommand } from "@wirecat/cli-core/meetings/cli";
8
8
  import { Command, CommanderError } from "commander";
9
9
  import { addZoomSkillCommands } from "./agent-skill.js";
10
- import { createAnswerRenderer } from "./answer-output.js";
10
+ import { bodyOf, renderBody, wholeList } from "./answer-output.js";
11
11
  import { hostFailureContext } from "./answer-policy.js";
12
- import { meetingAnswer } from "./answers.js";
13
12
  import { ZoomApiSource } from "./api.js";
14
13
  import { addArchiveCommands, } from "./archive-commands.js";
15
14
  import { applyArchiveImport, preflightArchiveImport } from "./archive-import.js";
16
15
  import { readArchiveTranscripts, searchArchiveTranscripts } from "./archive-transcripts.js";
17
16
  import { addStandardCommands, annotateMeetingCommands } from "./commands.js";
18
17
  import { profileAccountKey, readConfig, setConfig } from "./config.js";
19
- import { checkCancelled, ZoomError } from "./errors.js";
18
+ import { checkCancelled } from "./errors.js";
20
19
  import { bytes, duration, resetCliOptions, startExecution } from "./execution.js";
21
20
  import { FilesSource, importFile, readDownloadedFiles, validateDownloadedFiles } from "./files.js";
22
21
  import { addIngestionSearchCommands } from "./ingestion-search-commands.js";
23
- import { snakeKeys } from "./keys.js";
22
+ import { liftJsonFields } from "./json-fields.js";
24
23
  import { addLocalTranscriptionCommands } from "./local-transcription-commands.js";
25
24
  import { login } from "./login.js";
26
25
  import { addMeetingContextCommands } from "./meeting-context-commands.js";
27
26
  import { addMeetingIntegrationCommands } from "./meeting-integration-commands.js";
28
- import { addProjectEvidenceCommand } from "./meeting-project-evidence-commands.js";
27
+ import { addZoomMcpCommand } from "./meeting-mcp-command.js";
28
+ import { addMeetingReadBindings } from "./meeting-read-command-bindings.js";
29
29
  import { addMeetingSearchCommands } from "./meeting-search-commands.js";
30
- import { addMeetingEmbeddingCommand, validateMeetingModel, } from "./meeting-semantic-commands.js";
30
+ import { addMeetingEmbeddingCommand } from "./meeting-semantic-commands.js";
31
31
  import { createRecordingScheduleService } from "./recording-schedule.js";
32
32
  import { addRecordingScheduleCommands } from "./recording-schedule-commands.js";
33
33
  import { fileRecordingScheduleStore } from "./recording-schedule-store.js";
@@ -40,7 +40,7 @@ import { runUnifiedSearch } from "./unified-search.js";
40
40
  import { VERSION } from "./version.js";
41
41
  import { addWatchCommand } from "./watch-commands.js";
42
42
  const unavailable = async () => {
43
- throw new ZoomError("configuration_error", "the shared SQLite meeting store is not available yet");
43
+ throw new CliError("configuration_error", "the shared SQLite meeting store is not available yet");
44
44
  };
45
45
  const unavailableStore = {
46
46
  saveMeeting: unavailable,
@@ -62,7 +62,7 @@ const answerExitCodes = new WeakMap();
62
62
  export const createProgram = (deps) => {
63
63
  let config;
64
64
  const getConfig = () => (config ??= readConfig(deps.configPath));
65
- let connection;
65
+ let connecting;
66
66
  let parsing = false;
67
67
  let execution;
68
68
  let fields;
@@ -72,7 +72,7 @@ export const createProgram = (deps) => {
72
72
  const fetchWithSignal = (fetcher) => (input, init) => {
73
73
  checkCancelled(signal());
74
74
  if (program.opts().offline)
75
- throw new ZoomError("configuration_error", "the command requires network access; remove --offline");
75
+ throw new CliError("configuration_error", "the command requires network access; remove --offline");
76
76
  const operation = signal();
77
77
  return fetcher(input, {
78
78
  ...init,
@@ -82,7 +82,7 @@ export const createProgram = (deps) => {
82
82
  const tokens = () => (activeTokens ??= deps.tokens.withSignal(signal(), fetchWithSignal(deps.tokens.options.fetch)));
83
83
  const buffer = (text) => {
84
84
  if (!execution)
85
- throw new ZoomError("configuration_error", "command execution is not initialized");
85
+ throw new CliError("configuration_error", "command execution is not initialized");
86
86
  execution.output.data(text);
87
87
  };
88
88
  const guardedStore = (store) => new Proxy(store, {
@@ -102,133 +102,99 @@ export const createProgram = (deps) => {
102
102
  let selectedAccountId = deps.accountId;
103
103
  const requireAccount = () => {
104
104
  if (!Number.isSafeInteger(selectedAccountId) || !selectedAccountId || selectedAccountId < 1)
105
- throw new ZoomError("configuration_error", "the selected meeting account is unavailable");
105
+ throw new CliError("configuration_error", "the selected meeting account is unavailable");
106
106
  return selectedAccountId;
107
107
  };
108
+ const openStore = async (intent) => {
109
+ if (!deps.connectStore)
110
+ return unavailable();
111
+ const profile = getConfig().accountProfile;
112
+ if (!profile)
113
+ throw new CliError("configuration_error", "select a local profile with zm config set account.profile <label>");
114
+ try {
115
+ return await deps.connectStore({ profile, externalId: profileAccountKey(profile), intent });
116
+ }
117
+ catch (error) {
118
+ if (isCliError(error))
119
+ throw error;
120
+ throw new CliError("configuration_error", "could not open the shared meeting store");
121
+ }
122
+ };
123
+ const connected = (intent = "read") => (connecting ??= openStore(intent));
108
124
  const program = new Command()
109
125
  .name("zm")
110
126
  .version(VERSION)
111
127
  .description("Zoom meeting transcripts and summaries")
112
- .option("--json", "one JSON value")
128
+ .option("--json", "one JSON value; --json=id,title keeps only those fields")
113
129
  .option("--jsonl", "one JSON object per item")
114
130
  .option("--no-input", "disable interactive login")
115
131
  .option("--interactive", "permit browser approval in an interactive terminal")
116
132
  .option("--quiet", "suppress non-error diagnostics")
117
- .option("--fields <paths>", "project result fields, such as id,title")
118
133
  .option("--timeout <duration>", "command deadline: reads 30s, login 5m, downloads/transcription 1h; watch/MCP have no default", duration)
119
134
  .option("--max-output-bytes <bytes>", "bound rendered result bytes (default 4194304; zero is unlimited)", bytes)
120
135
  .option("--offline", "refuse network requests")
121
136
  .option("--debug", "on a failure, its whole record — cause and stack — in place of the short line")
122
137
  .exitOverride()
123
138
  .configureOutput({ writeOut: deps.data, writeErr: deps.diagnostic, outputError: () => { } });
124
- const render = createAnswerRenderer(program, (meta) => {
125
- const action = execution?.action;
126
- answerExitCodes.set(program, Math.max(answerExitCodes.get(program) ?? 0, exitCodeOfAnswer(meta, action ? metaOf(action).partial : false)));
127
- });
139
+ const formatOf = () => program.opts().jsonl ? "jsonl" : program.opts().json || !deps.outputIsTTY ? "json" : "pretty";
140
+ const rendered = (body, format = formatOf()) => {
141
+ if (!execution)
142
+ throw new CliError("configuration_error", "command execution is not initialized");
143
+ const answer = renderBody(execution.action, body, {
144
+ format,
145
+ meta: execution.meta(),
146
+ fields,
147
+ quiet: Boolean(program.opts().quiet),
148
+ diagnostic: deps.diagnostic,
149
+ });
150
+ answerExitCodes.set(program, Math.max(answerExitCodes.get(program) ?? 0, answer.exitCode));
151
+ return answer.text;
152
+ };
128
153
  const api = () => {
129
154
  if (program.opts().offline)
130
- throw new ZoomError("configuration_error", "the command requires network access; remove --offline");
155
+ throw new CliError("configuration_error", "the command requires network access; remove --offline");
131
156
  if (!getConfig().clientId)
132
- throw new ZoomError("configuration_error", "run zm config set zoom.clientId <Public Client ID> first");
157
+ throw new CliError("configuration_error", "run zm config set zoom.client_id <Public Client ID> first");
133
158
  };
134
159
  program.hook("preAction", async (_root, action) => {
135
160
  const opts = action.optsWithGlobals();
136
161
  if (opts.json && opts.jsonl)
137
- throw new ZoomError("validation_error", "choose --json or --jsonl");
138
- fields = opts.fields === undefined ? undefined : fieldsOf(opts.fields);
162
+ throw new CliError("validation_error", "choose --json or --jsonl");
163
+ checkJson(action, { json: opts.json === true, ...(fields ? { fields: fields.join(",") } : {}) }, false);
139
164
  execution = startExecution(action, { signal: deps.signal, sleep: deps.sleep, now: deps.now });
140
165
  checkCancelled(signal());
141
- let family = action;
142
- while (family.parent && family.parent !== program)
143
- family = family.parent;
144
- if ([
145
- "commands",
146
- "complete",
147
- "doctor",
148
- "config",
149
- "session",
150
- "recordings",
151
- "remote-meetings",
152
- "serve",
153
- "skill",
154
- "watch",
155
- "search",
156
- ].includes(family.name()) ||
157
- (family.name() === "meetings" &&
158
- ["passage", "evidence", "context", "task-proposal", "embeddings", "update", "link", "transcribe"].includes(action.name())))
166
+ if (!storeCommands.has(action))
159
167
  return;
160
168
  const config = getConfig();
161
- const ingestion = family.name() === "meetings" && ["sync", "import"].includes(action.name());
169
+ const ingestion = action.parent?.name() === "meetings" && ["sync", "import"].includes(action.name());
162
170
  if (opts.offline && ingestion && action.name() !== "import" && config.source === "api" && !deps.source)
163
- throw new ZoomError("configuration_error", "API sync requires network access; remove --offline");
171
+ throw new CliError("configuration_error", "API sync requires network access; remove --offline");
164
172
  if (!selectedStore) {
165
- if (!deps.connectStore)
166
- return unavailable();
167
- if (!config.accountProfile)
168
- throw new ZoomError("configuration_error", "select a local profile with zm config set account.profile <label>");
169
- try {
170
- connection = await deps.connectStore({
171
- profile: config.accountProfile,
172
- externalId: profileAccountKey(config.accountProfile),
173
- intent: ingestion ? "ingestion" : "read",
174
- });
175
- }
176
- catch (error) {
177
- if (error instanceof ZoomError || error instanceof MeetingError)
178
- throw error;
179
- throw new ZoomError("configuration_error", "could not open the shared meeting store");
180
- }
173
+ const connection = await connected(ingestion ? "ingestion" : "read");
181
174
  selectedStore = connection.store;
182
175
  selectedAccountId = connection.accountId;
183
176
  }
184
177
  requireAccount();
185
178
  });
186
- const output = (value) => buffer(render(value, program.opts().json ? "json" : program.opts().jsonl ? "jsonl" : "text", deps, fields, true, false, execution?.meta));
179
+ const output = (body) => buffer(rendered(body));
187
180
  const outputItems = async (values) => {
188
- const meta = execution?.meta;
189
- if (!meta)
190
- throw new ZoomError("configuration_error", "execution metadata is unavailable");
191
- const format = program.opts().jsonl ? "jsonl" : program.opts().json || !deps.outputIsTTY ? "json" : "text";
192
- const metadata = listed([]);
193
- delete metadata.items;
194
- let count = 0;
195
- if (format === "json")
196
- buffer('{"items":[');
181
+ const items = [];
182
+ // Fails on the row that crosses --max-output-bytes, so a long iterator stops reading there.
183
+ const measured = createOutputBuffer({ maxOutputBytes: program.opts().maxOutputBytes });
197
184
  for await (const value of values) {
198
185
  checkCancelled(signal());
199
186
  const item = snakeKeys(value);
200
- const projected = fields ? projectFields(listed([item]), fields).items[0] : item;
201
- if (format === "json") {
202
- if (count)
203
- buffer(",");
204
- buffer(render(projected, "json", deps).trimEnd());
205
- }
206
- else if (format === "jsonl") {
207
- const packet = meetingAnswer(projected, meta());
208
- buffer(`${JSON.stringify(jsonlRecords(packet)[0])}\n`);
209
- }
210
- else
211
- buffer(render(projected, format, deps, undefined, true, false, execution?.meta));
212
- count++;
213
- }
214
- metadata.limit = count;
215
- if (format === "json")
216
- buffer(`],"page":${JSON.stringify({ mode: "page", limit: Math.max(1, count), has_more: false })},"meta":${JSON.stringify(execution?.meta())}}\n`);
217
- else if (format === "jsonl") {
218
- const packet = meetingAnswer(listOf("meetings import", { items: [], limit: Math.max(1, count), has_more: false }), meta());
219
- buffer(`${jsonlRecords(packet)
220
- .map((record) => JSON.stringify(record))
221
- .join("\n")}\n`);
187
+ measured.data(JSON.stringify(fields ? projectFields(item, fields) : item));
188
+ items.push(item);
222
189
  }
223
- else if (format === "text")
224
- buffer(render(count ? metadata : listed([]), "text", deps));
190
+ output(wholeList("list", items));
225
191
  };
226
192
  const cfg = program.command("config").description("local Zoom configuration");
227
193
  cfg
228
194
  .command("show")
229
195
  .description("show local configuration")
230
196
  .action(() => {
231
- output(getConfig());
197
+ output(itemOf(getConfig()));
232
198
  });
233
199
  cfg
234
200
  .command("set")
@@ -236,7 +202,7 @@ export const createProgram = (deps) => {
236
202
  .argument("<key>", "setting name, such as account.profile")
237
203
  .argument("<value>", "new value")
238
204
  .action((key, value) => {
239
- output(setConfig(deps.configPath, key, value));
205
+ output(itemOf(setConfig(deps.configPath, key, value)));
240
206
  });
241
207
  let activeSource;
242
208
  const getSource = () => {
@@ -247,7 +213,7 @@ export const createProgram = (deps) => {
247
213
  if (config.source === "api")
248
214
  return new ZoomApiSource(tokens(), fetchWithSignal(deps.fetch));
249
215
  if (!config.filesFolder)
250
- throw new ZoomError("configuration_error", "set files.folder before pulling from files");
216
+ throw new CliError("configuration_error", "set files.folder before pulling from files");
251
217
  return new FilesSource(await (deps.readFiles ?? readDownloadedFiles)(config.filesFolder), config.filesTimezone);
252
218
  })();
253
219
  return activeSource;
@@ -294,10 +260,7 @@ export const createProgram = (deps) => {
294
260
  return validateDownloadedFiles(await (deps.readFiles ?? readDownloadedFiles)(folder), config.filesTimezone).map((file) => importFile(file, requireAccount(), config.filesTimezone));
295
261
  },
296
262
  now: deps.now,
297
- write: (value, format) => {
298
- const paged = typeof value === "object" && value !== null && "page" in value && typeof value.page === "object";
299
- buffer(render(value, format, deps, fields, paged, true, execution?.meta));
300
- },
263
+ write: (value) => output(bodyOf(value)),
301
264
  writeFile: deps.writeFile
302
265
  ? async (path, content) => {
303
266
  checkCancelled(signal());
@@ -306,10 +269,18 @@ export const createProgram = (deps) => {
306
269
  }
307
270
  : undefined,
308
271
  };
272
+ const before = new Set(program.commands);
309
273
  addMeetingCommands(program, meetingCommands);
274
+ const leaves = (command) => command.commands.length ? command.commands.flatMap(leaves) : [command];
275
+ // The meeting reads cli-core mounts read the store opened before their action; zoom's own commands open it lazily.
276
+ const storeCommands = new Set(program.commands.filter((group) => !before.has(group)).flatMap(leaves));
310
277
  addStandardCommands(program, {
311
278
  output,
312
- discovery: (value) => buffer(render(value, program.opts().json ? "json" : program.opts().jsonl ? "jsonl" : "text", deps, undefined, false, true)),
279
+ discovery: (value) => createRenderer({
280
+ format: formatOf(),
281
+ color: false,
282
+ streams: { data: (text) => buffer(`${text}\n`), diagnostic: deps.diagnostic },
283
+ }).result(value),
313
284
  fields: () => fields,
314
285
  raw: buffer,
315
286
  doctor: () => {
@@ -329,7 +300,7 @@ export const createProgram = (deps) => {
329
300
  return { configured: false, state: "not_configured", dataProfile: config.accountProfile, verified: false };
330
301
  if (check) {
331
302
  if (program.opts().offline)
332
- throw new ZoomError("configuration_error", "session verification requires network access; remove --offline");
303
+ throw new CliError("configuration_error", "session verification requires network access; remove --offline");
333
304
  api();
334
305
  return {
335
306
  configured: true,
@@ -353,7 +324,7 @@ export const createProgram = (deps) => {
353
324
  });
354
325
  const session = program.commands.find((command) => command.name() === "session");
355
326
  if (!session)
356
- throw new ZoomError("configuration_error", "session command group is unavailable");
327
+ throw new CliError("configuration_error", "session command group is unavailable");
357
328
  session
358
329
  .command("start")
359
330
  .description("log in to Zoom through your browser")
@@ -361,18 +332,18 @@ export const createProgram = (deps) => {
361
332
  .action(async (opts) => {
362
333
  const config = getConfig();
363
334
  if (!config.clientId)
364
- throw new ZoomError("configuration_error", "run zm config set zoom.clientId <Public Client ID> first");
335
+ throw new CliError("configuration_error", "run zm config set zoom.client_id <Public Client ID> first");
365
336
  const globals = program.opts();
366
337
  if (globals.offline)
367
- throw new ZoomError("configuration_error", "login requires network access; remove --offline");
338
+ throw new CliError("configuration_error", "login requires network access; remove --offline");
368
339
  const headless = deps.interactive === false ||
369
340
  Boolean(deps.env?.CI) ||
370
341
  (deps.interactive !== undefined &&
371
342
  (globals.json || globals.jsonl || deps.outputIsTTY === false) &&
372
343
  !globals.interactive);
373
344
  if (globals.input === false || headless)
374
- throw new ZoomError("configuration_error", "login requires browser approval; remove --no-input");
375
- output(await login({
345
+ throw new CliError("configuration_error", "login requires browser approval; remove --no-input");
346
+ output(itemOf(await login({
376
347
  tokens: tokens(),
377
348
  signal: signal(),
378
349
  openBrowser: (url) => deps.openBrowser(url, opts.browser),
@@ -381,13 +352,13 @@ export const createProgram = (deps) => {
381
352
  if (!program.opts().quiet)
382
353
  deps.diagnostic(`Open this URL to approve Zoom login:\n${url}\n`);
383
354
  },
384
- }));
355
+ })));
385
356
  });
386
357
  let watchConfig;
387
358
  let watchSince;
388
359
  const watchSleep = deps.sleep;
389
- const receipt = async (value) => {
390
- const text = render(value, program.opts().jsonl ? "jsonl" : program.opts().json ? "json" : "text", deps, fields, true, false, execution?.meta);
360
+ const receipt = async (body) => {
361
+ const text = rendered(body);
391
362
  const operation = signal();
392
363
  const grace = operation.aborted ? createDeadline({ timeoutMs: 1000 }) : undefined;
393
364
  try {
@@ -419,24 +390,24 @@ export const createProgram = (deps) => {
419
390
  };
420
391
  if (source === "files") {
421
392
  if (flags.sinceTime !== undefined || flags.lookbackDays !== undefined)
422
- throw new ZoomError("validation_error", "--since-time and --lookback-days apply only to API watching");
393
+ throw new CliError("validation_error", "--since-time and --lookback-days apply only to API watching");
423
394
  if (!plan.folder?.trim())
424
- throw new ZoomError("configuration_error", "set files.folder or provide a folder for file watching");
395
+ throw new CliError("configuration_error", "set files.folder or provide a folder for file watching");
425
396
  }
426
397
  else {
427
398
  if (folder !== undefined)
428
- throw new ZoomError("validation_error", "API watching does not accept a folder");
399
+ throw new CliError("validation_error", "API watching does not accept a folder");
429
400
  if (program.opts().offline)
430
- throw new ZoomError("configuration_error", "API watching requires network access; remove --offline");
401
+ throw new CliError("configuration_error", "API watching requires network access; remove --offline");
431
402
  if (!deps.source) {
432
403
  if (!config.clientId)
433
- throw new ZoomError("configuration_error", "run zm config set zoom.clientId <Public Client ID> first");
404
+ throw new CliError("configuration_error", "run zm config set zoom.client_id <Public Client ID> first");
434
405
  if (tokens().options.clientId !== config.clientId)
435
- throw new ZoomError("configuration_error", "the OAuth client changed before watch started; retry with matching configuration");
406
+ throw new CliError("configuration_error", "the OAuth client changed before watch started; retry with matching configuration");
436
407
  }
437
408
  }
438
409
  if (!deps.store && !config.accountProfile)
439
- throw new ZoomError("configuration_error", "select a local profile with zm config set account.profile <label>");
410
+ throw new CliError("configuration_error", "select a local profile with zm config set account.profile <label>");
440
411
  watchConfig = config;
441
412
  watchSince = plan.since;
442
413
  return plan;
@@ -445,33 +416,17 @@ export const createProgram = (deps) => {
445
416
  checkCancelled(operation);
446
417
  const config = watchConfig;
447
418
  if (!config)
448
- throw new ZoomError("configuration_error", "watch configuration is unavailable");
419
+ throw new CliError("configuration_error", "watch configuration is unavailable");
449
420
  let cycle;
450
421
  let failure;
451
422
  let result;
452
423
  try {
453
- if (!deps.store) {
454
- if (!deps.connectStore)
455
- return unavailable();
456
- if (!config.accountProfile)
457
- throw new ZoomError("configuration_error", "select a local profile with zm config set account.profile <label>");
458
- try {
459
- cycle = await deps.connectStore({
460
- profile: config.accountProfile,
461
- externalId: profileAccountKey(config.accountProfile),
462
- intent: "ingestion",
463
- });
464
- }
465
- catch (error) {
466
- if (isCliError(error))
467
- throw error;
468
- throw new ZoomError("configuration_error", "could not open the shared meeting store");
469
- }
470
- }
424
+ if (!deps.store)
425
+ cycle = await openStore("ingestion");
471
426
  checkCancelled(operation);
472
427
  const accountId = cycle?.accountId ?? deps.accountId;
473
428
  if (!Number.isSafeInteger(accountId) || !accountId || accountId < 1)
474
- throw new ZoomError("configuration_error", "the selected meeting account is unavailable");
429
+ throw new CliError("configuration_error", "the selected meeting account is unavailable");
475
430
  const store = guardedStore(cycle?.store ?? deps.store ?? unavailableStore);
476
431
  if (plan.source === "files") {
477
432
  const files = validateDownloadedFiles(await (deps.readFiles ?? readDownloadedFiles)(plan.folder ?? ""), config.filesTimezone);
@@ -543,7 +498,7 @@ export const createProgram = (deps) => {
543
498
  await cycle.close();
544
499
  }
545
500
  catch {
546
- failure ??= new ZoomError("configuration_error", "could not close the shared meeting store");
501
+ failure ??= new CliError("configuration_error", "could not close the shared meeting store");
547
502
  }
548
503
  }
549
504
  }
@@ -597,7 +552,7 @@ export const createProgram = (deps) => {
597
552
  if (dirname(deps.configPath) !== job.capture.configDir ||
598
553
  selected.accountProfile !== job.capture.profile ||
599
554
  selected.clientId !== job.capture.clientId)
600
- throw new ZoomError("configuration_error", "archive schedule requires its saved profile and Zoom client id; select those settings before running");
555
+ throw new CliError("configuration_error", "archive schedule requires its saved profile and Zoom client id; select those settings before running");
601
556
  return new ZoomRecordings(new TokenManager({
602
557
  clientId: job.capture.clientId,
603
558
  keyring: deps.tokens.options.keyring,
@@ -615,9 +570,9 @@ export const createProgram = (deps) => {
615
570
  capture: () => {
616
571
  const selected = getConfig();
617
572
  if (!selected.accountProfile || !selected.clientId)
618
- throw new ZoomError("configuration_error", "archive schedules require a configured local profile and Zoom client id");
573
+ throw new CliError("configuration_error", "archive schedules require a configured local profile and Zoom client id");
619
574
  if (!deps.recordingScheduleTarget)
620
- throw new ZoomError("configuration_error", "archive scheduler requires an explicit runtime and CLI path");
575
+ throw new CliError("configuration_error", "archive scheduler requires an explicit runtime and CLI path");
621
576
  return {
622
577
  profile: selected.accountProfile,
623
578
  clientId: selected.clientId,
@@ -634,220 +589,99 @@ export const createProgram = (deps) => {
634
589
  });
635
590
  addZoomSkillCommands(program, () => {
636
591
  const renderer = createRenderer({
637
- format: program.opts().json ? "json" : program.opts().jsonl ? "jsonl" : deps.outputIsTTY ? "pretty" : "json",
592
+ format: formatOf(),
638
593
  color: false,
639
594
  quiet: Boolean(program.opts().quiet),
640
595
  streams: { data: buffer, diagnostic: deps.diagnostic },
641
596
  });
642
597
  return {
643
- renderer: { ...renderer, result: output, stream: (items) => output({ items: [...items] }) },
598
+ renderer: {
599
+ ...renderer,
600
+ result: (value) => output(bodyOf(value)),
601
+ stream: (items) => output(wholeList("skill", [...items])),
602
+ },
644
603
  streams: { data: (text) => buffer(`${text}\n`), diagnostic: deps.diagnostic },
645
604
  env: deps.env,
646
605
  };
647
606
  });
648
- program
649
- .command("serve")
650
- .description("serve read-only meeting tools over MCP stdio")
651
- .requiredOption("--mcp", "use the MCP JSON-RPC protocol")
652
- .option("--unified-search", "include selected-profile meetings-only unified search")
653
- .option("--meeting-context", "include account-fixed evidence, person context and task proposals")
654
- .option("--semantic", "include read-only meeting vector search with an explicit query model")
655
- .option("--model <model>", "query embedding model: an installed one, or one served at --base-url")
656
- .option("--base-url <url>", "explicit remote embedding endpoint for semantic queries")
657
- .option("--dims <n>", "vector size the remote service returns, in dimensions", bytes)
658
- .action(async (options) => {
659
- const opts = program.opts();
660
- if (opts.json || opts.jsonl || opts.fields)
661
- throw new ZoomError("validation_error", "MCP stdio controls its own output; omit --json, --jsonl and --fields");
662
- if (!deps.serveMcp)
663
- throw new ZoomError("configuration_error", "the MCP server adapter is not available");
664
- if (options.semantic)
665
- validateMeetingModel({ model: options.model ?? "", baseUrl: options.baseUrl, dims: options.dims });
666
- else if (options.model !== undefined || options.baseUrl !== undefined || options.dims !== undefined)
667
- throw new ZoomError("validation_error", "MCP model options require --semantic");
668
- if (options.semantic && options.baseUrl !== undefined && opts.offline)
669
- throw new ZoomError("configuration_error", "remote embeddings require network access; remove --offline");
670
- await deps.serveMcp({
671
- commandRegistry: program,
672
- signal: signal(),
673
- maxResultBytes: program.opts().maxOutputBytes,
674
- ...(options.unifiedSearch ? { includeUnifiedSearch: true } : {}),
675
- ...(options.meetingContext ? { includeMeetingContext: true } : {}),
676
- ...(options.semantic
677
- ? { semanticModel: { model: options.model ?? "", baseUrl: options.baseUrl, dims: options.dims } }
678
- : {}),
679
- });
680
- });
607
+ const preparationOptions = {
608
+ credentials: () => {
609
+ api();
610
+ return tokens();
611
+ },
612
+ fetch: fetchWithSignal(deps.fetch),
613
+ remoteOptions,
614
+ };
615
+ addZoomMcpCommand(program, { fields: () => fields, signal, serve: deps.serveMcp, preparation: preparationOptions });
681
616
  addIngestionSearchCommands(program, {
682
617
  signal,
683
- output: (value) => buffer(render(value, program.opts().jsonl ? "jsonl" : program.opts().json ? "json" : "text", deps, fields, true, false, execution?.meta)),
618
+ output,
684
619
  outputItems,
685
620
  receipt,
686
621
  preflight: preflightArchiveImport,
687
622
  apply: async function* (plan) {
688
623
  if (plan.occurrences === 0)
689
624
  return;
690
- let store = deps.transcriptStore;
691
- let accountId = selectedAccountId;
692
- if (!store) {
693
- const config = getConfig();
694
- if (!config.accountProfile || !deps.connectStore)
695
- throw new ZoomError("configuration_error", "select a local profile with an available transcript append store");
696
- connection = await deps.connectStore({
697
- profile: config.accountProfile,
698
- externalId: profileAccountKey(config.accountProfile),
699
- intent: "ingestion",
700
- capability: "transcript-append",
701
- });
702
- accountId = connection.accountId;
703
- if (!connection.appendTranscripts && !connection.appendTranscriptsWithReceipt)
704
- throw new ZoomError("configuration_error", "the installed meeting store does not support transcript append");
705
- store = {
706
- appendTranscripts: connection.appendTranscripts,
707
- appendTranscriptsWithReceipt: connection.appendTranscriptsWithReceipt,
708
- };
709
- }
710
- for await (const item of applyArchiveImport(plan, store, {
711
- accountId: accountId ?? 0,
625
+ const connection = await connected("ingestion");
626
+ for await (const item of applyArchiveImport(plan, connection, {
627
+ accountId: connection.accountId,
712
628
  now: deps.now?.(),
713
629
  signal: signal(),
714
630
  }))
715
631
  yield item;
716
632
  },
717
- search: async (request) => {
718
- if (deps.unifiedSearch)
719
- return runUnifiedSearch(deps.unifiedSearch, request);
720
- const config = getConfig();
721
- if (!config.accountProfile || !deps.connectStore)
722
- throw new ZoomError("configuration_error", "select a stored local profile for unified search");
723
- connection = await deps.connectStore({
724
- profile: config.accountProfile,
725
- externalId: profileAccountKey(config.accountProfile),
726
- intent: "read",
727
- });
728
- if (!connection.unifiedSearch)
729
- throw new ZoomError("configuration_error", "unified search is unavailable in this store connector");
730
- return runUnifiedSearch(connection.unifiedSearch, request);
731
- },
633
+ search: async (request) => runUnifiedSearch((await connected()).unifiedSearch, request),
732
634
  });
733
- const integrationConnection = async (capability) => {
734
- const config = getConfig();
735
- if (!config.accountProfile || !deps.connectStore)
736
- throw new ZoomError("configuration_error", "select a stored local profile for meeting integration");
737
- connection = await deps.connectStore({
738
- profile: config.accountProfile,
739
- externalId: profileAccountKey(config.accountProfile),
740
- intent: "read",
741
- capability,
742
- });
743
- return connection;
744
- };
745
- const integrationOutput = (value) => buffer(render(value, program.opts().jsonl ? "jsonl" : program.opts().json ? "json" : "text", deps, fields, true, false, execution?.meta));
746
- addProjectEvidenceCommand(program, {
747
- read: deps.meetingProjectEvidence,
748
- connect: () => integrationConnection("meeting-project-evidence"),
749
- signal,
750
- now: deps.now,
751
- output: integrationOutput,
635
+ addMeetingReadBindings(program, {
636
+ project: {
637
+ read: async (project, request) => (await connected()).meetingProjectEvidence(project, request),
638
+ signal,
639
+ now: deps.now,
640
+ output: (value) => output(bodyOf(value)),
641
+ },
642
+ preparation: {
643
+ ...preparationOptions,
644
+ connect: () => openStore("read"),
645
+ },
752
646
  });
753
647
  addMeetingIntegrationCommands(program, {
754
648
  signal,
755
- output: integrationOutput,
649
+ output,
756
650
  receipt,
757
- integration: async () => {
758
- if (deps.meetingIntegration)
759
- return deps.meetingIntegration;
760
- const connected = await integrationConnection("meeting-integration");
761
- if (!connected.meetingIntegration)
762
- throw new ZoomError("configuration_error", "meeting integration is unavailable in this store connector");
763
- return connected.meetingIntegration;
764
- },
651
+ integration: async () => (await connected()).meetingIntegration,
765
652
  });
766
653
  addLocalTranscriptionCommands(program, {
767
654
  signal,
768
- output: integrationOutput,
655
+ output,
769
656
  receipt,
770
- capabilities: async () => {
771
- if (deps.meetingTranscription)
772
- return deps.meetingTranscription;
773
- const config = getConfig();
774
- if (!config.accountProfile || !deps.connectStore)
775
- throw new ZoomError("configuration_error", "select a stored local profile for transcription");
776
- connection = await deps.connectStore({
777
- profile: config.accountProfile,
778
- externalId: profileAccountKey(config.accountProfile),
779
- intent: "read",
780
- capability: "transcript-append",
781
- });
782
- if (!connection.meetingTranscription)
783
- throw new ZoomError("configuration_error", "local transcription is unavailable in this store connector");
784
- return connection.meetingTranscription;
785
- },
657
+ capabilities: async () => (await connected()).meetingTranscription,
786
658
  });
787
- const meetingContext = async () => {
788
- if (deps.meetingContext)
789
- return deps.meetingContext;
790
- const config = getConfig();
791
- if (!config.accountProfile || !deps.connectStore)
792
- throw new ZoomError("configuration_error", "select a stored local profile for meeting context");
793
- connection = await deps.connectStore({
794
- profile: config.accountProfile,
795
- externalId: profileAccountKey(config.accountProfile),
796
- intent: "read",
797
- });
798
- if (!connection.meetingContext)
799
- throw new ZoomError("configuration_error", "meeting context is unavailable in this store connector");
800
- return connection.meetingContext;
801
- };
659
+ const meetingContext = async () => (await connected()).meetingContext;
802
660
  addMeetingContextCommands(program, {
803
661
  signal,
804
- output: (value) => buffer(render(value, program.opts().jsonl ? "jsonl" : program.opts().json ? "json" : "text", deps, fields, true, false, execution?.meta)),
662
+ output,
805
663
  context: meetingContext,
806
664
  });
807
665
  addMeetingPassageCommand(program, {
808
666
  signal,
809
667
  read: async (reference, options) => {
810
668
  if (fields && options.format !== "json")
811
- throw new ZoomError("validation_error", "passage field selection requires --json or --format json");
812
- const context = await meetingContext();
813
- if (!context.passage)
814
- throw new ZoomError("configuration_error", "meeting passage is unavailable in this store connector");
815
- return context.passage(reference, options);
669
+ throw new CliError("validation_error", "passage field selection requires --json or --format json");
670
+ return (await meetingContext()).passage(reference, options);
816
671
  },
817
672
  output: (result, format) => {
818
673
  if (format === "json")
819
- buffer(render(result.packet, program.opts().jsonl ? "jsonl" : "json", deps, fields, true, false, execution?.meta));
674
+ buffer(rendered(bodyOf(result.packet), program.opts().jsonl ? "jsonl" : "json"));
820
675
  else
821
676
  buffer(result.content);
822
677
  },
823
678
  });
824
- const meetingSemantic = async () => {
825
- if (deps.meetingSemantic)
826
- return deps.meetingSemantic;
827
- const config = getConfig();
828
- if (!config.accountProfile || !deps.connectStore)
829
- throw new ZoomError("configuration_error", "select a stored local profile for meeting vectors");
830
- connection = await deps.connectStore({
831
- profile: config.accountProfile,
832
- externalId: profileAccountKey(config.accountProfile),
833
- intent: "read",
834
- });
835
- if (!connection.meetingSemantic)
836
- throw new ZoomError("configuration_error", "meeting vector capabilities are unavailable in this store connector");
837
- return connection.meetingSemantic;
838
- };
679
+ const meetingSemantic = async () => (await connected()).meetingSemantic;
839
680
  addMeetingSearchCommands(program, {
840
681
  signal,
841
682
  offline: () => Boolean(program.opts().offline),
842
- output: integrationOutput,
843
- words: async () => {
844
- if (deps.meetingSearch)
845
- return deps.meetingSearch;
846
- const connected = await integrationConnection("meeting-search");
847
- if (!connected.meetingSearch)
848
- throw new ZoomError("configuration_error", "meeting search is unavailable in this store connector");
849
- return connected.meetingSearch;
850
- },
683
+ output,
684
+ words: async () => (await connected()).meetingSearch,
851
685
  meaning: meetingSemantic,
852
686
  archive: (deps.archiveTranscripts ?? { search: searchArchiveTranscripts }).search,
853
687
  });
@@ -855,14 +689,14 @@ export const createProgram = (deps) => {
855
689
  signal,
856
690
  offline: () => Boolean(program.opts().offline),
857
691
  receipt,
858
- output: integrationOutput,
692
+ output,
859
693
  capabilities: meetingSemantic,
860
694
  });
861
695
  annotateMeetingCommands(program);
862
696
  const parseAsync = program.parseAsync.bind(program);
863
697
  program.parseAsync = async (...args) => {
864
698
  if (parsing)
865
- throw new ZoomError("validation_error", "concurrent command parsing is unavailable");
699
+ throw new CliError("validation_error", "concurrent command parsing is unavailable");
866
700
  resetCliOptions(program);
867
701
  parsing = true;
868
702
  answerExitCodes.set(program, 0);
@@ -872,11 +706,12 @@ export const createProgram = (deps) => {
872
706
  activeTokens = undefined;
873
707
  watchConfig = undefined;
874
708
  watchSince = undefined;
875
- fields = undefined;
709
+ const lifted = liftJsonFields(program, args);
710
+ fields = lifted.fields;
876
711
  let result = program;
877
712
  let failed = false;
878
713
  let failure;
879
- const running = parseAsync(...args);
714
+ const running = parseAsync(...lifted.args);
880
715
  void running.catch(() => { });
881
716
  try {
882
717
  const active = currentExecution();
@@ -888,18 +723,18 @@ export const createProgram = (deps) => {
888
723
  failure = error;
889
724
  }
890
725
  finally {
891
- if (connection) {
892
- const closing = connection;
893
- connection = undefined;
726
+ if (connecting) {
727
+ const closing = connecting;
728
+ connecting = undefined;
894
729
  selectedStore = deps.store;
895
730
  selectedAccountId = deps.accountId;
896
731
  try {
897
- await closing.close();
732
+ await (await closing.catch(() => undefined))?.close();
898
733
  }
899
734
  catch {
900
735
  if (!failed) {
901
736
  failed = true;
902
- failure = new ZoomError("configuration_error", "could not close the shared meeting store");
737
+ failure = new CliError("configuration_error", "could not close the shared meeting store");
903
738
  }
904
739
  }
905
740
  }
@@ -941,9 +776,9 @@ export const run = async (args, deps) => {
941
776
  const failure = isCliError(error)
942
777
  ? error
943
778
  : unknownOutcome
944
- ? new ZoomError("outcome_unknown", "operation outcome is unknown; verify stored state before retrying")
779
+ ? new CliError("outcome_unknown", "operation outcome is unknown; verify stored state before retrying")
945
780
  : error instanceof CommanderError
946
- ? new ZoomError("validation_error", "command failed; use --help for usage")
781
+ ? new CliError("validation_error", "command failed; use --help for usage")
947
782
  : error;
948
783
  const selected = commandSelection(program, args);
949
784
  return reportFailure(failure, args, deps, selected.path, hostFailureContext(program, metaOf(selected.action).effects));