@wirecat/zoom-cli 0.22.0 → 0.23.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 (87) hide show
  1. package/dist/answer-policy.d.ts +9 -0
  2. package/dist/answer-policy.d.ts.map +1 -1
  3. package/dist/answer-policy.js +30 -0
  4. package/dist/answer-policy.js.map +1 -1
  5. package/dist/api.d.ts +0 -1
  6. package/dist/api.d.ts.map +1 -1
  7. package/dist/api.js +44 -77
  8. package/dist/api.js.map +1 -1
  9. package/dist/archive-commands.d.ts +2 -1
  10. package/dist/archive-commands.d.ts.map +1 -1
  11. package/dist/archive-commands.js.map +1 -1
  12. package/dist/archive-transcripts.d.ts +1 -1
  13. package/dist/archive-transcripts.d.ts.map +1 -1
  14. package/dist/archive-transcripts.js +1 -1
  15. package/dist/archive-transcripts.js.map +1 -1
  16. package/dist/bin/main.js +5 -6
  17. package/dist/bin/main.js.map +1 -1
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/mcp-server.d.ts +1 -1
  23. package/dist/mcp-server.d.ts.map +1 -1
  24. package/dist/meeting-context.d.ts.map +1 -1
  25. package/dist/meeting-context.js +1 -2
  26. package/dist/meeting-context.js.map +1 -1
  27. package/dist/meeting-preparation-mcp.d.ts +86 -0
  28. package/dist/meeting-preparation-mcp.d.ts.map +1 -1
  29. package/dist/meeting-project-evidence-mcp.d.ts +1 -1
  30. package/dist/meeting-project-evidence-mcp.d.ts.map +1 -1
  31. package/dist/meeting-source.d.ts +15 -0
  32. package/dist/meeting-source.d.ts.map +1 -0
  33. package/dist/meeting-source.js +56 -0
  34. package/dist/meeting-source.js.map +1 -0
  35. package/dist/program.d.ts +4 -31
  36. package/dist/program.d.ts.map +1 -1
  37. package/dist/program.js +53 -510
  38. package/dist/program.js.map +1 -1
  39. package/dist/recording-archive.d.ts +1 -28
  40. package/dist/recording-archive.d.ts.map +1 -1
  41. package/dist/recording-archive.js +15 -248
  42. package/dist/recording-archive.js.map +1 -1
  43. package/dist/recording-manifest.d.ts +49 -0
  44. package/dist/recording-manifest.d.ts.map +1 -0
  45. package/dist/recording-manifest.js +183 -0
  46. package/dist/recording-manifest.js.map +1 -0
  47. package/dist/recording-promotion-store.d.ts +1 -1
  48. package/dist/recording-promotion-store.d.ts.map +1 -1
  49. package/dist/recording-schedule-setup.d.ts +16 -0
  50. package/dist/recording-schedule-setup.d.ts.map +1 -0
  51. package/dist/recording-schedule-setup.js +60 -0
  52. package/dist/recording-schedule-setup.js.map +1 -0
  53. package/dist/recording-schedule-store.d.ts.map +1 -1
  54. package/dist/recording-schedule-store.js +10 -24
  55. package/dist/recording-schedule-store.js.map +1 -1
  56. package/dist/recording-schedule-systemd.d.ts.map +1 -1
  57. package/dist/recording-schedule-systemd.js +2 -20
  58. package/dist/recording-schedule-systemd.js.map +1 -1
  59. package/dist/recording-sync-store.d.ts.map +1 -1
  60. package/dist/recording-sync-store.js +9 -23
  61. package/dist/recording-sync-store.js.map +1 -1
  62. package/dist/recordings.d.ts +4 -2
  63. package/dist/recordings.d.ts.map +1 -1
  64. package/dist/recordings.js +2 -1
  65. package/dist/recordings.js.map +1 -1
  66. package/dist/remote-http.d.ts +12 -0
  67. package/dist/remote-http.d.ts.map +1 -1
  68. package/dist/remote-http.js +43 -0
  69. package/dist/remote-http.js.map +1 -1
  70. package/dist/setup-commands.d.ts +26 -0
  71. package/dist/setup-commands.d.ts.map +1 -0
  72. package/dist/setup-commands.js +124 -0
  73. package/dist/setup-commands.js.map +1 -0
  74. package/dist/store-commands.d.ts +26 -0
  75. package/dist/store-commands.d.ts.map +1 -0
  76. package/dist/store-commands.js +130 -0
  77. package/dist/store-commands.js.map +1 -0
  78. package/dist/store-connection.d.ts +31 -1
  79. package/dist/store-connection.d.ts.map +1 -1
  80. package/dist/store-connection.js +33 -5
  81. package/dist/store-connection.js.map +1 -1
  82. package/dist/watch-service.d.ts +20 -0
  83. package/dist/watch-service.d.ts.map +1 -0
  84. package/dist/watch-service.js +148 -0
  85. package/dist/watch-service.js.map +1 -0
  86. package/package.json +3 -3
  87. package/skills/zoom-cli/SKILL.md +11 -2
package/dist/program.js CHANGED
@@ -1,63 +1,32 @@
1
- import { homedir } from "node:os";
2
- import { dirname, join } from "node:path";
3
- import { CliError, createDeadline, createOutputBuffer, createRenderer, errorObjectOf, errorRecordOf, exitCodeOfError, isCliError, projectFields, realSleep, renderError, } from "@wirecat/cli-base";
1
+ import { CliError, createDeadline, createOutputBuffer, createRenderer, isCliError, projectFields, } from "@wirecat/cli-base";
4
2
  import { metaOf } from "@wirecat/cli-base/commands";
5
- import { addMeetingBatchCommand, checkJson, formatMeetingBatch, itemOf, snakeKeys, } from "@wirecat/cli-core/cli";
6
- import { importFiles, pull, } from "@wirecat/cli-core/meetings";
7
- import { addMeetingCommands, addMeetingPassageCommand } from "@wirecat/cli-core/meetings/cli";
3
+ import { checkJson, snakeKeys } from "@wirecat/cli-core/cli";
4
+ import { addMeetingCommands } from "@wirecat/cli-core/meetings/cli";
8
5
  import { Command, CommanderError } from "commander";
9
6
  import { addZoomSkillCommands } from "./agent-skill.js";
10
7
  import { bodyOf, renderBody, wholeList } from "./answer-output.js";
11
- import { hostFailureContext } from "./answer-policy.js";
12
- import { ZoomApiSource } from "./api.js";
8
+ import { commandSelection, hostFailureContext, reportFailure } from "./answer-policy.js";
13
9
  import { addArchiveCommands, } from "./archive-commands.js";
14
- import { applyArchiveImport, preflightArchiveImport } from "./archive-import.js";
15
10
  import { readArchiveTranscripts, searchArchiveTranscripts } from "./archive-transcripts.js";
16
- import { addStandardCommands, annotateMeetingCommands } from "./commands.js";
17
- import { profileAccountKey, readConfig, setConfig } from "./config.js";
11
+ import { annotateMeetingCommands } from "./commands.js";
12
+ import { profileAccountKey, readConfig } from "./config.js";
18
13
  import { checkCancelled } from "./errors.js";
19
14
  import { bytes, duration, resetCliOptions, startExecution } from "./execution.js";
20
- import { FilesSource, importFile, readDownloadedFiles, validateDownloadedFiles } from "./files.js";
21
- import { addIngestionSearchCommands } from "./ingestion-search-commands.js";
15
+ import { importFile, readDownloadedFiles, validateDownloadedFiles } from "./files.js";
22
16
  import { liftJsonFields } from "./json-fields.js";
23
- import { addLocalTranscriptionCommands } from "./local-transcription-commands.js";
24
- import { login } from "./login.js";
25
- import { addMeetingContextCommands } from "./meeting-context-commands.js";
26
- import { addMeetingIntegrationCommands } from "./meeting-integration-commands.js";
27
17
  import { addZoomMcpCommand } from "./meeting-mcp-command.js";
28
- import { addMeetingReadBindings } from "./meeting-read-command-bindings.js";
29
- import { addMeetingSearchCommands } from "./meeting-search-commands.js";
30
- import { addMeetingEmbeddingCommand } from "./meeting-semantic-commands.js";
31
- import { createRecordingScheduleService } from "./recording-schedule.js";
18
+ import { configuredMeetingSource } from "./meeting-source.js";
32
19
  import { addRecordingScheduleCommands } from "./recording-schedule-commands.js";
33
- import { fileRecordingScheduleStore } from "./recording-schedule-store.js";
34
- import { createSystemdRecordingArchiveScheduler } from "./recording-schedule-systemd.js";
35
- import { getZoomProfile, inspectArchive, inspectArchiveLocks, recoverArchiveLocks, verifyArchive, ZoomRecordings, } from "./recordings.js";
20
+ import { zoomRecordingSchedule } from "./recording-schedule-setup.js";
21
+ import { inspectArchive, inspectArchiveLocks, recoverArchiveLocks, verifyArchive, ZoomRecordings, } from "./recordings.js";
36
22
  import { ZoomRemoteMeetings } from "./remote-meetings.js";
23
+ import { addConfigCommands, addSessionCommands } from "./setup-commands.js";
24
+ import { addStoreCommands } from "./store-commands.js";
25
+ import { connectSelectedProfile, storeUnavailable, unavailableStore, } from "./store-connection.js";
37
26
  import { emitReceipt } from "./streaming.js";
38
- import { TokenManager } from "./tokens.js";
39
- import { runUnifiedSearch } from "./unified-search.js";
40
27
  import { VERSION } from "./version.js";
41
28
  import { addWatchCommand } from "./watch-commands.js";
42
- const unavailable = async () => {
43
- throw new CliError("configuration_error", "the shared SQLite meeting store is not available yet");
44
- };
45
- const unavailableStore = {
46
- saveMeeting: unavailable,
47
- account: unavailable,
48
- meetings: unavailable,
49
- meeting: unavailable,
50
- participants: unavailable,
51
- search: unavailable,
52
- events: unavailable,
53
- eventCandidates: unavailable,
54
- createEvent: unavailable,
55
- createEventSeries: unavailable,
56
- setEventSeries: unavailable,
57
- linkMeeting: unavailable,
58
- cursor: unavailable,
59
- setCursor: unavailable,
60
- };
29
+ import { createWatchService } from "./watch-service.js";
61
30
  const answerExitCodes = new WeakMap();
62
31
  export const createProgram = (deps) => {
63
32
  let config;
@@ -107,12 +76,10 @@ export const createProgram = (deps) => {
107
76
  };
108
77
  const openStore = async (intent) => {
109
78
  if (!deps.connectStore)
110
- return unavailable();
79
+ return storeUnavailable();
111
80
  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
81
  try {
115
- return await deps.connectStore({ profile, externalId: profileAccountKey(profile), intent });
82
+ return await connectSelectedProfile(deps.connectStore, profile, intent);
116
83
  }
117
84
  catch (error) {
118
85
  if (isCliError(error))
@@ -189,64 +156,14 @@ export const createProgram = (deps) => {
189
156
  }
190
157
  output(wholeList("list", items));
191
158
  };
192
- const cfg = program.command("config").description("local Zoom configuration");
193
- cfg
194
- .command("show")
195
- .description("show local configuration")
196
- .action(() => {
197
- output(itemOf(getConfig()));
198
- });
199
- cfg
200
- .command("set")
201
- .description("set a configuration value")
202
- .argument("<key>", "setting name, such as account.profile")
203
- .argument("<value>", "new value")
204
- .action((key, value) => {
205
- output(itemOf(setConfig(deps.configPath, key, value)));
159
+ addConfigCommands(program, { configPath: deps.configPath, getConfig, output });
160
+ const configured = configuredMeetingSource({
161
+ deps,
162
+ getConfig,
163
+ tokens,
164
+ fetch: () => fetchWithSignal(deps.fetch),
206
165
  });
207
- let activeSource;
208
- const getSource = () => {
209
- if (deps.source)
210
- return Promise.resolve(deps.source);
211
- activeSource ??= (async () => {
212
- const config = getConfig();
213
- if (config.source === "api")
214
- return new ZoomApiSource(tokens(), fetchWithSignal(deps.fetch));
215
- if (!config.filesFolder)
216
- throw new CliError("configuration_error", "set files.folder before pulling from files");
217
- return new FilesSource(await (deps.readFiles ?? readDownloadedFiles)(config.filesFolder), config.filesTimezone);
218
- })();
219
- return activeSource;
220
- };
221
- const source = {
222
- get provider() {
223
- return deps.source?.provider ?? "zoom";
224
- },
225
- get name() {
226
- return deps.source?.name ?? (getConfig().source === "api" ? "api" : "file");
227
- },
228
- get transcriptFormat() {
229
- return deps.source ? deps.source.transcriptFormat : "vtt";
230
- },
231
- async meetings(since) {
232
- return (await getSource()).meetings(since);
233
- },
234
- async participants(id) {
235
- return (await getSource()).participants(id);
236
- },
237
- async transcript(id) {
238
- return (await getSource()).transcript(id);
239
- },
240
- async chat(id) {
241
- return (await getSource()).chat(id);
242
- },
243
- async summary(id) {
244
- return (await getSource()).summary(id);
245
- },
246
- async files(id) {
247
- return (await getSource()).files(id);
248
- },
249
- };
166
+ const source = configured.source;
250
167
  const meetingCommands = {
251
168
  get store() {
252
169
  return guardedStore(selectedStore ?? unavailableStore);
@@ -274,104 +191,28 @@ export const createProgram = (deps) => {
274
191
  const leaves = (command) => command.commands.length ? command.commands.flatMap(leaves) : [command];
275
192
  // The meeting reads cli-core mounts read the store opened before their action; zoom's own commands open it lazily.
276
193
  const storeCommands = new Set(program.commands.filter((group) => !before.has(group)).flatMap(leaves));
277
- addStandardCommands(program, {
194
+ addSessionCommands(program, {
195
+ deps,
196
+ getConfig,
278
197
  output,
279
- discovery: (value) => createRenderer({
280
- format: formatOf(),
281
- color: false,
282
- streams: { data: (text) => buffer(`${text}\n`), diagnostic: deps.diagnostic },
283
- }).result(value),
198
+ buffer,
199
+ formatOf,
284
200
  fields: () => fields,
285
- raw: buffer,
286
- doctor: () => {
287
- let config;
288
- try {
289
- config = getConfig();
290
- }
291
- catch (error) {
292
- if (!isCliError(error))
293
- throw error;
294
- return {
295
- version: VERSION,
296
- runtime: { node: process.versions.node },
297
- config: { readable: false, path: deps.configPath, error: error.message },
298
- dataProfile: null,
299
- authentication: { configured: null, state: "not_checked" },
300
- database: "not_checked",
301
- };
302
- }
303
- return {
304
- version: VERSION,
305
- runtime: { node: process.versions.node },
306
- config: { readable: true, path: deps.configPath, source: config.source },
307
- dataProfile: config.accountProfile,
308
- authentication: { configured: config.clientId !== null, state: "not_checked" },
309
- database: "not_checked",
310
- };
311
- },
312
- sessionStatus: async (check) => {
313
- const config = getConfig();
314
- if (!config.clientId)
315
- return { configured: false, state: "not_configured", dataProfile: config.accountProfile, verified: false };
316
- if (check) {
317
- if (program.opts().offline)
318
- throw new CliError("configuration_error", "session verification requires network access; remove --offline");
319
- api();
320
- return {
321
- configured: true,
322
- state: "verified",
323
- dataProfile: config.accountProfile,
324
- verified: true,
325
- profile: await (deps.checkSession
326
- ? deps.checkSession({ signal: signal() })
327
- : getZoomProfile(tokens(), fetchWithSignal(deps.fetch), { signal: signal() })),
328
- };
329
- }
330
- const saved = deps.tokens.load();
331
- return {
332
- configured: true,
333
- state: saved ? (saved.expiresAt > (deps.now?.() ?? Date.now()) ? "saved" : "expired") : "missing",
334
- dataProfile: config.accountProfile,
335
- verified: false,
336
- ...(saved ? { expiresAt: saved.expiresAt, scopes: saved.scopes } : {}),
337
- };
338
- },
339
- });
340
- const session = program.commands.find((command) => command.name() === "session");
341
- if (!session)
342
- throw new CliError("configuration_error", "session command group is unavailable");
343
- session
344
- .command("start")
345
- .description("log in to Zoom through your browser")
346
- .option("--browser <program>", "browser program")
347
- .action(async (opts) => {
348
- const config = getConfig();
349
- if (!config.clientId)
350
- throw new CliError("configuration_error", "run zm config set zoom.client_id <Public Client ID> first");
351
- const globals = program.opts();
352
- if (globals.offline)
353
- throw new CliError("configuration_error", "login requires network access; remove --offline");
354
- const headless = deps.interactive === false ||
355
- Boolean(deps.env?.CI) ||
356
- (deps.interactive !== undefined &&
357
- (globals.json || globals.jsonl || deps.outputIsTTY === false) &&
358
- !globals.interactive);
359
- if (globals.input === false || headless)
360
- throw new CliError("configuration_error", "login requires browser approval; remove --no-input");
361
- output(itemOf(await login({
362
- tokens: tokens(),
363
- signal: signal(),
364
- openBrowser: (url) => deps.openBrowser(url, opts.browser),
365
- readPaste: deps.readPaste,
366
- showUrl: (url) => {
367
- if (!program.opts().quiet)
368
- deps.diagnostic(`Open this URL to approve Zoom login:\n${url}\n`);
369
- },
370
- })));
201
+ api,
202
+ tokens,
203
+ fetch: () => fetchWithSignal(deps.fetch),
204
+ signal,
371
205
  });
372
- let watchConfig;
373
- let watchSince;
374
206
  const watchSleep = deps.sleep;
207
+ const watch = createWatchService({
208
+ deps,
209
+ getConfig,
210
+ tokens,
211
+ fetch: () => fetchWithSignal(deps.fetch),
212
+ offline: () => Boolean(program.opts().offline),
213
+ openStore,
214
+ guardedStore,
215
+ });
375
216
  const receipt = async (body) => {
376
217
  const text = rendered(body);
377
218
  const operation = signal();
@@ -393,136 +234,8 @@ export const createProgram = (deps) => {
393
234
  receipt,
394
235
  outputIsTTY: deps.outputIsTTY,
395
236
  sleep: watchSleep ? (ms, abort) => watchSleep(ms, abort, "retry") : undefined,
396
- prepare: (target, folder, flags) => {
397
- const config = { ...getConfig() };
398
- const source = target ?? config.source;
399
- const plan = {
400
- source,
401
- since: flags.sinceTime,
402
- lookbackDays: flags.lookbackDays ?? 0,
403
- intervalMs: flags.pause,
404
- folder: folder ?? config.filesFolder ?? undefined,
405
- };
406
- if (source === "files") {
407
- if (flags.sinceTime !== undefined || flags.lookbackDays !== undefined)
408
- throw new CliError("validation_error", "--since-time and --lookback-days apply only to API watching");
409
- if (!plan.folder?.trim())
410
- throw new CliError("configuration_error", "set files.folder or provide a folder for file watching");
411
- }
412
- else {
413
- if (folder !== undefined)
414
- throw new CliError("validation_error", "API watching does not accept a folder");
415
- if (program.opts().offline)
416
- throw new CliError("configuration_error", "API watching requires network access; remove --offline");
417
- if (!deps.source) {
418
- if (!config.clientId)
419
- throw new CliError("configuration_error", "run zm config set zoom.client_id <Public Client ID> first");
420
- if (tokens().options.clientId !== config.clientId)
421
- throw new CliError("configuration_error", "the OAuth client changed before watch started; retry with matching configuration");
422
- }
423
- }
424
- if (!deps.store && !config.accountProfile)
425
- throw new CliError("configuration_error", "select a local profile with zm config set account.profile <label>");
426
- watchConfig = config;
427
- watchSince = plan.since;
428
- return plan;
429
- },
430
- ingest: async (plan, operation) => {
431
- checkCancelled(operation);
432
- const config = watchConfig;
433
- if (!config)
434
- throw new CliError("configuration_error", "watch configuration is unavailable");
435
- let cycle;
436
- let failure;
437
- let result;
438
- try {
439
- if (!deps.store)
440
- cycle = await openStore("ingestion");
441
- checkCancelled(operation);
442
- const accountId = cycle?.accountId ?? deps.accountId;
443
- if (!Number.isSafeInteger(accountId) || !accountId || accountId < 1)
444
- throw new CliError("configuration_error", "the selected meeting account is unavailable");
445
- const store = guardedStore(cycle?.store ?? deps.store ?? unavailableStore);
446
- if (plan.source === "files") {
447
- const files = validateDownloadedFiles(await (deps.readFiles ?? readDownloadedFiles)(plan.folder ?? ""), config.filesTimezone);
448
- checkCancelled(operation);
449
- result = await importFiles(files.map((file) => importFile(file, accountId, config.filesTimezone)), store, deps.now?.());
450
- }
451
- else {
452
- const original = deps.source ??
453
- new ZoomApiSource(tokens(), fetchWithSignal(deps.fetch), {
454
- now: deps.now,
455
- sleep: (ms, abort) => (deps.sleep ?? realSleep)(ms, AbortSignal.any([operation, abort]), "retry"),
456
- });
457
- let sourceFailure;
458
- const source = new Proxy(original, {
459
- get(target, key, receiver) {
460
- const method = Reflect.get(target, key, receiver);
461
- return typeof method === "function"
462
- ? async (...args) => {
463
- if (sourceFailure)
464
- throw sourceFailure;
465
- checkCancelled(operation);
466
- try {
467
- const value = await method.apply(target, args);
468
- checkCancelled(operation);
469
- return value;
470
- }
471
- catch (error) {
472
- if (isCliError(error) && error.code === "outcome_unknown") {
473
- sourceFailure = error;
474
- throw error;
475
- }
476
- checkCancelled(operation);
477
- throw error;
478
- }
479
- }
480
- : method;
481
- },
482
- });
483
- let cursorAdvanced = false;
484
- const trackingStore = new Proxy(store, {
485
- get(target, key, receiver) {
486
- if (key === "setCursor")
487
- return async (...args) => {
488
- await target.setCursor(...args);
489
- cursorAdvanced = true;
490
- };
491
- return Reflect.get(target, key, receiver);
492
- },
493
- });
494
- result = await pull(source, trackingStore, {
495
- accountId,
496
- since: watchSince,
497
- lookbackMs: plan.lookbackDays * 86400000,
498
- now: deps.now?.(),
499
- });
500
- if (sourceFailure)
501
- throw sourceFailure;
502
- checkCancelled(operation);
503
- if (cursorAdvanced)
504
- watchSince = undefined;
505
- }
506
- }
507
- catch (error) {
508
- failure = error;
509
- }
510
- finally {
511
- if (cycle) {
512
- try {
513
- await cycle.close();
514
- }
515
- catch {
516
- failure ??= new CliError("configuration_error", "could not close the shared meeting store");
517
- }
518
- }
519
- }
520
- if (failure)
521
- throw failure;
522
- if (!result)
523
- return unavailable();
524
- return result;
525
- },
237
+ prepare: watch.prepare,
238
+ ingest: watch.ingest,
526
239
  });
527
240
  const retrySleep = deps.sleep;
528
241
  const remoteOptions = {
@@ -551,52 +264,8 @@ export const createProgram = (deps) => {
551
264
  recover: recoverArchiveLocks,
552
265
  },
553
266
  });
554
- let recordingSchedule = deps.recordingSchedule;
555
267
  addRecordingScheduleCommands(program, {
556
- service: () => {
557
- if (!recordingSchedule) {
558
- const env = deps.env ?? process.env;
559
- const configDir = dirname(deps.configPath);
560
- recordingSchedule = createRecordingScheduleService({
561
- store: fileRecordingScheduleStore(join(configDir, "recording-schedules")),
562
- backend: createSystemdRecordingArchiveScheduler({
563
- unitDirectory: join(env.XDG_CONFIG_HOME ?? join(env.HOME ?? homedir(), ".config"), "systemd", "user"),
564
- }),
565
- recordings: (job) => {
566
- const selected = readConfig(deps.configPath);
567
- if (dirname(deps.configPath) !== job.capture.configDir ||
568
- selected.accountProfile !== job.capture.profile ||
569
- selected.clientId !== job.capture.clientId)
570
- throw new CliError("configuration_error", "archive schedule requires its saved profile and Zoom client id; select those settings before running");
571
- return new ZoomRecordings(new TokenManager({
572
- clientId: job.capture.clientId,
573
- keyring: deps.tokens.options.keyring,
574
- service: `zoom-cli:${job.capture.configDir}`,
575
- fetch: fetchWithSignal(deps.tokens.options.fetch),
576
- now: deps.now,
577
- signal: signal(),
578
- log: deps.tokens.options.log,
579
- }), fetchWithSignal(deps.fetch), remoteOptions);
580
- },
581
- now: deps.now,
582
- });
583
- }
584
- return recordingSchedule;
585
- },
586
- capture: () => {
587
- const selected = getConfig();
588
- if (!selected.accountProfile || !selected.clientId)
589
- throw new CliError("configuration_error", "archive schedules require a configured local profile and Zoom client id");
590
- if (!deps.recordingScheduleTarget)
591
- throw new CliError("configuration_error", "archive scheduler requires an explicit runtime and CLI path");
592
- return {
593
- profile: selected.accountProfile,
594
- clientId: selected.clientId,
595
- configDir: dirname(deps.configPath),
596
- runtime: deps.recordingScheduleTarget.runtime,
597
- cliPath: deps.recordingScheduleTarget.cliPath,
598
- };
599
- },
268
+ ...zoomRecordingSchedule({ deps, getConfig, withSignal: fetchWithSignal, signal, remoteOptions }),
600
269
  offline: () => Boolean(program.opts().offline),
601
270
  signal,
602
271
  output,
@@ -629,120 +298,23 @@ export const createProgram = (deps) => {
629
298
  remoteOptions,
630
299
  };
631
300
  addZoomMcpCommand(program, { fields: () => fields, signal, serve: deps.serveMcp, preparation: preparationOptions });
632
- addIngestionSearchCommands(program, {
301
+ addStoreCommands(program, {
302
+ deps,
303
+ connected,
304
+ openStore,
305
+ preparation: preparationOptions,
633
306
  signal,
634
307
  output,
635
308
  outputItems,
636
309
  receipt,
637
- preflight: preflightArchiveImport,
638
- apply: async function* (plan) {
639
- if (plan.occurrences === 0)
640
- return;
641
- const connection = await connected("ingestion");
642
- for await (const item of applyArchiveImport(plan, connection, {
643
- accountId: connection.accountId,
644
- now: deps.now?.(),
645
- signal: signal(),
646
- }))
647
- yield item;
648
- },
649
- search: async (request) => runUnifiedSearch((await connected()).unifiedSearch, request),
650
- });
651
- addMeetingReadBindings(program, {
652
- project: {
653
- read: async (project, request) => (await connected()).meetingProjectEvidence(project, request),
654
- signal,
655
- now: deps.now,
656
- output: (value) => output(bodyOf(value)),
657
- },
658
- preparation: {
659
- ...preparationOptions,
660
- connect: () => openStore("read"),
661
- },
662
- });
663
- addMeetingIntegrationCommands(program, {
664
- signal,
665
- output,
666
- receipt,
667
- integration: async () => (await connected()).meetingIntegration,
668
- });
669
- addLocalTranscriptionCommands(program, {
670
- signal,
671
- output,
672
- receipt,
673
- capabilities: async () => (await connected()).meetingTranscription,
674
- });
675
- const meetingContext = async () => (await connected()).meetingContext;
676
- addMeetingContextCommands(program, {
677
- signal,
678
- output,
679
- context: meetingContext,
680
- });
681
- addMeetingPassageCommand(program, {
682
- signal,
683
- read: async (reference, options) => {
684
- if (fields && options.format !== "json")
685
- throw new CliError("validation_error", "passage field selection requires --json or --format json");
686
- return (await meetingContext()).passage(reference, options);
687
- },
688
- output: (result, format) => {
689
- if (format === "json")
690
- buffer(rendered(bodyOf(result.packet), program.opts().jsonl ? "jsonl" : "json"));
691
- else
692
- buffer(result.content);
693
- },
694
- });
695
- const meetingSemantic = async () => (await connected()).meetingSemantic;
696
- addMeetingSearchCommands(program, {
697
- signal,
698
- offline: () => Boolean(program.opts().offline),
699
- output,
700
- words: async () => (await connected()).meetingSearch,
701
- meaning: meetingSemantic,
702
- archive: (deps.archiveTranscripts ?? { search: searchArchiveTranscripts }).search,
703
- });
704
- addMeetingEmbeddingCommand(program, {
705
- signal,
706
- offline: () => Boolean(program.opts().offline),
707
- receipt,
708
- output,
709
- capabilities: meetingSemantic,
710
- });
711
- const batchReader = async () => {
712
- const reader = (await connected()).meetingBatch;
713
- if (!reader)
714
- throw new CliError("configuration_error", "the selected store connector does not support meeting batches");
715
- return reader;
716
- };
717
- addMeetingBatchCommand(program, {
718
- signal,
310
+ buffer,
311
+ rendered,
719
312
  fields: () => fields,
720
313
  meta: () => {
721
314
  if (!execution)
722
315
  throw new CliError("configuration_error", "command execution is not initialized");
723
316
  return execution.meta();
724
317
  },
725
- input: async (path, signal) => {
726
- if (!deps.readBatchInput)
727
- throw new CliError("configuration_error", "batch input reader is unavailable");
728
- return deps.readBatchInput(path, signal);
729
- },
730
- reader: {
731
- index: async (options) => (await batchReader()).index(options),
732
- search: async (query, options) => (await batchReader()).search(query, options),
733
- passage: async (reference, options) => (await batchReader()).passage(reference, options),
734
- },
735
- output: (body, report, format) => {
736
- const text = format === "json"
737
- ? rendered(body, program.opts().jsonl ? "jsonl" : "json", false)
738
- : formatMeetingBatch(report, format);
739
- if (Buffer.byteLength(text, "utf8") > 4194304)
740
- throw new CliError("invalid_response", "batch rendered output exceeds 4194304 bytes", {
741
- reason: "output.too-large",
742
- max_bytes: 4194304,
743
- });
744
- buffer(text);
745
- },
746
318
  });
747
319
  annotateMeetingCommands(program);
748
320
  const parseAsync = program.parseAsync.bind(program);
@@ -753,11 +325,10 @@ export const createProgram = (deps) => {
753
325
  parsing = true;
754
326
  answerExitCodes.set(program, 0);
755
327
  config = undefined;
756
- activeSource = undefined;
328
+ configured.reset();
757
329
  execution = undefined;
758
330
  activeTokens = undefined;
759
- watchConfig = undefined;
760
- watchSince = undefined;
331
+ watch.reset();
761
332
  const lifted = liftJsonFields(program, args);
762
333
  fields = lifted.fields;
763
334
  let result = program;
@@ -836,32 +407,4 @@ export const run = async (args, deps) => {
836
407
  return reportFailure(failure, args, deps, selected.path, hostFailureContext(program, metaOf(selected.action).effects));
837
408
  }
838
409
  };
839
- export const reportFailure = (failure, args, deps, command = "zm", context = hostFailureContext()) => {
840
- const end = args.indexOf("--");
841
- const flags = args.slice(0, end < 0 ? undefined : end);
842
- const machine = flags.some((word) => word === "--json" || word === "--jsonl");
843
- const object = errorObjectOf(failure, context);
844
- const record = flags.includes("--debug")
845
- ? errorRecordOf(failure, object, { command, service: "zm", version: VERSION })
846
- : undefined;
847
- const interactive = deps.outputIsTTY === true && !machine;
848
- deps.diagnostic(`${renderError(object, { cli: "zm", interactive, ...(record ? { record } : {}) })}\n`);
849
- return exitCodeOfError(object);
850
- };
851
- const commandSelection = (program, args) => {
852
- const words = [];
853
- let current = program;
854
- for (const word of args) {
855
- if (word === "--")
856
- break;
857
- if (word.startsWith("-"))
858
- continue;
859
- const next = current.commands.find((command) => command.name() === word || command.aliases().includes(word));
860
- if (!next)
861
- break;
862
- words.push(word);
863
- current = next;
864
- }
865
- return { path: words.length ? words.join(" ") : "zm", action: current };
866
- };
867
410
  //# sourceMappingURL=program.js.map